U8ThirtyPartyDatabaseServerService.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. <?php
  2. namespace App\Service;
  3. use Illuminate\Support\Facades\DB;
  4. use Illuminate\Support\Facades\Log;
  5. class U8ThirtyPartyDatabaseServerService extends Service
  6. {
  7. protected $connectionName = 'u8_third_sqlserver';
  8. /**
  9. * 获取一个具备“自愈”功能的数据库连接
  10. * 解决 Windows 环境下远程主机强迫关闭连接 (08S02) 的问题
  11. */
  12. private function safeDb()
  13. {
  14. $conn = DB::connection($this->connectionName);
  15. try {
  16. // 心跳探测:执行一个极轻量的查询
  17. $conn->getPdo()->query('SELECT 1');
  18. } catch (\Throwable $e) {
  19. // 捕获到任何连接异常(如 08S02 / 08001)
  20. Log::channel('apiLog')->warning("U8连接丢失,正在尝试重连...", [
  21. 'msg' => $e->getMessage()
  22. ]);
  23. // 彻底销毁旧连接句柄
  24. $conn->disconnect();
  25. DB::purge($this->connectionName);
  26. // 重新获取新连接
  27. $conn = DB::connection($this->connectionName);
  28. }
  29. return $conn;
  30. }
  31. // Service 内部查询
  32. public function getPendingBills($config, $lastId)
  33. {
  34. try {
  35. $db = $this->safeDb();
  36. $mainTable = $config['main'];
  37. $detailTable = $config['detail'];
  38. $mainKey = $config['main_key'];
  39. $foreignKey = $config['key'];
  40. $whereRaw = $config['whereRaw'];
  41. $main_field = $config['main_field'];
  42. $son_field = $config['son_field'];
  43. $limit = $config['limit'];
  44. // 1. 获取主表
  45. $mainRows = $db->table($mainTable)
  46. ->lock('WITH(NOLOCK)')
  47. ->where($mainKey, '>', $lastId) // 改用 ID
  48. ->whereRaw($whereRaw)
  49. ->select($main_field)
  50. ->orderBy($mainKey, 'ASC') // 按 ID 排序保证分页连续
  51. ->limit($limit)
  52. ->get();
  53. if ($mainRows->isEmpty()) return [true, []];
  54. if (empty($foreignKey) || empty($son_field)) {
  55. $array = $mainRows->map(function ($item) {
  56. return (array) $item;
  57. })->toArray();
  58. return [true, $array];
  59. }
  60. // 2. 批量获取子表
  61. $mainIds = $mainRows->pluck('id')->toArray();
  62. $details = $db->table($detailTable. ' as detail')
  63. ->lock('WITH(NOLOCK)')
  64. ->whereIn($foreignKey, $mainIds)
  65. ->select($son_field)
  66. ->addSelect(DB::raw("ROW_NUMBER() OVER(PARTITION BY detail.{$foreignKey} ORDER BY detail.AutoID) as lineNum"))
  67. ->get()
  68. ->groupBy('id');
  69. // 3. 组合
  70. $result = $mainRows->map(function($main) use ($details, $foreignKey) {
  71. $res = (array)$main;
  72. $mainId = $res['id'];
  73. $res['details'] = isset($details[$mainId])
  74. ? $details[$mainId]->map(function($item) {
  75. return (array)$item; // 强制把子表对象转成数组
  76. })->values()->toArray()
  77. : [];
  78. return $res;
  79. })->toArray();
  80. return [true, $result];
  81. } catch (\Throwable $e) {
  82. return [false, $e->getMessage()];
  83. }
  84. }
  85. public function getArrivalVouchById($orderId)
  86. {
  87. try {
  88. $db = $this->safeDb();
  89. // 1. 获取主表 (PU_ArrivalVouch) 并关联 采购类型表 (PurchaseType)
  90. $main = $db->table('PU_ArrivalVouch as main')
  91. ->leftJoin('PurchaseType as pt', 'main.cPTCode', '=', 'pt.cPTCode') // 关联采购类型表
  92. ->lock('WITH(NOLOCK)')
  93. ->where('main.ID', $orderId)
  94. ->select([
  95. 'main.ID as id',
  96. 'main.cCode as no',
  97. 'main.cVenCode as supply_code',
  98. 'main.cDepCode as depart_code',
  99. 'main.dDate as order_date',
  100. 'main.cBusType as b_type',
  101. 'main.cPTCode as cg_type',
  102. 'pt.cRdCode as rd_code'
  103. ])
  104. ->first();
  105. if (!$main) return [false, '采购退货单数据不存在'];
  106. $order = (array)$main;
  107. // 2. 获取子表 (PU_ArrivalVouchs)
  108. $details = $db->table('PU_ArrivalVouchs as detail')
  109. ->lock('WITH(NOLOCK)')
  110. ->where('ID', $orderId) // 子表里的 ID 关联主表的 ID
  111. ->select([
  112. 'detail.cInvCode',
  113. 'detail.iQuantity',
  114. 'detail.iQuantity as iNNum',
  115. 'detail.iinvexchrate',
  116. 'detail.cBatch',
  117. 'detail.dPDate',
  118. 'detail.dVDate',
  119. 'detail.Autoid as iArrsId',
  120. 'detail.ivouchrowno as iRowNo',
  121. 'detail.iOriTaxCost',
  122. 'detail.iTaxRate',
  123. // 'detail.cordercode',
  124. 'detail.cWhCode',
  125. ])
  126. ->orderBy('detail.ivouchrowno', 'ASC') // 按 U8 原始行号排序
  127. ->get();
  128. // 3. 组合数据并返回
  129. $order['details'] = $details->map(function ($item) {
  130. return (array)$item;
  131. })->toArray();
  132. return [true, $order];
  133. }catch (\Throwable $e) {
  134. return [false, $e->getMessage()];
  135. }
  136. }
  137. public function getInventoryData($config, $lastCode = null)
  138. {
  139. try {
  140. $db = $this->safeDb();
  141. $query = $db->table('Inventory as main')
  142. ->leftJoin('InventoryClass as sub', 'main.cInvCCode', '=', 'sub.cInvCCode')
  143. ->leftJoin('ComputationUnit as unit', 'main.cComUnitCode', '=', 'unit.cComUnitCode')
  144. ->select([
  145. 'main.cInvCode as product_code',
  146. 'main.cInvName as product_name',
  147. 'main.cInvStd as product_size',
  148. 'main.cInvCCode as product_category_code',
  149. 'sub.cInvCName as product_category_name', // 直接联查分类名
  150. 'main.cComUnitCode as product_unit',
  151. 'unit.cComUnitName as product_unit_title',
  152. // 'main.fOutExcess as out_limit',
  153. // 'main.cCurrencyName as common_name',
  154. 'main.fGrossW as grossWeight',
  155. 'main.bFree1 as param_one',
  156. 'main.bFree2 as param_two',
  157. 'main.bInvBatch as param_three',
  158. 'main.bInvQuality as param_four',
  159. // 关键点:将二进制 ufts 转换为 0x... 字符串
  160. DB::raw("master.sys.fn_varbintohexstr(main.pubufts) as ufts_str")
  161. ]);
  162. // 使用 product_code 做分页依据
  163. if ($lastCode) {
  164. $query->where('main.cInvCode', '>', $lastCode);
  165. }
  166. if (!empty($config['whereRaw'])) {
  167. $query->whereRaw($config['whereRaw']);
  168. }
  169. // 必须按编码排序,保证分页不重不漏
  170. $items = $query->orderBy('main.cInvCode', 'asc')
  171. ->limit($config['limit'])
  172. ->get();
  173. return [true, json_decode(json_encode($items), true)];
  174. } catch (\Throwable $e) {
  175. return [false, $e->getMessage()];
  176. }
  177. }
  178. //获取单个产品报检单的明细
  179. public function getBjOrder($id){
  180. try {
  181. $db = $this->safeDb();
  182. $array = $db->table('QMINSPECTVOUCHERS as detail')
  183. ->lock('WITH(NOLOCK)')
  184. ->where('detail.ID', $id)
  185. ->select('detail.*')
  186. ->get()
  187. ->map(function ($value) {
  188. return (array)$value;
  189. })
  190. ->keyBy('CINVCODE')
  191. ->toArray();
  192. return [true, $array];
  193. } catch (\Throwable $e) {
  194. return [false, $e->getMessage()];
  195. }
  196. }
  197. public function getJyOrder($id)
  198. {
  199. try {
  200. $db = $this->safeDb();
  201. // 1. 获取表头信息 (主表)
  202. $main = $db->table('QMCHECKVOUCHER')
  203. ->lock('WITH(NOLOCK)')
  204. ->where('ID', $id)
  205. ->first();
  206. if (!$main) return [false, '检验单不存在'];
  207. $main = (array)$main;
  208. return [true, $main];
  209. } catch (\Throwable $e) {
  210. return [false, $e->getMessage()];
  211. }
  212. }
  213. public function getScDetails($id)
  214. {
  215. try {
  216. $db = $this->safeDb();
  217. // 1. 获取表头信息 (主表)
  218. $main = $db->table('mom_orderdetail')
  219. ->lock('WITH(NOLOCK)')
  220. ->where('MoDid', $id)
  221. ->first();
  222. if (!$main) {
  223. return [false, '生成订单明细不存在']; // 或者返回空数组 []
  224. }
  225. $main = (array)$main;
  226. return [true, $main];
  227. } catch (\Throwable $e) {
  228. return [false, $e->getMessage()];
  229. }
  230. }
  231. //获取单个销售订单的信息
  232. public function getXsOrder($id)
  233. {
  234. try {
  235. $db = $this->safeDb();
  236. // 1. 获取销售订单主表信息 (SO_SOMain)
  237. $main = $db->table('SO_SOMain')
  238. ->lock('WITH(NOLOCK)')
  239. ->where('ID', $id)
  240. ->first();
  241. if (!$main) {
  242. return [false, '销售订单不存在'];
  243. }
  244. $main = (array)$main;
  245. // 2. 获取销售订单子表信息 (SO_SODetails)
  246. $details = $db->table('SO_SODetails')
  247. ->lock('WITH(NOLOCK)')
  248. ->where('ID', $id) // 子表通过 ID 关联主表
  249. ->get()
  250. ->map(function ($value) {
  251. return (array)$value;
  252. })
  253. ->toArray();
  254. // 3. 将子表数据放入 details 键中
  255. $main['details'] = $details;
  256. return [true, $main];
  257. } catch (\Throwable $e) {
  258. return [false, $e->getMessage()];
  259. }
  260. }
  261. public function getXsThOrder($id)
  262. {
  263. try {
  264. $db = $this->safeDb();
  265. // 1. 获取销售退货单主表信息 (DispatchList)
  266. $main = $db->table('DispatchList')
  267. ->lock('WITH(NOLOCK)')
  268. ->where('DLID', $id) // 注意:主键叫 DLID
  269. ->first();
  270. if (!$main) {
  271. return [false, '销售退货单不存在'];
  272. }
  273. $main = (array)$main;
  274. // 2. 获取销售退货单子表信息 (DispatchLists)
  275. $details =$db->table('DispatchLists')
  276. ->lock('WITH(NOLOCK)')
  277. ->where('DLID', $id) // 通过 DLID 关联
  278. ->get()
  279. ->map(function ($value) {
  280. return (array)$value;
  281. })
  282. ->toArray();
  283. // 3. 将子表数据放入 details 键中
  284. $main['details'] = $details;
  285. return [true, $main];
  286. } catch (\Throwable $e) {
  287. return [false, $e->getMessage()];
  288. }
  289. }
  290. public function getFhOrder($id)
  291. {
  292. try {
  293. $db = $this->safeDb();
  294. // 1. 获取销售发货单主表信息 (DispatchList)
  295. $main = $db->table('DispatchList')
  296. ->lock('WITH(NOLOCK)')
  297. ->where('DLID', $id) // U8发货单主键通常是 DLID
  298. ->first();
  299. if (!$main) {
  300. return [false, '销售发货单不存在'];
  301. }
  302. $main = (array)$main;
  303. // 2. 获取销售发货单子表信息 (DispatchLists)
  304. $details = $db->table('DispatchLists') // 注意这里是 DispatchLists
  305. ->lock('WITH(NOLOCK)')
  306. ->where('DLID', $id) // 子表通过 DLID 关联主表
  307. ->get()
  308. ->map(function ($value) {
  309. return (array)$value;
  310. })
  311. ->toArray();
  312. // 3. 将子表数据放入 details 键中
  313. $main['details'] = $details;
  314. return [true, $main];
  315. } catch (\Throwable $e) {
  316. return [false, $e->getMessage()];
  317. }
  318. }
  319. public function getCGDHDetails($id)
  320. {
  321. try {
  322. $db = $this->safeDb();
  323. // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
  324. $details = $db->table('PU_ArrivalVouchs')
  325. ->lock('WITH(NOLOCK)')
  326. ->where('ID', $id) // 通过 ID 关联主表
  327. ->get()
  328. ->map(function ($value) {
  329. return (array)$value;
  330. });
  331. // 3. 将子表数据以 cInvCode 为 Key 进行组织
  332. // 注意:如果一张单据里有重复的存货编码,后面的行会覆盖前面的行
  333. $details = $details->keyBy('cInvCode')->toArray();
  334. return [true, $details];
  335. } catch (\Throwable $e) {
  336. return [false, $e->getMessage()];
  337. }
  338. }
  339. public function getLlSQDetails($id)
  340. {
  341. try {
  342. $db = $this->safeDb();
  343. // 1. 获取领料申请单子表信息 (MaterialAppVouchs)
  344. $details = $db->table('MaterialAppVouchs') // 领料申请单子表名
  345. ->lock('WITH(NOLOCK)')
  346. ->where('ID', $id) // 通过 ID 关联主表
  347. ->get()
  348. ->map(function ($value) {
  349. return (array)$value;
  350. });
  351. // 2. 将子表数据以 cInvCode 为 Key 进行组织
  352. // 提示:领料申请单中同一存货可能出现在不同行(如:对应不同的生产订单行)
  353. // 如果确定 cInvCode 唯一,可用 keyBy;如果不唯一,建议直接返回数组或 keyBy('AutoID')
  354. $details = $details->keyBy('cInvCode')->toArray();
  355. return [true, $details];
  356. } catch (\Throwable $e) {
  357. return [false, $e->getMessage()];
  358. }
  359. }
  360. public function updateDhOrder($update, $insert)
  361. {
  362. try {
  363. // 1. 先通过心跳探测获取一个可靠的连接
  364. $db = $this->safeDb();
  365. return $db->transaction(function () use ($update, $insert,$db) {
  366. // 1. 处理更新部分 (子表: PU_ArrivalVouchs)
  367. if (!empty($update)) {
  368. foreach ($update as $autoId => $fields) {
  369. $db->table('PU_ArrivalVouchs') // 修正为子表名
  370. ->where('Autoid', $autoId) // U8 习惯大写 A 小写 utoid,但 SQL 不敏感
  371. ->update($fields);
  372. }
  373. }
  374. // 2. 处理插入部分 (拆分行)
  375. if (!empty($insert)) {
  376. $mainId = $insert[0]['ID'] ?? null;
  377. if ($mainId) {
  378. // 获取全表最大 Autoid,确保全局唯一
  379. $maxRowID = $db->table('PU_ArrivalVouchs') // 修正为子表名
  380. ->max('Autoid') ?? 0;
  381. foreach ($insert as &$newRow) {
  382. $maxRowID++;
  383. $newRow['Autoid'] = $maxRowID;
  384. }
  385. // 使用批量插入
  386. $db->table('PU_ArrivalVouchs')
  387. ->insert($insert);
  388. }
  389. }
  390. return [true, '']; // 事务成功返回
  391. });
  392. } catch (\Throwable $e) {
  393. // 打印错误堆栈有助于调试
  394. return [false, "修改采购到货单失败: " . $e->getMessage()];
  395. }
  396. }
  397. public function getCgOrder($id)
  398. {
  399. try {
  400. $db = $this->safeDb();
  401. // 1. 获取采购到货单主表信息 (PU_ArrivalVouch)
  402. // 关键:关联键是 ID
  403. $main = $db->table('PU_ArrivalVouch')
  404. ->lock('WITH(NOLOCK)')
  405. ->where('ID', $id)
  406. ->first();
  407. if (!$main) {
  408. return [false, '采购到货单不存在'];
  409. }
  410. $main = (array)$main;
  411. // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
  412. $details = $db->table('PU_ArrivalVouchs')
  413. ->lock('WITH(NOLOCK)')
  414. ->where('ID', $id) // 子表通过 ID 关联主表
  415. ->get()
  416. ->map(function ($value) {
  417. return (array)$value;
  418. })
  419. ->toArray();
  420. // 3. 将子表数据放入 details 键中
  421. $main['details'] = $details;
  422. return [true, $main];
  423. } catch (\Throwable $e) {
  424. return [false, $e->getMessage()];
  425. }
  426. }
  427. public function getJyOrder2($id)
  428. {
  429. try {
  430. $db = $this->safeDb();
  431. // 关联采购到货单子表 (PU_ArrivalVouchs) 获取金额字段
  432. $order = $db->table('QMCHECKVOUCHER as qm')
  433. ->leftJoin('PU_ArrivalVouchs as arr', 'qm.SOURCEAUTOID', '=', 'arr.Autoid')
  434. ->select(
  435. 'qm.*',
  436. 'arr.iCost', // 原币无税单价
  437. 'arr.iOriTaxCost', // 原币含税单价
  438. 'arr.iTaxRate' // 税率
  439. )
  440. ->where('qm.ID', $id) // 假设这是检验单主表ID
  441. ->first();
  442. return [true, $order ? (array)$order : []];
  443. } catch (\Throwable $e) {
  444. return [false, $e->getMessage()];
  445. }
  446. }
  447. public function updateLLOrder($update, $insert)
  448. {
  449. try {
  450. $db = $this->safeDb();
  451. return $db->transaction(function () use ($update, $insert, $db) {
  452. // 1. 处理更新部分 (子表: MaterialAppVouchs)
  453. if (!empty($update)) {
  454. foreach ($update as $autoId => $fields) {
  455. $db->table('MaterialAppVouchs') // 领料申请单子表
  456. ->where('autoid', $autoId) // 注意字段名在 U8 里可能是 autoid 或 AutoID
  457. ->update($fields);
  458. }
  459. }
  460. // 2. 处理插入部分 (拆分行/新增行)
  461. if (!empty($insert)) {
  462. // 获取当前领料申请单子表的最大 Autoid,确保手动分配不冲突
  463. $maxRowID = $db->table('MaterialAppVouchs')
  464. ->max('autoid') ?? 0;
  465. foreach ($insert as &$newRow) {
  466. $maxRowID++;
  467. // U8 的 autoid 通常必须手动指定
  468. $newRow['autoid'] = $maxRowID;
  469. }
  470. // 使用批量插入
  471. $db->table('MaterialAppVouchs')
  472. ->insert($insert);
  473. }
  474. return [true, ''];
  475. });
  476. } catch (\Throwable $e) {
  477. // 建议记录详细日志
  478. return [false, "修改领料申请单失败: " . $e->getMessage()];
  479. }
  480. }
  481. public function getLLOrder($id)
  482. {
  483. try {
  484. $db = $this->safeDb();
  485. // 关键:关联键是 ID
  486. $main = $db->table('MaterialAppVouch')
  487. ->lock('WITH(NOLOCK)')
  488. ->where('ID', $id)
  489. ->first();
  490. if (!$main) {
  491. return [false, '领料单不存在'];
  492. }
  493. $main = (array)$main;
  494. // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
  495. $details = $db->table('MaterialAppVouchs')
  496. ->lock('WITH(NOLOCK)')
  497. ->where('ID', $id) // 子表通过 ID 关联主表
  498. ->get()
  499. ->map(function ($value) {
  500. return (array)$value;
  501. })
  502. ->toArray();
  503. // 3. 将子表数据放入 details 键中
  504. $main['details'] = $details;
  505. return [true, $main];
  506. } catch (\Throwable $e) {
  507. return [false, $e->getMessage()];
  508. }
  509. }
  510. public function checkInventoryControl($invCodes)
  511. {
  512. try {
  513. $db = $this->safeDb();
  514. if (empty($invCodes)) {
  515. return [false, '存货编码为空'];
  516. }
  517. // 1. 查询存货档案
  518. $list = $db->table('Inventory')
  519. ->whereIn('cInvCode', $invCodes)
  520. ->select(['cInvCode', 'cInvName', 'bInvBatch', 'bInvQuality'])
  521. ->get();
  522. $noBatch = []; // 未开启批次管理的
  523. $noExpiration = []; // 未开启保质期管理的
  524. $notFound = array_diff($invCodes, $list->pluck('cInvCode')->toArray()); // 数据库中不存在的
  525. foreach ($list as $item) {
  526. // 检查批次管理 (bInvBatch 为 0 表示未开启)
  527. if (empty($item->bInvBatch)) {
  528. $noBatch[] = $item->cInvCode . '(' . $item->cInvName . ')';
  529. }
  530. // 检查保质期管理 (bInvQuality 为 0 表示未开启)
  531. if (empty($item->bInvQuality)) {
  532. $noExpiration[] = $item->cInvCode . '(' . $item->cInvName . ')';
  533. }
  534. }
  535. // 2. 组织提示结果
  536. $messages = [];
  537. if (!empty($noBatch)) {
  538. $messages[] = "【未开启批次管理】: " . implode(', ', $noBatch);
  539. }
  540. if (!empty($noExpiration)) {
  541. $messages[] = "【未开启保质期管理】: " . implode(', ', $noExpiration);
  542. }
  543. if (!empty($notFound)) {
  544. $messages[] = "【档案不存在】: " . implode(', ', $notFound);
  545. }
  546. if (empty($messages)) {
  547. return [true, ''];
  548. }
  549. return [false, implode("\n", $messages)];
  550. } catch (\Throwable $e) {
  551. return [false, $e->getMessage()];
  552. }
  553. }
  554. public function rebuildDhDetails($mainId, $insertData)
  555. {
  556. try {
  557. $db = $this->safeDb();
  558. return $db->transaction(function () use ($mainId, $insertData,$db) {
  559. // 1. 删除旧明细
  560. $db->table('PU_ArrivalVouchs')
  561. ->where('ID', $mainId)
  562. ->delete();
  563. // 2. 获取新的起始 Autoid
  564. $maxAutoid = $db->table('PU_ArrivalVouchs')
  565. ->max('Autoid') ?? 0;
  566. // 3. 分配新 Autoid 并插入
  567. foreach ($insertData as &$row) {
  568. $maxAutoid++;
  569. $row['Autoid'] = $maxAutoid;
  570. }
  571. $db->table('PU_ArrivalVouchs')
  572. ->insert($insertData);
  573. return [true, ''];
  574. });
  575. } catch (\Throwable $e) {
  576. return [false, "重建明细失败: " . $e->getMessage()];
  577. }
  578. }
  579. public function rebuildLLDetails($mainId, $insertData)
  580. {
  581. try {
  582. $db = $this->safeDb();
  583. return $db->transaction(function () use ($mainId, $insertData,$db) {
  584. // 1. 删除旧明细 (领料申请单子表)
  585. $db->table('MaterialAppVouchs')
  586. ->where('ID', $mainId)
  587. ->delete();
  588. // 2. 获取新的起始 autoid
  589. $maxAutoid = $db->table('MaterialAppVouchs')
  590. ->max('AutoID') ?? 0;
  591. // 3. 分配新 autoid 并插入
  592. foreach ($insertData as &$row) {
  593. $maxAutoid++;
  594. $row['AutoID'] = $maxAutoid;
  595. }
  596. $db->table('MaterialAppVouchs')
  597. ->insert($insertData);
  598. return [true, ''];
  599. });
  600. } catch (\Throwable $e) {
  601. return [false, "重组领料申请单失败: " . $e->getMessage()];
  602. }
  603. }
  604. public function rebuildBjDetails($mainId, $insertData)
  605. {
  606. try {
  607. $db = $this->safeDb();
  608. return $db->transaction(function () use ($mainId, $insertData, $db) {
  609. // 1. 删除旧明细
  610. $db->table('QMINSPECTVOUCHERS')
  611. ->where('ID', $mainId)
  612. ->delete();
  613. $maxAutoid = $db->table('QMINSPECTVOUCHERS')
  614. ->max('Autoid') ?? 0;
  615. // 过滤掉不可插入的字段,特别是 UFTS
  616. foreach ($insertData as $key => $row) {
  617. $maxAutoid++;
  618. // 彻底清理:移除 UFTS 字段,防止插入报错及 JSON 转换报错
  619. unset($row['UFTS']);
  620. $row['Autoid'] = $maxAutoid;
  621. $insertData[$key] = $row;
  622. }
  623. // 4. 批量插入
  624. $db->table('QMINSPECTVOUCHERS')
  625. ->insert($insertData);
  626. return [true, '操作成功'];
  627. });
  628. } catch (\Throwable $e) {
  629. // 这里返回错误信息时,确保不包含二进制内容
  630. return [false, "重组报检单失败: " . $e->getMessage()];
  631. }
  632. }
  633. }