ProcessDataJob.php 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. <?php
  2. namespace App\Jobs;
  3. use App\Model\DDEmployee;
  4. use App\Model\Inventory;
  5. use App\Model\Record;
  6. use App\Model\U8State;
  7. use App\Model\Vendor;
  8. use App\Service\U8DatabaseServerService;
  9. use Illuminate\Bus\Queueable;
  10. use Illuminate\Contracts\Queue\ShouldQueue;
  11. use Illuminate\Foundation\Bus\Dispatchable;
  12. use Illuminate\Queue\InteractsWithQueue;
  13. use Illuminate\Queue\SerializesModels;
  14. use Symfony\Component\Console\Output\ConsoleOutput;
  15. use Symfony\Component\Console\Output\OutputInterface;
  16. class ProcessDataJob implements ShouldQueue
  17. {
  18. use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  19. protected $data;
  20. public $timeout = 30;
  21. public function __construct($data)
  22. {
  23. //record表
  24. $this->data = $data;
  25. }
  26. public function handle()
  27. {
  28. try {
  29. list($bool, $msg) = $this->syncApprovedRecords($this->data);
  30. if(! $bool) $this->finalDo($msg, $this->data);
  31. } catch (\Throwable $e) {
  32. $this->finalDo("异常:" . $e->getMessage());
  33. $this->delete();
  34. }
  35. }
  36. private function finalDo($msg, $record){
  37. //进入到队列的数据 都是审核通过的 但是业务有没有成功就是另一回事
  38. Record::where('id', $record['id'])
  39. ->update(['result' => $msg]);
  40. U8State::where('del_time',0)
  41. ->where('type', $record['type'])
  42. ->where('login_type', $record['login_type'])
  43. ->where('order_number', $record['order_number'])
  44. ->update(['state' => U8State::state_one, 'result' => $msg]);
  45. }
  46. private function syncApprovedRecords($record)
  47. {
  48. try {
  49. $LoginType = $record['login_type'];
  50. $database = $record['database'];
  51. $service = new U8DatabaseServerService(['zt_database' => $database]);
  52. if ($service->error) return [false, $service->error];
  53. $time = date("Y-m-d H:i:s");
  54. $time1 = date("Y-m-d 00:00:00");
  55. if($record['del_time'] == 2){
  56. $type = $record['type'];
  57. $order_number = $record['order_number'];
  58. $system_name = "system";
  59. $name = DDEmployee::where('userid', $record['userid'])->where('login_type', $LoginType)->value('name');
  60. if(! empty($name)) $system_name = $name;
  61. if($type == Record::type_one){
  62. $service->db->table("PO_Pomain")
  63. ->where("cPOID", $order_number)
  64. ->update([
  65. "cVerifier" => $system_name,
  66. "iverifystateex" => 1,
  67. "cState" => 1,
  68. "cAuditTime" => $time . ".000",
  69. "cAuditDate" => $time1 . ".000",
  70. ]);
  71. }elseif($type == Record::type_two){
  72. $service->db->table("PU_AppVouch")
  73. ->where("cCode", $order_number)
  74. ->update([
  75. "iverifystateex" => 2,
  76. "cVerifier" => $system_name,
  77. "cAuditTime" => $time . ".000",
  78. "cAuditDate" => $time1 . ".000",
  79. ]);
  80. }elseif($type == Record::type_three){
  81. $service->db->table("RdRecord01")
  82. ->where("cCode", $order_number)
  83. ->update([
  84. "cHandler" => $system_name,
  85. "dnverifytime" => $time . ".000",
  86. "dVeriDate" => $time1 . ".000",
  87. ]);
  88. }elseif($type == Record::type_four){
  89. list($status, $msg) = $this->inventoryAddToU8($record, $name, $service->db);
  90. if(! $status) return [false, $msg];
  91. }elseif($type == Record::type_five){
  92. list($status, $msg) = $this->vendorAddToU8($record, $name, $service->db);
  93. if(! $status) return [false, $msg];
  94. }
  95. // 更新本地数据 通过状态
  96. Record::where("id", $record['id'])->update(['del_time' => 3]);
  97. // 更新状态为 通过状态
  98. U8State::updateOrCreate(
  99. ['order_number' => $record['order_number'], 'login_type' => $record['login_type'], 'type' => $record['type']],
  100. ['state' => U8State::state_one]
  101. );
  102. }
  103. $service->close();
  104. } catch (\Throwable $e) {
  105. return [false, $e->getMessage()];
  106. }
  107. return [true, ''];
  108. }
  109. public function inventoryAddToU81($data, $service){
  110. $inventory = Inventory::where('del_time', 0)
  111. ->where('order_number', $data['order_number'])
  112. ->where('login_type', $data['login_type'])
  113. ->first();
  114. if(empty($inventory)) return [false, '存货记录不存在或已被删除'];
  115. $inventory = $inventory->toArray();
  116. $title = $inventory['title'];
  117. $category_code = $inventory['category_code'];
  118. if(! empty($data['code'])){
  119. //用户传入
  120. $no = $inventory['code'];
  121. $flag_title = "重填";
  122. }else{
  123. //生成编码
  124. list($status, $msg) = $this->generate('inventory',$category_code, $service);
  125. if(! $status) return [false, $msg];
  126. $no = $msg;
  127. $flag_title = "重试";
  128. }
  129. $inventoryData = [
  130. 'cInvCode' => $no,
  131. 'cInvName' => $title,
  132. 'cInvCCode' => $category_code,
  133. 'cInvStd' => $inventory['size'] ?? null, // 规格型号
  134. 'bSale' => $inventory['bSale'], //内销
  135. 'bExpSale' => $inventory['bExpSale'], //外销
  136. 'bPurchase' => $inventory['bPurchase'], // 采购
  137. 'bSelf' => $inventory['bSelf'], // 自制
  138. 'bComsume' => $inventory['bComsume'], // 生产耗材
  139. 'iGroupType' => $inventory['unit_group_type'], // 计量单位组类别
  140. 'cGroupCode' => $inventory['unit_group_code'], //计量单位组
  141. 'cComUnitCode' => $inventory['unit_code'], // 主计量单位
  142. 'cShopUnit' => $inventory['unit_code'], // 零售计量单位
  143. 'iImpTaxRate' => $inventory['iImpTaxRate'], // 进项税率
  144. 'iTaxRate' => $inventory['iTaxRate'], // 销项税率
  145. 'dSDate' => date("Y-m-d 00:00:00.000"), // 启用日期
  146. 'cEnterprise' => $inventory['vendor_code_title'] ?? null,
  147. 'iSupplyType' => '0', // 供应类型
  148. 'fConvertRate' => '1.0', // 转换因子
  149. 'bInTotalCost' => '1', // 成本累计否
  150. 'cPlanMethod' => 'R',
  151. 'cSRPolicy' => 'PE',
  152. 'bBomMain' => '0', // 允许BOM母件
  153. 'bBomSub' => '0', // 允许BOM子件
  154. 'bProductBill' => '0', // 允许生产订单
  155. 'iPlanDefault' => '1',
  156. 'iAllocatePrintDgt' => '4',
  157. 'bService' => '0',
  158. 'bAccessary' => '0',
  159. 'iInvAdvance' => '0.0',
  160. 'bInvQuality' => '0',
  161. 'bInvBatch' => '0',
  162. 'bInvEntrust' => '0',
  163. 'bInvOverStock' => '0',
  164. 'bFree1' => '0',
  165. 'bFree2' => '0',
  166. 'bInvType' => '0',
  167. 'bFree3' => '0',
  168. 'bFree4' => '0',
  169. 'bFree5' => '0',
  170. 'bFree6' => '0',
  171. 'bFree7' => '0',
  172. 'bFree8' => '0',
  173. 'bFree9' => '0',
  174. 'bFree10' => '0',
  175. 'cCreatePerson' => 'demo',
  176. 'cModifyPerson' => 'demo', // 变更
  177. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  178. 'bFixExch' => '0',
  179. 'bTrack' => '0',
  180. 'bSerial' => '0',
  181. 'bBarCode' => '0',
  182. 'bSolitude' => '0',
  183. 'bSpecialties' => '0',
  184. 'bPropertyCheck' => '0',
  185. 'iRecipeBatch' => '0',
  186. 'bPromotSales' => '0',
  187. 'bPlanInv' => '0',
  188. 'bProxyForeign' => '0',
  189. 'bATOModel' => '0',
  190. 'bCheckItem' => '0',
  191. 'bPTOModel' => '0',
  192. 'bEquipment' => '0',
  193. 'bMPS' => '0',
  194. 'bROP' => '0',
  195. 'bRePlan' => '0',
  196. 'bBillUnite' => '0',
  197. 'bCutMantissa' => '0',
  198. 'bConfigFree1' => '0',
  199. 'bConfigFree2' => '0',
  200. 'bConfigFree3' => '0',
  201. 'bConfigFree4' => '0',
  202. 'bConfigFree5' => '0',
  203. 'bConfigFree6' => '0',
  204. 'bConfigFree7' => '0',
  205. 'bConfigFree8' => '0',
  206. 'bConfigFree9' => '0',
  207. 'bConfigFree10' => '0',
  208. 'bPeriodDT' => '0',
  209. 'bOutInvDT' => '0',
  210. 'bBackInvDT' => '0',
  211. 'bDTWarnInv' => '0',
  212. 'bImportMedicine' => '0',
  213. 'bFirstBusiMedicine' => '0',
  214. 'bForeExpland' => '0',
  215. 'bInvModel' => '0',
  216. 'bKCCutMantissa' => '0',
  217. 'bReceiptByDT' => '0',
  218. 'bCheckBSATP' => '0',
  219. 'bCheckFree1' => '0',
  220. 'bCheckFree2' => '0',
  221. 'bCheckFree3' => '0',
  222. 'bCheckFree4' => '0',
  223. 'bCheckFree5' => '0',
  224. 'bCheckFree6' => '0',
  225. 'bCheckFree7' => '0',
  226. 'bCheckFree8' => '0',
  227. 'bCheckFree9' => '0',
  228. 'bCheckFree10' => '0',
  229. 'iCheckATP' => '0',
  230. 'bPiece' => '0',
  231. 'bSrvItem' => '0',
  232. 'bSrvFittings' => '0',
  233. 'bSpecialOrder' => '0',
  234. 'bTrackSaleBill' => '0',
  235. 'bCheckBatch' => '0',
  236. 'bMngOldpart' => '0',
  237. ];
  238. $inventorySubData = [
  239. 'cInvSubCode' => $no,
  240. 'iSurenessType' => '1',
  241. 'bIsAttachFile' => '0',
  242. 'bInByProCheck' => '1',
  243. 'iRequireTrackStyle' => '0',
  244. 'iExpiratDateCalcu' => '0',
  245. 'iBOMExpandUnitType' => '1',
  246. 'iDrawType' => $inventory['iDrawType'] ?? 0, // 领用方式
  247. 'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1, // 海关换算率
  248. 'bInvKeyPart' => '1',
  249. 'iAcceptEarlyDays' => '999',
  250. 'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
  251. 'bPUQuota' => '0',
  252. 'bInvROHS' => '0',
  253. 'bPrjMat' => '0',
  254. 'bInvAsset' => '0',
  255. 'bSrvProduct' => '0',
  256. 'iAcceptDelayDays' => '0',
  257. 'bSCkeyProjections' => '0',
  258. 'iSupplyPeriodType' => '1',
  259. 'iAvailabilityDate' => '1',
  260. 'bImport' => '0',
  261. 'bCheckSubitemCost' => '1',
  262. 'fRoundFactor' => '0.0',
  263. 'bConsiderFreeStock' => '1',
  264. 'bSuitRetail' => '0',
  265. 'bFeatureMatch' => '0',
  266. 'bProduceByFeatureAllocate' => '0',
  267. 'bMaintenance' => '0',
  268. 'iMaintenanceCycleUnit' => '0',
  269. 'bCoupon' => '0',
  270. 'bStoreCard' => '0',
  271. 'bProcessProduct' => '0',
  272. 'bProcessMaterial' => '0',
  273. // 所有的价格自由项默认设为 '0'
  274. 'bPurPriceFree1' => '0', 'bPurPriceFree2' => '0', 'bPurPriceFree3' => '0', 'bPurPriceFree4' => '0', 'bPurPriceFree5' => '0',
  275. 'bPurPriceFree6' => '0', 'bPurPriceFree7' => '0', 'bPurPriceFree8' => '0', 'bPurPriceFree9' => '0', 'bPurPriceFree10' => '0',
  276. 'bOMPriceFree1' => '0', 'bOMPriceFree2' => '0', 'bOMPriceFree3' => '0', 'bOMPriceFree4' => '0', 'bOMPriceFree5' => '0',
  277. 'bOMPriceFree6' => '0', 'bOMPriceFree7' => '0', 'bOMPriceFree8' => '0', 'bOMPriceFree9' => '0', 'bOMPriceFree10' => '0',
  278. 'bSalePriceFree1' => '0', 'bSalePriceFree2' => '0', 'bSalePriceFree3' => '0', 'bSalePriceFree4' => '0', 'bSalePriceFree5' => '0',
  279. 'bSalePriceFree6' => '0', 'bSalePriceFree7' => '0', 'bSalePriceFree8' => '0', 'bSalePriceFree9' => '0', 'bSalePriceFree10' => '0',
  280. // 所有的控制自由项默认设为 '0'
  281. 'bControlFreeRange1' => '0', 'bControlFreeRange2' => '0', 'bControlFreeRange3' => '0', 'bControlFreeRange4' => '0', 'bControlFreeRange5' => '0',
  282. 'bControlFreeRange6' => '0', 'bControlFreeRange7' => '0', 'bControlFreeRange8' => '0', 'bControlFreeRange9' => '0', 'bControlFreeRange10' => '0',
  283. // 所有的批次属性默认设为 '0'
  284. 'bBatchProperty1' => '0', 'bBatchProperty2' => '0', 'bBatchProperty3' => '0', 'bBatchProperty4' => '0', 'bBatchProperty5' => '0',
  285. 'bBatchProperty6' => '0', 'bBatchProperty7' => '0', 'bBatchProperty8' => '0', 'bBatchProperty9' => '0', 'bBatchProperty10' => '0',
  286. 'bBondedInv' => '0',
  287. 'bBatchCreate' => '0',
  288. ];
  289. try {
  290. $service->beginTransaction();
  291. $exists = $service->table('Inventory')
  292. ->where('cInvCode', $inventoryData['cInvCode'])
  293. ->lockForUpdate() // 锁定该行,防止并发冲突
  294. ->exists();
  295. if ($exists) return [false, '存货编码已存在,请' . $flag_title];
  296. $service->table('Inventory')->insert($inventoryData);
  297. $service->table('Inventory_sub')->insert($inventorySubData);
  298. $service->commit();
  299. } catch (\Throwable $exception) {
  300. $service->rollBack();
  301. return [false, "创建用友失败: " . $exception->getMessage()];
  302. }
  303. return [true, ''];
  304. }
  305. public function inventoryAddToU82($data, $username, $service)
  306. {
  307. // 1. 获取本地存货记录
  308. $inventory = Inventory::where('del_time', 0)
  309. ->where('order_number', $data['order_number'])
  310. ->where('login_type', $data['login_type'])
  311. ->first();
  312. if (empty($inventory)) {
  313. return [false, '本地存货记录不存在或已被删除'];
  314. }
  315. $inventory = $inventory->toArray();
  316. // 2. 提取核心属性变量并转换为布尔/整数
  317. $bSale = (int)($inventory['bSale'] ?? 0); // 销售(内销)
  318. $bExpSale = (int)($inventory['bExpSale'] ?? 0); // 外销
  319. $bPurchase = (int)($inventory['bPurchase'] ?? 0); // 采购
  320. $bSelf = (int)($inventory['bSelf'] ?? 0); // 自制
  321. $bComsume = (int)($inventory['bComsume'] ?? 0); // 生产耗用
  322. $bProxy = (int)($inventory['bProxy'] ?? 0); // 委外 (若数据库无此字段,建议默认0)
  323. // --- 用友业务规则动态计算开始 ---
  324. // 2.1 计划默认属性 (iPlanDefault)
  325. // 规则:自制=1, 委外=2, 采购=3, 计划品=4。优先级:自制 > 委外 > 采购
  326. $iPlanDefault = 0;
  327. if ($bSelf) {
  328. $iPlanDefault = 1;
  329. } elseif ($bProxy) {
  330. $iPlanDefault = 2;
  331. } elseif ($bPurchase) {
  332. $iPlanDefault = 3;
  333. }
  334. // 2.2 允许BOM母件 (bBomMain)
  335. // 规则:自制、委外、计划品等默认为1;纯采购件默认为0
  336. $bBomMain = ($bSelf || $bProxy) ? 1 : 0;
  337. // 2.3 允许BOM子件 (bBomSub)
  338. // 规则:只要涉及到生产消耗或采购,通常都允许作为子件
  339. $bBomSub = ($bSelf || $bProxy || $bPurchase || $bComsume) ? 1 : 0;
  340. // 2.4 允许生产订单 (bProductBill)
  341. // 规则:只有“自制”属性为“是”时,才允许下达生产订单
  342. $bProductBill = $bSelf ? 1 : 0;
  343. // 2.5 计划方法 (cPlanMethod) 和 成本相关 (bInTotalCost)
  344. // 规则:如果非内外销且非生产耗用,但勾选了BOM子件,属于辅助性物料,不计算MRP
  345. $cPlanMethod = 'R'; // R: MRP/MPS计算
  346. $bInTotalCost = 1; // 默认参与成本累计
  347. if (!$bSale && !$bExpSale && !$bComsume && $bBomSub) {
  348. $cPlanMethod = 'N'; // N: 不计算
  349. $bInTotalCost = 0;
  350. }
  351. // --- 用友业务规则动态计算结束 ---
  352. // 3. 编码生成或使用传入编码
  353. $category_code = $inventory['category_code'];
  354. if (!empty($data['code'])) {
  355. $no = $data['code'];
  356. $flag_title = "重填";
  357. } else {
  358. // 调用编码生成器 (假设方法名为 generate)
  359. list($status, $msg) = $this->generate('inventory', $category_code, $service);
  360. if (!$status) {
  361. return [false, "生成存货编码失败: " . $msg];
  362. }
  363. $no = $msg;
  364. $flag_title = "重试";
  365. }
  366. // 4. 构建 Inventory 主表数据
  367. $inventoryData = [
  368. 'cInvCode' => $no,
  369. 'cInvName' => $inventory['title'],
  370. 'cInvCCode' => $category_code,
  371. 'cInvStd' => $inventory['size'] ?? null, // 规格型号
  372. 'bSale' => $bSale,
  373. 'bExpSale' => $bExpSale,
  374. 'bPurchase' => $bPurchase,
  375. 'bSelf' => $bSelf,
  376. 'bComsume' => $bComsume,
  377. 'bProxyForeign' => $bProxy, // 委外
  378. 'iGroupType' => $inventory['unit_group_type'],
  379. 'cGroupCode' => $inventory['unit_group_code'],
  380. 'cComUnitCode' => $inventory['unit_code'], // 主计量单位
  381. 'cShopUnit' => $inventory['unit_code'], // 零售单位
  382. 'iImpTaxRate' => $inventory['iImpTaxRate'], // 进项税率
  383. 'iTaxRate' => $inventory['iTaxRate'], // 销项税率
  384. 'dSDate' => date("Y-m-d 00:00:00.000"), // 启用日期
  385. 'cEnterprise' => $inventory['vendor_code_title'] ?? null,
  386. 'iSupplyType' => '0', // 领料方式:领用
  387. 'fConvertRate' => '1.0', // 转换因子
  388. 'bInTotalCost' => $bInTotalCost, // 动态计算
  389. 'cPlanMethod' => $cPlanMethod, // 动态计算
  390. 'cSRPolicy' => 'PE', // 供需政策:PE
  391. 'bBomMain' => $bBomMain, // 动态计算
  392. 'bBomSub' => $bBomSub, // 动态计算
  393. 'bProductBill' => $bProductBill, // 动态计算
  394. 'iPlanDefault' => $iPlanDefault, // 动态计算
  395. 'iAllocatePrintDgt' => '4',
  396. 'bService' => '0',
  397. 'bAccessary' => '0',
  398. 'iInvAdvance' => '0.0',
  399. 'bInvQuality' => '0',
  400. 'bInvBatch' => '0',
  401. 'bInvEntrust' => '0',
  402. 'bInvOverStock' => '0',
  403. 'cCreatePerson' => $username,
  404. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  405. 'bPlanInv' => '0',
  406. 'bATOModel' => '0',
  407. 'bPTOModel' => '0',
  408. 'bMPS' => ($iPlanDefault == 1 || $iPlanDefault == 2) ? '1' : '0', // 只有自制委外才可能作为MPS件
  409. 'bROP' => '0',
  410. 'bRePlan' => '0',
  411. 'bCutMantissa' => '0',
  412. 'bCheckBSATP' => '0',
  413. 'iCheckATP' => '0',
  414. // 以下为大量自由项/控制位字段,默认设为 0
  415. 'bFree1' => '0', 'bFree2' => '0', 'bFree3' => '0', 'bFree4' => '0', 'bFree5' => '0',
  416. 'bFree6' => '0', 'bFree7' => '0', 'bFree8' => '0', 'bFree9' => '0', 'bFree10' => '0',
  417. 'bConfigFree1' => '0', 'bConfigFree2' => '0', 'bConfigFree3' => '0', 'bConfigFree4' => '0',
  418. 'bConfigFree5' => '0', 'bConfigFree6' => '0', 'bConfigFree7' => '0', 'bConfigFree8' => '0',
  419. 'bConfigFree9' => '0', 'bConfigFree10' => '0',
  420. ];
  421. // 5. 构建 Inventory_sub 表数据
  422. $inventorySubData = [
  423. 'cInvSubCode' => $no,
  424. 'iSurenessType' => '1',
  425. 'bIsAttachFile' => '0',
  426. 'bInByProCheck' => '1',
  427. 'iRequireTrackStyle' => '0',
  428. 'iExpiratDateCalcu' => '0',
  429. 'iBOMExpandUnitType' => '1', // BOM展开单位:主计量
  430. 'iDrawType' => $inventory['iDrawType'] ?? 0, // 领用方式
  431. 'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1,
  432. 'bInvKeyPart' => '1',
  433. 'iAcceptEarlyDays' => '999',
  434. 'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
  435. 'bPUQuota' => '0',
  436. 'bInvROHS' => '0',
  437. 'bPrjMat' => '0',
  438. 'bInvAsset' => '0',
  439. 'bSrvProduct' => '0',
  440. 'iAcceptDelayDays' => '0',
  441. 'bSCkeyProjections' => '0',
  442. 'iSupplyPeriodType' => '1', // 供应期间类型:天
  443. 'iAvailabilityDate' => '1', // 第一需求日
  444. 'bImport' => '0',
  445. 'bCheckSubitemCost' => '1',
  446. 'fRoundFactor' => '0.0',
  447. 'bConsiderFreeStock' => '1',
  448. 'bSuitRetail' => '0',
  449. 'bFeatureMatch' => '0',
  450. 'bProduceByFeatureAllocate' => '0',
  451. 'bMaintenance' => '0',
  452. 'iMaintenanceCycleUnit' => '0',
  453. 'bCoupon' => '0',
  454. 'bStoreCard' => '0',
  455. 'bProcessProduct' => '0',
  456. 'bProcessMaterial' => '0',
  457. // 自由项价格控制全部设为 0
  458. 'bPurPriceFree1' => '0', 'bOMPriceFree1' => '0', 'bSalePriceFree1' => '0',
  459. 'bControlFreeRange1' => '0', 'bBatchProperty1' => '0',
  460. 'bBondedInv' => '0',
  461. 'bBatchCreate' => '0',
  462. ];
  463. // 6. 执行数据库同步(使用事务)
  464. try {
  465. $service->beginTransaction();
  466. // 检查存货编码是否冲突
  467. $exists = $service->table('Inventory')
  468. ->where('cInvCode', $no)
  469. ->lockForUpdate()
  470. ->exists();
  471. if ($exists) {
  472. $service->rollBack();
  473. return [false, '存货编码 [' . $no . '] 在用友系统中已存在,请' . $flag_title];
  474. }
  475. // 插入主表和从表
  476. $service->table('Inventory')->insert($inventoryData);
  477. $service->table('Inventory_sub')->insert($inventorySubData);
  478. $service->commit();
  479. } catch (\Throwable $exception) {
  480. $service->rollBack();
  481. return [false, "同步用友数据库失败: " . $exception->getMessage()];
  482. }
  483. return [true, '同步成功'];
  484. }
  485. public function vendorAddToU82($data, $username,$service){
  486. $vendor = Vendor::where('del_time', 0)
  487. ->where('order_number', $data['order_number'])
  488. ->where('login_type', $data['login_type'])
  489. ->first();
  490. if(empty($vendor)) return [false, '供应商记录不存在或已被删除'];
  491. $vendor = $vendor->toArray();
  492. if(! empty($vendor['code'])){
  493. //用户传入
  494. $no = $vendor['code'];
  495. $flag_title = "重填";
  496. }else{
  497. //生成编码
  498. list($status, $msg) = $this->generate('vendor','', $service);
  499. if(! $status) return [false, $msg];
  500. $no = $msg;
  501. $flag_title = "重试";
  502. }
  503. $vendorData = [
  504. 'cVenCode' => $no,
  505. 'cVenName' => $vendor['title'],
  506. 'cVenAbbName' => $vendor['easy_title'],
  507. 'cVCCode' => $vendor['category_code'],
  508. 'dVenDevDate' => date("Y-m-d 00:00:00.000"),
  509. 'iVenDisRate' => '0.0',
  510. 'iVenCreLine' => '0.0',
  511. 'iVenCreDate' => '0',
  512. 'cVenHeadCode' => $no,
  513. 'iAPMoney' => '0.0',
  514. 'iLastMoney' => '0.0',
  515. 'iLRMoney' => '0.0',
  516. 'iFrequency' => '0',
  517. 'bVenTax' => '1',
  518. 'cCreatePerson' => $username,
  519. 'cModifyPerson' => $username,
  520. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  521. 'iGradeABC' => '-1',
  522. 'bLicenceDate' => '0',
  523. 'bBusinessDate' => '0',
  524. 'bProxyDate' => '0',
  525. 'bPassGMP' => '0',
  526. 'bVenCargo' => '1', // 采购
  527. 'bProxyForeign' => '0', // 委外
  528. 'bVenService' => '0', // 服务
  529. 'bVenOverseas' => '0', // 国外
  530. 'cVenExch_name' => '人民币',
  531. 'iVenGSPType' => '0',
  532. 'iVenGSPAuth' => '-1',
  533. 'bVenAccPeriodMng' => '0',
  534. 'bVenHomeBranch' => '0',
  535. 'dVenCreateDatetime' => date("Y-m-d H:i:s.000"),
  536. 'bIsVenAttachFile' => '0',
  537. 'bRetail' => '0',
  538. ];
  539. try {
  540. $service->beginTransaction();
  541. $exists = $service->table('Vendor')
  542. ->where('cVenCode', $vendorData['cVenCode'])
  543. ->lockForUpdate() // 锁定该行,防止并发冲突
  544. ->exists();
  545. if ($exists) return [false, '供应商编码已存在,请' . $flag_title];
  546. $service->table('Vendor')->insert($vendorData);
  547. $service->commit();
  548. } catch (\Throwable $exception) {
  549. $service->rollBack();
  550. return [false, "创建供应商失败: " . $exception->getMessage()];
  551. }
  552. return [true, ''];
  553. }
  554. public function generate2($type, $classCode = "", $service)
  555. {
  556. try {
  557. // 1. 确定对象映射
  558. $cardNumber = ($type === 'inventory') ? 'inventory' : 'Vendor';
  559. $cardNumber_name = ($type === 'inventory') ? '存货' : '供应商';
  560. $table = ($type === 'inventory') ? 'Inventory' : 'Vendor';
  561. $codeField = ($type === 'inventory') ? 'cInvCode' : 'cVenCode';
  562. // 2. 获取 U8 规则定义
  563. $rule = $service->table('VoucherNumber')
  564. ->where('CardNumber', $cardNumber)
  565. ->first();
  566. if (!$rule) return [false, "未找到 {$cardNumber_name} 的规则定义"];
  567. /**
  568. * 3. 动态解析前缀 (Prefix1, Prefix2, Prefix3)
  569. * U8 的规则通常存放在 PrefixRule 或 Prefix 字段中
  570. */
  571. $prefix = "";
  572. for ($i = 1; $i <= 3; $i++) {
  573. $ruleField = "Prefix{$i}Rule";
  574. $valField = "Prefix{$i}";
  575. // 检查规则描述
  576. $ruleDesc = $rule->$ruleField ?? ''; // 例如 "存货分类编码" 或 "GYS"
  577. $staticVal = $rule->$valField ?? '';
  578. if (str_contains($ruleDesc, '分类') || str_contains($staticVal, '分类')) {
  579. // 如果规则提到“分类”,则填入传入的分类编码
  580. $prefix .= $classCode;
  581. } elseif (!empty($ruleDesc)) {
  582. // 如果规则是具体的字符(如 "GYS"),直接拼接
  583. $prefix .= $ruleDesc;
  584. } elseif (!empty($staticVal) && $staticVal !== '手工输入' && $staticVal !== '存货分类编码') {
  585. // 如果静态值不是提示语,则作为前缀
  586. $prefix .= $staticVal;
  587. }
  588. }
  589. // 4. 获取流水号配置 (Glide)
  590. $glideLen = $rule->GlideLen > 0 ? $rule->GlideLen : 4;
  591. $startNum = $rule->iStartNumber ?? 1;
  592. // 5. 查找当前最大编码
  593. $expectedLen = strlen($prefix) + $glideLen;
  594. $lastCode = $service->table($table)
  595. ->where($codeField, 'like', $prefix . '%')
  596. ->whereRaw("LEN($codeField) = $expectedLen")
  597. ->orderBy($codeField, 'desc')
  598. ->value($codeField);
  599. // 6. 生成编码
  600. if (!$lastCode) {
  601. // 初始:前缀 + 起始值补零
  602. $finalCode = $prefix . str_pad($startNum, $glideLen, '0', STR_PAD_LEFT);
  603. } else {
  604. // 截取流水号自增
  605. $lastSerial = substr($lastCode, -$glideLen);
  606. $nextSerial = ++$lastSerial;
  607. // 溢出检查
  608. if (strlen($nextSerial) > $glideLen) {
  609. return [false, "流水号已溢出"];
  610. }
  611. $finalCode = $prefix . str_pad($nextSerial, $glideLen, '0', STR_PAD_LEFT);
  612. }
  613. return [true, $finalCode];
  614. } catch (\Throwable $e) {
  615. return [false, "生成失败: " . $e->getMessage()];
  616. }
  617. }
  618. /**
  619. * 将存货信息同步到用友 U8 系统
  620. * @param array $data 包含 order_number 和 login_type 等关键参数
  621. * @param string $username 当前操作人
  622. * @param object $service 用友数据库连接实例 (DB Service)
  623. * @return array [bool, string]
  624. */
  625. public function inventoryAddToU83($data, $username, $service)
  626. {
  627. // 1. 获取本地存货记录
  628. $inventory = Inventory::where('del_time', 0)
  629. ->where('order_number', $data['order_number'])
  630. ->where('login_type', $data['login_type'])
  631. ->first();
  632. if (empty($inventory)) {
  633. return [false, '本地存货记录不存在或已被删除'];
  634. }
  635. $inventory = $inventory->toArray();
  636. // 2. 提取核心属性变量并转换为布尔/整数
  637. $bSale = (int)($inventory['bSale'] ?? 0); // 销售(内销)
  638. $bExpSale = (int)($inventory['bExpSale'] ?? 0); // 外销
  639. $bPurchase = (int)($inventory['bPurchase'] ?? 0); // 采购
  640. $bSelf = (int)($inventory['bSelf'] ?? 0); // 自制
  641. $bComsume = (int)($inventory['bComsume'] ?? 0); // 生产耗用
  642. $bProxy = (int)($inventory['bProxy'] ?? 0); // 委外
  643. // --- 用友业务规则动态计算 ---
  644. $iPlanDefault = $bSelf ? 1 : ($bProxy ? 2 : ($bPurchase ? 3 : 0));
  645. $bBomMain = ($bSelf || $bProxy) ? 1 : 0;
  646. $bBomSub = ($bSelf || $bProxy || $bPurchase || $bComsume) ? 1 : 0;
  647. $bProductBill = $bSelf ? 1 : 0;
  648. $cPlanMethod = 'R';
  649. $bInTotalCost = 1;
  650. if (!$bSale && !$bExpSale && !$bComsume && $bBomSub) {
  651. $cPlanMethod = 'N';
  652. $bInTotalCost = 0;
  653. }
  654. // 3. 编码生成逻辑
  655. $category_code = $inventory['category_code'];
  656. $serialInfo = null;
  657. if (!empty($data['code'])) {
  658. $no = $data['code'];
  659. $flag_title = "重填";
  660. } else {
  661. list($status, $res) = $this->generate('inventory', $category_code, $service);
  662. if (!$status) return [false, "生成存货编码失败: " . $res];
  663. $no = $res['finalCode'];
  664. $serialInfo = $res;
  665. $flag_title = "重试";
  666. }
  667. // 4. 构建 Inventory 主表数据 (还原所有原始字段)
  668. $inventoryData = [
  669. 'cInvCode' => $no,
  670. 'cInvName' => $inventory['title'],
  671. 'cInvCCode' => $category_code,
  672. 'cInvStd' => $inventory['size'] ?? null,
  673. 'bSale' => $bSale,
  674. 'bExpSale' => $bExpSale,
  675. 'bPurchase' => $bPurchase,
  676. 'bSelf' => $bSelf,
  677. 'bComsume' => $bComsume,
  678. 'bProxyForeign' => $bProxy,
  679. 'iGroupType' => $inventory['unit_group_type'],
  680. 'cGroupCode' => $inventory['unit_group_code'],
  681. 'cComUnitCode' => $inventory['unit_code'],
  682. 'cShopUnit' => $inventory['unit_code'],
  683. 'iImpTaxRate' => $inventory['iImpTaxRate'],
  684. 'iTaxRate' => $inventory['iTaxRate'],
  685. 'dSDate' => date("Y-m-d 00:00:00.000"),
  686. 'cEnterprise' => $inventory['vendor_code_title'] ?? null,
  687. 'iSupplyType' => '0',
  688. 'fConvertRate' => '1.0',
  689. 'bInTotalCost' => $bInTotalCost,
  690. 'cPlanMethod' => $cPlanMethod,
  691. 'cSRPolicy' => 'PE',
  692. 'bBomMain' => $bBomMain,
  693. 'bBomSub' => $bBomSub,
  694. 'bProductBill' => $bProductBill,
  695. 'iPlanDefault' => $iPlanDefault,
  696. 'iAllocatePrintDgt' => '4',
  697. 'bService' => '0',
  698. 'bAccessary' => '0',
  699. 'iInvAdvance' => '0.0',
  700. 'bInvQuality' => '0',
  701. 'bInvBatch' => '0',
  702. 'bInvEntrust' => '0',
  703. 'bInvOverStock' => '0',
  704. 'cCreatePerson' => $username,
  705. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  706. 'bPlanInv' => '0',
  707. 'bATOModel' => '0',
  708. 'bPTOModel' => '0',
  709. 'bMPS' => ($iPlanDefault == 1 || $iPlanDefault == 2) ? '1' : '0',
  710. 'bROP' => '0',
  711. 'bRePlan' => '0',
  712. 'bCutMantissa' => '0',
  713. 'bCheckBSATP' => '0',
  714. 'iCheckATP' => '0',
  715. 'bFree1' => '0', 'bFree2' => '0', 'bFree3' => '0', 'bFree4' => '0', 'bFree5' => '0',
  716. 'bFree6' => '0', 'bFree7' => '0', 'bFree8' => '0', 'bFree9' => '0', 'bFree10' => '0',
  717. 'bConfigFree1' => '0', 'bConfigFree2' => '0', 'bConfigFree3' => '0', 'bConfigFree4' => '0',
  718. 'bConfigFree5' => '0', 'bConfigFree6' => '0', 'bConfigFree7' => '0', 'bConfigFree8' => '0',
  719. 'bConfigFree9' => '0', 'bConfigFree10' => '0',
  720. ];
  721. // 5. 构建 Inventory_sub 表数据
  722. $inventorySubData = [
  723. 'cInvSubCode' => $no,
  724. 'iSurenessType' => '1',
  725. 'bIsAttachFile' => '0',
  726. 'bInByProCheck' => '1',
  727. 'iRequireTrackStyle' => '0',
  728. 'iExpiratDateCalcu' => '0',
  729. 'iBOMExpandUnitType' => '1',
  730. 'iDrawType' => $inventory['iDrawType'] ?? 0,
  731. 'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1,
  732. 'bInvKeyPart' => '1',
  733. 'iAcceptEarlyDays' => '999',
  734. 'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
  735. 'bPUQuota' => '0',
  736. 'bInvROHS' => '0',
  737. 'bPrjMat' => '0',
  738. 'bInvAsset' => '0',
  739. 'bSrvProduct' => '0',
  740. 'iAcceptDelayDays' => '0',
  741. 'bSCkeyProjections' => '0',
  742. 'iSupplyPeriodType' => '1',
  743. 'iAvailabilityDate' => '1',
  744. 'bImport' => '0',
  745. 'bCheckSubitemCost' => '1',
  746. 'fRoundFactor' => '0.0',
  747. 'bConsiderFreeStock' => '1',
  748. 'bSuitRetail' => '0',
  749. 'bFeatureMatch' => '0',
  750. 'bProduceByFeatureAllocate' => '0',
  751. 'bMaintenance' => '0',
  752. 'iMaintenanceCycleUnit' => '0',
  753. 'bCoupon' => '0',
  754. 'bStoreCard' => '0',
  755. 'bProcessProduct' => '0',
  756. 'bProcessMaterial' => '0',
  757. 'bPurPriceFree1' => '0', 'bOMPriceFree1' => '0', 'bSalePriceFree1' => '0',
  758. 'bControlFreeRange1' => '0', 'bBatchProperty1' => '0',
  759. 'bBondedInv' => '0',
  760. 'bBatchCreate' => '0',
  761. ];
  762. // 6. 执行同步
  763. try {
  764. $service->beginTransaction();
  765. $exists = $service->table('Inventory')->where('cInvCode', $no)->lockForUpdate()->exists();
  766. if ($exists) {
  767. $service->rollBack();
  768. return [false, '存货编码 [' . $no . '] 在用友系统中已存在,请' . $flag_title];
  769. }
  770. $service->table('Inventory')->insert($inventoryData);
  771. $service->table('Inventory_sub')->insert($inventorySubData);
  772. // 更新流水号表
  773. if ($serialInfo) {
  774. $service->table('VoucherHistory')->updateOrInsert(
  775. ['CardNumber' => 'inventory', 'cContent' => '存货分类编码', 'cSeed' => $category_code],
  776. ['cNumber' => $serialInfo['serial']]
  777. );
  778. }
  779. $service->commit();
  780. } catch (\Throwable $exception) {
  781. $service->rollBack();
  782. return [false, "同步用友数据库失败: " . $exception->getMessage()];
  783. }
  784. return [true, '同步成功'];
  785. }
  786. public function inventoryAddToU8($data, $username, $service)
  787. {
  788. // 1. 获取本地存货记录
  789. $inventory = Inventory::where('del_time', 0)
  790. ->where('order_number', $data['order_number'])
  791. ->where('login_type', $data['login_type'])
  792. ->first();
  793. if (empty($inventory)) {
  794. return [false, '本地存货记录不存在或已被删除'];
  795. }
  796. $inventory = $inventory->toArray();
  797. // 2. 提取核心属性变量
  798. $bSale = (int)($inventory['bSale'] ?? 0);
  799. $bExpSale = (int)($inventory['bExpSale'] ?? 0);
  800. $bPurchase = (int)($inventory['bPurchase'] ?? 0);
  801. $bSelf = (int)($inventory['bSelf'] ?? 0);
  802. $bComsume = (int)($inventory['bComsume'] ?? 0);
  803. $bProxy = (int)($inventory['bProxy'] ?? 0);
  804. // --- 用友业务规则动态计算 ---
  805. $iPlanDefault = $bSelf ? 1 : ($bProxy ? 2 : ($bPurchase ? 3 : 0));
  806. $bBomMain = ($bSelf || $bProxy) ? 1 : 0;
  807. $bBomSub = ($bSelf || $bProxy || $bPurchase || $bComsume) ? 1 : 0;
  808. $bProductBill = $bSelf ? 1 : 0;
  809. $cPlanMethod = 'R';
  810. $bInTotalCost = 1;
  811. if (!$bSale && !$bExpSale && !$bComsume && $bBomSub) {
  812. $cPlanMethod = 'N';
  813. $bInTotalCost = 0;
  814. }
  815. // 3. 编码生成逻辑
  816. $category_code = $inventory['category_code'];
  817. $serialInfo = null;
  818. if (!empty($data['code'])) {
  819. $no = $data['code'];
  820. $flag_title = "重填";
  821. } else {
  822. list($status, $res) = $this->generate('inventory', $category_code, $service);
  823. if (!$status) return [false, "生成存货编码失败: " . $res];
  824. $no = $res['finalCode'];
  825. $serialInfo = $res;
  826. $flag_title = "重试";
  827. }
  828. // 4. 构建 Inventory 主表数据
  829. $inventoryData = [
  830. 'cInvCode' => $no,
  831. 'cInvName' => $inventory['title'],
  832. 'cInvCCode' => $category_code,
  833. 'cInvStd' => $inventory['size'] ?? null,
  834. 'bSale' => $bSale,
  835. 'bExpSale' => $bExpSale,
  836. 'bPurchase' => $bPurchase,
  837. 'bSelf' => $bSelf,
  838. 'bComsume' => $bComsume,
  839. 'bProxyForeign' => $bProxy,
  840. 'iGroupType' => $inventory['unit_group_type'],
  841. 'cGroupCode' => $inventory['unit_group_code'],
  842. 'cComUnitCode' => $inventory['unit_code'],
  843. 'cShopUnit' => $inventory['unit_code'],
  844. 'iImpTaxRate' => $inventory['iImpTaxRate'],
  845. 'iTaxRate' => $inventory['iTaxRate'],
  846. 'dSDate' => date("Y-m-d 00:00:00.000"),
  847. 'cEnterprise' => $inventory['vendor_code_title'] ?? null,
  848. 'iSupplyType' => '0',
  849. 'fConvertRate' => '1.0',
  850. 'bInTotalCost' => $bInTotalCost,
  851. 'cPlanMethod' => $cPlanMethod,
  852. 'cSRPolicy' => 'PE',
  853. 'bBomMain' => $bBomMain,
  854. 'bBomSub' => $bBomSub,
  855. 'bProductBill' => $bProductBill,
  856. 'iPlanDefault' => $iPlanDefault,
  857. 'iAllocatePrintDgt' => '4',
  858. 'bService' => '0',
  859. 'bAccessary' => '0',
  860. 'iInvAdvance' => '0.0',
  861. 'bInvQuality' => '0',
  862. 'bInvBatch' => '0',
  863. 'bInvEntrust' => '0',
  864. 'bInvOverStock' => '0',
  865. 'cCreatePerson' => $username,
  866. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  867. 'bPlanInv' => '0',
  868. 'bATOModel' => '0',
  869. 'bPTOModel' => '0',
  870. 'bMPS' => ($iPlanDefault == 1 || $iPlanDefault == 2) ? '1' : '0',
  871. 'bROP' => '0',
  872. 'bRePlan' => '0',
  873. 'bCutMantissa' => '0',
  874. 'bCheckBSATP' => '0',
  875. 'iCheckATP' => '0',
  876. 'bFree1' => '0', 'bFree2' => '0', 'bFree3' => '0', 'bFree4' => '0', 'bFree5' => '0',
  877. 'bFree6' => '0', 'bFree7' => '0', 'bFree8' => '0', 'bFree9' => '0', 'bFree10' => '0',
  878. 'bConfigFree1' => '0', 'bConfigFree2' => '0', 'bConfigFree3' => '0', 'bConfigFree4' => '0',
  879. 'bConfigFree5' => '0', 'bConfigFree6' => '0', 'bConfigFree7' => '0', 'bConfigFree8' => '0',
  880. 'bConfigFree9' => '0', 'bConfigFree10' => '0',
  881. ];
  882. // 5. 构建 Inventory_sub 表数据
  883. $inventorySubData = [
  884. 'cInvSubCode' => $no,
  885. 'iSurenessType' => '1',
  886. 'bIsAttachFile' => '0',
  887. 'bInByProCheck' => '1',
  888. 'iRequireTrackStyle' => '0',
  889. 'iExpiratDateCalcu' => '0',
  890. 'iBOMExpandUnitType' => '1',
  891. 'iDrawType' => $inventory['iDrawType'] ?? 0,
  892. 'fInvCIQExch' => $inventory['customs_change_rate'] ?? 1,
  893. 'bInvKeyPart' => '1',
  894. 'iAcceptEarlyDays' => '999',
  895. 'dInvCreateDatetime' => date("Y-m-d H:i:s.000"),
  896. 'bPUQuota' => '0',
  897. 'bInvROHS' => '0',
  898. 'bPrjMat' => '0',
  899. 'bInvAsset' => '0',
  900. 'bSrvProduct' => '0',
  901. 'iAcceptDelayDays' => '0',
  902. 'bSCkeyProjections' => '0',
  903. 'iSupplyPeriodType' => '1',
  904. 'iAvailabilityDate' => '1',
  905. 'bImport' => '0',
  906. 'bCheckSubitemCost' => '1',
  907. 'fRoundFactor' => '0.0',
  908. 'bConsiderFreeStock' => '1',
  909. 'bSuitRetail' => '0',
  910. 'bFeatureMatch' => '0',
  911. 'bProduceByFeatureAllocate' => '0',
  912. 'bMaintenance' => '0',
  913. 'iMaintenanceCycleUnit' => '0',
  914. 'bCoupon' => '0',
  915. 'bStoreCard' => '0',
  916. 'bProcessProduct' => '0',
  917. 'bProcessMaterial' => '0',
  918. 'bPurPriceFree1' => '0', 'bOMPriceFree1' => '0', 'bSalePriceFree1' => '0',
  919. 'bControlFreeRange1' => '0', 'bBatchProperty1' => '0',
  920. 'bBondedInv' => '0',
  921. 'bBatchCreate' => '0',
  922. ];
  923. // 6. 执行同步
  924. try {
  925. $service->beginTransaction();
  926. $exists = $service->table('Inventory')->where('cInvCode', $no)->lockForUpdate()->exists();
  927. if ($exists) {
  928. $service->rollBack();
  929. return [false, '存货编码 [' . $no . '] 在用友系统中已存在,请' . $flag_title];
  930. }
  931. // --- 核心插入操作 ---
  932. $service->table('Inventory')->insert($inventoryData);
  933. $service->table('Inventory_sub')->insert($inventorySubData);
  934. // --- 新增:插入 bas_part 表 ---
  935. // 1. 获取 U8 内部最大 PartId (或者从 bas_part_seq 获取,这里采用最大值+1的简易方案)
  936. $maxPartId = $service->table('bas_part')->max('PartId');
  937. $newPartId = (int)$maxPartId + 1;
  938. $basPartData = [
  939. 'PartId' => $newPartId,
  940. 'InvCode' => $no,
  941. 'Free1' => '', 'Free2' => '', 'Free3' => '', 'Free4' => '', 'Free5' => '',
  942. 'Free6' => '', 'Free7' => '', 'Free8' => '', 'Free9' => '', 'Free10' => '',
  943. 'SafeQty' => null,
  944. 'MinQty' => null,
  945. 'MulQty' => null,
  946. 'FixQty' => null,
  947. 'bVirtual' => 1, // 默认非虚仓,如果是虚拟件请改为 1
  948. 'DrawCode' => null,
  949. 'LLC' => 0, // 低层码,新增时默认为 0,U8全检时会更新
  950. 'iSurenessType' => 1, // 对应 Inventory_sub 的设置
  951. 'RoundingFactor' => '0',
  952. 'FreeStockFlag' => '0',
  953. 'bFreeStop' => '0'
  954. ];
  955. $service->table('bas_part')->insert($basPartData);
  956. // 更新流水号表
  957. if ($serialInfo) {
  958. $service->table('VoucherHistory')->updateOrInsert(
  959. ['CardNumber' => 'inventory', 'cContent' => '存货分类编码', 'cSeed' => $category_code],
  960. ['cNumber' => $serialInfo['serial']]
  961. );
  962. }
  963. $service->commit();
  964. Inventory::where('del_time', 0)
  965. ->where('order_number', $data['order_number'])
  966. ->where('login_type', $data['login_type'])
  967. ->update(['code' => $no]);
  968. } catch (\Throwable $exception) {
  969. $service->rollBack();
  970. return [false, "同步用友数据库失败: " . $exception->getMessage()];
  971. }
  972. return [true, '同步成功'];
  973. }
  974. /**
  975. * U8 供应商新增 (全量版)
  976. */
  977. public function vendorAddToU8($data, $username, $service)
  978. {
  979. $vendor = Vendor::where('del_time', 0)
  980. ->where('order_number', $data['order_number'])
  981. ->where('login_type', $data['login_type'])
  982. ->first();
  983. if (empty($vendor)) return [false, '供应商记录不存在或已被删除'];
  984. $vendor = $vendor->toArray();
  985. $serialInfo = null;
  986. if (!empty($vendor['code'])) {
  987. $no = $vendor['code'];
  988. $flag_title = "重填";
  989. } else {
  990. list($status, $res) = $this->generate('vendor', '', $service);
  991. if (!$status) return [false, $res];
  992. $no = $res['finalCode'];
  993. $serialInfo = $res;
  994. $flag_title = "重试";
  995. }
  996. $vendorData = [
  997. 'cVenCode' => $no,
  998. 'cVenName' => $vendor['title'],
  999. 'cVenAbbName' => $vendor['easy_title'],
  1000. 'cVCCode' => $vendor['category_code'],
  1001. 'dVenDevDate' => date("Y-m-d 00:00:00.000"),
  1002. 'iVenDisRate' => '0.0',
  1003. 'iVenCreLine' => '0.0',
  1004. 'iVenCreDate' => '0',
  1005. 'cVenHeadCode' => $no,
  1006. 'iAPMoney' => '0.0',
  1007. 'iLastMoney' => '0.0',
  1008. 'iLRMoney' => '0.0',
  1009. 'iFrequency' => '0',
  1010. 'bVenTax' => '1',
  1011. 'cCreatePerson' => $username,
  1012. 'cModifyPerson' => $username,
  1013. 'dModifyDate' => date("Y-m-d H:i:s.000"),
  1014. 'iGradeABC' => '-1',
  1015. 'bLicenceDate' => '0',
  1016. 'bBusinessDate' => '0',
  1017. 'bProxyDate' => '0',
  1018. 'bPassGMP' => '0',
  1019. 'bVenCargo' => '1',
  1020. 'bProxyForeign' => '0',
  1021. 'bVenService' => '0',
  1022. 'bVenOverseas' => '0',
  1023. 'cVenExch_name' => '人民币',
  1024. 'iVenGSPType' => '0',
  1025. 'iVenGSPAuth' => '-1',
  1026. 'bVenAccPeriodMng' => '0',
  1027. 'bVenHomeBranch' => '0',
  1028. 'dVenCreateDatetime' => date("Y-m-d H:i:s.000"),
  1029. 'bIsVenAttachFile' => '0',
  1030. 'bRetail' => '0',
  1031. ];
  1032. try {
  1033. $service->beginTransaction();
  1034. $exists = $service->table('Vendor')->where('cVenCode', $no)->lockForUpdate()->exists();
  1035. if ($exists) {
  1036. $service->rollBack();
  1037. return [false, '供应商编码已存在,请' . $flag_title];
  1038. }
  1039. $service->table('Vendor')->insert($vendorData);
  1040. // 更新流水号表
  1041. if ($serialInfo) {
  1042. $service->table('VoucherHistory')->updateOrInsert(
  1043. ['CardNumber' => 'Vendor', 'cContent' => NULL, 'cSeed' => NULL],
  1044. ['cNumber' => $serialInfo['serial']]
  1045. );
  1046. }
  1047. $service->commit();
  1048. Vendor::where('del_time', 0)
  1049. ->where('order_number', $data['order_number'])
  1050. ->where('login_type', $data['login_type'])
  1051. ->update(['code' => $no]);
  1052. } catch (\Throwable $exception) {
  1053. $service->rollBack();
  1054. return [false, "创建供应商失败: " . $exception->getMessage()];
  1055. }
  1056. return [true, '同步成功'];
  1057. }
  1058. /**
  1059. * 编码生成器 (增加流水数据返回)
  1060. */
  1061. public function generate($type, $classCode = "", $service)
  1062. {
  1063. try {
  1064. $cardNumber = ($type === 'inventory') ? 'inventory' : 'Vendor';
  1065. $table = ($type === 'inventory') ? 'Inventory' : 'Vendor';
  1066. $codeField = ($type === 'inventory') ? 'cInvCode' : 'cVenCode';
  1067. $rule = $service->table('VoucherNumber')->where('CardNumber', $cardNumber)->first();
  1068. if (!$rule) return [false, "未找到规则定义"];
  1069. $prefix = "";
  1070. for ($i = 1; $i <= 3; $i++) {
  1071. $ruleField = "Prefix{$i}Rule";
  1072. $valField = "Prefix{$i}";
  1073. $ruleDesc = $rule->$ruleField ?? '';
  1074. $staticVal = $rule->$valField ?? '';
  1075. if (str_contains($ruleDesc, '分类') || str_contains($staticVal, '分类')) {
  1076. $prefix .= $classCode;
  1077. } elseif (!empty($ruleDesc) && !in_array($ruleDesc, ['手工输入', '无'])) {
  1078. $prefix .= $ruleDesc;
  1079. }
  1080. }
  1081. $glideLen = $rule->GlideLen ?: 4;
  1082. $startNum = $rule->iStartNumber ?: 1;
  1083. $lastCode = $service->table($table)
  1084. ->where($codeField, 'like', $prefix . '%')
  1085. ->whereRaw("LEN($codeField) = " . (strlen($prefix) + $glideLen))
  1086. ->orderBy($codeField, 'desc')
  1087. ->value($codeField);
  1088. $nextSerial = (!$lastCode) ? (int)$startNum : (int)substr($lastCode, -$glideLen) + 1;
  1089. $finalCode = $prefix . str_pad($nextSerial, $glideLen, '0', STR_PAD_LEFT);
  1090. return [true, [
  1091. 'finalCode' => $finalCode,
  1092. 'prefix' => $prefix,
  1093. 'serial' => $nextSerial
  1094. ]];
  1095. } catch (\Throwable $e) {
  1096. return [false, "生成失败: " . $e->getMessage()];
  1097. }
  1098. }
  1099. protected function echoMessage(OutputInterface $output)
  1100. {
  1101. //输出消息
  1102. $output->writeln(json_encode($this->data));
  1103. }
  1104. }