ZopOrderService.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. <?php
  2. namespace app\common\service;
  3. use app\common\model\Area;
  4. use app\common\model\MobileOrder;
  5. use app\common\model\Produce;
  6. /**
  7. * 联通商城zop订单统一接入文档
  8. */
  9. class ZopOrderService extends ZopBaseService
  10. {
  11. /**
  12. * 推送订单到联通商城
  13. *
  14. * @param integer $orderId
  15. * @return array
  16. */
  17. public static function push($orderId = 0)
  18. {
  19. // 获取订单信息
  20. $order = MobileOrder::where('id', $orderId)->with('produce')->find();
  21. if (empty($order)) {
  22. return self::error('订单不存在');
  23. }
  24. $produce = $order->produce ?? null;
  25. if (empty($produce)) {
  26. return self::error('商品不存在');
  27. }
  28. if ($order->is_cancel == 1) {
  29. return self::error('订单已取消');
  30. }
  31. // 根据商品类型, 调用不同的推送方法
  32. $operator = $produce->operator ?? '';
  33. $result = [];
  34. switch ($operator) {
  35. case 'cucc':
  36. $result = self::cuccPush($order, $produce);
  37. break;
  38. case 'cmcc':
  39. break;
  40. case 'ctcc':
  41. break;
  42. default:
  43. $result = self::error('运营商类型错误');
  44. }
  45. return $result;
  46. }
  47. /**
  48. * 联通推送
  49. *
  50. * @param MobileOrder $order
  51. * @param Produce $produce
  52. * @return void
  53. */
  54. public static function cuccPush(MobileOrder $order, Produce $produce)
  55. {
  56. // 1. 资源上传
  57. $goodsId = $produce->api_goods_id ?? 0;
  58. $channel = $produce->contact_code ?? '';
  59. $images = $produce->images ?? '';
  60. $resourceId = $produce->resource_id ?? 0;
  61. // if (empty($resourceId)) {
  62. if (empty($goodsId)) {
  63. return self::error('上游编码为空');
  64. }
  65. if (empty($channel)) {
  66. return self::error('触点编码为空');
  67. }
  68. if (empty($images)) {
  69. return self::error('图片为空');
  70. }
  71. // 如果图片是地址的话, 就转换成base64
  72. if (strpos($images, 'http') === 0) {
  73. $imagesBase = base64_encode(file_get_contents($images));
  74. // 获取图片 MIME 类型
  75. $sizeInfo = getimagesize($images);
  76. $mimeType = $sizeInfo['mime'];
  77. // 构建数据 URI
  78. $images = 'data:' . $mimeType . ';base64,' . $imagesBase;
  79. }
  80. $resourceParams = [
  81. 'goodsId' => $goodsId,
  82. 'channel' => $channel,
  83. 'resourceContents' => [
  84. [
  85. 'content' => $images,
  86. 'sort' => 0
  87. ]
  88. ],
  89. ];
  90. $resourceResult = self::resourceUpload($resourceParams, $order);
  91. if ($resourceResult['code'] != 0) {
  92. // 写入订单错误信息
  93. $order->failure_reason = $resourceResult['message'];
  94. $order->save();
  95. return $resourceResult;
  96. }
  97. // 获取资源ID
  98. $resourceId = $resourceResult['data']['resourceId'] ?? '';
  99. $produce->resource_id = $resourceId;
  100. $produce->save();
  101. // }
  102. // 2. 客户资料校验
  103. $cityData = $order->city ?? '';
  104. $cityData = explode(',', $cityData);
  105. if (count($cityData) < 2) {
  106. return self::error('城市信息不完整');
  107. }
  108. $province = $cityData[0] ?? 0;
  109. $city = $cityData[1] ?? 0;
  110. $district = $cityData[2] ?? 0;
  111. $provinceNumCode = Area::where('id', $province)->value('num_code');
  112. $cityNumCode = Area::where('id', $city)->value('num_code');
  113. $certName = $order->name ?? '';
  114. $certNum = $order->id_no ?? '';
  115. if (empty($provinceNumCode) || empty($cityNumCode) || empty($certName) || empty($certNum)) {
  116. return self::error('客户信息不完整');
  117. }
  118. $identityParams = [
  119. 'province' => $provinceNumCode,
  120. 'city' => $cityNumCode,
  121. 'certName' => $certName,
  122. 'certNum' => $certNum,
  123. ];
  124. $identityResult = self::identityCust($identityParams, $order);
  125. if ($identityResult['code'] != 0) {
  126. // 写入订单错误信息
  127. $order->failure_reason = $identityResult['message'];
  128. $order->save();
  129. return $identityResult;
  130. }
  131. // 获取uuid
  132. $uuid = $identityResult['data']['uuid'] ?? '';
  133. // 3.0 判断有没有手机号, 如果没有手机号, 则走自动选好接口
  134. $orderId = $order->order_no ?? '';
  135. $contactNum = $order->phone ?? '';
  136. $postProvinceCode = Area::where('id', $province)->value('post_code');
  137. $postCityCode = Area::where('id', $city)->value('post_code');
  138. $postDistrictCode = Area::where('id', $district)->value('post_code');
  139. $postAddr = $order->address ?? '';
  140. $createTime = $order->create_time ?? '';
  141. $updateTime = $order->update_time ?? '';
  142. $amount = $order->amount ?? 0;
  143. $orderTotalFee = bcmul($amount, 1000, 0);
  144. $pageUrl = $produce->link ?? '';
  145. // 判断产品是否使用用户收货地址区号
  146. $numProvinceCode = $postProvinceCode;
  147. $numCityCode = $postCityCode;
  148. $homeLocationType = $produce->home_location_type ?? 'address';
  149. if ($homeLocationType == 'assign') {
  150. $numProvinceCode = $produce->home_location_province ?? 0;
  151. $numCityCode = $produce->home_location_city ?? 0;
  152. }
  153. $no = $order['no'];
  154. if (empty($no)) {
  155. // 自动选号-订单同步接口
  156. $autoOrderParams = [
  157. 'orderId' => $orderId,
  158. 'goodsId' => $goodsId,
  159. 'certName' => $certName,
  160. 'certNo' => $certNum,
  161. 'contactNum' => $contactNum,
  162. 'numProvinceCode' => $numProvinceCode,
  163. 'numCityCode' => $numCityCode,
  164. 'postProvinceCode' => $postProvinceCode,
  165. 'postCityCode' => $postCityCode,
  166. 'postDistrictCode' => $postDistrictCode,
  167. 'postAddr' => $postAddr,
  168. 'channel' => $channel,
  169. 'createTime' => $createTime,
  170. 'updateTime' => $updateTime,
  171. 'orderTotalFee' => $orderTotalFee,
  172. 'pageUrl' => $pageUrl,
  173. 'resourceId' => $resourceId,
  174. ];
  175. $orderResult = self::autoNumSync($autoOrderParams, $order);
  176. if ($orderResult['code'] != 0) {
  177. // 写入订单错误信息
  178. $order->failure_reason = $orderResult['message'];
  179. $order->save();
  180. return $orderResult;
  181. }
  182. $no = $orderResult['data']['preNumber'] ?? '';
  183. $order->no = $no;
  184. $order->save();
  185. } else {
  186. // 3. 选号后置-意向单同步
  187. $preOrderParams = [
  188. 'orderId' => $orderId,
  189. 'goodsId' => $goodsId,
  190. 'certName' => $certName,
  191. 'certNo' => $certNum,
  192. 'contactNum' => $contactNum,
  193. 'postProvinceCode' => $postProvinceCode,
  194. 'postCityCode' => $postCityCode,
  195. 'postDistrictCode' => $postDistrictCode,
  196. 'postAddr' => $postAddr,
  197. 'channel' => $channel,
  198. 'createTime' => $createTime,
  199. 'updateTime' => $updateTime,
  200. 'orderTotalFee' => $orderTotalFee,
  201. 'pageUrl' => $pageUrl,
  202. 'resourceId' => $resourceId,
  203. ];
  204. $preOrderResult = self::preOrdersync($preOrderParams, $order);
  205. if ($preOrderResult['code'] != 0) {
  206. // 写入订单错误信息
  207. $order->failure_reason = $preOrderResult['message'];
  208. $order->save();
  209. return $preOrderResult;
  210. }
  211. $token = $preOrderResult['data']['token'] ?? '';
  212. // 4. 选号服务(暂不需要)
  213. // 5. 选号后置-正式单同步(非提前预占版)
  214. $phoneNum = $order->no ?? '';
  215. $isOpenCF = 0;
  216. $orderParams = [
  217. 'goodsId' => $goodsId,
  218. 'provinceCode' => $numProvinceCode,
  219. 'cityCode' => $numCityCode,
  220. 'phoneNum' => $phoneNum,
  221. 'token' => $token,
  222. 'createTime' => $createTime,
  223. 'isOpenCF' => $isOpenCF,
  224. ];
  225. $orderResult = self::ordersync($orderParams, $order);
  226. if ($orderResult['code'] != 0) {
  227. // 写入订单错误信息
  228. $order->failure_reason = $orderResult['message'];
  229. $order->save();
  230. return $orderResult;
  231. }
  232. }
  233. $order->failure_reason = '操作成功';
  234. $order->is_push_zop = 1;
  235. $order->save();
  236. return $orderResult;
  237. }
  238. /**
  239. * 资源上传
  240. *
  241. * @param array $params [channel: 渠道, goodsId: 商品ID, resourceContents: [content: 资源内容, sort: 排序]]]
  242. * @return array
  243. */
  244. public static function resourceUpload($params = [], $order = null)
  245. {
  246. $url = '/link/king/resource/upload/v1';
  247. $data = array_only($params, [
  248. 'channel',
  249. 'goodsId',
  250. 'resourceContents'
  251. ]);
  252. $result = self::send($url, $data, $order);
  253. if (empty($result)) {
  254. return self::error('资源上传请求失败');
  255. }
  256. $resArr = json_decode($result, true);
  257. if ($resArr['rspCode'] != '0000') {
  258. return self::error('资源上传请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  259. }
  260. $body = $resArr['body'];
  261. return self::success($body);
  262. }
  263. /**
  264. * 客户资料校验
  265. *
  266. * @param array $params [province: 省份编码, city.地市编码, certName. 证件姓名, certNum. 证件编码]
  267. * @return array
  268. */
  269. public static function identityCust($params = [], $order = null)
  270. {
  271. $url = '/link/king/identity/cust/v2';
  272. $data = array_only($params, [
  273. 'province',
  274. 'city',
  275. 'certName',
  276. 'certNum'
  277. ]);
  278. $result = self::send($url, $data, $order);
  279. if (empty($result)) {
  280. return self::error('客户资料校验请求失败');
  281. }
  282. $resArr = json_decode($result, true);
  283. if ($resArr['aCode'] != '0000') {
  284. return self::error('客户资料校验请求失败, 错误编码为: ' . $resArr['aCode'] . '错误信息为: ' . $resArr['aDesc']);
  285. }
  286. if ($resArr['bCode'] != '0000') {
  287. return self::error('客户资料校验请求失败, 错误编码为: ' . $resArr['bCode'] . '错误信息为: ' . $resArr['bDesc']);
  288. }
  289. $uuid = $resArr['uuid'] ?? '';
  290. return self::success(['uuid' => $uuid]);
  291. }
  292. /**
  293. * 选号后置-意向单同步
  294. *
  295. * @param array $params [orderId: 订单ID, goodsId: 商品ID, certName: 证件姓名, certNo: 证件编码, contactNum: 联系电话, postProvinceCode: 省份编码, postCityCode: 地市编码, postDistrictCode: 区县编码, postAddr: 详细地址, channel: 渠道, createTime: 创建时间, updateTime: 更新时间, orderTotalFee: 订单总金额, pageUrl: 页面地址, resourceId: 资源ID]
  296. * @return array
  297. */
  298. public static function preOrdersync($params = [], $order = null)
  299. {
  300. $url = '/link/king/card/preOrder/preOrdersync';
  301. $data = array_only($params, [
  302. 'orderId',
  303. 'goodsId',
  304. 'certName',
  305. 'certNo',
  306. 'contactNum',
  307. 'postProvinceCode',
  308. 'postCityCode',
  309. 'postDistrictCode',
  310. 'postAddr',
  311. 'channel',
  312. 'createTime',
  313. 'updateTime',
  314. 'orderTotalFee',
  315. 'pageUrl',
  316. 'resourceId'
  317. ]);
  318. $data['launchPlatform'] = self::getRandLaunchPlatform();
  319. $result = self::send($url, $data, $order);
  320. if (empty($result)) {
  321. return self::error('意向单同步请求失败');
  322. }
  323. $resArr = json_decode($result, true);
  324. if ($resArr['rspCode'] != '0000') {
  325. return self::error('意向单同步请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  326. }
  327. $body = $resArr['body'] ?? '';
  328. if (is_string($body)) {
  329. $body = json_decode($body, true);
  330. }
  331. return self::success($body);
  332. }
  333. /**
  334. * 随机获取投放平台
  335. *
  336. * @return void
  337. */
  338. public static function getRandLaunchPlatform()
  339. {
  340. $data = [
  341. '抖音APP',
  342. '快手APP',
  343. '拼多多APP',
  344. '腾讯视频APP',
  345. '手淘APP',
  346. '百度APP',
  347. '美团APP',
  348. '拼团微信小程序',
  349. '生态合作',
  350. '广点通',
  351. '巨量引擎'
  352. ];
  353. $randKey = array_rand($data);
  354. $platform = $data[$randKey];
  355. return $platform;
  356. }
  357. /**
  358. * 选号服务
  359. *
  360. * @param array $params [goodsId: 商品ID, provinceCode: 省份编码, cityCode: 地市编码, searchCategory: 搜索类别: 1、普通选号 2、靓号选号 3、全部(普通、靓号都包括)]
  361. * @return array
  362. */
  363. public static function linkNumSelect($params = [], $order = null)
  364. {
  365. $url = '/link/num/select/v1';
  366. $data = array_only($params ,[
  367. 'goodsId',
  368. 'provinceCode',
  369. 'cityCode',
  370. 'searchCategory',
  371. ]);
  372. $data['qryType'] = '02';
  373. $result = self::send($url, $data, $order);
  374. if (empty($result)) {
  375. return self::error('选号服务请求失败');
  376. }
  377. $resArr = json_decode($result, true);
  378. if ($resArr['rspCode'] != 'M0') {
  379. return self::error('选号服务请求失败: ' . $resArr['rspDesc']);
  380. }
  381. $body = $resArr['body'] ?? '';
  382. $numArray = $body['numArray'] ?? [];
  383. $splitLen = $body['splitLen'] ?? 12;
  384. if (!empty($numArray)) {
  385. $numArray = array_column(array_chunk($numArray, $splitLen), 0);
  386. }
  387. return self::success($numArray);
  388. }
  389. /**
  390. * 选号后置-正式单同步(非提前预占版)
  391. *
  392. * @param array $params
  393. * @return array
  394. */
  395. public static function ordersync($params = [], $order = null)
  396. {
  397. $url = '/link/king/card/preOrder/ordersync/v2';
  398. $data = array_only($params, [
  399. 'goodsId',
  400. 'provinceCode',
  401. 'cityCode',
  402. 'phoneNum',
  403. 'token',
  404. 'createTime',
  405. 'isOpenCF'
  406. ]);
  407. $result = self::send($url, $data, $order);
  408. if (empty($result)) {
  409. return self::error('正式单同步请求失败');
  410. }
  411. $resArr = json_decode($result, true);
  412. if ($resArr['rspCode'] != '0000') {
  413. return self::error('正式单同步请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  414. }
  415. $body = $resArr['body'] ?? '';
  416. if (is_string($body)) {
  417. $body = json_decode($body, true);
  418. }
  419. return self::success($body);
  420. }
  421. /**
  422. * 查询省市区信息
  423. *
  424. * @param array $params
  425. * @return array
  426. */
  427. public static function postInfo($params = [], $order = null)
  428. {
  429. $url = '/link/king/postInfo/qry';
  430. $data = array_only($params, [
  431. 'provinceCode'
  432. ]);
  433. $result = self::send($url, $data, $order);
  434. if (empty($result)) {
  435. return self::error('查询省市区信息请求失败');
  436. }
  437. $resArr = json_decode($result, true);
  438. if ($resArr['rspCode'] != '0000') {
  439. return self::error('查询省市区信息请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  440. }
  441. $body = $resArr['body'] ?? '';
  442. if (is_string($body)) {
  443. $body = json_decode($body, true);
  444. }
  445. return self::success($body);
  446. }
  447. /**
  448. * 获取订单消息
  449. *
  450. * @return void
  451. */
  452. public static function orderMsg($type = 4)
  453. {
  454. $messageChannelCode = config('site.message_channel_code');
  455. if (empty($messageChannelCode)) {
  456. common_log('获取订单消息请求失败: 消息渠道编码为空');
  457. return self::error('获取订单消息请求失败: 消息渠道编码为空');
  458. }
  459. $url = '/link/king/card/msg/get/v1';
  460. $data = [
  461. 'msgChannel' => config('site.message_channel_code'),
  462. 'type' => $type,
  463. ];
  464. $result = self::send($url, $data);
  465. if (empty($result)) {
  466. common_log('获取订单消息请求失败');
  467. return self::error('获取订单消息请求失败');
  468. }
  469. $resArr = json_decode($result, true);
  470. if ($resArr['rspCode'] != '0000') {
  471. common_log('获取订单消息请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  472. return self::error('获取订单消息请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  473. }
  474. $body = $resArr['body'] ?? '';
  475. if (is_string($body)) {
  476. $body = json_decode($body, true);
  477. }
  478. $delMsgIds = [];
  479. foreach ($body as $val) {
  480. // 根据返回信息, 更新订单状态
  481. $orderNo = $val['order'] ?? '';
  482. // 订单变更类型:1:激活,2:退单(激活前),3:转套餐(要根据产品id判断是否为享有特权的套餐),4:销户(激活后),6:首充数据同步,C1:开户完成,E0:发货,SX:未支付超期,AX:未支付用户取消,SX和AX状态目前仅支持3.27接口同步订单
  483. $state = $val['state'] ?? '';
  484. $id = $val['id'] ?? '';
  485. $order = MobileOrder::where('order_no', $orderNo)->find();
  486. if (empty($order)) {
  487. $delMsgIds[] = $id;
  488. continue;
  489. }
  490. if ($state == 1) {
  491. // 激活
  492. $order->produce_activation = 1;
  493. $order->save();
  494. } else if ($state == 6) {
  495. // 首充
  496. $amount = $val['lgtsId'] ?? 0;
  497. $order->produce_is_recharge = 1;
  498. $order->first_amount = $amount;
  499. $order->save();
  500. } else if ($state == 'C1') {
  501. // 开户
  502. $order->produce_status = 1;
  503. $order->save();
  504. } else if ($state == 'E0') {
  505. // 发货
  506. $order->logistics_numbers = $val['trackingNumber'] ?? '';
  507. $order->save();
  508. }
  509. $delMsgIds[] = $id;
  510. }
  511. $delMsgIds = implode(',', $delMsgIds);
  512. self::delOrderMsg($delMsgIds, $type);
  513. }
  514. /**
  515. * 删除订单消息
  516. *
  517. * @return void
  518. */
  519. public static function delOrderMsg($msgId = '', $type = 4)
  520. {
  521. $url = '/link/king/card/msg/del/v1';
  522. $data = [
  523. 'msgId' => $msgId,
  524. 'type' => $type,
  525. ];
  526. $result = self::send($url, $data);
  527. if (empty($result)) {
  528. common_log('删除订单消息请求失败');
  529. return self::error('删除订单消息请求失败');
  530. }
  531. $resArr = json_decode($result, true);
  532. if ($resArr['rspCode'] != '0000') {
  533. common_log('删除订单消息请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  534. return self::error('删除订单消息请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  535. }
  536. $body = $resArr['body'] ?? '';
  537. if (is_string($body)) {
  538. $body = json_decode($body, true);
  539. }
  540. $delSuccessNum = $body['delSuccessNum'] ?? 0;
  541. common_log('删除成功数量: ' . $delSuccessNum . ', 删除成功ID: ' . $msgId);
  542. return self::success('删除成功数量: ' . $delSuccessNum);
  543. }
  544. /**
  545. * 自动选号-订单同步接口
  546. *
  547. * @param array $params [orderId: 订单ID, goodsId: 商品ID, certName: 证件姓名, certNo: 证件编码, contactNum: 联系电话, postProvinceCode: 省份编码, postCityCode: 地市编码, postDistrictCode: 区县编码, postAddr: 详细地址, channel: 渠道, createTime: 创建时间, updateTime: 更新时间, orderTotalFee: 订单总金额, pageUrl: 页面地址, resourceId: 资源ID]
  548. * @return array
  549. */
  550. public static function autoNumSync($params = [], $order = null)
  551. {
  552. $url = '/link/king/card/preOrder/autoNumSync';
  553. $data = array_only($params, [
  554. 'orderId',
  555. 'goodsId',
  556. 'certName',
  557. 'certNo',
  558. 'contactNum',
  559. 'numProvinceCode',
  560. 'numCityCode',
  561. 'postProvinceCode',
  562. 'postCityCode',
  563. 'postDistrictCode',
  564. 'postAddr',
  565. 'channel',
  566. 'createTime',
  567. 'updateTime',
  568. 'orderTotalFee',
  569. 'pageUrl',
  570. 'resourceId',
  571. ]);
  572. $data['launchPlatform'] = self::getRandLaunchPlatform();
  573. // 额外加
  574. $data['contractId'] = '91200266';
  575. $result = self::send($url, $data, $order);
  576. if (empty($result)) {
  577. return self::error('自动选号请求失败');
  578. }
  579. $resArr = json_decode($result, true);
  580. if ($resArr['rspCode'] != '0000') {
  581. return self::error('自动选号请求失败, 错误编码为: ' . $resArr['rspCode'] . '错误信息为: ' . $resArr['rspDesc']);
  582. }
  583. $body = $resArr['body'] ?? '';
  584. if (is_string($body)) {
  585. $body = json_decode($body, true);
  586. }
  587. return self::success($body);
  588. }
  589. }