IntraCityExpress.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. <?php
  2. namespace common\components;
  3. use hd\models\IntraCity\StoreFeeForm;
  4. use Yii;
  5. use yii\helpers\Json;
  6. //use linslin\yii2\curl;
  7. use bizHd\wx\classes\WxOpenClass;
  8. use phpseclib\Crypt\RSA;
  9. class IntraCityExpress
  10. {
  11. /**
  12. * 订单状态常量
  13. */
  14. const ORDER_STATUS_CREATED = 10000; // 订单创建成功
  15. const ORDER_STATUS_CANCELED_BY_MERCHANT = 20000; // 商家取消订单
  16. const ORDER_STATUS_CANCELED_BY_DELIVERY = 20001; // 配送方取消订单
  17. const ORDER_STATUS_ACCEPTED = 30000; // 配送员接单
  18. const ORDER_STATUS_ARRIVED = 40000; // 配送员到店
  19. const ORDER_STATUS_DELIVERING = 50000; // 配送中
  20. const ORDER_STATUS_WITHDRAWN = 60000; // 配送员撤单
  21. const ORDER_STATUS_COMPLETED = 70000; // 配送完成
  22. const ORDER_STATUS_EXCEPTION = 90000; // 配送异常
  23. // 物品类型
  24. const GOODS_TYPE_FLOWER = 14; // 鲜花
  25. /**
  26. * 获取 access_token
  27. * @param $merchant
  28. * @param int $ptStyle
  29. * @return string
  30. */
  31. public static function getAccessToken($merchant, $ptStyle = 0)
  32. {
  33. if ($ptStyle == 0) {
  34. $ptStyle = dict::getDict('ptStyle', 'hd');
  35. }
  36. // 直接复用 miniUtil 的获取小程序 access_token 方法
  37. return miniUtil::getMiniProgramAccessToken($merchant, $ptStyle);
  38. }
  39. public static function getMerchant()
  40. {
  41. $merchant = WxOpenClass::getWxInfo();
  42. return $merchant;
  43. }
  44. /**
  45. * 使用 WxApi 方式生成微信API签名
  46. * @param string $url 请求URL
  47. * @param string $appId 小程序AppID
  48. * @param int $timestamp 时间戳
  49. * @param string $reqData 请求体JSON字符串
  50. * @return string 签名字符串
  51. */
  52. private static function generateWxApiSignature($url, $appId, $timestamp, $reqData)
  53. {
  54. // 获取私钥
  55. $env = getenv('YII_ENV') == 'production' ? 'production' : 'dev';
  56. $privateKeyPath = __DIR__ . '/wxapi/' . $env . '/rsa-private-key.txt';
  57. if (!file_exists($privateKeyPath)) {
  58. throw new \Exception("私钥文件不存在: {$privateKeyPath}");
  59. }
  60. $privateKey = file_get_contents($privateKeyPath);
  61. if (!$privateKey) {
  62. throw new \Exception('无法获取私钥文件');
  63. }
  64. // 构建签名载荷,格式:$url\n$appId\n$timestamp\n$reqData
  65. $payload = "$url\n$appId\n$timestamp\n$reqData";
  66. // 方案一: 使用 OpenSSL(推荐方式,与微信官方示例一致)
  67. // $signature = '';
  68. // $result = openssl_sign($payload, $signature, $privateKey, OPENSSL_ALGO_SHA256);
  69. // if (!$result) {
  70. // throw new \Exception('OpenSSL签名失败: ' . openssl_error_string());
  71. // }
  72. // $base64Signature = base64_encode($signature);
  73. // \Yii::info("生成的签名: " . $base64Signature, 'intracity_signature');
  74. // return $base64Signature;
  75. // 方案二:使用 RSA SHA256签名
  76. try {
  77. // 使用RSA SHA256签名
  78. $rsa = new RSA();
  79. $rsa->loadKey($privateKey);
  80. $rsa->setHash("sha256");
  81. $rsa->setMGFHash("sha256");
  82. $signature = $rsa->sign($payload);
  83. // $rsa = new RSA();
  84. // $rsa->loadKey($privateKey);
  85. // $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); // 明确使用PKCS#1 v1.5
  86. // $rsa->setHash("sha256");
  87. // 不要设置MGF,PKCS#1 v1.5不使用MGF
  88. // $signature = $rsa->sign($payload);
  89. $base64Signature = base64_encode($signature);
  90. \Yii::info("phpseclib生成的签名: " . $base64Signature, 'intracity_signature');
  91. return $base64Signature;
  92. } catch (\Exception $e) {
  93. \Yii::error("所有签名方法都失败 - OpenSSL: " . $e->getMessage() . " phpseclib: " . $e->getMessage(), 'intracity_signature');
  94. throw new \Exception('签名生成失败: OpenSSL和phpseclib都失败');
  95. }
  96. }
  97. /**
  98. * 发送HTTP请求
  99. * @param string $url 请求URL
  100. * @param array $data 请求数据
  101. * @param string $accessToken access_token
  102. * @return array
  103. */
  104. public static function sendRequest($url, $data, $accessToken)
  105. {
  106. // ================ 选择哪个 appId =================
  107. // 微信开放平台 appId
  108. $open = \biz\wx\classes\WxOpenClass::getByCondition(['style' => dict::getDict('ptStyle', 'hd')]);
  109. if (empty($open)) {
  110. util::fail('没有找到平台信息');
  111. }
  112. $component_app_id = $open['appId'];
  113. $appId = $component_app_id;
  114. // 当前小程序的 appId
  115. //$appId = $merchant['miniAppId'] ?? util::fail('app-id 出错');
  116. // 方式一: 使用WxApi方式处理请求 ============================
  117. try {
  118. $wxApi = new \common\components\wxapi\WxApi($appId, $accessToken);
  119. $result = $wxApi->request($url, $data);
  120. return $result;
  121. } catch (\Exception $e) {
  122. Yii::error($e->getMessage());
  123. $msg = $e->getMessage();
  124. // 如果WxApi方式失败,回退到简单方式
  125. util::fail($msg);
  126. }
  127. // 添加access_token到URL
  128. $urlWithToken = $url . (strpos($url, '?') !== false ? '&' : '?') . 'access_token=' . $accessToken;
  129. $timestamp = time();
  130. $body = Json::encode($data);
  131. if ($body === '[]') {
  132. $body = '{}';
  133. }
  134. // 方式二: 自己处理请求 =========== 失败,不使用(可删除)
  135. // $signature = self::generateWxApiSignature($url, $appId, $timestamp, $body);
  136. // 构建请求头,包含微信API签名所需的头部
  137. // $headers = [
  138. // 'Content-Type: application/json',
  139. // 'Accept: application/json',
  140. // 'Wechatmp-Appid: ' . $appId,
  141. // 'Wechatmp-TimeStamp: ' . $timestamp,
  142. // 'Wechatmp-Signature: ' . $signature
  143. // ];
  144. // $curl = new curl\Curl();
  145. // $response = $curl->setOption(CURLOPT_POSTFIELDS, $body)
  146. // ->setOption(CURLOPT_HTTPHEADER, $headers)
  147. // ->post($urlWithToken);
  148. // if (is_array($response)) {
  149. // return $response;
  150. // }
  151. // return Json::decode($response, true);
  152. }
  153. // ==================== API URL常量 ====================
  154. const API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin/express/intracity';
  155. // 门店管理
  156. const API_CREATE_STORE = self::API_BASE_URL . '/createstore';
  157. const API_UPDATE_STORE = self::API_BASE_URL . '/updatestore';
  158. const API_QUERY_STORE = self::API_BASE_URL . '/querystore';
  159. // 开通门店权限
  160. const API_APPLY_STORE = self::API_BASE_URL . '/apply';
  161. // 订单管理
  162. const API_ADD_ORDER = self::API_BASE_URL . '/addorder';
  163. const API_CANCEL_ORDER = self::API_BASE_URL . '/cancelorder';
  164. const API_GET_ORDER = self::API_BASE_URL . '/queryorder';
  165. // 预下单
  166. const API_PRE_ADD_ORDER = self::API_BASE_URL . '/preaddorder';
  167. // 资金管理
  168. const API_BALANCE_QUERY = self::API_BASE_URL . '/balancequery';
  169. const API_STORE_CHARGE = self::API_BASE_URL . '/storecharge';
  170. const API_STORE_REFUND = self::API_BASE_URL . '/storerefund';
  171. const API_CHARGE_RECORD = self::API_BASE_URL . '/queryflow';
  172. // 测试接口
  173. const API_MOCK_NOTIFY = self::API_BASE_URL . '/mocknotify';
  174. // ==================== 门店管理接口 ====================
  175. /**
  176. * 创建门店
  177. * @param array $storeData 门店信息
  178. * @param string $merchant 商户信息
  179. * @param int $ptStyle
  180. * @return array
  181. */
  182. public static function createStore($storeData, $merchant = null, $ptStyle = 0)
  183. {
  184. if ($merchant === null) {
  185. $merchant = self::getMerchant();
  186. }
  187. $accessToken = self::getAccessToken($merchant, $ptStyle);
  188. $data = [
  189. 'out_store_id' => $storeData['out_store_id'],
  190. 'store_name' => $storeData['store_name'],
  191. 'order_pattern' => 1,
  192. "address_info" => $storeData['address_info']
  193. ];
  194. return self::sendRequest(self::API_CREATE_STORE, $data, $accessToken);
  195. }
  196. /**
  197. * 更新门店
  198. * @param array $storeData 门店信息
  199. * @param string $merchant 商户信息
  200. * @param int $ptStyle
  201. * @return array
  202. */
  203. public static function updateStore($storeData, $merchant = null, $ptStyle = 0)
  204. {
  205. if ($merchant === null) {
  206. $merchant = self::getMerchant();
  207. }
  208. $accessToken = self::getAccessToken($merchant, $ptStyle);
  209. $data = $storeData;
  210. return self::sendRequest(self::API_UPDATE_STORE, $data, $accessToken);
  211. }
  212. /**
  213. * 查询门店
  214. * @param string $outStoreId 门店ID
  215. * @param string $merchant 商户信息
  216. * @param int $ptStyle
  217. * @return array
  218. */
  219. public static function getStore($outStoreId, $merchant = null, $ptStyle = 0)
  220. {
  221. if ($merchant === null) {
  222. $merchant = self::getMerchant();
  223. }
  224. $accessToken = self::getAccessToken($merchant, $ptStyle);
  225. $data = [
  226. 'out_store_id' => $outStoreId,
  227. ];
  228. return self::sendRequest(self::API_QUERY_STORE, $data, $accessToken);
  229. }
  230. /**
  231. * 开通门店权限
  232. * @param null $merchant
  233. * @param int $ptStyle
  234. * @return array
  235. */
  236. public static function applyStore($merchant = null, $ptStyle = 0)
  237. {
  238. if ($merchant === null) {
  239. $merchant = self::getMerchant();
  240. }
  241. $accessToken = self::getAccessToken($merchant, $ptStyle);
  242. return self::sendRequest(self::API_APPLY_STORE, [], $accessToken);
  243. }
  244. // ==================== 订单管理接口 ====================
  245. /**
  246. * 创建订单
  247. * @param array $orderData 订单信息
  248. * @param string $merchant 商户信息
  249. * @param int $ptStyle
  250. * @return array
  251. */
  252. public static function createOrder($orderData, $merchant = null, $ptStyle = 0)
  253. {
  254. if ($merchant === null) {
  255. $merchant = self::getMerchant();
  256. }
  257. $accessToken = self::getAccessToken($merchant, $ptStyle);
  258. //开发环境只能使用沙箱 ssh
  259. if (getenv('YII_ENV') != 'production') {
  260. $orderData['use_sandbox'] = 1;
  261. $orderData['user_name'] = '顺丰同城';
  262. $orderData['user_phone'] = (string)13881979410;
  263. $orderData['user_address'] = '北京市海淀区学清嘉创大厦A座15层';
  264. $orderData['user_lng'] = (double)116.352954;
  265. $orderData['user_lat'] = (double)40.014747;
  266. }
  267. $data = $orderData;
  268. return self::sendRequest(self::API_ADD_ORDER, $data, $accessToken);
  269. }
  270. /**
  271. * 预下单(查询运费)
  272. * @param array $orderData
  273. * @param null $merchant
  274. * @param int $ptStyle
  275. * @return array
  276. */
  277. public static function preAddOrder($orderData, $merchant = null, $ptStyle = 0)
  278. {
  279. // 花好鲜鲜花批发(安海部) user_name会被阻挡,不要打开
  280. // // 创建表单验证模型
  281. // $form = new StoreFeeForm();
  282. // $form->setScenario('query_fee');
  283. // $form->load($orderData, ''); // 直接从 post 数据加载,不使用模型名作为前缀
  284. // // 执行表单验证
  285. // $form->validateForm();
  286. if ($merchant === null) {
  287. $merchant = self::getMerchant();
  288. }
  289. $accessToken = self::getAccessToken($merchant, $ptStyle);
  290. //开发环境只能使用沙箱 ssh
  291. if (getenv('YII_ENV') != 'production') {
  292. $orderData['use_sandbox'] = 1;
  293. $orderData['user_name'] = '顺丰同城';
  294. $orderData['user_phone'] = (string)13881979410;
  295. $orderData['user_address'] = '北京市海淀区学清嘉创大厦A座15层';
  296. $orderData['user_lng'] = (double)116.352954;
  297. $orderData['user_lat'] = (double)40.014747;
  298. }
  299. // 请求体
  300. $data = $orderData;
  301. return self::sendRequest(self::API_PRE_ADD_ORDER, $data, $accessToken);
  302. }
  303. /**
  304. * 取消订单
  305. * @param string $wxOrderId 微信订单号
  306. * @param string $storeOrderId 商户订单号
  307. * @param string $wxStoreId 门店ID
  308. * @param string $merchant 商户信息
  309. * @param int $ptStyle
  310. * @return array
  311. */
  312. public static function cancelOrder($wxOrderId = '', $storeOrderId = '', $wxStoreId = '', $merchant = null, $ptStyle = 0)
  313. {
  314. if ($merchant === null) {
  315. $merchant = self::getMerchant();
  316. }
  317. $accessToken = self::getAccessToken($merchant, $ptStyle);
  318. $data = [];
  319. if (!empty($wxOrderId)) {
  320. $data['wx_order_id'] = $wxOrderId;
  321. }
  322. if (!empty($storeOrderId)) {
  323. $data['store_order_id'] = $storeOrderId;
  324. }
  325. if (!empty($wxStoreId)) {
  326. $data['wx_store_id'] = $wxStoreId;
  327. }
  328. $cancelReasons = []; // 1:不需要了 2:信息填错 3:无人接单 99:其他
  329. $data['cancel_reason_id'] = 1;
  330. return self::sendRequest(self::API_CANCEL_ORDER, $data, $accessToken);
  331. }
  332. /**
  333. * 查询订单
  334. * @param string $wxOrderId 微信订单号
  335. * @param string $outOrderId 商户订单号
  336. * @param string $outStoreId 门店ID
  337. * @param string $merchant 商户信息
  338. * @param int $ptStyle
  339. * @return array
  340. */
  341. public static function queryOrder($wxStoreId, $storeOrderId = '', $wxOrderId = '', $merchant = null, $ptStyle = 0)
  342. {
  343. if ($merchant === null) {
  344. $merchant = self::getMerchant();
  345. }
  346. $accessToken = self::getAccessToken($merchant, $ptStyle);
  347. if (empty($wxOrderId) && (empty($storeOrderId) || empty($wxStoreId))) {
  348. util::fail("参数不足:wx_order_id 或 (store_order_id + wx_store_id) 必须提供一组");
  349. }
  350. $data = [];
  351. if ($wxStoreId != '') {
  352. $data['wx_order_id'] = $wxOrderId;
  353. }
  354. $data['store_order_id'] = $storeOrderId;
  355. $data['wx_store_id'] = $wxStoreId;
  356. return self::sendRequest(self::API_GET_ORDER, $data, $accessToken);
  357. }
  358. // ==================== 资金管理接口 ====================
  359. /**
  360. * 查询门店余额
  361. * @param string $wxStoreId
  362. * @param null $merchant
  363. * @param int $ptStyle
  364. * @return array
  365. */
  366. public static function getBalance($wxStoreId, $merchant = null, $ptStyle = 0)
  367. {
  368. if ($merchant === null) {
  369. $merchant = self::getMerchant();
  370. }
  371. $accessToken = self::getAccessToken($merchant, $ptStyle);
  372. $data = ['wx_store_id' => $wxStoreId]; //'out_store_id' => $outStoreId,
  373. return self::sendRequest(self::API_BALANCE_QUERY, $data, $accessToken);
  374. }
  375. /**
  376. * 门店充值
  377. * @param string $wxStoreId
  378. * @param string $outChargeId
  379. * @param int $amount
  380. * @param null $merchant
  381. * @param int $ptStyle
  382. * @return array
  383. */
  384. public static function storeCharge($wxStoreId, $chargeId, $amount, $merchant = null, $ptStyle = 0)
  385. {
  386. if ($merchant === null) {
  387. $merchant = self::getMerchant();
  388. }
  389. $accessToken = self::getAccessToken($merchant, $ptStyle);
  390. $data = [
  391. 'wx_store_id' => $wxStoreId,
  392. 'service_trans_id' => $chargeId,
  393. 'amount' => $amount,
  394. ];
  395. return self::sendRequest(self::API_STORE_CHARGE, $data, $accessToken);
  396. }
  397. /**
  398. * 门店退款
  399. * @param string $wxStoreId
  400. * @param string $payMode
  401. * @param string $transId
  402. * @param null $merchant
  403. * @param int $ptStyle
  404. * @return array
  405. */
  406. public static function storeFund($wxStoreId, $payMode, $transId, $merchant = null, $ptStyle = 0)
  407. {
  408. if ($merchant === null) {
  409. $merchant = self::getMerchant();
  410. }
  411. $accessToken = self::getAccessToken($merchant, $ptStyle);
  412. $data = [
  413. 'wx_store_id' => $wxStoreId,
  414. 'pay_mode' => $payMode,
  415. 'service_trans_id' => $transId,
  416. ];
  417. return self::sendRequest(self::API_STORE_REFUND, $data, $accessToken);
  418. }
  419. /**
  420. * 查询充值记录
  421. * @param string $outChargeId
  422. * @param null $merchant
  423. * @param int $ptStyle
  424. * @return array
  425. */
  426. public static function getChargeRecord($outChargeId, $merchant = null, $ptStyle = 0)
  427. {
  428. if ($merchant === null) {
  429. $merchant = self::getMerchant();
  430. }
  431. $accessToken = self::getAccessToken($merchant, $ptStyle);
  432. $data = ['out_charge_id' => $outChargeId];
  433. return self::sendRequest(self::API_CHARGE_RECORD, $data, $accessToken);
  434. }
  435. // ==================== 测试接口 ====================
  436. /**
  437. * 模拟回调接口
  438. * @param string $wxOrderId 微信订单号
  439. * @param string $outStoreId 门店ID
  440. * @param string $outOrderId 商户订单号
  441. * @param int $orderStatus 订单状态
  442. * @param string $merchant 商户信息
  443. * @param int $ptStyle
  444. * @return array
  445. */
  446. public static function mockNotify($orderStatus, $wxOrderId = '', $outStoreId = '', $outOrderId = '', $merchant = null, $ptStyle = 0)
  447. {
  448. if ($merchant === null) {
  449. $merchant = self::getMerchant();
  450. }
  451. $accessToken = self::getAccessToken($merchant, $ptStyle);
  452. $data = [
  453. 'order_status' => $orderStatus,
  454. ];
  455. if (!empty($wxOrderId)) {
  456. $data['wx_order_id'] = $wxOrderId;
  457. }
  458. // 注意:文档中模拟回调使用的是 wx_store_id 和 store_order_id
  459. if (!empty($outStoreId) && !empty($outOrderId)) {
  460. $data['wx_store_id'] = $outStoreId;
  461. $data['store_order_id'] = $outOrderId;
  462. }
  463. return self::sendRequest(self::API_MOCK_NOTIFY, $data, $accessToken);
  464. }
  465. /**
  466. * 生成回调签名
  467. * @param array $params 回调参数
  468. * @param string $token 安全token
  469. * @return string
  470. */
  471. public static function generateCallbackSignature($params, $token)
  472. {
  473. // 1. 筛选出参与签名的字段
  474. $signParams = [];
  475. $fieldsToSign = ['appid', 'order_status', 'service_trans_id', 'status_change_time', 'store_order_id', 'timestamp', 'wx_order_id', 'wx_store_id'];
  476. foreach ($fieldsToSign as $field) {
  477. if (isset($params[$field])) {
  478. $signParams[$field] = $params[$field];
  479. }
  480. }
  481. // 2. 按字典序排序参数
  482. ksort($signParams);
  483. // 3. 拼接参数字符串
  484. $signStr = '';
  485. foreach ($signParams as $key => $value) {
  486. $signStr .= $key . '=' . $value . '&';
  487. }
  488. $signStr .= 'token=' . $token;
  489. // 4. 计算MD5并转为小写
  490. return strtolower(md5($signStr));
  491. }
  492. // ==================== 回调验证接口 ====================
  493. /**
  494. * 验证回调签名
  495. * @param array $params 回调参数
  496. * @param string $token 安全token
  497. * @return bool
  498. */
  499. public static function verifyCallback($params, $token)
  500. {
  501. if (!isset($params['sign'])) {
  502. return false;
  503. }
  504. $receivedSign = $params['sign'];
  505. unset($params['sign']);
  506. $calculatedSign = self::generateCallbackSignature($params, $token);
  507. return $receivedSign === $calculatedSign;
  508. }
  509. /**
  510. * 处理订单状态回调
  511. * @param array $callbackData 回调数据
  512. * @param string $token 安全token
  513. * @return array
  514. */
  515. public static function handleOrderCallback($callbackData, $token)
  516. {
  517. // 验证签名
  518. if (!self::verifyCallback($callbackData, $token)) {
  519. return [
  520. 'return_code' => 1,
  521. 'return_msg' => '签名验证失败'
  522. ];
  523. }
  524. // 处理订单状态变化
  525. $orderStatus = $callbackData['order_status'];
  526. $wxOrderId = $callbackData['wx_order_id'];
  527. $outOrderId = $callbackData['store_order_id'] ?? '';
  528. $outStoreId = $callbackData['wx_store_id'] ?? '';
  529. // 这里可以添加具体的业务逻辑处理
  530. // 例如:更新数据库中的订单状态、发送通知等
  531. // 伪代码示例:
  532. /*
  533. switch ($orderStatus) {
  534. case 10000: // 订单创建成功
  535. // 处理订单创建成功逻辑
  536. break;
  537. case 30000: // 配送员接单
  538. // 处理配送员接单逻辑
  539. break;
  540. case 40000: // 配送员到店
  541. // 处理配送员到店逻辑
  542. break;
  543. case 50000: // 配送中
  544. // 处理配送中逻辑
  545. break;
  546. case 70000: // 配送完成
  547. // 处理配送完成逻辑
  548. break;
  549. case 20000: // 商家取消订单
  550. case 20001: // 配送方取消订单
  551. case 60000: // 配送员撤单
  552. // 处理订单取消逻辑
  553. break;
  554. case 90000: // 配送异常
  555. // 处理配送异常逻辑
  556. break;
  557. }
  558. */
  559. return [
  560. 'return_code' => 0,
  561. 'return_msg' => 'OK'
  562. ];
  563. }
  564. }