U8ThirtyPartyDatabaseServerService.php 27 KB

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