MaiyatianForm.php 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\admin\models\maiyatian;
  8. use app\models\Option;
  9. use app\constants\OptionSetting;
  10. use app\models\AccountLog;
  11. use app\models\User;
  12. use app\models\SaasUser;
  13. use app\models\Cat;
  14. use app\models\Goods;
  15. use app\models\Supplier;
  16. use app\models\Attr;
  17. use app\models\AttrGroup;
  18. use app\modules\admin\models\GoodsForm;
  19. use app\models\GoodsCat;
  20. use app\models\Order;
  21. use app\models\OrderDetail;
  22. use app\modules\admin\models\OrderListForm;
  23. use app\models\Store;
  24. use app\models\DeliveryInfo;
  25. use app\models\DeliveryMaiyatian;
  26. class MaiyatianForm extends Model
  27. {
  28. public static $confs = [];
  29. public static $saasConf = [];
  30. public $store_id;
  31. public static $test = [];
  32. const ORDER_STATUS_UNPROGRESS = 'UNPROGRESS';
  33. const ORDER_STATUS_CREATED = 'CREATED';
  34. const ORDER_STATUS_CONFIRM = 'CONFIRM';
  35. const ORDER_STATUS_DELIVERY = 'DELIVERY';
  36. const ORDER_STATUS_PICKUP = 'PICKUP';
  37. const ORDER_STATUS_DELIVERING = 'DELIVERING';
  38. const ORDER_STATUS_DONE = 'DONE';
  39. const ORDER_STATUS_CANCEL = 'CANCEL';
  40. const ORDER_STATUS_DELETE = 'DELETE';
  41. const ORDER_STATUS_EXPECT = 'EXPECT';
  42. public static $order_status_list = [
  43. self::ORDER_STATUS_UNPROGRESS => '未处理',
  44. self::ORDER_STATUS_CREATED => '待确认',
  45. self::ORDER_STATUS_CONFIRM => '已确认',
  46. self::ORDER_STATUS_DELIVERY => '待抢单',
  47. self::ORDER_STATUS_PICKUP => '待取货',
  48. self::ORDER_STATUS_DELIVERING => '配送中',
  49. self::ORDER_STATUS_DONE => '已完成',
  50. self::ORDER_STATUS_CANCEL => '已取消',
  51. self::ORDER_STATUS_DELETE => '已删除',
  52. self::ORDER_STATUS_EXPECT => '配送异常',
  53. ];
  54. const DELIVERY_STATUS_PENDING = 'PENDING';
  55. const DELIVERY_STATUS_GRABBED = 'GRABBED';
  56. const DELIVERY_STATUS_PICKUP = 'PICKUP';
  57. const DELIVERY_STATUS_DELIVERING = 'DELIVERING';
  58. const DELIVERY_STATUS_DONE = 'DONE';
  59. const DELIVERY_STATUS_CANCEL = 'CANCEL';
  60. const DELIVERY_STATUS_BACK = 'BACK';
  61. const DELIVERY_STATUS_TRANSFER = 'TRANSFER';
  62. const DELIVERY_STATUS_CREATE_FAILED = 'CREATE_FAILED';
  63. public static $delivery_status_list = [
  64. self::DELIVERY_STATUS_PENDING => '未分配骑手',
  65. self::DELIVERY_STATUS_GRABBED => '已分配骑手',
  66. self::DELIVERY_STATUS_PICKUP => '已到店',
  67. self::DELIVERY_STATUS_DELIVERING => '配送中',
  68. self::DELIVERY_STATUS_DONE => '已完单',
  69. self::DELIVERY_STATUS_CANCEL => '配送取消',
  70. self::DELIVERY_STATUS_BACK => '配送退回',
  71. self::DELIVERY_STATUS_TRANSFER => '配送转单',
  72. self::DELIVERY_STATUS_CREATE_FAILED => '订单创建失败',
  73. ];
  74. public static $category = [
  75. 'xiaochi'=>'小吃美食',
  76. 'canyin'=>'正餐快餐',
  77. 'shaokao'=>'龙虾烧烤',
  78. 'dangao'=>'烘焙蛋糕',
  79. 'tianpin'=>'甜品奶茶',
  80. 'liaoli'=>'西餐料理',
  81. 'huoguo'=>'火锅串串',
  82. 'xianhua'=>'浪漫鲜花',
  83. 'shuiguo'=>'生鲜果蔬',
  84. 'yinpin'=>'酒水零售',
  85. 'chaoshi'=>'超市百货',
  86. 'chengren'=>'医药成人',
  87. ];
  88. public static $logistic_tag_list = [
  89. 'MEITUAN'=>'美团骑手',
  90. 'SHUNFENG'=>'顺丰',
  91. 'DADA'=>'达达',
  92. 'FENGNIAO'=>'蜂鸟跑腿',
  93. 'ELEZB'=>'饿了么众包',
  94. 'EBAIZB'=>'饿百众包',
  95. 'BINGEX'=>'闪送',
  96. 'UUPT'=>'UU跑腿',
  97. 'BANGLA'=>'帮拉',
  98. 'LINQU'=>'邻趣',
  99. 'CAOSONG'=>'曹操送',
  100. 'ZHIDONG'=>'指动跑腿',
  101. 'CAOCAO'=>'曹操跑腿',
  102. 'PAOPAO'=>'喊跑跑',
  103. 'DAXIA'=>'大侠跑腿',
  104. 'DIANWO'=>'点我达',
  105. 'IPAOTUI'=>'爱跑腿',
  106. 'XIAOBANG'=>'小帮',
  107. 'RIDER'=>'蚂蚁派',
  108. 'PINBIDA'=>'拼必达',
  109. 'JIUJIU'=>'久久跑腿',
  110. 'SAICAOCAO'=>'赛曹操',
  111. 'ZHITONG'=>'直通车',
  112. 'XIAOGE'=>'小哥快运',
  113. 'YUNDA'=>'云递配',
  114. 'HUICONG'=>'零点壹',
  115. 'SHILU'=>'时路网',
  116. 'SONGSHUWU'=>'聚合配送',
  117. 'ZBS'=>'宅帮手',
  118. 'KAOPU'=>'靠谱送',
  119. 'KUAIMA'=>'0851跑腿',
  120. 'XIANGZI'=>'祥子',
  121. 'KUAIDAO'=>'快到',
  122. 'EPAI'=>'E派速达',
  123. 'FEIKE'=>'一城飞客',
  124. 'NADUDA'=>'哪都达',
  125. 'FUWUJIA'=>'服务之家',
  126. 'BIANLI'=>'便利专送',
  127. 'HONGSU'=>'鸿速同城急送',
  128. 'GUOXIAODI'=>'裹小递',
  129. 'FUWU'=>'快服务',
  130. 'KELOOP'=>'快跑者',
  131. 'HAOJI'=>'好急跑腿',
  132. 'JDPS'=>'京东配送',
  133. 'PENGJIU'=>'鹏九跑腿',
  134. 'HUOLALA'=>'货拉拉',
  135. 'DAIBANG'=>'代帮跑腿',
  136. 'LAILA'=>'来啦跑腿',
  137. 'LANZHU'=>'懒猪跑腿',
  138. 'KUAIPAO'=>'快跑者急送',
  139. 'FEITU'=>'飞兔跑腿',
  140. 'SONGDAO'=>'送道',
  141. 'ANKEFO'=>'安克弗跑腿',
  142. 'SONGDONGXI'=>'送个东西跑腿',
  143. 'ANXUN'=>'安讯即配',
  144. 'PICKER'=>'自提',
  145. 'OTHER'=>'其他',
  146. 'ONESELF'=>'自配送',
  147. ];
  148. public static function urlPush($store_id = 0){
  149. $url = 'https://open-api.maiyatian.com/v1/channel/';
  150. if(self::isTest($store_id)){
  151. $url = 'https://open-api-test.maiyatian.com/v1/channel/';
  152. }
  153. return $url;
  154. }
  155. public static function urlPushAuth($store_id = 0){
  156. $url = 'https://saas.maiyatian.com/oauth/';
  157. if(self::isTest($store_id)){
  158. $url = 'http://saas.open.test.maiyatian.com/oauth/index/';
  159. }
  160. return $url;
  161. }
  162. public static function setTest($store_id = 0){
  163. self::$test[$store_id] = 1;
  164. }
  165. public static function isTest($store_id = 0){
  166. $confTest = self::getConf($store_id, 'test');
  167. if($confTest){
  168. return true;
  169. }
  170. return self::$test[$store_id] ? true : false;
  171. }
  172. public static function type(){
  173. return [
  174. 'waimai'=>'外卖',
  175. 'shop'=>'店铺',
  176. 'other'=>'其他',
  177. ];
  178. }
  179. public static function callbackCommandTest($command, array $data){
  180. self::setTest();
  181. return self::callbackCommand($command, $data);
  182. }
  183. public static function callbackCommand($command, array $data){
  184. debug_log([__FUNCTION__, __LINE__, $command, $data], __CLASS__ . '.log');
  185. $command = 'cb_' . $command;
  186. if($data['data']){
  187. $data = json_decode($data['data'], true);
  188. }
  189. $res = call_user_func_array([new MaiyatianCallback(), $command], [$data]);
  190. if($res['code'] === 0){
  191. $res['code'] = 200;
  192. }
  193. debug_log([__FUNCTION__, __LINE__, $command, $res], __CLASS__ . '.log');
  194. return $res;
  195. }
  196. public static function access_token($store_id, $code){
  197. $access_token = self::api($store_id, 'access_token', [
  198. "grant_type" => "shop", //授权类型 默认:shop
  199. "code" => $code, //状态码
  200. "shop_id" => (string)$store_id, //平台方渠道ID
  201. "category" => self::getConf($store_id, 'category'), //订单分类(麦芽田枚举)
  202. "name" => self::getConf($store_id, 'name'), //门店名称
  203. "type" => self::getConf($store_id, 'type'), //店铺类型 ["waimai","shop","other"]
  204. "longitude" => self::getConf($store_id, 'longitude'), //经度(国测局02标准,如高德)
  205. "latitude" => self::getConf($store_id, 'latitude'), //纬度(国测局02标准,如高德)
  206. ]);
  207. return $access_token;
  208. }
  209. public static function refreshToken($store_id = 0) {
  210. if(!self::isopen($store_id)){
  211. return;
  212. }
  213. $refreshToken = self::api($store_id, 'refresh_token', [
  214. "token" => self::getConf($store_id, 'token'),
  215. "refresh_token" => self::getConf($store_id, 'refresh_token'),
  216. ]);
  217. if($refreshToken['code'] != 0){
  218. return $refreshToken;
  219. }
  220. $data = $refreshToken['data'];
  221. self::saveConf($store_id, $data);
  222. return $refreshToken;
  223. }
  224. public static function authUrl($store_id){
  225. $url = self::urlPushAuth($store_id);
  226. $saasConf = self::saasConf();
  227. $url .= '?' . http_build_query([
  228. 'app_key' => $saasConf['app_key'],
  229. 'response_type' => 'code',
  230. 'view' => 'web',
  231. 'state' => $store_id,
  232. 'shop_id' => (string)$store_id,
  233. 'redirect_uri' => $saasConf['url_callback_auth'],
  234. ]);
  235. return $url;
  236. }
  237. public static function signatureData(array $data, $command, $appKey, $appSecret, $token)
  238. {
  239. $signData = [
  240. 'app_key' => $appKey,
  241. 'command' => $command,
  242. 'data' => json_encode($data),
  243. 'timestamp' => time(),
  244. 'token' => $token,
  245. ];
  246. ksort($signData);
  247. $dataToSign = '';
  248. foreach ($signData as $k => $v) {
  249. $dataToSign .= $k . '=' . $v . ',';
  250. }
  251. $dataToSign = substr($dataToSign, 0, -1);
  252. $hash = hash_hmac('sha256', $dataToSign, $appSecret, true);
  253. $signData['signature'] = strtr(base64_encode($hash), '+/', '-_');
  254. unset($signData['command']);
  255. return $signData;
  256. }
  257. public static function sendRequest($type = 'POST', $baseUrl = '', $url = '', array $options = []):array
  258. {
  259. $url = $baseUrl . $url;
  260. $curl = curl_init();
  261. curl_setopt_array($curl, [
  262. CURLOPT_URL => $url,
  263. CURLOPT_RETURNTRANSFER => true,
  264. CURLOPT_ENCODING => "",
  265. CURLOPT_MAXREDIRS => 10,
  266. CURLOPT_TIMEOUT => 10,
  267. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  268. CURLOPT_CUSTOMREQUEST => strtoupper($type),
  269. CURLOPT_POSTFIELDS => json_encode($options),
  270. CURLOPT_HTTPHEADER => [
  271. "content-type: application/json"
  272. ],
  273. ]);
  274. $response = curl_exec($curl);
  275. $err = curl_error($curl);
  276. curl_close($curl);
  277. $res = [];
  278. if ($err) {
  279. $res = [
  280. 'code' => 1,
  281. 'msg' => "cURL Error #:" . $err,
  282. ];
  283. } else {
  284. $res = json_decode($response, true);
  285. }
  286. return $res;
  287. }
  288. public static function api($store_id = 0, $_a = 'shop_info', $params = [], $type = 'post') {
  289. $baseUrl = self::urlPush($store_id);
  290. $saasConf = self::saasConf();
  291. $token = self::isopen($store_id) ? self::getConf($store_id, 'token') : $store_id;
  292. $data = self::signatureData($params, $_a, $saasConf['app_key'], $saasConf['app_secret'], $token);
  293. $data['request_id'] = md5(microtime(true));
  294. $response = self::sendRequest($type, $baseUrl, $_a, $data);
  295. debug_log([__LINE__, $_a, $response, $store_id, $type, $data], __CLASS__ . '.log');
  296. if(isset($response['code'])){
  297. if($response['code'] != 200){
  298. debug_log(['code!=200', $response, $store_id, $type, $data], __CLASS__ . '.log');
  299. }else{
  300. $response['code'] = 0;
  301. $response['data'] = json_decode($response['data'], true);
  302. }
  303. }
  304. return $response;
  305. }
  306. public static function saasConf($refresh = 0) {
  307. if(!empty(self::$saasConf) && !$refresh){
  308. return self::$saasConf;
  309. }
  310. $conf = Option::get(OptionSetting::MAIYATIAN_SAAS, 0, 'saas')['value'];
  311. if($conf){
  312. $conf = json_decode($conf, true);
  313. }else{
  314. $conf = [
  315. 'app_key' => '',
  316. 'app_secret' => '',
  317. 'tag' => '',
  318. ];
  319. }
  320. $url_callback_test = \Yii::$app->request->hostInfo . '/index.php/maiyatian/test/callback/';
  321. $url_callback = \Yii::$app->request->hostInfo . '/index.php/maiyatian/callback/';
  322. $url_callback_auth = \Yii::$app->request->hostInfo . '/index.php/maiyatian/callback/cyy_auth';
  323. $conf['url_callback'] = $url_callback;
  324. $conf['url_callback_test'] = $url_callback_test;
  325. $conf['url_callback_auth'] = $url_callback_auth;
  326. self::$saasConf = $conf;
  327. return $conf;
  328. }
  329. public static function saasConfSave($config = []) {
  330. $set = Option::set(OptionSetting::MAIYATIAN_SAAS, json_encode($config), 0, 'saas');
  331. self::saasConf(1);
  332. return $set;
  333. }
  334. public static function isSaasOpen() {
  335. $conf = self::saasConf();
  336. return empty($conf['app_key']) ? 0 : 1;
  337. }
  338. public static function conf($store_id = 0, $refresh = 0) {
  339. if(isset(self::$confs[$store_id]) && !$refresh){
  340. return self::$confs[$store_id];
  341. }
  342. $conf = Option::get(OptionSetting::MAIYATIAN, $store_id, 'store')['value'];
  343. if($conf){
  344. $conf = json_decode($conf, true);
  345. }else{
  346. $conf = [
  347. "shop_id" => "0", //平台方渠道ID
  348. "category" => "", //订单分类(麦芽田枚举)
  349. "name" => "", //门店名称
  350. "type" => "", //店铺类型 ["waimai","shop","other"]
  351. "longitude" => "", //经度(国测局02标准,如高德)
  352. "latitude" => "", //纬度(国测局02标准,如高德)
  353. //自定义参数
  354. "is_open" => 0, //是否开启
  355. "cyy_delivery_time" => "91", //配送时间(分钟)
  356. "cyy_delivery_fee" => "10", //配送费用(元)
  357. ];
  358. }
  359. $conf['is_open'] = (int)$conf['is_open'];
  360. self::$confs[$store_id] = $conf;
  361. return $conf;
  362. }
  363. public static function saveConf($store_id = 0, $config = []) {
  364. $oldConf = self::conf($store_id, 1);
  365. if($oldConf['token'] != $config['token']){
  366. $config['refresh_time'] = time();
  367. }
  368. $conf = array_merge($oldConf, $config);
  369. $set = Option::set(OptionSetting::MAIYATIAN, json_encode($conf), $store_id, 'store');
  370. self::conf($store_id, 1);
  371. return $set;
  372. }
  373. public static function getConf($store_id = 0, $key = '') {
  374. $config = self::conf($store_id);
  375. return $config[$key];
  376. }
  377. public static function setConf($store_id = 0, $key = '', $val = '') {
  378. $config = self::conf($store_id);
  379. $config[$key] = $val;
  380. return self::saveConf($store_id, $config);
  381. }
  382. public static function isopen($store_id = 0) {
  383. $is_open = self::getConf($store_id, 'is_open');
  384. if($is_open){
  385. $expires_time = self::getConf($store_id, 'expire_time');
  386. if(!isset($expires_time)){
  387. $is_open = 0;
  388. }
  389. if($expires_time > 0 && $expires_time < time()){
  390. $is_open = 0;
  391. }
  392. }
  393. return $is_open == 1 ? true : false;
  394. }
  395. public static function createUrl($store_id = 0) {
  396. try{
  397. $isSaasOpen = self::isSaasOpen();
  398. if(!$isSaasOpen){
  399. throw new \Exception('平台未配置此功能');
  400. }
  401. $storeName = self::getConf($store_id, 'name');
  402. if(!$storeName){
  403. throw new \Exception('请先提交表单信息');
  404. }
  405. $url = self::authUrl($store_id);
  406. return [
  407. 'code' => 0,
  408. 'data' => $url,
  409. ];
  410. } catch (\Exception $ex) {
  411. \Yii::error([__METHOD__, __LINE__, $ex->getMessage()]);
  412. return [
  413. 'code' => 1,
  414. 'msg' => $ex->getMessage(),
  415. ];
  416. }
  417. }
  418. public static function getUserByStoreSaasuser($store_id = 0, $saas_user = []) {
  419. $user = User::find()->where([
  420. 'store_id' => $store_id,
  421. 'binding' => $saas_user['mobile'],
  422. 'is_delete' => 0,
  423. ])->one();
  424. return $user;
  425. }
  426. public static function afterOrderSave($insert, $changedAttributes, $order){
  427. try{
  428. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, $order->store_id, 'store')['value'];
  429. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, $order->store_id, 'pay', $local_type)['value'];
  430. \Yii::error($local_type);
  431. if($local_type != 'maiyatian'){
  432. return;
  433. }
  434. //取消订单
  435. if (($order->is_delivery == 1) &&
  436. ($order->trade_status == Order::ORDER_FLOW_CANCEL) &&
  437. ($changedAttributes['trade_status'] != Order::ORDER_FLOW_CANCEL)) {
  438. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order->order_no, 'store_id' => $order->store_id]);
  439. if($delivery){
  440. $order_canceled = self::order_canceled($order->store_id, $order->id);
  441. if($order_canceled['code'] !== 0){
  442. throw new Exception($order_canceled['msg']);
  443. }
  444. $order_apply_refund = self::order_apply_refund($order->store_id, $order->id);
  445. if($order_apply_refund['code'] !== 0){
  446. throw new Exception($order_apply_refund['msg']);
  447. }
  448. }
  449. }
  450. } catch (\Exception $ex) {
  451. \Yii::error($ex);
  452. debug_log([__FUNCTION__, __LINE__, $ex->getMessage(), $ex->getTrace()], __CLASS__ . '.log');
  453. }
  454. }
  455. public static function orderList($store_id, $params){
  456. $form = new OrderListForm();
  457. if($params['dateEnd']){
  458. $params['dateEnd'] .= ' 23:59:59';
  459. }
  460. $form->attributes = $params;
  461. $form->store_id = $store_id;
  462. $form->maiyatian = 1;
  463. $form->is_delivery = true;
  464. $list = $form->search();
  465. unset($list['data']['export_list']);
  466. unset($list['data']['express_list']);
  467. foreach($list['data']['data'] as &$item){
  468. $deliveryModel = DeliveryMaiyatian::findOne(['order_no' => $item['order_no']]);
  469. $delivery = $deliveryModel->attributes;
  470. $delivery['delivery_status_name'] = self::$delivery_status_list[$delivery['delivery_status']] ?? '';
  471. $delivery['order_status_name'] = self::$order_status_list[$delivery['order_status']] ?? '';
  472. $delivery['refund_status_name'] = $deliveryModel->getRefundStatusName();
  473. $item['delivery'] = $delivery;
  474. }
  475. $list['maiyatian'] = [
  476. 'order_status_list' => self::$order_status_list,
  477. 'delivery_status_list' => self::$delivery_status_list,
  478. 'logistic_tag_list' => self::$logistic_tag_list,
  479. ];
  480. return $list;
  481. }
  482. public static function shop_info($store_id){
  483. $data = self::api($store_id, 'shop_info', [
  484. "shop_id" => (string)$store_id, //平台方渠道ID
  485. ]);
  486. return $data;
  487. }
  488. public static function order_created($store_id, $order_id = 0){
  489. $order = Order::findOne($order_id);
  490. if(!$order){
  491. return [
  492. 'code' => 1,
  493. 'msg' => '订单信息错误',
  494. ];
  495. }
  496. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order->order_no, 'store_id' => $store_id]);
  497. if($delivery){
  498. return [
  499. 'code' => 1,
  500. 'msg' => '订单信息已存在',
  501. ];
  502. }
  503. $data = self::getOrder($store_id, $order);
  504. $res = self::api($store_id, 'order_created', $data);
  505. if($res['code'] != 0){
  506. return $res;
  507. }
  508. self::data_order_created($store_id, $order, $data);
  509. return $res;
  510. }
  511. public static function order_modified($store_id, $order_id = 0){
  512. $order = Order::findOne($order_id);
  513. if(!$order){
  514. return [
  515. 'code' => 1,
  516. 'msg' => '订单信息错误',
  517. ];
  518. }
  519. $data = self::getOrder($store_id, $order);
  520. $res = self::api($store_id, 'order_modified', $data);
  521. return $res;
  522. }
  523. public static function preAddOrder($store_id, $order_no, $freight) {
  524. if (!$order_no) {
  525. return [
  526. 'code' => 1,
  527. 'msg' => '缺少订单号参数'
  528. ];
  529. }
  530. DeliveryInfo::deleteAll(['order_no' => $order_no, 'store_id' => $store_id, 'status' => 0]);
  531. $delivery_info = new DeliveryInfo();
  532. $delivery_info->store_id = $store_id;
  533. $delivery_info->order_no = $order_no;
  534. $delivery_info->delivery_type = '';
  535. $delivery_info->fee = $freight;
  536. $delivery_info->created_at = time();
  537. $save = $delivery_info->save();
  538. if(!$save){
  539. return [
  540. 'code' => 1,
  541. 'msg' => array_shift($delivery_info->getFirstErrors()),
  542. ];
  543. }
  544. return [
  545. 'code' => 0,
  546. 'msg' => 'ok',
  547. 'data' => [
  548. "resultcode" => 0,
  549. 'fee' => (float)$delivery_info->fee,
  550. ],
  551. ];
  552. }
  553. public static function data_order_created($store_id, $order, $data){
  554. $delivery = new DeliveryMaiyatian();
  555. $delivery->store_id = $store_id;
  556. $delivery->order_no = $order->order_no;
  557. $delivery->delivery_status = self::DELIVERY_STATUS_PENDING;
  558. $delivery->order_status = self::ORDER_STATUS_UNPROGRESS;
  559. $save = $delivery->save();
  560. if(!$save){
  561. return [
  562. 'code' => 1,
  563. 'msg' => array_shift($delivery->getFirstErrors()),
  564. ];
  565. }
  566. if($order->trade_status < Order::ORDER_FLOW_SEND){
  567. $order->trade_status = Order::ORDER_FLOW_SEND;
  568. $order->send_time = time();
  569. if (!$order->save()) {
  570. debug_log([__FUNCTION__, __LINE__, '订单发货失败', array_shift($order->getFirstErrors())], __CLASS__ . '.log');
  571. return [
  572. 'code' => 1,
  573. 'msg' => '订单发货失败',
  574. ];
  575. }
  576. }
  577. return [
  578. 'code' => 0,
  579. 'msg' => 'ok',
  580. ];
  581. }
  582. public static function getOrder($store_id, $order) {
  583. $address_data = json_decode($order->address_data, true);
  584. $is_pre_order = false;
  585. if(!empty($order->delivery_time)){
  586. $is_pre_order = true;
  587. $delivery_time = $order->delivery_time;
  588. }else{
  589. $delivery_time = time() + 60 * self::getConf($store_id, 'cyy_delivery_time');
  590. }
  591. $data = [
  592. "order" => [
  593. "order_id" => $order->order_no,
  594. "order_sn" => $order->id,
  595. "shop_id" => (string)$store_id,
  596. "shop_name" => self::getConf($store_id, 'name'),
  597. "category" => self::getConf($store_id, 'category'),
  598. "is_pre_order" => $is_pre_order,
  599. "total_price" => intval($order->total_price * 100),
  600. "balance_price" => intval($order->pay_price * 100),
  601. "create_time" => $order->created_at,
  602. "delivery_time" => $delivery_time,
  603. // "delivery_end" => 1657099625,
  604. "is_picker" => false,
  605. // "pick_time" => 0,
  606. "user_remark" => $order->remark,
  607. // "greeting" => "",
  608. // "pickup_code" => "",
  609. "order_fee" => [
  610. "total_fee" => intval($order->total_price * 100),
  611. "send_fee" => 0,
  612. "package_fee" => 0,
  613. "discount_fee" => intval(($order->total_price - $order->pay_price) * 100),
  614. "shop_fee" => intval($order->pay_price * 100),
  615. "user_fee" => intval($order->pay_price * 100),
  616. "pay_type" => 2,
  617. // "need_invoice" => true,
  618. // "invoice" => [
  619. // "type" => 1,
  620. // "title" => "麦芽田",
  621. // "taxer_id" => "123123123csd123",
  622. // "email" => "123@qq.com",
  623. // "form_type" => 2
  624. // ],
  625. // "commission" => 0,
  626. // "activity" => [
  627. // [
  628. // "type" => 1,
  629. // "title" => "满30减10",
  630. // "merchant" => 3000,
  631. // "reduce" => 1000
  632. // ]
  633. // ],
  634. // "is_first" => true,
  635. // "is_favorite" => false
  636. ],
  637. "order_goods" => [
  638. [
  639. "goods_id" => "1001",
  640. "goods_name" => "烧鸡",
  641. "thumb" => "https://p1.meituan.net/210.0/dpmerchantpic/f6c19b87623aead81776d86bc1f6b629335919.jpg",
  642. "sku_id" => "10001",
  643. "sku_name" => "原味",
  644. "sku_attributes" => [
  645. [
  646. "name" => "烧鸡200g"
  647. ]
  648. ],
  649. "unit" => "包",
  650. "weight" => 100,
  651. // "upc" => "123123123",
  652. // "shelf_no" => "123123",
  653. "number" => 2,
  654. "goods_price" => 500,
  655. "goods_total_fee" => 1000,
  656. // "package_number" => 1,
  657. // "package_price" => 100,
  658. // "package_total_fee" => 100,
  659. "reduce_fee" => 980,
  660. "discount_fee" => 20,
  661. // "discount_platform_fee" => 0,
  662. // "discount_merchant_fee" => 0,
  663. // "discount_agent_fee" => 0,
  664. // "discount_logistics_fee" => 0,
  665. "total_fee" => 980,
  666. // "goods_code" => "123123",
  667. // "sku_code" => "123123"
  668. ]
  669. ]
  670. ],
  671. "order_customer" => [
  672. "real_name" => $order->name,
  673. "phone" => $order->mobile,
  674. "secret_phone" => substr_replace($order->mobile, '****', 3, 4),
  675. // "order_phone" => "15626476455",
  676. // "reserve_phone" => "15735039271_7095",
  677. "address" => $order->address,
  678. "longitude" => $address_data['longitude'] ?? '',
  679. "latitude" => $address_data['latitude'] ?? '',
  680. ],
  681. "update_time" => $order->pay_time,
  682. ];
  683. $data['order']['order_goods'] = [];
  684. $ods = $order->detail;
  685. foreach($ods as $od){
  686. $goods = $od->goods;
  687. $attrs = json_decode($od->attr, true);
  688. $item = [
  689. "goods_id" => (string)$od->goods_id,
  690. "goods_name" => mb_substr($od->goods_name, 0, 10),
  691. "thumb" => $od->pic,
  692. "sku_id" => implode('_', array_column($attrs, 'attr_id')),
  693. "sku_name" => implode('_', array_column($attrs, 'attr_name')),
  694. "sku_attributes" => [
  695. [
  696. "name" => implode('_', array_column($attrs, 'attr_name')),
  697. ]
  698. ],
  699. "unit" => $goods->unit,
  700. "weight" => $goods->weight,
  701. // "upc" => "123123123",
  702. // "shelf_no" => "123123",
  703. "number" => $od->num,
  704. "goods_price" => intval($goods->price * 100),
  705. "goods_total_fee" => intval($od->total_price * 100),
  706. // "package_number" => 1,
  707. // "package_price" => 100,
  708. // "package_total_fee" => 100,
  709. "reduce_fee" => 0,
  710. "discount_fee" => 0,
  711. // "discount_platform_fee" => 0,
  712. // "discount_merchant_fee" => 0,
  713. // "discount_agent_fee" => 0,
  714. // "discount_logistics_fee" => 0,
  715. "total_fee" => intval($od->total_price * 100),
  716. // "goods_code" => "123123",
  717. // "sku_code" => "123123"
  718. ];
  719. $data['order']['order_goods'][] = $item;
  720. }
  721. return $data;
  722. }
  723. /**
  724. * 订单申请退款
  725. * @param type $store_id
  726. * @param type $order_id
  727. * @param type $type //退款类型 1全部 2部分
  728. * @param type $reason //原因
  729. */
  730. public static function order_apply_refund($store_id, $order_id = 0, $type = 1, $reason = '申请退款'){
  731. $order = Order::findOne($order_id);
  732. if(!$order){
  733. return [
  734. 'code' => 1,
  735. 'msg' => '订单信息错误',
  736. ];
  737. }
  738. $params = [
  739. 'type' => (int)$type,
  740. 'reason' => (string)$reason,
  741. ];
  742. $res = self::api($store_id, 'order_apply_refund', array_merge(
  743. self::getOrderRefund($store_id, $order),
  744. $params,
  745. )
  746. );
  747. if($res['code'] != 0){
  748. return $res;
  749. }
  750. self::data_order_refund($store_id, $order->order_no, $params);
  751. return $res;
  752. }
  753. /**
  754. * 订单退款
  755. * @param type $store_id
  756. * @param type $order_id
  757. * @param type $status //退款状态 1确认 2驳回 3用户取消退款申请
  758. */
  759. public static function order_refunded($store_id, $order_id = 0, $status = 1){
  760. $order = Order::findOne($order_id);
  761. if(!$order){
  762. return [
  763. 'code' => 1,
  764. 'msg' => '订单信息错误',
  765. ];
  766. }
  767. $params = [
  768. 'status' => (int)$status,
  769. ];
  770. $res = self::api($store_id, 'order_refunded', array_merge(
  771. self::getOrderRefund($store_id, $order),
  772. $params,
  773. )
  774. );
  775. if($res['code'] != 0){
  776. return $res;
  777. }
  778. self::data_order_refund($store_id, $order->order_no, $params);
  779. return $res;
  780. }
  781. /**
  782. * 订单取消
  783. * @param type $store_id
  784. * @param type $order_id
  785. * @param type $reason
  786. * @param type $reason_code //取消类型 1用户 2商户 3客服 4系统 5其他
  787. */
  788. public static function order_canceled($store_id, $order_id = 0, $reason = '取消', $reason_code = 1){
  789. $order = Order::findOne($order_id);
  790. if(!$order){
  791. return [
  792. 'code' => 1,
  793. 'msg' => '订单信息错误',
  794. ];
  795. }
  796. $params = [
  797. 'reason' => (string)$reason,
  798. 'reason_code' => (int)$reason_code,
  799. ];
  800. $res = self::api($store_id, 'order_canceled', array_merge(
  801. self::getOrderRefund($store_id, $order),
  802. $params,
  803. )
  804. );
  805. if($res['code'] != 0){
  806. return $res;
  807. }
  808. self::data_order_canceled($store_id, $order->order_no, $params);
  809. //取消后自动退款
  810. self::order_apply_refund($store_id, $order_id, 1, $reason);
  811. $res = self::order_refunded($store_id, $order_id);
  812. return $res;
  813. }
  814. public static function getOrderRefund($store_id, $order) {
  815. $goods = [];
  816. $ods = $order->detail;
  817. foreach($ods as $od){
  818. $attrs = json_decode($od->attr, true);
  819. $item = [
  820. "goods_id" => (string)$od->goods_id,
  821. "goods_name" => mb_substr($od->goods_name, 0, 10),
  822. "sku_id" => implode('_', array_column($attrs, 'attr_id')),
  823. "upc" => "",
  824. "shelf_no" => "",
  825. "number" => $od->num,
  826. "goods_total_fee" => intval($od->total_price * 100),
  827. "package_number" => 1,
  828. "package_fee" => 0,
  829. "refund_fee" => intval($od->total_price * 100),
  830. ];
  831. $goods[] = $item;
  832. }
  833. $res = [
  834. 'order_id' => $order->order_no,
  835. 'shop_id' => (string)$store_id,
  836. 'goods' => $goods,
  837. 'total_price' => intval($order->total_price * 100),
  838. 'count' => count($ods),
  839. 'update_time' => time(),
  840. ];
  841. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order->order_no, 'store_id' => $store_id]);
  842. $delivery['refund_type'] && $res['type'] = $delivery['refund_type'];
  843. $delivery['refund_reason'] && $res['reason'] = $delivery['refund_reason'];
  844. return $res;
  845. }
  846. public static function order_confirmed($store_id, $order_id = 0){
  847. $order = Order::findOne($order_id);
  848. if(!$order){
  849. return [
  850. 'code' => 1,
  851. 'msg' => '订单信息错误',
  852. ];
  853. }
  854. $res = self::api($store_id, 'order_confirmed', [
  855. 'order_id' => $order->order_no,
  856. 'shop_id' => (string)$store_id,
  857. 'update_time' => time(),
  858. ]);
  859. if($res['code'] != 0){
  860. return $res;
  861. }
  862. self::data_order_confirm($store_id, $order->order_no);
  863. return $res;
  864. }
  865. public static function order_done($store_id, $order_id = 0){
  866. $order = Order::findOne($order_id);
  867. if(!$order){
  868. return [
  869. 'code' => 1,
  870. 'msg' => '订单信息错误',
  871. ];
  872. }
  873. $res = self::api($store_id, 'order_done', [
  874. 'order_id' => $order->order_no,
  875. 'shop_id' => (string)$store_id,
  876. 'update_time' => time(),
  877. ]);
  878. if($res['code'] != 0){
  879. return $res;
  880. }
  881. self::data_order_done($store_id, $order->order_no);
  882. return $res;
  883. }
  884. public static function query_order($store_id, $order_id = 0){
  885. $order = Order::findOne($order_id);
  886. if(!$order){
  887. return [
  888. 'code' => 1,
  889. 'msg' => '订单信息错误',
  890. ];
  891. }
  892. $res = self::api($store_id, 'query_order', [
  893. 'order_id' => $order->order_no,
  894. 'shop_id' => (string)$store_id,
  895. ]);
  896. return $res;
  897. }
  898. public static function data_order_refund($store_id, $order_no = '', $params = []){
  899. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  900. $delivery->is_refund = 1;
  901. $params['type'] && $delivery->refund_type = $params['type'];
  902. $params['reason'] && $delivery->refund_reason = $params['reason'];
  903. $params['status'] && $delivery->refund_status = $params['status'];
  904. $save = $delivery->save();
  905. if(!$save){
  906. return [
  907. 'code' => 1,
  908. 'msg' => array_shift($delivery->getFirstErrors()),
  909. ];
  910. }
  911. return [
  912. 'code' => 0,
  913. 'msg' => 'ok',
  914. ];
  915. }
  916. public static function data_order_canceled($store_id, $order_no = '', $params = []){
  917. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  918. $delivery->is_cancel = 1;
  919. $params['reason'] && $delivery->cancel_reason = $params['reason'];
  920. $params['reason_code'] && $delivery->cancel_reason_code = $params['reason_code'];
  921. $save = $delivery->save();
  922. if(!$save){
  923. return [
  924. 'code' => 1,
  925. 'msg' => array_shift($delivery->getFirstErrors()),
  926. ];
  927. }
  928. return [
  929. 'code' => 0,
  930. 'msg' => 'ok',
  931. ];
  932. }
  933. public static function data_order_done($store_id, $order_no = ''){
  934. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  935. $delivery->order_status = self::ORDER_STATUS_DONE;
  936. $save = $delivery->save();
  937. if(!$save){
  938. return [
  939. 'code' => 1,
  940. 'msg' => array_shift($delivery->getFirstErrors()),
  941. ];
  942. }
  943. return [
  944. 'code' => 0,
  945. 'msg' => 'ok',
  946. ];
  947. }
  948. public static function data_order_confirm($store_id, $order_no = ''){
  949. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  950. $delivery->order_status = self::ORDER_STATUS_CONFIRM;
  951. $save = $delivery->save();
  952. if(!$save){
  953. return [
  954. 'code' => 1,
  955. 'msg' => array_shift($delivery->getFirstErrors()),
  956. ];
  957. }
  958. return [
  959. 'code' => 0,
  960. 'msg' => 'ok',
  961. ];
  962. }
  963. public static function data_order_change($store_id, $order_no = '', $data = []){
  964. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  965. $delivery->order_status = $data['status'];
  966. $save = $delivery->save();
  967. if(!$save){
  968. return [
  969. 'code' => 1,
  970. 'msg' => array_shift($delivery->getFirstErrors()),
  971. ];
  972. }
  973. return [
  974. 'code' => 0,
  975. 'msg' => 'ok',
  976. ];
  977. }
  978. public static function data_delivery_change($store_id, $order_no = '', $data = []){
  979. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  980. $delivery->delivery_status = $data['status'];
  981. $delivery->rider_name = $data['rider_name'];
  982. $delivery->rider_mobile = $data['rider_phone'];
  983. $delivery->logistic_tag = $data['logistic_tag'];
  984. $delivery->logistic_no = $data['logistic_no'];
  985. $delivery->lng = $data['longitude'];
  986. $delivery->lat = $data['latitude'];
  987. $save = $delivery->save();
  988. if(!$save){
  989. return [
  990. 'code' => 1,
  991. 'msg' => array_shift($delivery->getFirstErrors()),
  992. ];
  993. }
  994. if($delivery->delivery_status == self::DELIVERY_STATUS_DONE){
  995. debug_log([__FUNCTION__, __LINE__, '确认收货', $delivery->delivery_status], __CLASS__ . '.log');
  996. //确认收货
  997. $order = Order::find()->where(['order_no' => $order_no])->andWhere(['trade_status' => Order::ORDER_FLOW_SEND])->one();
  998. if(!$order){
  999. return [
  1000. 'code' => 1,
  1001. 'msg' => '确认收货订单信息错误',
  1002. ];
  1003. }
  1004. $order->trade_status = Order::ORDER_FLOW_CONFIRM;
  1005. $order->confirm_time = time();
  1006. if (!$order->save()) {
  1007. debug_log([__FUNCTION__, __LINE__, '确认收货失败', array_shift($order->getFirstErrors())], __CLASS__ . '.log');
  1008. return [
  1009. 'code' => 1,
  1010. 'msg' => '确认收货失败',
  1011. ];
  1012. }
  1013. }
  1014. return [
  1015. 'code' => 0,
  1016. 'msg' => 'ok',
  1017. ];
  1018. }
  1019. public static function data_multi_rider_location($data = []){
  1020. foreach($data['locations'] as $item){
  1021. $delivery = DeliveryMaiyatian::findOne(['order_no' => $item['order_id'], 'store_id' => $item['shop_id']]);
  1022. $delivery->logistic_tag = $item['logistic_tag'];
  1023. $delivery->logistic_no = $item['logistic_no'];
  1024. $delivery->lng = $item['longitude'];
  1025. $delivery->lat = $item['latitude'];
  1026. $save = $delivery->save();
  1027. }
  1028. if(isset($save) && !$save){
  1029. return [
  1030. 'code' => 1,
  1031. 'msg' => array_shift($delivery->getFirstErrors()),
  1032. ];
  1033. }
  1034. return [
  1035. 'code' => 0,
  1036. 'msg' => 'ok',
  1037. ];
  1038. }
  1039. public static function data_order_agree_refund($store_id, $order_no = '', $data = []){
  1040. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  1041. $delivery->refund_status = 1;
  1042. $data['refund_id'] && $delivery->refund_id = $data['refund_id'];
  1043. $data['reason'] && $delivery->refund_status_reason = $data['reason'];
  1044. $save = $delivery->save();
  1045. if(!$save){
  1046. return [
  1047. 'code' => 1,
  1048. 'msg' => array_shift($delivery->getFirstErrors()),
  1049. ];
  1050. }
  1051. return [
  1052. 'code' => 0,
  1053. 'msg' => 'ok',
  1054. ];
  1055. }
  1056. public static function data_order_reject_refund($store_id, $order_no = '', $data = []){
  1057. $delivery = DeliveryMaiyatian::findOne(['order_no' => $order_no, 'store_id' => $store_id]);
  1058. $delivery->refund_status = 2;
  1059. $data['refund_id'] && $delivery->refund_id = $data['refund_id'];
  1060. $data['reason'] && $delivery->refund_status_reason = $data['reason'];
  1061. $save = $delivery->save();
  1062. if(!$save){
  1063. return [
  1064. 'code' => 1,
  1065. 'msg' => array_shift($delivery->getFirstErrors()),
  1066. ];
  1067. }
  1068. return [
  1069. 'code' => 0,
  1070. 'msg' => 'ok',
  1071. ];
  1072. }
  1073. public static function data_order_list($store_id, $data = []){
  1074. $query = DeliveryMaiyatian::find()->where(['store_id' => $store_id])->orderBy('id DESC')->asArray();
  1075. $query->andWhere(['>=', 'created_at', $data['start_time']/1000]);
  1076. $query->andWhere(['<=', 'created_at', $data['end_time']/1000]);
  1077. $countQuery = clone $query;
  1078. $count = $countQuery->count();
  1079. $query->offset(($data['page'] - 1) * $data['page_size'])->limit($data['page_size']);
  1080. $list = $query->all();
  1081. $dataList = [];
  1082. foreach($list as $item){
  1083. $order = Order::findOne(['order_no' => $item['order_no']]);
  1084. $dataList[] = self::getOrder($store_id, $order);
  1085. }
  1086. return [
  1087. 'code' => 0,
  1088. 'msg' => 'ok',
  1089. 'data' => json_encode([
  1090. "page" => 1,
  1091. "total" => $count,
  1092. "total_page" => 1,
  1093. "data" => $dataList,
  1094. ]),
  1095. ];
  1096. }
  1097. public static function data_order_detail($store_id, $order_no = ''){
  1098. $order = Order::findOne(['order_no' => $order_no]);
  1099. $data = self::getOrder($store_id, $order);
  1100. return [
  1101. 'code' => 0,
  1102. 'msg' => 'ok',
  1103. 'data' => json_encode($data),
  1104. ];
  1105. }
  1106. }