ProcessDataJob.php 41 KB

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