ProcessWMSDataJob.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <?php
  2. namespace App\Jobs;
  3. use App\Model\SyncTempRecord;
  4. use App\Service\U8ThirdPartyService;
  5. use Illuminate\Bus\Queueable;
  6. use Illuminate\Contracts\Queue\ShouldQueue;
  7. use Illuminate\Foundation\Bus\Dispatchable;
  8. use Illuminate\Queue\InteractsWithQueue;
  9. use Illuminate\Queue\SerializesModels;
  10. use Illuminate\Support\Facades\DB;
  11. use Illuminate\Support\Facades\Log;
  12. use Symfony\Component\Console\Output\ConsoleOutput;
  13. use Symfony\Component\Console\Output\OutputInterface;
  14. class ProcessWMSDataJob implements ShouldQueue
  15. {
  16. use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  17. protected $data;
  18. public $timeout = 30;
  19. public function __construct($data)
  20. {
  21. //record表
  22. $this->data = $data;
  23. }
  24. public function handle()
  25. {
  26. try {
  27. list($bool, $msg) = $this->settle();
  28. if(! $bool) $this->finalDo($msg);
  29. } catch (\Throwable $e) {
  30. $this->finalDo("异常:" . $e->getMessage());
  31. $this->delete();
  32. }
  33. }
  34. private function finalDo($msg){
  35. SyncTempRecord::where('id', $this->data['id'])
  36. ->update(['error_msg' => $msg, 'status' => SyncTempRecord::status_one]);
  37. }
  38. private function settle()
  39. {
  40. $id = $this->data['id'];
  41. $record = SyncTempRecord::where('id', $id)->first();
  42. // 1. 安全检查:如果记录不存在,或者已经是成功状态(status_one),则退出
  43. if (!$record || $record->status != SyncTempRecord::status_zero) {
  44. return [true, '已处理或记录不存在'];
  45. }
  46. // 2. 解析 U8 原始数据
  47. $u8Data = is_array($record->payload) ? $record->payload : json_decode($record->payload, true);
  48. $type = $record->type;
  49. if($type == SyncTempRecord::type_eight){
  50. //检验单
  51. list($status, $msg) = $this->bjOrder($record, $u8Data);
  52. }else{
  53. //同步到音飞
  54. list($status, $msg) = $this->orderInsert($record, $u8Data);
  55. }
  56. return [$status, $msg];
  57. }
  58. public function orderInsert($record, $u8Data){
  59. $orderType = SyncTempRecord::$map[$record->type];
  60. if(is_array($orderType)) $orderType = $orderType[$record->type_2];
  61. // 3. 组装报文
  62. $jsonBody = [
  63. 'orderType' => $orderType,
  64. 'orderNo' => $record->u8_no,
  65. 'orderId' => $record->u8_id,
  66. 'operationType' => SyncTempRecord::$opMapping[$record->op_type],
  67. 'lottar1' => '',
  68. 'lottar2' => '',
  69. 'lottar3' => '',
  70. 'lottar4' => '',
  71. 'lottar5' => '',
  72. 'lottar6' => '',
  73. 'lottar7' => '',
  74. 'lottar8' => '',
  75. 'lottar9' => '',
  76. 'details' => []
  77. ];
  78. // 4. 接口路由
  79. $inboundTypes = [SyncTempRecord::type_one, SyncTempRecord::type_three, SyncTempRecord::type_six, SyncTempRecord::type_five];
  80. $path = in_array($record->type, $inboundTypes) ? '/erp/inbound' : '/erp/outbound';
  81. if($record->type_2 == 1 && $record->type == SyncTempRecord::type_one) $path = '/erp/outbound';
  82. $apiUrl = config('wms.api_url') . $path;
  83. if (isset($u8Data['details']) && is_array($u8Data['details'])) {
  84. if($path == '/erp/inbound'){ //入
  85. foreach ($u8Data['details'] as $item) {
  86. $productDate = "";
  87. if(! empty($item['dMDate'])) $productDate = date("Y-m-d", strtotime($item['dMDate']));
  88. $validTime = 0;
  89. if(! empty($item['iMassDate'])) $validTime = $item['iMassDate'];
  90. $lot = "";
  91. if(! empty($item['cBatch'])) $lot = $item['cBatch'];
  92. $jsonBody['details'][] = [
  93. 'lineNum' => $item['lineNum'] ?? 0,
  94. 'materialCode' => $item['materialCode'] ?? '',
  95. 'planQty' => (float)abs($item['planQty']),
  96. 'productDate' => $productDate,
  97. 'validTime' => $validTime,
  98. 'lot' => $lot,
  99. 'lottar1' => $item['cDefine23'] ?? "",
  100. 'lottar2' => "",
  101. 'lottar3' => '',
  102. 'lottar4' => '',
  103. 'lottar5' => '',
  104. 'lottar6' => '',
  105. 'lottar7' => '',
  106. 'lottar8' => '',
  107. 'lottar9' => '',
  108. ];
  109. }
  110. }else{//出
  111. foreach ($u8Data['details'] as $item) {
  112. $jsonBody['details'][] = [
  113. 'lineNum' => $item['lineNum'] ?? 0,
  114. 'materialCode' => $item['materialCode'] ?? '',
  115. 'planQty' => (float)abs($item['planQty']),
  116. 'lottar1' => "",
  117. 'lottar2' => $item['cBatch'] ?? "",
  118. 'lottar3' => '',
  119. 'lottar4' => '',
  120. 'lottar5' => '',
  121. 'lottar6' => '',
  122. 'lottar7' => '',
  123. 'lottar8' => '',
  124. 'lottar9' => '',
  125. ];
  126. }
  127. }
  128. }
  129. // 5. 调用 post_helper
  130. list($status, $result) = $this->post_helper($apiUrl, $jsonBody, ['Content-Type: application/json']);
  131. if (!$status) {
  132. // 接口返回失败或网络失败
  133. $record->update(['status' => SyncTempRecord::status_two, 'error_msg' => $result]);
  134. return [false, $result];
  135. }
  136. // 6. 接口返回成功 (200) 的后续操作
  137. DB::transaction(function () use ($record, $u8Data) {
  138. // 更新本地流水状态为成功
  139. $record->update([
  140. 'status' => SyncTempRecord::status_one,
  141. ]);
  142. // 同步维护快照表,保证下次 Command 比对正确
  143. if ($record->op_type == SyncTempRecord::opt_two) {
  144. DB::table('sync_snapshot')
  145. ->where('type', $record->type)
  146. ->where('u8_no', $record->u8_no)
  147. ->where('u8_id', $record->u8_id)
  148. ->delete();
  149. } else {
  150. DB::table('sync_snapshot')->updateOrInsert(
  151. ['type' => $record->type, 'u8_no' => $record->u8_no],
  152. ['u8_id' => $record->u8_id,'last_upd_time' => $record->u8_upd, 'order_date' => $u8Data['order_date'], 'payload' => json_encode($u8Data)]
  153. );
  154. }
  155. });
  156. return [true, ''];
  157. }
  158. //代码是有bug的 因为业务
  159. public function bjOrder($record, $u8Data){
  160. $hg_quantity = $u8Data['hg_quantity'] ?? 0;
  161. $rb_quantity = $u8Data['rb_quantity'] ?? 0;
  162. $hg_not_quantity = $u8Data['hg_not_quantity'] ?? 0;
  163. if($hg_quantity > 0){
  164. list($status, $msg) = $this->zj($record, $u8Data, 1);
  165. }elseif ($rb_quantity > 0) {
  166. list($status, $msg) = $this->zj($record, $u8Data,3);
  167. }elseif($hg_not_quantity > 0){
  168. list($status, $msg) = $this->zj($record, $u8Data,2);
  169. }
  170. return [$status ?? true, $msg ?? ""];
  171. }
  172. public function zj($record, $u8Data, $type){
  173. if($record['type_2'] == 1){
  174. $orderNo = $u8Data['from_order'];
  175. }else{
  176. $orderNo = $u8Data['bj_order'];
  177. }
  178. // 3. 组装报文
  179. $jsonBody = [
  180. 'orderNo' => $orderNo,
  181. 'materialCode' => $u8Data['materialCode'],
  182. 'lot' => $u8Data['lot'] ?? "",
  183. 'inspectionStatus' => $type,
  184. ];
  185. // 4. 接口路由
  186. $apiUrl = config('wms.api_url') . '/erp/inspection';
  187. // 5. 调用 post_helper
  188. list($status, $result) = $this->post_helper($apiUrl, $jsonBody, ['Content-Type: application/json']);
  189. if (!$status) {
  190. // 接口返回失败或网络失败
  191. $record->update(['status' => SyncTempRecord::status_two, 'error_msg' => $result]);
  192. return [false, $result];
  193. }
  194. //生成用友单据
  195. $service = new U8ThirdPartyService();
  196. //报检单类型
  197. $bg_type = $record['type_2'];
  198. if($bg_type == 1){
  199. //采购
  200. if($type == 1 || $type == 3){
  201. //合格 让步 =》 采购入库
  202. list($status, $msg) = $service->purchaseInByZj(['record' => $record, 'payload' => $u8Data,'cvouchtype' => 'QM03','type' => $type]);
  203. }else{
  204. //不合格 =》其他入库单
  205. list($status, $msg) = $service->otherInByZj(['record' => $record, 'payload' => $u8Data, 'cvouchtype' => 'QM03']);
  206. }
  207. }elseif ($bg_type == 2){
  208. //产品
  209. if($type == 1 || $type == 3){
  210. //合格 让步 =》 产成品入库
  211. list($status, $msg) = $service->productInByZj(['record' => $record, 'payload' => $u8Data, 'cvouchtype' => 'QM04','type' => $type]);
  212. }else{
  213. //不合格 =》其他入库单
  214. list($status, $msg) = $service->otherInByZj(['record' => $record, 'payload' => $u8Data, 'cvouchtype' => 'QM04']);
  215. }
  216. }else{
  217. //退货 不需要了
  218. list($status, $msg) = [true, ''];
  219. }
  220. if (!$status) {
  221. // 接口返回失败或网络失败
  222. $record->update(['status' => SyncTempRecord::status_two, 'error_msg' => $msg]);
  223. return [false, $msg];
  224. }
  225. // 6. 接口返回成功 (200) 的后续操作
  226. DB::transaction(function () use ($record, $u8Data) {
  227. // 更新本地流水状态为成功
  228. $record->update([
  229. 'status' => SyncTempRecord::status_one,
  230. ]);
  231. // 同步维护快照表,保证下次 Command 比对正确
  232. if ($record->op_type == SyncTempRecord::opt_two) {
  233. DB::table('sync_snapshot')
  234. ->where('type', $record->type)
  235. ->where('u8_no', $record->u8_no)
  236. ->where('u8_id', $record->u8_id)
  237. ->delete();
  238. } else {
  239. DB::table('sync_snapshot')->updateOrInsert(
  240. ['type' => $record->type, 'u8_no' => $record->u8_no],
  241. ['u8_id' => $record->u8_id,'last_upd_time' => $record->u8_upd, 'order_date' => $u8Data['order_date'], 'payload' => json_encode($u8Data)]
  242. );
  243. }
  244. });
  245. return [true, ''];
  246. }
  247. public function post_helper($url, $data, $header = [], $timeout = 30)
  248. {
  249. Log::channel('apiLog')->info('WMS_POST_START', ["api" => $url, "param" => $data]);
  250. $ch = curl_init();
  251. curl_setopt($ch, CURLOPT_URL, $url);
  252. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  253. curl_setopt($ch, CURLOPT_POST, 1);
  254. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  255. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  256. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  257. if(!is_null($data)) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  258. $r = curl_exec($ch);
  259. if ($r === false) {
  260. $errorMessage = curl_error($ch);
  261. curl_close($ch);
  262. Log::channel('apiLog')->error('WMS_CURL_ERROR', ["msg" => $errorMessage]);
  263. return [false, "网络错误: " . $errorMessage];
  264. }
  265. curl_close($ch);
  266. $return = json_decode($r, true);
  267. Log::channel('apiLog')->info('WMS_POST_RETURN', ["res" => $return]);
  268. // 判断逻辑:code 存在且为 200 才算 true
  269. if (isset($return['code']) && $return['code'] == 200) {
  270. return [true, $return];
  271. }
  272. $msg = $return['message'] ?? '未知接口错误';
  273. return [false, $msg];
  274. }
  275. protected function echoMessage(OutputInterface $output)
  276. {
  277. //输出消息
  278. $output->writeln(json_encode($this->data));
  279. }
  280. }