Delivery.php 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\utils\Delivery;
  8. use app\models\DeliveryInfo;
  9. use app\models\District;
  10. use app\models\Option;
  11. use app\models\Order;
  12. use app\models\SaasUser;
  13. use app\models\Store;
  14. use app\models\User;
  15. use app\utils\address\Address;
  16. use yii\base\BaseObject;
  17. use yii\helpers\Json;
  18. /**
  19. * 即时配送
  20. * Class Delivery
  21. * @package app\utils\Delivery
  22. */
  23. class Delivery extends DeliveryService
  24. {
  25. /**
  26. * @var array $args 下单参数
  27. */
  28. private static $args;
  29. /**
  30. * 顺丰
  31. */
  32. const SF = 1;
  33. /**
  34. * 达达
  35. */
  36. const DD = 2;
  37. /**
  38. * 闪送
  39. */
  40. const SS = 3;
  41. /**
  42. * 美团
  43. */
  44. const MT = 4;
  45. /**
  46. * uu跑腿
  47. */
  48. const UU = 5;
  49. /**
  50. * 测试
  51. */
  52. const TEST = 6;
  53. /**
  54. * @var string[] $deliveryIdArr 数组
  55. */
  56. public static $deliveryIdArr = [
  57. self::SF => 'SFTC', // 顺丰同城急送
  58. self::DD => 'DADA', // 达达
  59. self::SS => 'SS', // 闪送
  60. self::MT => 'MTPS', // 美团配送
  61. self::UU => 'UU', // uu跑腿
  62. self::TEST => 'TEST' // TEST
  63. ];
  64. /**
  65. * @var string[] $deliveryType 数组
  66. */
  67. public static $deliveryType = [
  68. self::SF => '顺丰同城急送',
  69. self::DD => '达达',
  70. self::SS => '闪送',
  71. self::MT => '美团配送',
  72. self::UU => 'uu跑腿',
  73. self::TEST => '测试' // TEST
  74. ];
  75. /**
  76. * order_status 枚举值
  77. */
  78. const DELIVERY_STATUS_101 = 101;
  79. const DELIVERY_STATUS_102 = 102;
  80. const DELIVERY_STATUS_103 = 103;
  81. const DELIVERY_STATUS_201 = 201;
  82. const DELIVERY_STATUS_202 = 202;
  83. const DELIVERY_STATUS_203 = 203;
  84. const DELIVERY_STATUS_204 = 204;
  85. const DELIVERY_STATUS_205 = 205;
  86. const DELIVERY_STATUS_301 = 301;
  87. const DELIVERY_STATUS_302 = 302;
  88. const DELIVERY_STATUS_303 = 303;
  89. const DELIVERY_STATUS_304 = 304;
  90. const DELIVERY_STATUS_305 = 305;
  91. const DELIVERY_STATUS_401 = 401;
  92. const DELIVERY_STATUS_501 = 501;
  93. const DELIVERY_STATUS_502 = 502;
  94. public static $validOrderStatus = [
  95. self::DELIVERY_STATUS_101 => '等待分配骑手',
  96. self::DELIVERY_STATUS_102 => '分配骑手成功',
  97. self::DELIVERY_STATUS_103 => '商家取消订单',
  98. self::DELIVERY_STATUS_201 => '骑手到店开始取货',
  99. self::DELIVERY_STATUS_202 => '取货成功',
  100. self::DELIVERY_STATUS_203 => '取货失败,商家取消订单',
  101. self::DELIVERY_STATUS_204 => '取货失败,骑手因自身原因取消订单',
  102. self::DELIVERY_STATUS_205 => '取货失败,骑手因商家原因取消订单',
  103. self::DELIVERY_STATUS_301 => '配送中',
  104. self::DELIVERY_STATUS_302 => '配送成功',
  105. self::DELIVERY_STATUS_303 => '商家取消订单,配送物品开始返还商家',
  106. self::DELIVERY_STATUS_304 => '无法联系收货人,配送物品开始返还商家',
  107. self::DELIVERY_STATUS_305 => '收货人拒收,配送物品开始返还商家',
  108. self::DELIVERY_STATUS_401 => '货品返还商户成功',
  109. self::DELIVERY_STATUS_501 => '因运力系统原因取消',
  110. self::DELIVERY_STATUS_502 => '因不可抗拒因素(天气,道路管制等原因)取消'
  111. ];
  112. /**
  113. * @var int[] 骑手已接单
  114. */
  115. public static $validRiderReceive = [
  116. self::DELIVERY_STATUS_102
  117. ];
  118. /**
  119. * @var int[] 骑手已取货
  120. */
  121. public static $validRiderGetGoods = [
  122. self::DELIVERY_STATUS_202,
  123. self::DELIVERY_STATUS_301
  124. ];
  125. /**
  126. * @var int[] 配送已完成
  127. */
  128. public static $validComplete = [
  129. self::DELIVERY_STATUS_302,
  130. ];
  131. /**
  132. * @var int[] 配送异常
  133. */
  134. public static $validError = [
  135. self::DELIVERY_STATUS_103,
  136. self::DELIVERY_STATUS_203,
  137. self::DELIVERY_STATUS_204,
  138. self::DELIVERY_STATUS_205,
  139. self::DELIVERY_STATUS_303,
  140. self::DELIVERY_STATUS_304,
  141. self::DELIVERY_STATUS_305,
  142. self::DELIVERY_STATUS_501,
  143. self::DELIVERY_STATUS_502
  144. ];
  145. /**
  146. * 取消配送单原因枚举
  147. */
  148. const REASON_ID_1 = 1;
  149. const REASON_ID_2 = 2;
  150. const REASON_ID_3 = 3;
  151. const REASON_ID_4 = 4;
  152. const REASON_ID_5 = 5;
  153. const REASON_ID_6 = 6;
  154. public static $validReason = [
  155. self::REASON_ID_1 => '暂时不需要邮寄',
  156. self::REASON_ID_2 => '价格不合适',
  157. self::REASON_ID_3 => '订单信息有误,重新下单',
  158. self::REASON_ID_4 => '骑手取货不及时',
  159. self::REASON_ID_5 => '骑手配送不及时',
  160. self::REASON_ID_6 => '其他原因'
  161. ];
  162. /**
  163. * 分类品目
  164. */
  165. const CATEGORY_1 = 1; // 美食夜宵(一级)
  166. const CATEGORY_2 = 2; // 零食小吃
  167. const CATEGORY_3 = 3; // 香锅/烤鱼
  168. const CATEGORY_4 = 4; // 西餐
  169. const CATEGORY_5 = 5; // 日韩料理
  170. const CATEGORY_6 = 6; // 海鲜/烧烤
  171. const CATEGORY_7 = 7; // 快餐/地方菜
  172. const CATEGORY_8 = 8; // 小龙虾
  173. const CATEGORY_9 = 9; // 披萨
  174. const CATEGORY_10 = 10; // 甜品饮料(一级)
  175. const CATEGORY_11 = 11; // 甜品
  176. const CATEGORY_12 = 12; // 奶茶果汁
  177. const CATEGORY_13 = 13; // 咖啡
  178. const CATEGORY_14 = 14; // 面包/甜点
  179. const CATEGORY_15 = 15; // 冰淇淋
  180. const CATEGORY_16 = 16; // 蛋糕(一级)
  181. const CATEGORY_17 = 17; // 蛋糕
  182. const CATEGORY_18 = 18; // 日用百货(一级)
  183. const CATEGORY_19 = 19; // 便利店
  184. const CATEGORY_20 = 20; // 水站/奶站
  185. const CATEGORY_21 = 21; // 零食/干果
  186. const CATEGORY_22 = 22; // 五金日用
  187. const CATEGORY_23 = 23; // 粮油调味
  188. const CATEGORY_24 = 24; // 文具店
  189. const CATEGORY_25 = 25; // 酒水行
  190. const CATEGORY_26 = 26; // 地方特产
  191. const CATEGORY_27 = 27; // 进口食品
  192. const CATEGORY_28 = 28; // 宠物用品
  193. const CATEGORY_29 = 29; // 超市
  194. const CATEGORY_30 = 30; // 书店
  195. const CATEGORY_31 = 31; // 宠物食品用品
  196. const CATEGORY_32 = 32; // 办公家居用品
  197. const CATEGORY_33 = 33; // 果蔬生鲜
  198. const CATEGORY_34 = 34; // 果蔬
  199. const CATEGORY_35 = 35; // 海鲜水产
  200. const CATEGORY_36 = 36; // 冷冻速食
  201. const CATEGORY_37 = 37; // 鲜花
  202. const CATEGORY_38 = 38; // 鲜花
  203. const CATEGORY_39 = 39; // 医药健康
  204. const CATEGORY_40 = 40; // 送药
  205. const CATEGORY_41 = 41; // 器材器具
  206. const CATEGORY_42 = 42; // 美妆护肤
  207. const CATEGORY_43 = 43; // 日化美妆
  208. const CATEGORY_44 = 44; // 母婴
  209. const CATEGORY_45 = 45; // 孕婴用品
  210. const CATEGORY_46 = 46; // 文件或票务
  211. const CATEGORY_47 = 47; // 保单
  212. const CATEGORY_48 = 48; // 票务文件
  213. const CATEGORY_49 = 49; // 政府文件
  214. const CATEGORY_50 = 50; // 证件
  215. const CATEGORY_51 = 51; // 服饰鞋帽
  216. const CATEGORY_52 = 52; // 服饰鞋帽综合
  217. const CATEGORY_53 = 53; // 洗涤
  218. const CATEGORY_54 = 54; // 脏衣服收
  219. const CATEGORY_55 = 55; // 干净衣服派
  220. const CATEGORY_56 = 56; // 珠宝奢侈品
  221. const CATEGORY_57 = 57; // 珠宝饰品
  222. const CATEGORY_58 = 58; // 奢侈品
  223. const CATEGORY_59 = 59; // 家居家装
  224. const CATEGORY_60 = 60; // 家具
  225. const CATEGORY_61 = 61; // 装修建材
  226. const CATEGORY_62 = 62; // 厨房卫浴
  227. const CATEGORY_63 = 63; // 数码产品
  228. const CATEGORY_64 = 64; // 数码产品
  229. const CATEGORY_65 = 65; // 配件器材
  230. const CATEGORY_66 = 66; // 配件器材
  231. const CATEGORY_67 = 67; // 电商
  232. const CATEGORY_68 = 68; // 电视购物
  233. const CATEGORY_69 = 69; // 线上商城
  234. const CATEGORY_70 = 70; // 现场勘查
  235. const CATEGORY_71 = 71; // 现场勘查
  236. const CATEGORY_72 = 72; // 快递业务
  237. const CATEGORY_73 = 73; // 快递配送
  238. const CATEGORY_74 = 74; // 其他
  239. const CATEGORY_75 = 75; // 其他
  240. public static $validLevelOneCategory = [
  241. self::CATEGORY_1 => '美食夜宵',
  242. self::CATEGORY_10 => '甜品饮料',
  243. self::CATEGORY_16 => '蛋糕',
  244. self::CATEGORY_18 => '日用百货',
  245. self::CATEGORY_33 => '果蔬生鲜',
  246. self::CATEGORY_37 => '鲜花',
  247. self::CATEGORY_39 => '医药健康',
  248. self::CATEGORY_42 => '美妆护肤',
  249. self::CATEGORY_44 => '母婴',
  250. self::CATEGORY_46 => '文件或票务',
  251. self::CATEGORY_51 => '服饰鞋帽',
  252. self::CATEGORY_53 => '洗涤',
  253. self::CATEGORY_56 => '珠宝奢侈品',
  254. self::CATEGORY_59 => '家居家装',
  255. self::CATEGORY_63 => '数码产品',
  256. self::CATEGORY_65 => '配件器材',
  257. self::CATEGORY_67 => '电商',
  258. self::CATEGORY_70 => '现场勘查',
  259. self::CATEGORY_72 => '快递业务',
  260. self::CATEGORY_74 => '其他'
  261. ];
  262. public static $validLevelCategory = [
  263. self::CATEGORY_1 => [
  264. self::CATEGORY_2 => '零食小吃',
  265. self::CATEGORY_3 => '香锅/烤鱼',
  266. self::CATEGORY_4 => '西餐',
  267. self::CATEGORY_5 =>' 日韩料理',
  268. self::CATEGORY_6 => '海鲜/烧烤',
  269. self::CATEGORY_7 => '快餐/地方菜',
  270. self::CATEGORY_8 => '小龙虾',
  271. self::CATEGORY_9 => '披萨'
  272. ],
  273. self::CATEGORY_10 => [
  274. self::CATEGORY_11 => '甜品',
  275. self::CATEGORY_12 => '奶茶果汁',
  276. self::CATEGORY_13 => '咖啡',
  277. self::CATEGORY_14 => '面包/甜点',
  278. self::CATEGORY_15 => '冰淇淋'
  279. ],
  280. self::CATEGORY_16 => [
  281. self::CATEGORY_17 => '蛋糕'
  282. ],
  283. self::CATEGORY_18 => [
  284. self::CATEGORY_19 => '便利店',
  285. self::CATEGORY_20 => '水站/奶站',
  286. self::CATEGORY_21 => '零食/干果',
  287. self::CATEGORY_22 => '五金日用',
  288. self::CATEGORY_23 => '粮油调味',
  289. self::CATEGORY_24 => '文具店',
  290. self::CATEGORY_25 => '酒水行',
  291. self::CATEGORY_26 => '地方特产',
  292. self::CATEGORY_27 => '进口食品',
  293. self::CATEGORY_28 => '宠物用品',
  294. self::CATEGORY_29 => '超市',
  295. self::CATEGORY_30 => '书店',
  296. self::CATEGORY_31 => '宠物食品用品',
  297. self::CATEGORY_32 => '办公家居用品',
  298. ],
  299. self::CATEGORY_33 => [
  300. self::CATEGORY_34 => '果蔬',
  301. self::CATEGORY_35 => '海鲜水产',
  302. self::CATEGORY_36 => '冷冻速食'
  303. ],
  304. self::CATEGORY_37 => [
  305. self::CATEGORY_38 => '鲜花',
  306. ],
  307. self::CATEGORY_39 => [
  308. self::CATEGORY_40 => '送药',
  309. self::CATEGORY_41 => '器材器具',
  310. ],
  311. self::CATEGORY_42 => [
  312. self::CATEGORY_43 => '日化美妆',
  313. ],
  314. self::CATEGORY_44 => [
  315. self::CATEGORY_45 => '孕婴用品',
  316. ],
  317. self::CATEGORY_46 => [
  318. self::CATEGORY_47 => '保单',
  319. self::CATEGORY_48 => '票务文件',
  320. self::CATEGORY_49 => ' 政府文件',
  321. self::CATEGORY_50 => '证件'
  322. ],
  323. self::CATEGORY_51 => [
  324. self::CATEGORY_52 => '服饰鞋帽综合'
  325. ],
  326. self::CATEGORY_53 => [
  327. self::CATEGORY_54 => '脏衣服收',
  328. self::CATEGORY_55 => '干净衣服派'
  329. ],
  330. self::CATEGORY_56 => [
  331. self::CATEGORY_57 => '珠宝饰品',
  332. self::CATEGORY_58 => '奢侈品',
  333. ],
  334. self::CATEGORY_59 => [
  335. self::CATEGORY_60 => '家具',
  336. self::CATEGORY_61 => '装修建材',
  337. self::CATEGORY_62 => '厨房卫浴'
  338. ],
  339. self::CATEGORY_63 => [
  340. self::CATEGORY_64 => '数码产品',
  341. ],
  342. self::CATEGORY_65 => [
  343. self::CATEGORY_66 => '配件器材',
  344. ],
  345. self::CATEGORY_67 => [
  346. self::CATEGORY_68 => '电视购物',
  347. self::CATEGORY_69 => '线上商城'
  348. ],
  349. self::CATEGORY_70 => [
  350. self::CATEGORY_71 => '现场勘查'
  351. ],
  352. self::CATEGORY_72 => [
  353. self::CATEGORY_73 => '快递配送'
  354. ],
  355. self::CATEGORY_74 => [
  356. self::CATEGORY_75 => '其他'
  357. ],
  358. ];
  359. /**
  360. * @var DeliveryService $service
  361. */
  362. public static $service;
  363. /**
  364. * @var string $prefix 请求url前缀
  365. */
  366. public static $prefix = 'https://api.weixin.qq.com/cgi-bin/express/local/business/';
  367. /**
  368. * @var string $preAddOrderEndpoint 预下单接口
  369. */
  370. public static $preAddOrderEndpoint = 'order/pre_add';
  371. /**
  372. * @var string $preCancelOrderEndpoint 预取消接口
  373. */
  374. public static $preCancelOrderEndpoint = 'order/precancel';
  375. /**
  376. * @var string $cancelOrderEndpoint 取消接口
  377. */
  378. public static $cancelOrderEndpoint = 'order/cancel';
  379. /**
  380. * @var string $addOrderEndpoint 下单接口
  381. */
  382. public static $addOrderEndpoint = 'order/add';
  383. /**
  384. * @var string $getAllImmeDeliveryEndpoint 获取已支持的配送公司接口列表
  385. */
  386. public static $getAllImmeDeliveryEndpoint = 'delivery/getall';
  387. /**
  388. * @var string $getBindAccountEndpoint 拉取已绑定账号
  389. */
  390. public static $getBindAccountEndpoint = 'shop/get';
  391. /**
  392. * @var string $getOrderEndpoint 拉取配送单信息
  393. */
  394. public static $getOrderEndpoint = 'order/get';
  395. /**
  396. * @var string $openEndpoint 第三方代商户发起开通即时配送权限
  397. */
  398. public static $openEndpoint = 'open';
  399. /**
  400. * @var string $mockUpdateOrderEndpoint 模拟配送公司更新配送单状态, 该接口只用于沙盒环境,即订单并没有真实流转到运力方
  401. */
  402. public static $mockUpdateOrderEndpoint = 'test_update_order';
  403. /**
  404. * @var string $realMockUpdateOrderEndpoint 模拟配送公司更新配送单状态, 该接口用于测试账户下的单,将请求转发到运力测试环境
  405. */
  406. public static $realMockUpdateOrderEndpoint = 'realmock_update_order';
  407. /**
  408. * 测试数据
  409. */
  410. // public static $delivery_id = 'TEST'; // 测试运力
  411. // public static $shop_id = 'test_shop_id'; // 测试商户(appkey)
  412. // public static $app_secret = 'test_app_secrect'; // 测试商户
  413. // public static $shop_no = '123456'; // shop_no
  414. /**
  415. * 顺丰测试账号
  416. */
  417. // public static $delivery_id = 'SFTC'; // 测试运力
  418. // public static $shop_id = '1534713176'; // 测试商户(appkey)
  419. // public static $app_secret = 'd80400f91e156f63b38886e616d84590'; // 测试商户
  420. // public static $shop_no = '3243279847393'; // shop_no
  421. // public static $shop_order_id = 'tianxin100'; // 订单id
  422. // public static $openid = 'or1pO5afofkMrp94tXwIJjAdoCQE';
  423. /**
  424. * @var string $shop_id appkey
  425. */
  426. protected static $shop_id;
  427. /**
  428. * @var string $shop_no 商铺号
  429. */
  430. protected static $shop_no;
  431. /**
  432. * @var string $app_secret 配送方侧密钥
  433. */
  434. protected static $app_secret;
  435. /**
  436. * @var string category
  437. */
  438. protected static $category;
  439. /**
  440. * @var Store $store
  441. */
  442. protected static $store;
  443. /**
  444. * @var integer $delivery_type
  445. */
  446. protected static $delivery_type;
  447. /**
  448. * @param $method
  449. * @param $args
  450. * @return false|mixed
  451. */
  452. public static function __callStatic($method, $args) {
  453. $store = Store::findOne(get_store_id());
  454. self::$delivery_type = $store->delivery_type;
  455. $delivery_config = Option::getDeliveryConfig();
  456. if (self::$delivery_type == 1) {
  457. self::$shop_no = $delivery_config['sf']['sf_shop_no'];
  458. self::$shop_id = $delivery_config['sf']['sf_app_key'];
  459. self::$app_secret = $delivery_config['sf']['sf_app_secret'];
  460. } else if (self::$delivery_type == 2){
  461. self::$shop_no = $delivery_config['dd']['dd_shop_no'];
  462. self::$shop_id = $delivery_config['dd']['dd_app_key'];
  463. self::$app_secret = $delivery_config['dd']['dd_app_secret'];
  464. } else if (self::$delivery_type == 3) {
  465. self::$shop_no = $delivery_config['ss']['ss_shop_no'];
  466. self::$shop_id = $delivery_config['ss']['ss_app_key'];
  467. self::$app_secret = $delivery_config['ss']['ss_app_secret'];
  468. } else if (self::$delivery_type == 4) {
  469. self::$shop_no = $delivery_config['mt']['mt_shop_no'];
  470. self::$shop_id = $delivery_config['mt']['mt_app_key'];
  471. self::$app_secret = $delivery_config['mt']['mt_app_secret'];
  472. } else if (self::$delivery_type == 5) {
  473. self::$shop_no = $delivery_config['uu']['uu_shop_no'];
  474. self::$shop_id = $delivery_config['uu']['uu_app_key'];
  475. self::$app_secret = $delivery_config['uu']['uu_app_secret'];
  476. } else {
  477. self::$shop_no = '123456';
  478. self::$shop_id = 'test_shop_id';
  479. self::$app_secret = 'test_app_secret';
  480. }
  481. self::$store = $store;
  482. self::$category = $store->delivery_category;
  483. self::$service = new DeliveryService();
  484. return call_user_func_array(array(Delivery::class, $method), $args);
  485. }
  486. /**
  487. * 预下单接口
  488. * @param array $goods_list
  489. * @param integer $order_no
  490. * @return array
  491. */
  492. protected static function preAddOrder($goods_list, $order_no) {
  493. if (!$order_no) {
  494. return [
  495. 'code' => 1,
  496. 'msg' => '缺少订单号参数'
  497. ];
  498. }
  499. $res = self::format($goods_list, self::$delivery_type, $order_no);
  500. if (isset($res['code'])) {
  501. return $res;
  502. }
  503. $res = self::$service->request(self::getUrl(self::$preAddOrderEndpoint), self::$args);
  504. $res = Json::decode($res);
  505. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  506. DeliveryInfo::deleteAll(['order_no' => $order_no, 'store_id' => get_store_id(), 'status' => 0]);
  507. // 入表
  508. $delivery_info = new DeliveryInfo();
  509. $delivery_info->store_id = get_store_id();
  510. $delivery_info->order_no = $order_no;
  511. $delivery_info->fee = $res['fee'];
  512. $delivery_info->delivery_token = $res['delivery_token'];
  513. $delivery_info->delivery_type = self::$delivery_type;
  514. $delivery_info->created_at = time();
  515. $delivery_info->save();
  516. return [
  517. 'code' => 0,
  518. 'msg' => 'success',
  519. 'data' => $res
  520. ];
  521. }
  522. return [
  523. 'code' => 1,
  524. 'errorno' => $res['resultcode'],
  525. 'msg' => $res['resultmsg'],
  526. 'args' => self::$args
  527. ];
  528. }
  529. /**
  530. * 下单接口
  531. * @param array $goods_list
  532. * [
  533. * [
  534. * 'name' => '苹果',
  535. * 'price' => 10,
  536. * 'num' => 10,
  537. * 'pic' => 'https://chidian.cyyvip.com/web/uploads/images/store_8/2021-07-22/ad8537bd77ddc367e30591e62d97b2e46eb08ff4.jpg'
  538. * ],
  539. * [
  540. * 'name' => '香蕉',
  541. * 'price' => 5,
  542. * 'num' => 2,
  543. * 'pic' => 'https://chidian.cyyvip.com/web/uploads/images/store_8/2021-07-22/ad8537bd77ddc367e30591e62d97b2e46eb08ff4.jpg'
  544. * ],
  545. * ]
  546. * @param string $order_no
  547. * @return array
  548. */
  549. protected static function addOrder($goods_list, $order_no) {
  550. if (!$order_no) {
  551. return [
  552. 'code' => 1,
  553. 'msg' => '缺少订单号参数'
  554. ];
  555. }
  556. $res = self::format($goods_list, self::$delivery_type, $order_no);
  557. if (isset($res['code'])) {
  558. return $res;
  559. }
  560. $res = self::$service->request(self::getUrl(self::$addOrderEndpoint), self::$args);
  561. $res = Json::decode($res);
  562. \Yii::error(['同城配送下单数据', $res]);
  563. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  564. // 入表
  565. $delivery_info = DeliveryInfo::findOne(['store_id' => get_store_id(), 'order_no' => $order_no, 'delivery_type' => self::$delivery_type]);
  566. if ($delivery_info) {
  567. $delivery_info->status = $res['order_status'];
  568. $delivery_info->waybill_id = $res['waybill_id'];
  569. // $delivery_info->fee = $res['fee'];ML20211101195946262565
  570. $delivery_info->updated_at = time();
  571. $delivery_info->save();
  572. }
  573. return [
  574. 'code' => 0,
  575. 'msg' => 'success',
  576. 'data' => $res
  577. ];
  578. }
  579. return [
  580. 'code' => 1,
  581. 'errorno' => $res['resultcode'],
  582. 'msg' => $res['resultmsg'],
  583. ];
  584. }
  585. /**
  586. * 组装数据
  587. * @param array $goods_list 商品列表
  588. * @param integer $type 运力类型
  589. * @param string $order_no 订单号
  590. * @return array
  591. */
  592. protected static function format($goods_list, $type, $order_no) {
  593. if (empty($goods_list) || !is_array($goods_list) || empty($order_no)) {
  594. return [
  595. 'code' => 1,
  596. 'msg' => '商品列表有空或数据格式错误'
  597. ];
  598. }
  599. if (!in_array($type, array_keys(self::$deliveryIdArr))) {
  600. return [
  601. 'code' => 1,
  602. 'msg' => '非法运力类型'
  603. ];
  604. }
  605. $order = Order::findOne(['order_no' => $order_no]);
  606. if ($order) {
  607. $user = User::findOne($order->user_id);
  608. $saas_user = SaasUser::findOne(['mobile' => $user->binding]);
  609. }
  610. $args = [
  611. 'shopid' => self::$shop_id,
  612. 'shop_order_id' => $order_no,
  613. 'shop_no' => self::$shop_no,
  614. 'shop' => [
  615. 'goods_count' => count($goods_list),
  616. 'goods_name' => $goods_list[0]['name'],
  617. 'img_url' => $goods_list[0]['pic'],
  618. 'wxa_path' => "/pages/order/order"
  619. ],
  620. 'delivery_id' => self::$deliveryIdArr[$type],
  621. 'delivery_sign' => self::getDeliverySign(self::$shop_id, $order_no, self::$app_secret),
  622. 'openid' => isset($user) && !empty($user) ? $user->wechat_open_id : get_user()->wechat_open_id,
  623. // 开发者的open_id
  624. // 'openid' => 'or1pO5afofkMrp94tXwIJjAdoCQE'
  625. ];
  626. $delivery_info_token = DeliveryInfo::findOne(['order_no' => $order_no])->delivery_token;
  627. if ($delivery_info_token) {
  628. $args['delivery_token'] = $delivery_info_token;
  629. }
  630. $goods = [];
  631. $total_price = 0;
  632. foreach ($goods_list as $value) {
  633. $goods[] = [
  634. 'good_count' => $value['num'],
  635. 'good_price' => $value['price'],
  636. 'good_name' => $value['name'],
  637. 'good_unit' => '元'
  638. ];
  639. $total_price += $value['price'];
  640. }
  641. $category_arr = explode(',', self::$category);
  642. $first_class = self::$validLevelOneCategory[$category_arr[0]];
  643. $second_class = self::$validLevelCategory[$category_arr[0]][$category_arr[1]];
  644. // 货物信息
  645. $args['cargo'] = [
  646. 'cargo_first_class' => $first_class,
  647. 'cargo_second_class' => $second_class,
  648. 'goods_detail' => [
  649. 'goods' => $goods
  650. ],
  651. 'goods_value' => $total_price,
  652. ];
  653. // 商家门店编号,在配送公司登记,美团、闪送必填 TODO
  654. if (in_array($type, [self::MT, self::SS])) {
  655. $args['shop_no'] = self::$shop_no;
  656. if (empty($args['shop_no'])) {
  657. return [
  658. 'code' => 1,
  659. 'msg' => '请配置美团或者闪送的门店编号'
  660. ];
  661. }
  662. }
  663. // order_info
  664. $args['order_info'] = [
  665. 'order_time' => time(),
  666. 'order_type' => 0
  667. ];
  668. // 商家门店编号,在配送公司登记,闪送必填 TODO
  669. if (in_array($type, [self::SS])) {
  670. $args['order_info']['is_direct_delivery'] = 1;
  671. }
  672. // sender :uu跑腿 || 发件人信息,闪送、顺丰同城急送必须填写 || 美团配送、达达,不传shop_no的值需填该字段
  673. if ($type == self::UU || in_array($type, [self::SS, self::SF])
  674. || (in_array($type, [self::MT, self::DD]) && empty($args['shop_no']))) {
  675. $coordinate = self::$store->coordinate;
  676. $province = District::findOne(self::$store->province_id)->name;
  677. $city = District::findOne(self::$store->city_id)->name;
  678. $district = District::findOne(self::$store->district_id)->name;
  679. if (empty($coordinate) || empty(self::$store->address) || empty($province) || empty($city) || empty($district)) {
  680. return [
  681. 'code' => 1,
  682. 'msg' => '店铺位置信息未配置'
  683. ];
  684. }
  685. if (empty(self::$store->user_name) || empty(self::$store->contact_tel)) {
  686. return [
  687. 'code' => 1,
  688. 'msg' => '店铺联系人信息未配置'
  689. ];
  690. }
  691. $args['sender'] = [
  692. 'address' => $province . $district . $city,
  693. 'address_detail' => self::$store->address,
  694. 'city' => $city,
  695. 'lat' => explode(',', $coordinate)[0],
  696. 'lng' => explode(',', $coordinate)[1],
  697. 'name' => self::$store->user_name,
  698. 'phone' => self::$store->contact_tel,
  699. 'coordinate_type' => 1,
  700. ];
  701. }
  702. // 收货人信息
  703. $address_info = \app\models\Address::findOne(['is_delete' => 0, 'is_default' => 1, 'user_id' => get_saas_user_id()]);
  704. if (!$address_info) {
  705. $address_info = \app\models\Address::findOne(['is_delete' => 0, 'user_id' => get_saas_user_id()]);
  706. }
  707. if (!$address_info) {
  708. $address_info = \app\models\Address::findOne(['is_delete' => 0, 'user_id' => get_user_id()]);
  709. }
  710. if (!$address_info) {
  711. return [
  712. 'code' => 1,
  713. 'msg' => '请先设置收货地址'
  714. ];
  715. }
  716. $args['receiver'] = [
  717. 'address' => $address_info->province . $address_info->city . $address_info->district,
  718. 'address_detail' => $address_info->detail,
  719. 'city' => $address_info->city,
  720. 'lat' => $address_info->latitude,
  721. 'lng' => $address_info->longitude,
  722. 'name' => $address_info->name,
  723. 'phone' => $address_info->mobile,
  724. 'coordinate_type' => 1,
  725. ];
  726. \Yii::error($args);
  727. self::$args = $args;
  728. }
  729. /**
  730. * 获取完整url
  731. * @param string $endpoint
  732. * @return string
  733. */
  734. protected static function getUrl(string $endpoint) {
  735. return self::$prefix . $endpoint;
  736. }
  737. /**
  738. * sha1 加签
  739. * @param string $shop_id
  740. * @param string $shop_order_id
  741. * @param string $app_secret
  742. * @return string
  743. */
  744. private static function getDeliverySign($shop_id, $shop_order_id, $app_secret) {
  745. return SHA1($shop_id . $shop_order_id . $app_secret);
  746. }
  747. /**
  748. * 获取已支持的配送公司列表接口
  749. * @return array
  750. */
  751. protected static function getAllDelivery() {
  752. $res = self::$service->request(self::getUrl(self::$getAllImmeDeliveryEndpoint), []);
  753. $res = Json::decode($res);
  754. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  755. return [
  756. 'code' => 0,
  757. 'msg' => 'success',
  758. 'data' => $res
  759. ];
  760. } else {
  761. return [
  762. 'code' => 1,
  763. 'errorno' => $res['resultcode'],
  764. 'msg' => $res['resultmsg'],
  765. ];
  766. }
  767. }
  768. /**
  769. * 获取已支持的配送公司列表接口
  770. * @return array
  771. */
  772. protected static function getBindAccount() {
  773. $res = self::$service->request(self::getUrl(self::$getBindAccountEndpoint), []);
  774. $res = Json::decode($res);
  775. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  776. return [
  777. 'code' => 0,
  778. 'msg' => 'success',
  779. 'data' => $res
  780. ];
  781. } else {
  782. return [
  783. 'code' => 1,
  784. 'errorno' => $res['errcode'],
  785. 'msg' => $res['errmsg'],
  786. ];
  787. }
  788. }
  789. /**
  790. * 拉取配送单信息
  791. * @return array
  792. */
  793. protected static function getOrder($order_no) {
  794. if (empty($order_no)) {
  795. return [
  796. 'code' => 1,
  797. 'msg' => '订单号不能为空'
  798. ];
  799. }
  800. $args = [
  801. 'shopid' => self::$shop_id,
  802. 'shop_order_id' => $order_no,
  803. 'delivery_sign' => self::getDeliverySign(self::$shop_id, $order_no, self::$app_secret),
  804. 'shop_no' => self::$shop_no
  805. ];
  806. \Yii::error($args);
  807. $res = self::$service->request(self::getUrl(self::$getOrderEndpoint), $args);
  808. $res = Json::decode($res);
  809. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  810. return [
  811. 'code' => 0,
  812. 'msg' => 'success',
  813. 'data' => $res
  814. ];
  815. } else {
  816. return [
  817. 'code' => 1,
  818. 'errorno' => $res['resultcode'],
  819. 'msg' => $res['resultmsg'],
  820. ];
  821. }
  822. }
  823. /**
  824. * 预取消配送单接口
  825. * @param string $order_no
  826. * @param integer $reason_id
  827. * @param string $reason
  828. * @return array
  829. */
  830. protected static function preCancelOrder($order_no, $reason_id = 0, $reason = '') {
  831. if (empty($order_no)) {
  832. return [
  833. 'code' => 1,
  834. 'msg' => '缺少订单号参数'
  835. ];
  836. }
  837. $delivery_info = DeliveryInfo::findOne(['store_id' => get_store_id(), 'order_no' => $order_no]);
  838. if (!$delivery_info) {
  839. return [
  840. 'code' => 1,
  841. 'msg' => '未找到配送单信息'
  842. ];
  843. }
  844. $args = [
  845. 'shopid' => self::$shop_id,
  846. 'shop_order_id' => $order_no,
  847. 'delivery_sign' => self::getDeliverySign(self::$shop_id, $order_no, self::$app_secret),
  848. 'shop_no' => self::$shop_no,
  849. 'delivery_id' => self::$deliveryIdArr[$delivery_info->delivery_type],
  850. 'waybill_id' => $delivery_info->waybill_id,
  851. 'cancel_reason_id' => $reason_id,
  852. 'cancel_reason' => $reason
  853. ];
  854. \Yii::error($args);
  855. $res = self::$service->request(self::getUrl(self::$preCancelOrderEndpoint), $args);
  856. $res = Json::decode($res);
  857. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  858. /**
  859. * @var array $res
  860. * [
  861. * "resultcode" => 0,
  862. * "resultmsg" => "ok",
  863. * "deduct_fee" => 5, // 费用
  864. * "desc" => "blabla" // 描述
  865. * ]
  866. */
  867. $delivery_info->deduct_fee = $res['deduct_fee'];
  868. $delivery_info->save();
  869. return [
  870. 'code' => 0,
  871. 'msg' => 'success',
  872. 'data' => $res
  873. ];
  874. } else {
  875. return [
  876. 'code' => 1,
  877. 'errorno' => $res['resultcode'],
  878. 'msg' => $res['resultmsg'],
  879. ];
  880. }
  881. }
  882. /**
  883. * 取消配送单接口
  884. * @param string $order_no
  885. * @param integer $reason_id
  886. * @param string $reason
  887. * @return array
  888. */
  889. protected static function cancelOrder($order_no, $reason_id = 0, $reason = '') {
  890. if (empty($order_no)) {
  891. return [
  892. 'code' => 1,
  893. 'msg' => '缺少订单号参数'
  894. ];
  895. }
  896. $delivery_info = DeliveryInfo::findOne(['store_id' => get_store_id(), 'order_no' => $order_no]);
  897. if (!$delivery_info) {
  898. return [
  899. 'code' => 1,
  900. 'msg' => '未找到配送单信息'
  901. ];
  902. }
  903. $args = [
  904. 'shopid' => self::$shop_id,
  905. 'shop_order_id' => $order_no,
  906. 'delivery_sign' => self::getDeliverySign(self::$shop_id, $order_no, self::$app_secret),
  907. 'shop_no' => self::$shop_no,
  908. 'delivery_id' => self::$deliveryIdArr[$delivery_info->delivery_type],
  909. 'waybill_id' => $delivery_info->waybill_id,
  910. 'cancel_reason_id' => $reason_id,
  911. 'cancel_reason' => $reason
  912. ];
  913. \Yii::error($args);
  914. $res = self::$service->request(self::getUrl(self::$cancelOrderEndpoint), $args);
  915. $res = Json::decode($res);
  916. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  917. /**
  918. * @var array $res
  919. * [
  920. * "resultcode" => 0,
  921. * "resultmsg" => "ok",
  922. * "deduct_fee" => 5, // 费用
  923. * "desc" => "blabla" // 描述
  924. * ]
  925. */
  926. $delivery_info->deduct_fee = $res['deduct_fee'];
  927. $delivery_info->reason_id = $reason_id;
  928. $delivery_info->save();
  929. return [
  930. 'code' => 0,
  931. 'msg' => 'success',
  932. 'data' => $res
  933. ];
  934. } else {
  935. return [
  936. 'code' => 1,
  937. 'errorno' => $res['resultcode'],
  938. 'msg' => $res['resultmsg'],
  939. ];
  940. }
  941. }
  942. /**
  943. * 第三方代商户发起开通即时配送权限
  944. * @return array
  945. */
  946. protected static function open() {
  947. $res = self::$service->request(self::getUrl(self::$openEndpoint), []);
  948. $res = Json::decode($res);
  949. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  950. return [
  951. 'code' => 0,
  952. 'msg' => 'success',
  953. 'data' => $res
  954. ];
  955. } else {
  956. return [
  957. 'code' => 1,
  958. 'errorno' => $res['resultcode'],
  959. 'msg' => $res['resultmsg'],
  960. ];
  961. }
  962. }
  963. /**
  964. * 模拟配送公司更新配送单状态(测试账户下单)
  965. * @return array
  966. */
  967. protected static function realMockUpdateOrder($order_no) {
  968. if (empty($order_no)) {
  969. return [
  970. 'code' => 1,
  971. 'msg' => '缺少订单号参数'
  972. ];
  973. }
  974. $args = [
  975. 'shopid' => self::$shop_id,
  976. 'shop_order_id' => $order_no,
  977. 'delivery_sign' => self::getDeliverySign(self::$shop_id, $order_no, self::$app_secret),
  978. 'action_time' => time(),
  979. 'order_status' => 102,
  980. 'action_msg' => '', // 附加信息
  981. ];
  982. \Yii::error($args);
  983. $res = self::$service->request(self::getUrl(self::$realMockUpdateOrderEndpoint), $args);
  984. $res = Json::decode($res);
  985. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  986. return [
  987. 'code' => 0,
  988. 'msg' => 'success',
  989. 'data' => $res
  990. ];
  991. } else {
  992. return [
  993. 'code' => 1,
  994. 'errorno' => $res['resultcode'],
  995. 'msg' => $res['resultmsg'],
  996. ];
  997. }
  998. }
  999. /**
  1000. * 模拟配送公司更新配送单状态(不转发到运力环境)
  1001. * @return array
  1002. */
  1003. protected static function mockUpdateOrder($order_no) {
  1004. if (empty($order_no)) {
  1005. return [
  1006. 'code' => 1,
  1007. 'msg' => '缺少订单号参数'
  1008. ];
  1009. }
  1010. $args = [
  1011. 'shopid' => self::$shop_id,
  1012. 'shop_order_id' => $order_no,
  1013. 'delivery_sign' => self::getDeliverySign(self::$shop_id, $order_no, self::$app_secret),
  1014. 'action_time' => time(),
  1015. 'order_status' => 102,
  1016. 'action_msg' => '', // 附加信息
  1017. ];
  1018. \Yii::error($args);
  1019. $res = self::$service->request(self::getUrl(self::$mockUpdateOrderEndpoint), $args);
  1020. $res = Json::decode($res);
  1021. if (isset($res['resultcode']) && $res['resultcode'] == 0) {
  1022. return [
  1023. 'code' => 0,
  1024. 'msg' => 'success',
  1025. 'data' => $res
  1026. ];
  1027. } else {
  1028. return [
  1029. 'code' => 1,
  1030. 'errorno' => $res['resultcode'],
  1031. 'msg' => $res['resultmsg'],
  1032. ];
  1033. }
  1034. }
  1035. }