U8ThirtyPartyDatabaseServerService.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  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. // 关键点:将二进制 ufts 转换为 0x... 字符串
  158. DB::raw("master.sys.fn_varbintohexstr(main.pubufts) as ufts_str")
  159. ]);
  160. // 使用 product_code 做分页依据
  161. if ($lastCode) {
  162. $query->where('main.cInvCode', '>', $lastCode);
  163. }
  164. if (!empty($config['whereRaw'])) {
  165. $query->whereRaw($config['whereRaw']);
  166. }
  167. // 必须按编码排序,保证分页不重不漏
  168. $items = $query->orderBy('main.cInvCode', 'asc')
  169. ->limit($config['limit'])
  170. ->get();
  171. return [true, json_decode(json_encode($items), true)];
  172. } catch (\Throwable $e) {
  173. return [false, $e->getMessage()];
  174. }
  175. }
  176. //获取单个产品报检单的明细
  177. public function getBjOrder($id){
  178. try {
  179. $db = $this->safeDb();
  180. $array = $db->table('QMINSPECTVOUCHERS as detail')
  181. ->lock('WITH(NOLOCK)')
  182. ->where('detail.ID', $id)
  183. ->select('detail.*')
  184. ->get()
  185. ->map(function ($value) {
  186. return (array)$value;
  187. })
  188. ->keyBy('CINVCODE')
  189. ->toArray();
  190. return [true, $array];
  191. } catch (\Throwable $e) {
  192. return [false, $e->getMessage()];
  193. }
  194. }
  195. public function getJyOrder($id)
  196. {
  197. try {
  198. $db = $this->safeDb();
  199. // 1. 获取表头信息 (主表)
  200. $main = $db->table('QMCHECKVOUCHER')
  201. ->lock('WITH(NOLOCK)')
  202. ->where('ID', $id)
  203. ->first();
  204. if (!$main) return [false, '检验单不存在'];
  205. $main = (array)$main;
  206. return [true, $main];
  207. } catch (\Throwable $e) {
  208. return [false, $e->getMessage()];
  209. }
  210. }
  211. public function getScDetails($id)
  212. {
  213. try {
  214. $db = $this->safeDb();
  215. // 1. 获取表头信息 (主表)
  216. $main = $db->table('mom_orderdetail')
  217. ->lock('WITH(NOLOCK)')
  218. ->where('MoDid', $id)
  219. ->first();
  220. if (!$main) {
  221. return [false, '生成订单明细不存在']; // 或者返回空数组 []
  222. }
  223. $main = (array)$main;
  224. return [true, $main];
  225. } catch (\Throwable $e) {
  226. return [false, $e->getMessage()];
  227. }
  228. }
  229. //获取单个销售订单的信息
  230. public function getXsOrder($id)
  231. {
  232. try {
  233. $db = $this->safeDb();
  234. // 1. 获取销售订单主表信息 (SO_SOMain)
  235. $main = $db->table('SO_SOMain')
  236. ->lock('WITH(NOLOCK)')
  237. ->where('ID', $id)
  238. ->first();
  239. if (!$main) {
  240. return [false, '销售订单不存在'];
  241. }
  242. $main = (array)$main;
  243. // 2. 获取销售订单子表信息 (SO_SODetails)
  244. $details = $db->table('SO_SODetails')
  245. ->lock('WITH(NOLOCK)')
  246. ->where('ID', $id) // 子表通过 ID 关联主表
  247. ->get()
  248. ->map(function ($value) {
  249. return (array)$value;
  250. })
  251. ->toArray();
  252. // 3. 将子表数据放入 details 键中
  253. $main['details'] = $details;
  254. return [true, $main];
  255. } catch (\Throwable $e) {
  256. return [false, $e->getMessage()];
  257. }
  258. }
  259. public function getXsThOrder($id)
  260. {
  261. try {
  262. $db = $this->safeDb();
  263. // 1. 获取销售退货单主表信息 (DispatchList)
  264. $main = $db->table('DispatchList')
  265. ->lock('WITH(NOLOCK)')
  266. ->where('DLID', $id) // 注意:主键叫 DLID
  267. ->first();
  268. if (!$main) {
  269. return [false, '销售退货单不存在'];
  270. }
  271. $main = (array)$main;
  272. // 2. 获取销售退货单子表信息 (DispatchLists)
  273. $details =$db->table('DispatchLists')
  274. ->lock('WITH(NOLOCK)')
  275. ->where('DLID', $id) // 通过 DLID 关联
  276. ->get()
  277. ->map(function ($value) {
  278. return (array)$value;
  279. })
  280. ->toArray();
  281. // 3. 将子表数据放入 details 键中
  282. $main['details'] = $details;
  283. return [true, $main];
  284. } catch (\Throwable $e) {
  285. return [false, $e->getMessage()];
  286. }
  287. }
  288. public function getFhOrder($id)
  289. {
  290. try {
  291. $db = $this->safeDb();
  292. // 1. 获取销售发货单主表信息 (DispatchList)
  293. $main = $db->table('DispatchList')
  294. ->lock('WITH(NOLOCK)')
  295. ->where('DLID', $id) // U8发货单主键通常是 DLID
  296. ->first();
  297. if (!$main) {
  298. return [false, '销售发货单不存在'];
  299. }
  300. $main = (array)$main;
  301. // 2. 获取销售发货单子表信息 (DispatchLists)
  302. $details = $db->table('DispatchLists') // 注意这里是 DispatchLists
  303. ->lock('WITH(NOLOCK)')
  304. ->where('DLID', $id) // 子表通过 DLID 关联主表
  305. ->get()
  306. ->map(function ($value) {
  307. return (array)$value;
  308. })
  309. ->toArray();
  310. // 3. 将子表数据放入 details 键中
  311. $main['details'] = $details;
  312. return [true, $main];
  313. } catch (\Throwable $e) {
  314. return [false, $e->getMessage()];
  315. }
  316. }
  317. public function getCGDHDetails($id)
  318. {
  319. try {
  320. $db = $this->safeDb();
  321. // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
  322. $details = $db->table('PU_ArrivalVouchs')
  323. ->lock('WITH(NOLOCK)')
  324. ->where('ID', $id) // 通过 ID 关联主表
  325. ->get()
  326. ->map(function ($value) {
  327. return (array)$value;
  328. });
  329. // 3. 将子表数据以 cInvCode 为 Key 进行组织
  330. // 注意:如果一张单据里有重复的存货编码,后面的行会覆盖前面的行
  331. $details = $details->keyBy('cInvCode')->toArray();
  332. return [true, $details];
  333. } catch (\Throwable $e) {
  334. return [false, $e->getMessage()];
  335. }
  336. }
  337. public function getLlSQDetails($id)
  338. {
  339. try {
  340. $db = $this->safeDb();
  341. // 1. 获取领料申请单子表信息 (MaterialAppVouchs)
  342. $details = $db->table('MaterialAppVouchs') // 领料申请单子表名
  343. ->lock('WITH(NOLOCK)')
  344. ->where('ID', $id) // 通过 ID 关联主表
  345. ->get()
  346. ->map(function ($value) {
  347. return (array)$value;
  348. });
  349. // 2. 将子表数据以 cInvCode 为 Key 进行组织
  350. // 提示:领料申请单中同一存货可能出现在不同行(如:对应不同的生产订单行)
  351. // 如果确定 cInvCode 唯一,可用 keyBy;如果不唯一,建议直接返回数组或 keyBy('AutoID')
  352. $details = $details->keyBy('cInvCode')->toArray();
  353. return [true, $details];
  354. } catch (\Throwable $e) {
  355. return [false, $e->getMessage()];
  356. }
  357. }
  358. public function updateDhOrder($update, $insert)
  359. {
  360. try {
  361. // 1. 先通过心跳探测获取一个可靠的连接
  362. $db = $this->safeDb();
  363. return $db->transaction(function () use ($update, $insert,$db) {
  364. // 1. 处理更新部分 (子表: PU_ArrivalVouchs)
  365. if (!empty($update)) {
  366. foreach ($update as $autoId => $fields) {
  367. $db->table('PU_ArrivalVouchs') // 修正为子表名
  368. ->where('Autoid', $autoId) // U8 习惯大写 A 小写 utoid,但 SQL 不敏感
  369. ->update($fields);
  370. }
  371. }
  372. // 2. 处理插入部分 (拆分行)
  373. if (!empty($insert)) {
  374. $mainId = $insert[0]['ID'] ?? null;
  375. if ($mainId) {
  376. // 获取全表最大 Autoid,确保全局唯一
  377. $maxRowID = $db->table('PU_ArrivalVouchs') // 修正为子表名
  378. ->max('Autoid') ?? 0;
  379. foreach ($insert as &$newRow) {
  380. $maxRowID++;
  381. $newRow['Autoid'] = $maxRowID;
  382. }
  383. // 使用批量插入
  384. $db->table('PU_ArrivalVouchs')
  385. ->insert($insert);
  386. }
  387. }
  388. return [true, '']; // 事务成功返回
  389. });
  390. } catch (\Throwable $e) {
  391. // 打印错误堆栈有助于调试
  392. return [false, "修改采购到货单失败: " . $e->getMessage()];
  393. }
  394. }
  395. public function getCgOrder($id)
  396. {
  397. try {
  398. $db = $this->safeDb();
  399. // 1. 获取采购到货单主表信息 (PU_ArrivalVouch)
  400. // 关键:关联键是 ID
  401. $main = $db->table('PU_ArrivalVouch')
  402. ->lock('WITH(NOLOCK)')
  403. ->where('ID', $id)
  404. ->first();
  405. if (!$main) {
  406. return [false, '采购到货单不存在'];
  407. }
  408. $main = (array)$main;
  409. // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
  410. $details = $db->table('PU_ArrivalVouchs')
  411. ->lock('WITH(NOLOCK)')
  412. ->where('ID', $id) // 子表通过 ID 关联主表
  413. ->get()
  414. ->map(function ($value) {
  415. return (array)$value;
  416. })
  417. ->toArray();
  418. // 3. 将子表数据放入 details 键中
  419. $main['details'] = $details;
  420. return [true, $main];
  421. } catch (\Throwable $e) {
  422. return [false, $e->getMessage()];
  423. }
  424. }
  425. public function getJyOrder2($id)
  426. {
  427. try {
  428. $db = $this->safeDb();
  429. // 关联采购到货单子表 (PU_ArrivalVouchs) 获取金额字段
  430. $order = $db->table('QMCHECKVOUCHER as qm')
  431. ->leftJoin('PU_ArrivalVouchs as arr', 'qm.SOURCEAUTOID', '=', 'arr.Autoid')
  432. ->select(
  433. 'qm.*',
  434. 'arr.iCost', // 原币无税单价
  435. 'arr.iOriTaxCost', // 原币含税单价
  436. 'arr.iTaxRate' // 税率
  437. )
  438. ->where('qm.ID', $id) // 假设这是检验单主表ID
  439. ->first();
  440. return [true, $order ? (array)$order : []];
  441. } catch (\Throwable $e) {
  442. return [false, $e->getMessage()];
  443. }
  444. }
  445. public function updateLLOrder($update, $insert)
  446. {
  447. try {
  448. $db = $this->safeDb();
  449. return $db->transaction(function () use ($update, $insert, $db) {
  450. // 1. 处理更新部分 (子表: MaterialAppVouchs)
  451. if (!empty($update)) {
  452. foreach ($update as $autoId => $fields) {
  453. $db->table('MaterialAppVouchs') // 领料申请单子表
  454. ->where('autoid', $autoId) // 注意字段名在 U8 里可能是 autoid 或 AutoID
  455. ->update($fields);
  456. }
  457. }
  458. // 2. 处理插入部分 (拆分行/新增行)
  459. if (!empty($insert)) {
  460. // 获取当前领料申请单子表的最大 Autoid,确保手动分配不冲突
  461. $maxRowID = $db->table('MaterialAppVouchs')
  462. ->max('autoid') ?? 0;
  463. foreach ($insert as &$newRow) {
  464. $maxRowID++;
  465. // U8 的 autoid 通常必须手动指定
  466. $newRow['autoid'] = $maxRowID;
  467. }
  468. // 使用批量插入
  469. $db->table('MaterialAppVouchs')
  470. ->insert($insert);
  471. }
  472. return [true, ''];
  473. });
  474. } catch (\Throwable $e) {
  475. // 建议记录详细日志
  476. return [false, "修改领料申请单失败: " . $e->getMessage()];
  477. }
  478. }
  479. public function getLLOrder($id)
  480. {
  481. try {
  482. $db = $this->safeDb();
  483. // 关键:关联键是 ID
  484. $main = $db->table('MaterialAppVouch')
  485. ->lock('WITH(NOLOCK)')
  486. ->where('ID', $id)
  487. ->first();
  488. if (!$main) {
  489. return [false, '领料单不存在'];
  490. }
  491. $main = (array)$main;
  492. // 2. 获取采购到货单子表信息 (PU_ArrivalVouchs)
  493. $details = $db->table('MaterialAppVouchs')
  494. ->lock('WITH(NOLOCK)')
  495. ->where('ID', $id) // 子表通过 ID 关联主表
  496. ->get()
  497. ->map(function ($value) {
  498. return (array)$value;
  499. })
  500. ->toArray();
  501. // 3. 将子表数据放入 details 键中
  502. $main['details'] = $details;
  503. return [true, $main];
  504. } catch (\Throwable $e) {
  505. return [false, $e->getMessage()];
  506. }
  507. }
  508. public function checkInventoryControl($invCodes)
  509. {
  510. try {
  511. $db = $this->safeDb();
  512. if (empty($invCodes)) {
  513. return [false, '存货编码为空'];
  514. }
  515. // 1. 查询存货档案
  516. $list = $db->table('Inventory')
  517. ->whereIn('cInvCode', $invCodes)
  518. ->select(['cInvCode', 'cInvName', 'bInvBatch', 'bInvQuality'])
  519. ->get();
  520. $noBatch = []; // 未开启批次管理的
  521. $noExpiration = []; // 未开启保质期管理的
  522. $notFound = array_diff($invCodes, $list->pluck('cInvCode')->toArray()); // 数据库中不存在的
  523. foreach ($list as $item) {
  524. // 检查批次管理 (bInvBatch 为 0 表示未开启)
  525. if (empty($item->bInvBatch)) {
  526. $noBatch[] = $item->cInvCode . '(' . $item->cInvName . ')';
  527. }
  528. // 检查保质期管理 (bInvQuality 为 0 表示未开启)
  529. if (empty($item->bInvQuality)) {
  530. $noExpiration[] = $item->cInvCode . '(' . $item->cInvName . ')';
  531. }
  532. }
  533. // 2. 组织提示结果
  534. $messages = [];
  535. if (!empty($noBatch)) {
  536. $messages[] = "【未开启批次管理】: " . implode(', ', $noBatch);
  537. }
  538. if (!empty($noExpiration)) {
  539. $messages[] = "【未开启保质期管理】: " . implode(', ', $noExpiration);
  540. }
  541. if (!empty($notFound)) {
  542. $messages[] = "【档案不存在】: " . implode(', ', $notFound);
  543. }
  544. if (empty($messages)) {
  545. return [true, ''];
  546. }
  547. return [false, implode("\n", $messages)];
  548. } catch (\Throwable $e) {
  549. return [false, $e->getMessage()];
  550. }
  551. }
  552. public function rebuildDhDetails($mainId, $insertData)
  553. {
  554. try {
  555. $db = $this->safeDb();
  556. return $db->transaction(function () use ($mainId, $insertData,$db) {
  557. // 1. 删除旧明细
  558. $db->table('PU_ArrivalVouchs')
  559. ->where('ID', $mainId)
  560. ->delete();
  561. // 2. 获取新的起始 Autoid
  562. $maxAutoid = $db->table('PU_ArrivalVouchs')
  563. ->max('Autoid') ?? 0;
  564. // 3. 分配新 Autoid 并插入
  565. foreach ($insertData as &$row) {
  566. $maxAutoid++;
  567. $row['Autoid'] = $maxAutoid;
  568. }
  569. $db->table('PU_ArrivalVouchs')
  570. ->insert($insertData);
  571. return [true, ''];
  572. });
  573. } catch (\Throwable $e) {
  574. return [false, "重建明细失败: " . $e->getMessage()];
  575. }
  576. }
  577. public function rebuildLLDetails($mainId, $insertData)
  578. {
  579. try {
  580. $db = $this->safeDb();
  581. return $db->transaction(function () use ($mainId, $insertData,$db) {
  582. // 1. 删除旧明细 (领料申请单子表)
  583. $db->table('MaterialAppVouchs')
  584. ->where('ID', $mainId)
  585. ->delete();
  586. // 2. 获取新的起始 autoid
  587. $maxAutoid = $db->table('MaterialAppVouchs')
  588. ->max('AutoID') ?? 0;
  589. // 3. 分配新 autoid 并插入
  590. foreach ($insertData as &$row) {
  591. $maxAutoid++;
  592. $row['AutoID'] = $maxAutoid;
  593. }
  594. $db->table('MaterialAppVouchs')
  595. ->insert($insertData);
  596. return [true, ''];
  597. });
  598. } catch (\Throwable $e) {
  599. return [false, "重组领料申请单失败: " . $e->getMessage()];
  600. }
  601. }
  602. public function rebuildBjDetails($mainId, $insertData)
  603. {
  604. try {
  605. $db = $this->safeDb();
  606. return $db->transaction(function () use ($mainId, $insertData, $db) {
  607. // 1. 删除旧明细
  608. $db->table('QMINSPECTVOUCHERS')
  609. ->where('ID', $mainId)
  610. ->delete();
  611. $maxAutoid = $db->table('QMINSPECTVOUCHERS')
  612. ->max('Autoid') ?? 0;
  613. // 过滤掉不可插入的字段,特别是 UFTS
  614. foreach ($insertData as $key => $row) {
  615. $maxAutoid++;
  616. // 彻底清理:移除 UFTS 字段,防止插入报错及 JSON 转换报错
  617. unset($row['UFTS']);
  618. $row['Autoid'] = $maxAutoid;
  619. $insertData[$key] = $row;
  620. }
  621. // 4. 批量插入
  622. $db->table('QMINSPECTVOUCHERS')
  623. ->insert($insertData);
  624. return [true, '操作成功'];
  625. });
  626. } catch (\Throwable $e) {
  627. // 这里返回错误信息时,确保不包含二进制内容
  628. return [false, "重组报检单失败: " . $e->getMessage()];
  629. }
  630. }
  631. }