ProcessDataJob.php 50 KB

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