Logistics.php 14 KB

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