ADelivery.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\utils\Delivery\Alipay;
  8. use app\modules\admin\models\AlipayThirdForm;
  9. use app\models\User;
  10. use app\models\Store;
  11. use app\models\SaasUser;
  12. use yii\base\Model;
  13. use yii\data\Pagination;
  14. use app\models\Option;
  15. use app\constants\OptionSetting;
  16. use app\models\StoreAliMini;
  17. use app\models\DeliveryInfo;
  18. use app\utils\Delivery\Delivery;
  19. use app\models\Order;
  20. class ADelivery extends Model
  21. {
  22. public $mini_id;
  23. public $store_id;
  24. public $pageSize = 5;
  25. public $page = 1;
  26. public $status;
  27. /**
  28. * {@inheritdoc}
  29. */
  30. public function rules()
  31. {
  32. return [
  33. [['store_id', 'mini_id', 'page', 'pageSize'], 'integer'],
  34. [['status'], 'safe'],
  35. ];
  36. }
  37. public static function getShopNo($mini_id) {
  38. $mini = StoreAliMini::findOne($mini_id);
  39. return $mini->auth_app_id . '_' . $mini->store_id . '_' . $mini->id;
  40. }
  41. public static function getConf($store_id, $mini_id, $check = null, $account = null, $md = null) {
  42. $shop_no = Option::get(OptionSetting::ALIPAY_DELIVERY_SHOP_NO . $mini_id, $store_id, 'alipay', '')['value'];
  43. if(!$check && !$shop_no){
  44. throw new \Exception('请管理员先配置支付宝同城配送的门店信息,小程序ID:'.$mini_id);
  45. }
  46. $company = Option::get(OptionSetting::ALIPAY_DELIVERY_COMPANY . $mini_id, $store_id, 'alipay', '')['value'];
  47. if(!$check && !$company){
  48. throw new \Exception('请管理员先配置支付宝同城配送的配送公司信息,小程序ID:'.$mini_id);
  49. }
  50. if($check){
  51. $account = 1;
  52. $md = 1;
  53. }
  54. $account && $account = self::getAccount($store_id, $mini_id);
  55. if(is_array($account) && empty($account['data']->logistics_account_status)){
  56. $account['data']->logistics_account_status = [];
  57. }
  58. $md && $md = self::getMd($store_id, $mini_id);
  59. if($check){
  60. $check = self::check($company, $account, $md);
  61. }
  62. $res = [
  63. 'shop_no' => $shop_no,
  64. 'company' => $company,
  65. ];
  66. $check && $res['check'] = $check;
  67. $account && $res['account'] = $account;
  68. $md && $res['md'] = $md;
  69. return $res;
  70. }
  71. public static function check($company, $account, $md) {
  72. if($account['code'] != 0){
  73. return ['code' => 1, 'msg' => '账户信息异常'];
  74. }
  75. if($md['code'] != 0){
  76. return ['code' => 1, 'msg' => '门店信息异常'];
  77. }
  78. $logistics_code = $company;
  79. if(isset($md['data']->logistics_shop_status)){
  80. $has = false;
  81. foreach ($md['data']->logistics_shop_status as $item) {
  82. if($item->logistics_code == $logistics_code){
  83. $has = true;
  84. if($item->status == 'VALID'){
  85. break;
  86. }else{
  87. return ['code' => 1, 'msg' => '门店当前状态:'.$item->status .' (AUDITING:审核中,AUDIT_REJECT:审核驳回,VALID:已生效,UPDATING:更新中,WAIT_CREATE:待开通)'];
  88. }
  89. }
  90. }
  91. if(!$has){
  92. return ['code' => 1, 'msg' => '门店无配送公司信息'];
  93. }
  94. }else{
  95. return ['code' => 1, 'msg' => '门店状态异常错误'];
  96. }
  97. if(isset($account['data']->logistics_account_status)){
  98. $has = false;
  99. foreach ($account['data']->logistics_account_status as $item) {
  100. if($item->logistics_code == $logistics_code){
  101. $has = true;
  102. if($item->status == 'VALID'){
  103. break;
  104. }else{
  105. return ['code' => 1, 'msg' => '账户当前状态:'.$item->status .' (AUDITING:审核中,AUDIT_REJECT:审核驳回,VALID:已生效)'];
  106. }
  107. }
  108. }
  109. if(!$has){
  110. return ['code' => 1, 'msg' => '账户无配送公司信息'];
  111. }
  112. }else{
  113. return ['code' => 1, 'msg' => '账户状态异常错误'];
  114. }
  115. if($account['data']->balance < 50){
  116. return ['code' => 1, 'msg' => '商家支付宝账户可用余额不足50元,请充值'];
  117. }
  118. return ['code' => 0, 'msg' => 'ok'];
  119. }
  120. public static function getAccount($store_id, $mini_id) {
  121. try{
  122. $form = new AlipayThirdForm();
  123. $form->mini_id = $mini_id;
  124. $res = $form->AlipayOpenInstantdeliveryAccountQueryRequest();
  125. return $res;
  126. } catch (\Exception $e) {
  127. \Yii::error([__METHOD__, $store_id, $mini_id, $e]);
  128. return [
  129. 'code'=>1,
  130. 'msg'=>$e->getMessage(),
  131. ];
  132. }
  133. }
  134. public static function createAccount($store_id, $mini_id, $logistics_codes) {
  135. try{
  136. $form = new AlipayThirdForm();
  137. $form->mini_id = $mini_id;
  138. $out_biz_no = microtime(true);
  139. $res = $form->AlipayOpenInstantdeliveryAccountCreate($out_biz_no, $logistics_codes);
  140. if($res['code'] == 0){
  141. Option::set(OptionSetting::ALIPAY_DELIVERY_COMPANY . $mini_id, $logistics_codes[0], $store_id, 'alipay');
  142. }
  143. return $res;
  144. } catch (\Exception $e) {
  145. \Yii::error([__METHOD__, $store_id, $mini_id, $e]);
  146. return [
  147. 'code'=>1,
  148. 'msg'=>$e->getMessage(),
  149. ];
  150. }
  151. }
  152. public static function createMd($store_id, $mini_id, $biz_content) {
  153. try{
  154. $shop_no = Option::get(OptionSetting::ALIPAY_DELIVERY_SHOP_NO . $mini_id, $store_id, 'alipay', '')['value'];
  155. if($shop_no){
  156. return self::updateMd($store_id, $mini_id, $biz_content);
  157. }
  158. $form = new AlipayThirdForm();
  159. $form->mini_id = $mini_id;
  160. $biz_content['shop_no'] = self::getShopNo($mini_id);
  161. $res = $form->AlipayOpenInstantdeliveryMerchantshopCreate($biz_content);
  162. if($res['code'] == 0){
  163. Option::set(OptionSetting::ALIPAY_DELIVERY_SHOP_NO . $mini_id, self::getShopNo($mini_id), $store_id, 'alipay');
  164. }
  165. return $res;
  166. } catch (\Exception $e) {
  167. \Yii::error([__METHOD__, $store_id, $mini_id, $e]);
  168. return [
  169. 'code'=>1,
  170. 'msg'=>$e->getMessage(),
  171. ];
  172. }
  173. }
  174. public static function updateMd($store_id, $mini_id, $biz_content) {
  175. try{
  176. $form = new AlipayThirdForm();
  177. $form->mini_id = $mini_id;
  178. $biz_content2['shop_no'] = self::getShopNo($mini_id);
  179. $biz_content2['contact_name'] = $biz_content['contact_name'];
  180. $biz_content2['phone'] = $biz_content['phone'];
  181. $biz_content2['logistics_codes'] = [];
  182. $md = self::getMd($store_id, $mini_id);
  183. if($md['code'] != 0){
  184. return [
  185. 'code'=>1,
  186. 'msg'=>'获取信息错误',
  187. ];
  188. }
  189. foreach ($md['data']->logistics_shop_status as $item) {
  190. $biz_content2['logistics_codes'][] = $item->logistics_code;
  191. }
  192. $res = $form->AlipayOpenInstantdeliveryMerchantshopModify($biz_content2);
  193. if($res['code'] == 0){
  194. Option::set(OptionSetting::ALIPAY_DELIVERY_SHOP_NO . $mini_id, self::getShopNo($mini_id), $store_id, 'alipay');
  195. }
  196. return $res;
  197. } catch (\Exception $e) {
  198. \Yii::error([__METHOD__, $store_id, $mini_id, $e]);
  199. return [
  200. 'code'=>1,
  201. 'msg'=>$e->getMessage(),
  202. ];
  203. }
  204. }
  205. public static function getMd($store_id, $mini_id) {
  206. try{
  207. $shop_no = self::getShopNo($mini_id);
  208. $form = new AlipayThirdForm();
  209. $form->mini_id = $mini_id;
  210. $res = $form->AlipayOpenInstantdeliveryMerchantshopQueryRequest($shop_no);
  211. return $res;
  212. } catch (\Exception $e) {
  213. \Yii::error([__METHOD__, $store_id, $mini_id, $e]);
  214. return [
  215. 'code'=>1,
  216. 'msg'=>$e->getMessage(),
  217. ];
  218. }
  219. }
  220. public static function createOrder($pre, $store_id, $mini_id, $alipay_open_id, $goods_list, $order_no, $address_id) {
  221. try{
  222. if(!$address_id){
  223. throw new \Exception('请先选择收货地址');
  224. }
  225. $conf = self::getConf($store_id, $mini_id);
  226. $store = Store::findOne($store_id);
  227. $address_info = \app\models\Address::findOne($address_id);
  228. if (!$address_info) {
  229. return [
  230. 'code' => 1,
  231. 'msg' => '请先设置收货地址'
  232. ];
  233. }
  234. $biz_content = [];
  235. $biz_content['out_order_no'] = $order_no;
  236. $biz_content['logistics_companies']['logistics_code'] = $conf['company'];
  237. $biz_content['shop_no'] = $conf['shop_no'];
  238. $biz_content['consumer_source'] = 'alipay';
  239. $biz_content['consumer_id'] = $alipay_open_id;
  240. $biz_content['receiver'] = [
  241. 'name' => $address_info->name,
  242. 'city' => $address_info->city,
  243. 'address' => $address_info->province . $address_info->city . $address_info->district,
  244. 'address_detail' => $address_info->detail,
  245. 'mobile_no' => $address_info->mobile,
  246. 'lng' => $address_info->longitude,
  247. 'lat' => $address_info->latitude,
  248. 'coordinate_type' => 0,
  249. ];
  250. $weight = 0.5;
  251. $total_price = 0;
  252. foreach ($goods_list as $value) {
  253. $total_price += $value['price'];
  254. }
  255. $biz_content['goods_info'] = [
  256. 'price' => $total_price,
  257. 'weight' => $weight,
  258. 'first_class' => '同城',
  259. 'second_class' => '配送',
  260. ];
  261. $gimg = $goods_list[0]['pic'];
  262. if(strpos($gimg, 'http') !== 0){
  263. $gimg = 'https:' . $gimg;
  264. }
  265. $biz_content['consumer_notify'] = [
  266. 'tiny_app_id' => '',
  267. 'goods_img' => $gimg,
  268. 'goods_name' => $goods_list[0]['name'],
  269. 'goods_count' => 1,
  270. 'merchant_name' => $store['name'],
  271. 'merchant_mobile' => $store->contact_tel,
  272. ];
  273. $form = new AlipayThirdForm();
  274. $form->mini_id = $mini_id;
  275. if($pre){
  276. $res = $form->AlipayCommerceLogisticsOrderInstantdeliveryPrecreateRequest($biz_content);
  277. \Yii::error([__METHOD__, '同城配送下单数据', $res, $biz_content]);
  278. if (isset($res['code']) && $res['code'] == 0) {
  279. DeliveryInfo::deleteAll(['order_no' => $order_no, 'store_id' => $store_id, 'status' => 0]);
  280. // 入表
  281. $delivery_info = new DeliveryInfo();
  282. $delivery_info->mini_id = $mini_id;
  283. $delivery_info->address_id = $address_id;
  284. $delivery_info->store_id = $store_id;
  285. $delivery_info->order_no = $order_no;
  286. $delivery_info->fee = $res['data']->waybills->fee;
  287. $delivery_info->delivery_token = $res['data']->waybills->logistics_token;
  288. $delivery_info->delivery_type = $res['data']->waybills->logistics_code;
  289. $delivery_info->created_at = time();
  290. $delivery_info->save();
  291. }
  292. }else{
  293. $delivery_info_token = DeliveryInfo::findOne(['order_no' => $order_no])->delivery_token;
  294. if ($delivery_info_token) {
  295. $biz_content['logistics_token'] = $delivery_info_token;
  296. }
  297. $res = $form->AlipayCommerceLogisticsOrderInstantdeliveryCreateRequest($biz_content);
  298. \Yii::error([__METHOD__, '同城配送下单数据', $res, $biz_content]);
  299. if (isset($res['code']) && $res['code'] == 0) {
  300. // 入表
  301. $delivery_info = DeliveryInfo::findOne(['store_id' => $store_id, 'order_no' => $order_no]);
  302. if ($delivery_info) {
  303. $delivery_info->status = $res['data']->status;
  304. $delivery_info->waybill_id = $res['data']->waybill_no;
  305. // $delivery_info->fee = $res['fee'];ML20211101195946262565
  306. $delivery_info->updated_at = time();
  307. $delivery_info->save();
  308. }
  309. }
  310. }
  311. return $res;
  312. } catch (\Exception $e) {
  313. \Yii::error([__METHOD__, func_get_args(), $e]);
  314. return [
  315. 'code'=>1,
  316. 'msg'=>$e->getMessage(),
  317. ];
  318. }
  319. }
  320. public static function cancelOrder($pre, $store_id, $mini_id, $order_no, $reason_id = 5, $reason = '其他原因') {
  321. if (empty($order_no)) {
  322. return [
  323. 'code' => 1,
  324. 'msg' => '缺少订单号参数'
  325. ];
  326. }
  327. $delivery_info = DeliveryInfo::findOne(['store_id' => $store_id, 'order_no' => $order_no]);
  328. if (!$delivery_info) {
  329. return [
  330. 'code' => 1,
  331. 'msg' => '未找到配送单信息'
  332. ];
  333. }
  334. try{
  335. $biz_content = [];
  336. $biz_content['out_order_no'] = $order_no;
  337. $biz_content['logistics_code'] = $delivery_info->delivery_type;
  338. $biz_content['waybill_no'] = $delivery_info->waybill_id;
  339. $biz_content['cancel_reason_id'] = $reason_id;
  340. $biz_content['cancel_reason'] = $reason;
  341. $form = new AlipayThirdForm();
  342. $form->mini_id = $mini_id;
  343. if($pre){
  344. $res = $form->AlipayCommerceLogisticsOrderIstdcancelPreconsultRequest($biz_content);
  345. }else{
  346. $res = $form->AlipayCommerceLogisticsOrderInstantdeliveryCancelRequest($biz_content);
  347. if (isset($res['code']) && $res['code'] == 0) {
  348. $delivery_info->reason_id = $reason_id . $reason;
  349. $delivery_info->save();
  350. return [
  351. 'code' => 0,
  352. 'msg' => 'success',
  353. 'data' => $res
  354. ];
  355. }
  356. }
  357. return $res;
  358. } catch (\Exception $e) {
  359. \Yii::error([__METHOD__, func_get_args(), $e]);
  360. return [
  361. 'code'=>1,
  362. 'msg'=>$e->getMessage(),
  363. ];
  364. }
  365. }
  366. /**
  367. * 拉取配送单信息
  368. * @return array
  369. */
  370. public static function getOrder($store_id, $mini_id, $order_no) {
  371. if (empty($order_no)) {
  372. return [
  373. 'code' => 1,
  374. 'msg' => '订单号不能为空'
  375. ];
  376. }
  377. $delivery_info = DeliveryInfo::findOne(['store_id' => $store_id, 'order_no' => $order_no]);
  378. if (!$delivery_info) {
  379. return [
  380. 'code' => 1,
  381. 'msg' => '未找到配送单信息'
  382. ];
  383. }
  384. try{
  385. $biz_content = [];
  386. $biz_content['out_order_no'] = $order_no;
  387. $biz_content['logistics_code'] = $delivery_info->delivery_type;
  388. $biz_content['waybill_no'] = $delivery_info->waybill_id;
  389. $biz_content['shop_no'] = self::getShopNo($mini_id);
  390. $form = new AlipayThirdForm();
  391. $form->mini_id = $mini_id;
  392. $res = $form->AlipayCommerceLogisticsWaybillIstddetailQueryRequest($biz_content);
  393. return $res;
  394. } catch (\Exception $e) {
  395. \Yii::error([__METHOD__, func_get_args(), $e]);
  396. return [
  397. 'code'=>1,
  398. 'msg'=>$e->getMessage(),
  399. ];
  400. }
  401. }
  402. public static function alipayCommerceLogisticsWaybillIstdstatusChanged($data) {
  403. $delivery_info = DeliveryInfo::findOne(['order_no' => $data['out_order_no'], 'waybill_id' => $data['waybill_no']]);
  404. if (!$delivery_info) {
  405. \Yii::error(['即时配送状态更改回调===============>', '获取商户信息失败']);
  406. return;
  407. }
  408. $data['status'] = str_replace('i_', '', $data['status']);
  409. $delivery_info->status = $data['status'];
  410. $delivery_info->updated_at = strtotime($data['action_time']);
  411. if (!empty($data['rider_name']) && !empty($data['rider_mobile'])) {
  412. $delivery_info->rider_name = $data['rider_name'];
  413. $delivery_info->rider_mobile = $data['rider_mobile'];
  414. }
  415. if (!$delivery_info->save()) {
  416. \Yii::error(['即时配送状态更改回调===============>', '更新数据状态失败']);
  417. return;
  418. }
  419. $order = Order::findOne(['order_no' => $data['out_order_no']]);
  420. if (in_array($data['status'], Delivery::$validRiderGetGoods)) {
  421. $order->trade_status = Order::ORDER_FLOW_SEND;
  422. }
  423. if (in_array($data['status'], Delivery::$validComplete)) {
  424. $order->trade_status = Order::ORDER_FLOW_CONFIRM;
  425. }
  426. if (in_array($data['status'], Delivery::$validError)) {
  427. $order->trade_status = Order::ORDER_FLOW_CANCEL;
  428. }
  429. $order->save();
  430. }
  431. }