U8ThirdPartyService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. namespace App\Service;
  3. use App\Model\SyncSnapShot;
  4. use App\Model\SyncTempRecord;
  5. use Illuminate\Support\Facades\Cache;
  6. use Illuminate\Support\Facades\Log;
  7. class U8ThirdPartyService extends Service
  8. {
  9. const one = 1;
  10. const two = 2;
  11. const three = 3;
  12. const four = 4;
  13. const five = 5;
  14. const six = 6;
  15. const seven = 7;
  16. const eight = 8;
  17. const type_all = [
  18. self::one => '采购入库',
  19. self::two => '采购退货',
  20. self::three => '材料出库',
  21. self::four => '采购入库',
  22. self::five => '采购入库',
  23. self::six => '采购入库',
  24. self::seven => '采购入库',
  25. self::eight => '采购入库',
  26. ];
  27. public function settleU8Data($data){
  28. if(empty($data['type'])) return [false, 'type类型不能为空'];
  29. if(! isset(self::type_all[$data['type']])) return [false, 'type类型错误'];
  30. $type = $data['type'];
  31. list($status, $msg) = $this->getToken();
  32. // if(! $status) return [false, $msg];
  33. $data['u8_data'] = $msg;
  34. if($type == self::one){
  35. list($status, $msg) = $this->purchaseIn($data);
  36. }elseif ($type == self::two){
  37. list($status, $msg) = $this->purchaseReturn($data);
  38. }elseif ($type == self::three){
  39. list($status, $msg) = $this->materialOut($data);
  40. }elseif ($type == self::four){
  41. list($status, $msg) = $this->purchaseIn($data);
  42. }elseif ($type == self::five){
  43. list($status, $msg) = $this->purchaseIn($data);
  44. }elseif ($type == self::six){
  45. list($status, $msg) = $this->purchaseIn($data);
  46. }elseif ($type == self::seven){
  47. list($status, $msg) = $this->purchaseIn($data);
  48. }elseif ($type == self::eight){
  49. list($status, $msg) = $this->purchaseIn($data);
  50. }
  51. }
  52. public function getToken(){
  53. $key = "drb_u8_api";
  54. $config = config('wms.drb');
  55. // 1. 自检网络通畅
  56. list($bool, $msg) = $this->checkNetworkStatus($config['api_host'], $config['api_port']);
  57. if (!$bool) return [false, "网络连接失败: " . $msg];
  58. $host = $config['api_host'] . ":" . $config['api_port'];
  59. // 2. 尝试从缓存获取
  60. $token = Cache::get($key);
  61. if (! $token) {
  62. // 3. 缓存失效,请求新 Token
  63. $url = $host . "/api/System/GetToken";
  64. $date = date("Y-m-d");
  65. $json = [
  66. "U8DbName" => $config['database'],
  67. "sUserId" => $config['user_id'],
  68. "sPassword" => $config['user_password'],
  69. "LoginDateTime" => $date,
  70. "bPersist" => true
  71. ];
  72. $header = ['Content-Type:application/json'];
  73. // 调用你的 POST 辅助函数
  74. list($status, $result) = $this->post_helper1($url, json_encode($json), $header);
  75. if (!$status) return [false, "用友token获取失败: " . $result];
  76. if (!isset($result['code'])) return [false, '获取用友登录信息失败: 响应格式异常'];
  77. if ($result['code'] != 0) return [false, "U8错误: " . ($result['msg'] ?? '未知错误')];
  78. $token = $result['data']['Token'] ?? "";
  79. if (empty($token)) return [false, "接口返回的 Token 为空"];
  80. // 30分钟 = 1800秒
  81. Cache::put($key, $token, now()->addMinutes(30));
  82. }
  83. return [true, ['host' => $host, 'token' => $token]];
  84. }
  85. public function purchaseIn($data){
  86. if(empty($data['orderId'])) return [false, '采购到货单ID不能为空'];
  87. if(empty($data['orderNo'])) return [false, '采购到货单单号不能为空'];
  88. if(empty($data['detail'])) return [false, '表体信息detail不能为空'];
  89. $body = [];
  90. foreach ($data['detail'] as $key => $value){
  91. if(empty($value['lineNum'])) return [false, '行号不能为空'];
  92. if(! is_numeric($value['lineNum'])) return [false, '行号错误'];
  93. if(empty($value['materialCode'])) return [false, '存货编码不能为空'];
  94. if(empty($value['productDate']) || ! $this->validateProductDate($value['productDate'])) return [false, '生产日期为空或格式错误'];
  95. if(empty($value['failureDate']) || ! $this->validateProductDate($value['failureDate'])) return [false, '失效日期为空或格式错误'];
  96. if(empty($value['lot'])) return [false, '批号不能为空'];
  97. $body[] = [
  98. 'ivouchrowno' => $value['lineNum'],
  99. 'dPDate' => $value['productDate'],
  100. 'dVDate' => $value['failureDate'],
  101. 'cBatch' => $value['lot'],
  102. 'editprop' => 'M',
  103. ];
  104. }
  105. //调用所需
  106. $host = $data['u8_data']['host'];
  107. $token = $data['u8_data']['token'];
  108. //采购到货单弃审
  109. $header = ["Authorization: {$token}",'Content-Type:application/json'];
  110. $url = $host . "/api/PuArrVouch/UnVerify";
  111. $json = [
  112. "VouchId" => $data['orderId'],
  113. ];
  114. $json = json_encode($json);
  115. list($status, $result) = $this->post_helper1($url,$json, $header, 30);
  116. if(! $status) return [false, $result];
  117. if(! isset($result['code'])) return [false, '采购到货单弃审失败'];
  118. if($result['code'] != 0) return [false, $result['msg']];
  119. //采购到货单编辑并审核
  120. $url = $host . "/api/PuArrVouch/Update";
  121. $json_final[] = [
  122. "Inum" => "PuArrVouch",
  123. "data" =>[
  124. "iHead" => [
  125. "cCode" => $data['orderNo'],
  126. "IsVerify" => true,
  127. "debug" => true,
  128. ],
  129. "iBody" => $body,
  130. ],
  131. ];
  132. $json = json_encode($json_final);
  133. list($status, $result) = $this->post_helper1($url,$json, $header, 30);
  134. if(! $status) return [false, $result];
  135. if(! isset($result['code'])) return [false, '采购到货单编辑并审核失败'];
  136. if($result['code'] != 0) return [false, $result['msg']];
  137. return [true, ''];
  138. }
  139. public function materialOut($data){
  140. if(empty($data['orderId'])) return [false, '领料申请单ID不能为空'];
  141. if(empty($data['orderNo'])) return [false, '领料申请单单号不能为空'];
  142. if(empty($data['detail'])) return [false, '表体信息detail不能为空'];
  143. $body = [];
  144. foreach ($data['detail'] as $key => $value){
  145. if(empty($value['lineNum'])) return [false, '行号不能为空'];
  146. if(! is_numeric($value['lineNum'])) return [false, '行号错误'];
  147. if(empty($value['materialCode'])) return [false, '存货编码不能为空'];
  148. if(empty($value['productDate']) || ! $this->validateProductDate($value['productDate'])) return [false, '生产日期为空或格式错误'];
  149. if(empty($value['failureDate']) || ! $this->validateProductDate($value['failureDate'])) return [false, '失效日期为空或格式错误'];
  150. if(empty($value['lot'])) return [false, '批号不能为空'];
  151. $body[] = [
  152. 'ivouchrowno' => $value['lineNum'],
  153. 'dPDate' => $value['productDate'],
  154. 'dVDate' => $value['failureDate'],
  155. 'cBatch' => $value['lot'],
  156. 'editprop' => 'M',
  157. ];
  158. }
  159. //调用所需
  160. $host = $data['u8_data']['host'];
  161. $token = $data['u8_data']['token'];
  162. //采购到货单弃审
  163. $header = ["Authorization: {$token}",'Content-Type:application/json'];
  164. $url = $host . "/api/PuArrVouch/UnVerify";
  165. $json = [
  166. "VouchId" => $data['orderId'],
  167. ];
  168. $json = json_encode($json);
  169. list($status, $result) = $this->post_helper1($url,$json, $header, 30);
  170. if(! $status) return [false, $result];
  171. if(! isset($result['code'])) return [false, '采购到货单弃审失败'];
  172. if($result['code'] != 0) return [false, $result['msg']];
  173. //采购到货单编辑并审核
  174. $url = $host . "/api/PuArrVouch/Update";
  175. $json_final[] = [
  176. "Inum" => "PuArrVouch",
  177. "data" =>[
  178. "iHead" => [
  179. "cCode" => $data['orderNo'],
  180. "IsVerify" => true,
  181. "debug" => true,
  182. ],
  183. "iBody" => $body,
  184. ],
  185. ];
  186. $json = json_encode($json_final);
  187. list($status, $result) = $this->post_helper1($url,$json, $header, 30);
  188. if(! $status) return [false, $result];
  189. if(! isset($result['code'])) return [false, '采购到货单编辑并审核失败'];
  190. if($result['code'] != 0) return [false, $result['msg']];
  191. return [true, ''];
  192. }
  193. public function purchaseReturn($data){
  194. if(empty($data['orderId'])) return [false, '采购退货单ID不能为空'];
  195. if(empty($data['orderNo'])) return [false, '采购退货单单号不能为空'];
  196. //获取单据
  197. $service = new U8ThirtyPartyDatabaseServerService();
  198. list($status, $order) = $service->getArrivalVouchById($data['orderId']);
  199. if(! $status) return [false, $order];
  200. dd($order);
  201. $final_data = [];
  202. foreach ($order['details'] as $value){
  203. if(empty($value['cWhCode'])) continue;
  204. if(isset($final_data[$value['cWhCode']])){
  205. }else{
  206. $tmp = [
  207. "Inum" => "PurchaseIn",
  208. "data" =>[
  209. "iHead" => [
  210. "bIsRedVouch" => true, // 表体必须负数
  211. "bCalPrice" => true, // 是否由接口计算金额
  212. "cWhCode" => $value['cWhCode'],
  213. "cRdCode" => $order['rd_code'], // 入库类别
  214. "cDepCode" => $order['depart_code'],
  215. "cARVCode" => $order['no'],
  216. "cSource" => "采购到货单",
  217. "cBusType" => "普通采购",
  218. "cMemo" => "",
  219. "dDate" => date("Y-m-d"),
  220. "IsVerify" => true,
  221. ],
  222. "iBody" => $order['details'],
  223. ],
  224. ];
  225. }
  226. }
  227. //调用所需
  228. $host = $data['u8_data']['host'] ?? "";
  229. $token = $data['u8_data']['token'] ?? "";
  230. //采购退货单生成
  231. $header = ["Authorization: {$token}",'Content-Type:application/json'];
  232. //生成红字采购入库单
  233. $url = $host . "/api/PurchaseIn/Add";
  234. $json_final[] = [
  235. "Inum" => "PurchaseIn",
  236. "data" =>[
  237. "iHead" => [
  238. "bIsRedVouch" => true, // 表体必须负数
  239. "bCalPrice" => true, // 是否由接口计算金额
  240. "cWhCode" => $data['warehouseCode'],
  241. "cRdCode" => $order['rd_code'], // 入库类别
  242. "cDepCode" => $order['depart_code'],
  243. "cARVCode" => $order['no'],
  244. "cSource" => "采购到货单",
  245. "cBusType" => "普通采购",
  246. "cMemo" => "",
  247. "dDate" => date("Y-m-d"),
  248. "IsVerify" => true,
  249. ],
  250. "iBody" => $order['details'],
  251. ],
  252. ];
  253. $json = json_encode($json_final);
  254. list($status, $result) = $this->post_helper1($url,$json, $header, 30);
  255. if(! $status) return [false, $result];
  256. if(! isset($result['code'])) return [false, '红字采购入库单生成并审核失败'];
  257. if($result['code'] != 0) return [false, $result['msg']];
  258. return [true, ''];
  259. }
  260. public function post_helper1($url, $data, $header = [], $timeout = 20){
  261. Log::channel('apiLog')->info('POST', ["api" => $url , "param" => json_decode($data,true) ,"header" => $header]);
  262. $ch = curl_init();
  263. curl_setopt($ch, CURLOPT_URL, $url);
  264. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  265. curl_setopt($ch, CURLOPT_ENCODING, '');
  266. curl_setopt($ch, CURLOPT_POST, 1);
  267. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
  268. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  269. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  270. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  271. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  272. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
  273. if(!is_null($data)) curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  274. $r = curl_exec($ch);
  275. if ($r === false) {
  276. // 获取错误号
  277. $errorNumber = curl_errno($ch);
  278. // 获取错误信息
  279. $errorMessage = curl_error($ch);
  280. $message = "cURL Error #{$errorNumber}: {$errorMessage}";
  281. Log::channel('apiLog')->info('POST结果', ["message" => $message ]);
  282. return [false, $message];
  283. }
  284. curl_close($ch);
  285. $return = json_decode($r, true);
  286. unset($r);
  287. Log::channel('apiLog')->info('POST结果', ["message" => $return ]);
  288. return [true, $return];
  289. }
  290. function validateProductDate($dateStr) {
  291. // SQL Server 常用的 datetime 格式包含 .v (毫秒)
  292. // 注意:这里的格式必须严格对应 " 2025-12-13 00:00:00.000"
  293. // 如果字符串开头有空格,格式字符串里也要留空格
  294. $format = ' Y-m-d H:i:s.v';
  295. $d = \DateTime::createFromFormat($format, $dateStr);
  296. // 检查是否转换成功,并且转换后的格式与原字符串完全一致
  297. return $d && $d->format($format) === $dateStr;
  298. }
  299. }