Logistics.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <?php
  2. namespace common\helpers;
  3. use common\models\OrderGoods;
  4. use common\models\Region;
  5. use common\models\ShopGoods;
  6. use Yii;
  7. class Logistics
  8. {
  9. const prodDomain = 'https//warehouse.taoplus.com.my';
  10. const testDomain = 'http://warehouse.worldsyntech.com';
  11. // 1.获取bearer token,此token是其他api调用时的必传参数.
  12. const authenticationUrl = 'http://warehouse.taoplus.com.my/index.php?route=rest/admin_security/api_login&grant_type=client_credentials';
  13. // 2.创建订单和产品(以前不存在/已提交的产品).
  14. const createOrderUrl = 'http://warehouse.taoplus.com.my/index.php?route=rest/warehouse_api/add_order';
  15. // 3.获取产品/包裹的重量和状态.
  16. const getProductUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/get_order_product';
  17. // 4.获取订单重量,m3,包装的包裹数量,费用跟踪号码和状态.
  18. const getOrderUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/get_order';
  19. // 5.通知仓库已经付款,包裹可以投递.
  20. const notifyDeliveryUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/ warehouse_api/notify_delivery';
  21. // 6.创建产品/包裹.
  22. const addProductUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/add_order_product';
  23. // 7.创建交付订单并将现有产品绑定到订单.需要先调用接口6创建商品.
  24. const createOrderSimpleUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/add_order_simple';
  25. // 8.计算订单费用,并将订单状态改为待付款.
  26. const stockOutUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/stock_out';
  27. // 9.通知物流系统订单不可删除.error包含错误的订单ID.
  28. const notifyOrderUndeletableUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/notify_order_undeletable';
  29. // 10.取消订单产品/包裹。它将状态更改为无效,并保留订单产品/包裹.
  30. const cancelOrderProductUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/cancel_order_product';
  31. // 11.从数据库中删除订购产品/包裹.
  32. const deleteOrderProductUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/delete_order_product';
  33. // 12.取消订单,状态改为无效,保留订单不删除.
  34. const cancelOrderUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/cancel_order';
  35. // 13.从数据库中删除订单.
  36. const deleteOrderUrl = 'http://warehouse.worldsyntech.com/index.php?route=rest/warehouse_api/delete_order';
  37. // 14.运单追踪.
  38. const trackOrderUrl = 'https://taoplus.com.my/index.php?route=information/order_tracking/json&order_tracking_search=';
  39. // accessToken的缓存key
  40. const wstLogisticsBearerTokenKey = 'wstLogisticsBearerToken';
  41. // 国家
  42. const country = 'China';
  43. function __construct()
  44. {
  45. // if (!\Yii::$app->redis->get(self::wstLogisticsBearerTokenKey)) {
  46. $this->getAuthentication();
  47. // }
  48. }
  49. /**
  50. * 通用curl接口.
  51. * @param string $url api接口url
  52. * @param array $request_body 参数
  53. * @return mixed
  54. */
  55. function curl($url, $request_body)
  56. {
  57. $accessToken = \Yii::$app->redis->get(self::wstLogisticsBearerTokenKey);
  58. $ch = curl_init($url);
  59. header('Content-Type: application/json');
  60. $authorization = "Authorization: Bearer " . $accessToken;
  61. curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', $authorization]);
  62. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
  63. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  64. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request_body));
  65. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  66. $response = curl_exec($ch);
  67. curl_close($ch);
  68. return json_decode($response, true);
  69. }
  70. // 1.获取bearer token,此token是其他api调用时的必传参数.
  71. function getAuthentication()
  72. {
  73. $request = [
  74. 'user_name' => Yii::$app->params['wst']['userName'],
  75. 'password' => Yii::$app->params['wst']['password'],
  76. 'agent_id' => Yii::$app->params['wst']['agentId'],
  77. ];
  78. $ch = curl_init(self::authenticationUrl);
  79. header('Content-Type: application/json');
  80. $authorization = "Authorization: Basic " . Yii::$app->params['wst']['baseToken'];
  81. curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', $authorization]);
  82. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
  83. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  84. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));
  85. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  86. $response = curl_exec($ch);
  87. curl_close($ch);
  88. $result = json_decode($response, true);
  89. if ($result['success']) {
  90. // token和过期时间写入redis
  91. \Yii::$app->redis->set(self::wstLogisticsBearerTokenKey, $result['data']['access_token']);
  92. \Yii::$app->redis->expire(self::wstLogisticsBearerTokenKey, $result['data']['expires_in']);
  93. }
  94. }
  95. // 2.创建订单和产品(以前不存在/已提交的产品).
  96. function createOrder($order)
  97. {
  98. $request = [
  99. 'order_no' => $order['SN'], // 客户系统中的订单号
  100. 'delivery_method_id' => '60', // 快递方式ID. TODO: 133(test)
  101. 'warehouse_id' => '1', // 仓库ID. TODO:
  102. 'country' => 'China', // 收件人国家 Malaysia
  103. 'state' => Region::getCnName($order['PROVINCE']), // , // 收件人省 Johor(test)
  104. 'city' => Region::getCnName($order['CITY']) . Region::getCnName($order['COUNTY']), // 收件市县
  105. 'post_code' => $order['ZIP_CODE'], // 收件人邮政编码
  106. 'address' => $order['ADDRESS'], // 收件人送货地址
  107. 'consignee' => $order['CONSIGNEE_REAL_NAME'], // 收货人姓名,使用订单中的收货人真实姓名
  108. 'consignee_ic_number' => $order['CONSIGNEE_ID_NO'], // 收件人身份证号
  109. 'telephone' => $order['MOBILE'], // 收件人电话号码
  110. 'sender' => 'Elken', // 发件人名字
  111. 'sender_country' => 'Malaysia', // 发件人国家
  112. 'sender_state' => 'Selangor', // , // 发件人省
  113. 'sender_city' => 'Kuala Lumpur', // 发件人市县
  114. 'sender_post_code' => '47620', // 发件人邮政编码
  115. 'sender_address' => '11, 2nd Floor, Jalan TP5, Taman Perindustrian UEP, Subang Jaya', // 发件人地址
  116. 'sender_telephone' => '0380210088', // 发件人电话号码
  117. 'volumetric_details' => '3*4*20', // 规格
  118. ];
  119. // 查询商品
  120. $orderGoods = OrderGoods::find()
  121. ->alias('O')
  122. ->join('INNER JOIN', ShopGoods::tableName() . ' AS G', 'G.ID=O.GOODS_ID')
  123. ->where('O.ORDER_SN=:ORDER_SN', [':ORDER_SN' => $order['SN']])->select('O.ORDER_SN,O.REAL_PRICE,O.BUY_NUMS,O.SKU_CODE,O.GOODS_TITLE,G.CONTENT')
  124. ->asArray()
  125. ->all();
  126. // 需要数量乘倍数的产品编号
  127. $stackedProducts = Cache::getSystemConfig()['stackedProducts']['VALUE'];
  128. $stackedProducts = explode(',', $stackedProducts);
  129. $products = [];
  130. foreach ($orderGoods as $item) {
  131. $products[] = [
  132. 'product_no' => $item['SKU_CODE'], // 客户系统中的产品编号
  133. 'product_name' => $item['GOODS_TITLE'], // 产品名称
  134. 'tracking_number' => Date::today('Ymd') . $this->_random(10, 1),
  135. 'quantity' => in_array($item['SKU_CODE'], $stackedProducts) ? $item['BUY_NUMS'] * 2 : $item['BUY_NUMS'], // 产品数量
  136. 'total_price' => number_format(100, 2, '.', ''), // 订单总金额,Decimal 方便通关,固定100马币
  137. 'currency_code' => 'MYR', // 产品的货币代码. 如USD(美元),MYR(马来西亚林吉特),SGD(新加坡元),CNY(人民币)
  138. 'supplier' => 'MRT', // 品牌
  139. // 'remark' => '300ML', // 备注:规格
  140. 'remark' => $item['CONTENT'], // 备注:规格
  141. ];
  142. }
  143. $request['products'] = $products;
  144. LoggerTool::debug($request);
  145. // return $this->curl(self::createOrderUrl, $request);
  146. }
  147. // 3.获取产品/包裹的重量和状态.
  148. function getProduct($order)
  149. {
  150. $request = [
  151. 'tracking_number' => '027300027300',
  152. ];
  153. $response = $this->curl(self::getProductUrl, $request);
  154. LoggerTool::info($response);
  155. return $response;
  156. }
  157. // 4.获取订单重量,m3,包装的包裹数量,费用跟踪号码和状态
  158. function getOrder($order)
  159. {
  160. $request = [
  161. 'order_id' => 'elg8-785',
  162. ];
  163. $response = $this->curl(self::getOrderUrl, $request);
  164. LoggerTool::info($response);
  165. return $response;
  166. }
  167. // 5.通知仓库已经付款,包裹可以投递.
  168. function notifyDelivery($order)
  169. {
  170. $request = [
  171. 'order_id' => 'elg8-785',
  172. ];
  173. $response = $this->curl(self::notifyDeliveryUrl, $request);
  174. LoggerTool::info($response);
  175. return $response;
  176. }
  177. // 6.创建产品/包裹.
  178. function addProduct($orderProducts)
  179. {
  180. $products = [];
  181. foreach ($orderProducts as $item) {
  182. $products[] = [
  183. "product_no" => $item['SKU_CODE'],
  184. "product_name" => $item['GOODS_TITLE'],
  185. "tracking_number" => '',
  186. "quantity" => $item['BUY_NUMS'],
  187. "total_price" => $item['REAL_PV'],
  188. "currency_code" => "CNY",
  189. ];
  190. }
  191. $request = [
  192. 'warehouse_id' => '1',
  193. "products" => $products
  194. ];
  195. $response = $this->curl(self::addProductUrl, $request);
  196. LoggerTool::info($response);
  197. return $response;
  198. }
  199. // 7.创建交付订单并将现有产品绑定到订单.需要先调用接口6创建商品.
  200. function createOrderSimple($order)
  201. {
  202. $request = [
  203. "order_no" => "T-1000",
  204. "delivery_method_id" => "39",
  205. "warehouse_id" => "1",
  206. "country" => "Malaysia",
  207. "state" => "Pulau Pinang",
  208. "city" => "Bukit Mertajam",
  209. "post_code" => "14000",
  210. "address" => "1584,JALAN NANGKA,TAMAN JAMBU MAWAR,14000 BUKIT MERTAJAM",
  211. "consignee" => "TSA",
  212. "consignee_ic_number" => "111111-11-1111",
  213. "telephone" => "017-5423223",
  214. "cod" => "CNY",
  215. "cod_currency_code" => "100",
  216. "address_area" => "",
  217. "address_subdivision" => "",
  218. "products" => [
  219. [
  220. "product_no" => "12345",
  221. "tracking_number" => "2019061112A1",
  222. ],
  223. [
  224. "product_no" => "23456",
  225. "tracking_number" => "20190604_A12",
  226. ]
  227. ]
  228. ];
  229. $response = $this->curl(self::createOrderSimpleUrl, $request);
  230. LoggerTool::info($response);
  231. return $response;
  232. }
  233. // 8.根据货物重量计算订单费用,并更改订单状态为待付款
  234. function stockOut($order)
  235. {
  236. $request = [
  237. 'order_id' => 'elg8-785',
  238. 'weight' => '2.5', // 订单重量(KG)
  239. ];
  240. $response = $this->curl(self::stockOutUrl, $request);
  241. LoggerTool::info($response);
  242. return $response;
  243. }
  244. // 9.通知物流系统订单不可删除. error包含错误的订单ID.
  245. function notifyOrderUndeletable($order)
  246. {
  247. $request = [
  248. 'order_ids' => ['elg8-785']
  249. ];
  250. $response = $this->curl(self::notifyOrderUndeletableUrl, $request);
  251. LoggerTool::info($response);
  252. return $response;
  253. }
  254. // 10.取消订单产品/包裹。它将状态更改为无效,并保留订单产品/包裹.
  255. function cancelOrderProduct($order)
  256. {
  257. $request = [
  258. 'order_product_ids' => ['15895', '15896', '15897']
  259. ];
  260. $response = $this->curl(self::cancelOrderProductUrl, $request);
  261. LoggerTool::info($response);
  262. return $response;
  263. }
  264. // 11.从数据库中删除订购产品/包裹.
  265. function deleteOrderProduct($order)
  266. {
  267. $request = [
  268. 'order_product_ids' => ['15895', '15896', '15897']
  269. ];
  270. $response = $this->curl(self::deleteOrderProductUrl, $request);
  271. LoggerTool::info($response);
  272. return $response;
  273. }
  274. // 12.取消订单,状态改为无效,保留订单不删除.
  275. function cancelOrder($order)
  276. {
  277. $request = [
  278. 'order_ids' => ['elg8-787', 'elg8-786']
  279. ];
  280. $response = $this->curl(self::cancelOrderUrl, $request);
  281. LoggerTool::info($response);
  282. return $response;
  283. }
  284. // 13.从数据库中删除订单.
  285. function deleteOrder($order)
  286. {
  287. $request = [
  288. 'order_ids' => ['elg8-787', 'elg8-786']
  289. ];
  290. $response = $this->curl(self::deleteOrderUrl, $request);
  291. LoggerTool::info($response);
  292. return $response;
  293. }
  294. // 13.从数据库中删除订单.
  295. function trackOrder($trackNo)
  296. {
  297. // 运单号
  298. $trackNo = 'TBS10182495KJ2430';
  299. $curl = curl_init();
  300. curl_setopt($curl,CURLOPT_TIMEOUT,5000);
  301. curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
  302. curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
  303. curl_setopt($curl,CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
  304. curl_setopt($curl,CURLOPT_URL, self::trackOrderUrl . $trackNo);
  305. curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
  306. $response = curl_exec($curl);
  307. if (!$response) {
  308. $error = curl_errno($curl);
  309. curl_close($curl);
  310. LoggerTool::error($error);
  311. return false;
  312. }
  313. curl_close($curl);
  314. $result = json_decode($response, true);
  315. LoggerTool::info($result);
  316. return $result['data'];
  317. }
  318. /**
  319. * 生成随机数
  320. * @param $length
  321. * @param int $numeric
  322. * @return string
  323. */
  324. private function _random($length, $numeric = 0) {
  325. $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
  326. $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
  327. $hash = '';
  328. $max = strlen($seed) - 1;
  329. for ($i = 0; $i < $length; $i++) {
  330. $hash .= $seed[mt_rand(0, $max)];
  331. }
  332. return $hash;
  333. }
  334. }