Logistics.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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. 'telephone' => $order['MOBILE'], // 收件人电话号码
  140. 'products' => [
  141. [
  142. 'product_no' => $order['SKU_CODE'], // 客户系统中的产品编号
  143. 'product_name' => $order['GOODS_TITLE'], // 产品名称
  144. 'tracking_number' => Date::today('Ymd') . $this->_random(10, 1), // TODO:快递号 027300027302
  145. 'quantity' => $order['BUY_NUMS'], // 产品数量
  146. 'total_price' => $order['PAY_AMOUNT'], // 订单总金额,Decimal
  147. 'currency_code' => 'CNY', // 产品的货币代码. 如USD(美元),MYR(马来西亚林吉特),SGD(新加坡元),CNY(人民币)
  148. ],
  149. ],
  150. ];
  151. return $this->curl(self::createOrderUrl, $request);
  152. }
  153. // 3.获取产品/包裹的重量和状态.
  154. function getProduct($order)
  155. {
  156. $request = [
  157. 'tracking_number' => '027300027300',
  158. ];
  159. $response = $this->curl(self::getProductUrl, $request);
  160. LoggerTool::info($response);
  161. return $response;
  162. }
  163. // 4.获取订单重量,m3,包装的包裹数量,费用跟踪号码和状态
  164. function getOrder($order)
  165. {
  166. $request = [
  167. 'order_id' => 'elg8-785',
  168. ];
  169. $response = $this->curl(self::getOrderUrl, $request);
  170. LoggerTool::info($response);
  171. return $response;
  172. }
  173. // 5.通知仓库已经付款,包裹可以投递.
  174. function notifyDelivery($order)
  175. {
  176. $request = [
  177. 'order_id' => 'elg8-785',
  178. ];
  179. $response = $this->curl(self::notifyDeliveryUrl, $request);
  180. LoggerTool::info($response);
  181. return $response;
  182. }
  183. // 6.创建产品/包裹.
  184. function addProduct($orderProducts)
  185. {
  186. $products = [];
  187. foreach ($orderProducts as $item) {
  188. $products[] = [
  189. "product_no" => $item['SKU_CODE'],
  190. "product_name" => $item['GOODS_TITLE'],
  191. "tracking_number" => '',
  192. "quantity" => $item['BUY_NUMS'],
  193. "total_price" => $item['REAL_PV'],
  194. "currency_code" => "CNY",
  195. ];
  196. }
  197. $request = [
  198. 'warehouse_id' => '1',
  199. "products" => $products
  200. ];
  201. $response = $this->curl(self::addProductUrl, $request);
  202. LoggerTool::info($response);
  203. return $response;
  204. }
  205. // 7.创建交付订单并将现有产品绑定到订单.需要先调用接口6创建商品.
  206. function createOrderSimple($order)
  207. {
  208. $request = [
  209. "order_no" => "T-1000",
  210. "delivery_method_id" => "39",
  211. "warehouse_id" => "1",
  212. "country" => "Malaysia",
  213. "state" => "Pulau Pinang",
  214. "city" => "Bukit Mertajam",
  215. "post_code" => "14000",
  216. "address" => "1584,JALAN NANGKA,TAMAN JAMBU MAWAR,14000 BUKIT MERTAJAM",
  217. "consignee" => "TSA",
  218. "consignee_ic_number" => "111111-11-1111",
  219. "telephone" => "017-5423223",
  220. "cod" => "CNY",
  221. "cod_currency_code" => "100",
  222. "address_area" => "",
  223. "address_subdivision" => "",
  224. "products" => [
  225. [
  226. "product_no" => "12345",
  227. "tracking_number" => "2019061112A1",
  228. ],
  229. [
  230. "product_no" => "23456",
  231. "tracking_number" => "20190604_A12",
  232. ]
  233. ]
  234. ];
  235. $response = $this->curl(self::createOrderSimpleUrl, $request);
  236. LoggerTool::info($response);
  237. return $response;
  238. }
  239. // 8.根据货物重量计算订单费用,并更改订单状态为待付款
  240. function stockOut($order)
  241. {
  242. $request = [
  243. 'order_id' => 'elg8-785',
  244. 'weight' => '2.5', // 订单重量(KG)
  245. ];
  246. $response = $this->curl(self::stockOutUrl, $request);
  247. LoggerTool::info($response);
  248. return $response;
  249. }
  250. // 9.通知物流系统订单不可删除. error包含错误的订单ID.
  251. function notifyOrderUndeletable($order)
  252. {
  253. $request = [
  254. 'order_ids' => ['elg8-785']
  255. ];
  256. $response = $this->curl(self::notifyOrderUndeletableUrl, $request);
  257. LoggerTool::info($response);
  258. return $response;
  259. }
  260. // 10.取消订单产品/包裹。它将状态更改为无效,并保留订单产品/包裹.
  261. function cancelOrderProduct($order)
  262. {
  263. $request = [
  264. 'order_product_ids' => ['15895', '15896', '15897']
  265. ];
  266. $response = $this->curl(self::cancelOrderProductUrl, $request);
  267. LoggerTool::info($response);
  268. return $response;
  269. }
  270. // 11.从数据库中删除订购产品/包裹.
  271. function deleteOrderProduct($order)
  272. {
  273. $request = [
  274. 'order_product_ids' => ['15895', '15896', '15897']
  275. ];
  276. $response = $this->curl(self::deleteOrderProductUrl, $request);
  277. LoggerTool::info($response);
  278. return $response;
  279. }
  280. // 12.取消订单,状态改为无效,保留订单不删除.
  281. function cancelOrder($order)
  282. {
  283. $request = [
  284. 'order_ids' => ['elg8-787', 'elg8-786']
  285. ];
  286. $response = $this->curl(self::cancelOrderUrl, $request);
  287. LoggerTool::info($response);
  288. return $response;
  289. }
  290. // 13.从数据库中删除订单.
  291. function deleteOrder($order)
  292. {
  293. $request = [
  294. 'order_ids' => ['elg8-787', 'elg8-786']
  295. ];
  296. $response = $this->curl(self::deleteOrderUrl, $request);
  297. LoggerTool::info($response);
  298. return $response;
  299. }
  300. // 13.从数据库中删除订单.
  301. function trackOrder($trackNo)
  302. {
  303. // 运单号
  304. $trackNo = 'TBS10182495KJ2430';
  305. $curl = curl_init();
  306. curl_setopt($curl,CURLOPT_TIMEOUT,5000);
  307. curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
  308. curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
  309. curl_setopt($curl,CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
  310. curl_setopt($curl,CURLOPT_URL, self::trackOrderUrl . $trackNo);
  311. curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
  312. $response = curl_exec($curl);
  313. if (!$response) {
  314. $error = curl_errno($curl);
  315. curl_close($curl);
  316. LoggerTool::error($error);
  317. return false;
  318. }
  319. curl_close($curl);
  320. $result = json_decode($response, true);
  321. LoggerTool::info($result);
  322. return $result['data'];
  323. }
  324. /**
  325. * 生成随机数
  326. * @param $length
  327. * @param int $numeric
  328. * @return string
  329. */
  330. private function _random($length, $numeric = 0) {
  331. $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
  332. $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
  333. $hash = '';
  334. $max = strlen($seed) - 1;
  335. for ($i = 0; $i < $length; $i++) {
  336. $hash .= $seed[mt_rand(0, $max)];
  337. }
  338. return $hash;
  339. }
  340. }