OrderController.php 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754
  1. <?php
  2. namespace backend\modules\mall\controllers;
  3. use addons\Community\common\service\HeadService;
  4. use addons\QiJuhe\common\models\OrderRefundModel;
  5. use addons\Community\common\models\CommunityGoodsSetting;
  6. use addons\ScoreExpansion\common\enums\ScoreExpansionEnum;
  7. use addons\ScoreExpansion\common\models\ScoreExpansion;
  8. use common\enums\AddonsEnum;
  9. use common\components\export\CsvTool;
  10. use common\enums\DownloadEnum;
  11. use common\enums\ExpressEnum;
  12. use common\enums\GlobalFuncEnum;
  13. use common\enums\GoodsTypeEnum;
  14. use common\enums\MarketingTypeEnum;
  15. use common\enums\OrderCommentEnum;
  16. use common\enums\OrderSourceEnum;
  17. use common\enums\OrderStatusEnum;
  18. use common\enums\RabbitMqEnum;
  19. use common\enums\RefundStatusEnum;
  20. use common\enums\RefundTypeEnum;
  21. use common\enums\ShippingTypeEnum;
  22. use backend\controllers\MallController;
  23. use backend\modules\mall\services\RefundService as MallRefundService;
  24. use common\enums\PayTypeEnum;
  25. use common\enums\StatusEnum;
  26. use common\events\order\OrderLeaveEvent;
  27. use common\events\order\OrderRemarkEvent;
  28. use common\events\order\ShippingValidateEvent;
  29. use common\globals\GlobalInvoke;
  30. use common\helpers\LockHelper;
  31. use common\listeners\order\OrderDeliveryListener;
  32. use common\logic\order\OrderRefundLogic;
  33. use common\models\common\Addons;
  34. use common\models\common\CapitalLog;
  35. use common\models\common\Download;
  36. use common\models\common\Express;
  37. use common\models\common\GlobalVarMap;
  38. use common\models\common\MallSetting;
  39. use common\models\common\PaymentRefund;
  40. use common\models\common\PaymentTrade;
  41. use common\models\common\PaymentTradeOrder;
  42. use common\models\elasticsearch\order\OrderAction as OrderActionEs;
  43. use common\models\goods\Goods;
  44. use common\models\goods\GoodsAttr;
  45. use common\models\goods\GoodsReserveSku;
  46. use common\models\mall\MallAddons;
  47. use common\models\order\Order;
  48. use common\models\order\OrderAction;
  49. use common\models\order\OrderBatchDelivery;
  50. use common\models\order\OrderBatchDeliveryError;
  51. use common\models\order\OrderDetail;
  52. use common\models\order\OrderExpress;
  53. use common\models\order\OrderExpressLog;
  54. use common\models\order\OrderExtra;
  55. use common\models\order\OrderMarketing;
  56. use common\models\order\OrderRefund;
  57. use common\models\order\OrderRefundStep;
  58. use common\models\user\DigitalLog;
  59. use common\models\user\UserLevel;
  60. use common\models\order\OrderInvoice;
  61. use Exception;
  62. use Yii;
  63. use yii\helpers\Json;
  64. use common\helpers\csv\CsvExportHelper;
  65. use common\models\order\OrderUserHandle;
  66. use common\models\user\User;
  67. use common\enums\ApiStatusEnum;
  68. use common\enums\RefundReasonEnum;
  69. use common\events\data\backend\GetOrderListEvent;
  70. use addons\ValetOrder\common\models\ValetOrder;
  71. use addons\QiDingDong\common\service\RefundService;
  72. use addons\ServicePointAppointment\common\service\OrderService;
  73. use common\enums\UserWalletEnum;
  74. use common\events\mall\OrderGetExpressEvent;
  75. use services\common\UserWalletService;
  76. use backend\modules\mall\services\OrderService as MallOrderService;
  77. /**
  78. * 商品订单控制器
  79. *
  80. * @Author bing
  81. * @DateTime 2021-09-06 14:11:55
  82. * @copyright: Copyright (c) 2020 广东七件事集团
  83. */
  84. class OrderController extends MallController
  85. {
  86. // 预约订单
  87. public function actionReserve()
  88. {
  89. $is_show_username = Yii::$app->services->setting->mall->get($this->mall_id, 'order.is_show_username');
  90. return $this->render($this->action->id, ['is_show_username' => $is_show_username ?? 0]);
  91. }
  92. /**
  93. * 预约订单详情
  94. * @return string
  95. */
  96. public function actionReserveDetail()
  97. {
  98. return $this->render($this->action->id);
  99. }
  100. public function actionIndex()
  101. {
  102. date_default_timezone_set('PRC');
  103. if (\Yii::$app->request->isAjax) {
  104. if (\Yii::$app->request->isGet) {
  105. //商品列表筛选
  106. $get = Yii::$app->request->get();
  107. $isReserve = $get['is_reserve'] ?? 0;
  108. if($isReserve){
  109. $order_status_list = OrderStatusEnum::getReserveMap();
  110. }else{
  111. $order_status_list = OrderStatusEnum::getMap();
  112. }
  113. $payment_type_list = PayTypeEnum::getMap();
  114. $shipping_type_list = ShippingTypeEnum::getMap();
  115. $rules = [
  116. [['order_status'], 'in', 'range' => array_keys($order_status_list)],
  117. [['payment_type'], 'in', 'range' => array_keys($payment_type_list)],
  118. [['shipping_type'], 'in', 'range' => array_keys($shipping_type_list)],
  119. [['start', 'end'], 'datetime', 'format' => 'php:Y-m-d H:i:s'],
  120. [['order_no', 'mobile', 'order_id', 'province', 'is_use_coupon'], 'safe'],
  121. [['type', 'type_value', 'marketing_type', 'cate_id', 'not_marketing_type'], 'string'],
  122. [['is_reserve'],'in', 'range' => [0,1]],
  123. // ['mobile', 'match', 'pattern' => '/^1\d{10}$/', 'message' => '请输入正确的手机号码'],
  124. ];
  125. $res = Yii::$app->services->validate->validate($get, $rules);
  126. if (!$res) return $this->error(Yii::$app->services->validate->getErrorMessage());
  127. $where = Order::searchParams($this->mall_id, $get);
  128. $with = ['base_user', 'detail','reserve', 'extra'];
  129. $order = "id desc";
  130. $params = compact('where', 'with', 'order');
  131. $page_data = Order::listPage($params, false, true);
  132. if ($page_data === false) return $this->error(Goods::getStaticError());
  133. if (!empty($page_data['list'])) {
  134. $shippingValidateEventEvent = new ShippingValidateEvent($this->mall_id);
  135. $shippingValidateEventEvent->setOrderIds(array_column($page_data['list'], 'id') ?: []);
  136. Yii::$app->services->events->dispatch($shippingValidateEventEvent);
  137. $user_handle_ids = OrderUserHandle::lists([
  138. 'where' => [
  139. ['order_id' => array_column($page_data['list'], 'id') ?? []],
  140. ['order_status' => OrderStatusEnum::ACCOMPLISH],
  141. ['mall_id' => $this->mall_id]
  142. ],
  143. 'select' => 'order_id',
  144. ]);
  145. $user_handle_ids = array_column($user_handle_ids, 'order_id') ?? [];
  146. foreach ($page_data['list'] as &$order) {
  147. $order['show_botton'] = true;
  148. $order_expresses = OrderExpress::getOrderExpresses([['order_id' => $order['id']]]);
  149. $order['is_user_handle_finish'] = in_array($order['id'], $user_handle_ids) ? 1 : 0;
  150. //获取留言
  151. $order['leave'] = $order['extra']['message'] ?? '';
  152. // 判断是否无需物流信息
  153. $order['need_not_express'] = true;
  154. $order['is_allow_shipping'] = $shippingValidateEventEvent->getIsAllow($order['id'])['isAllow'];
  155. foreach ($order['detail'] as &$detail) {
  156. // 获取商品信息
  157. $goodsInfo = Goods::getOne([['=', 'mall_id', $this->mall_id], ['=', 'id', $detail['goods_id']]], false, '', '', 'unit,goods_type, freight_type');
  158. $detail['goods_unit'] = $goodsInfo['unit'];
  159. $is_community_enable = false;
  160. // 判断是否是社区团购
  161. if (MallAddons::isInstall($this->mall_id, 'Community')) {
  162. $is_community_enable = CommunityGoodsSetting::getEnable($this->mall_id, $detail['goods_id']);
  163. }
  164. if (!empty($goodsInfo['freight_type']) || $is_community_enable) $order['need_not_express'] = false;
  165. $order['is_virtual'] = $detail['is_virtual'];
  166. // 物流信息
  167. $detail['express'] = '';
  168. foreach ($order_expresses as $record) {
  169. $order_detail_ids = empty($record['order_detail_ids']) ? [] : json_decode($record['order_detail_ids'], true);
  170. if (is_string($order_detail_ids)) $order_detail_ids = [];
  171. if (in_array($detail['id'], $order_detail_ids)) {
  172. $detail['express'] = $record['express_name'] . ' | ' . $record['express_no'];
  173. if ($record['shipping_type'] == 0) $detail['express'] = '--';
  174. }
  175. }
  176. if(empty($detail['goods_attr_name']) && $detail['goods_attr_id']){
  177. if ($isReserve) {
  178. $attr_info = GoodsReserveSku::getOne([['=','id',$detail['goods_attr_id']]],true,['goods']);
  179. } else {
  180. $attr_info = GoodsAttr::getOne([['=','id',$detail['goods_attr_id']]],true,['goods']);
  181. }
  182. $detail['goods_attr_name'] = $attr_info ? $attr_info['name'] : '';
  183. $detail['pic_url'] = !empty($attr_info['pic_url']) ? $attr_info['pic_url'] : (!empty($attr_info['goods']['cover_pic']) ? $attr_info['goods']['cover_pic'] : $detail['pic_url']);
  184. }
  185. }
  186. }
  187. }
  188. $page_data['list'] = GlobalInvoke::exec(GlobalFuncEnum::BACKEND_ORDER_LIST, $this->mall_id, [
  189. 'order' => $page_data['list'], 'mall_id' => $this->mall_id
  190. ]) ?:$page_data['list'];
  191. // 获取插件内容
  192. $event = new GetOrderListEvent($this->mall_id, $page_data['list']);
  193. Yii::$app->services->events->dispatch($event);
  194. $page_data['list'] = $event->getResultList();
  195. $export_list = Order::fieldsList();
  196. $marketing_type_map = MarketingTypeEnum::getMap();
  197. $marketing_type_map['order_user_handle_finish'] = '放弃退换货';
  198. $marketing_type_map[OrderSourceEnum::SOURCE_CLOUD_PRESCRIPTION] = OrderSourceEnum::getMap()[OrderSourceEnum::SOURCE_CLOUD_PRESCRIPTION];
  199. $sum_where = $where;
  200. array_unshift($sum_where, 'AND');
  201. $total_area_money = (float)Order::find()->where($sum_where)->sum('pay_money');
  202. $page_data['total_area_money'] = $total_area_money;
  203. $page_data['total_order_count'] = (int)Order::find()->where($sum_where)->count();
  204. $compact_params = array_keys($page_data);
  205. extract($page_data);
  206. $addons_commission_arr = GlobalInvoke::exec(GlobalInvoke::INVOKE_COMMISSION_TYPE, $this->mall_id, ['mall_id' => $this->mall_id]);
  207. //判断积分拓客插件有没有安装
  208. //获取商城已安装插件列表
  209. $valid_addons = MallAddons::getValidAddons($this->mall_id);
  210. if (in_array(AddonsEnum::ADDONS_NAME_SCORE_EXPANSION, $valid_addons)){
  211. $ScoreExpansionArr = (new ScoreExpansion())->getGoodsModeCommssionType();
  212. foreach($ScoreExpansionArr as $type){
  213. $addons_commission_arr[AddonsEnum::ADDONS_NAME_SCORE_EXPANSION][]= $type;
  214. }
  215. }
  216. //判断积分拓客插件有没有安装end
  217. $commission_type = [
  218. ['name' => 'commission', 'label' => '佣金'], ['name' => 'score', 'label' => '积分']
  219. ];
  220. foreach ($addons_commission_arr as $item){
  221. foreach($item as $v){
  222. $commission_type[] = $v;
  223. }
  224. }
  225. $down = Download::getOne([
  226. ['mall_id'=>$this->mall_id],
  227. ['type'=>DownloadEnum::TYPE_ORDERS],
  228. ['like','name','订单列表'.'%',false]
  229. ],true,[],'id desc');
  230. $fields = [];
  231. if(!empty($down)){
  232. $down['params'] = json_decode($down['params'],true);
  233. $fields = $down['params']['fields'];
  234. }
  235. $print_url = \Yii::$app->request->hostInfo . '/print.html';
  236. return $this->success('操作成功', compact($compact_params, 'fields','order_status_list', 'payment_type_list',
  237. 'shipping_type_list','export_list','marketing_type_map', 'commission_type','valid_addons', 'print_url'), ApiStatusEnum::CODE_SUCCESS, JSON_BIGINT_AS_STRING);
  238. }
  239. if (\Yii::$app->request->post('flag') == 'EXPORT') {
  240. $post = \Yii::$app->request->post();
  241. $post['mall_id'] = $this->mall_id;
  242. $post['store_id'] = 0;
  243. $post['mch_id'] = 0;
  244. $filename = '订单列表-' . date('YmdHis') . '_' . rand(10000, 99999);
  245. $res = CsvExportHelper::exportDownLoadOrder($this->mall_id, $filename, DownloadEnum::TYPE_ORDERS, Order::class, 'exportHandle', $post);
  246. if ($res === false) return $this->error('加入导出任务失败' . CsvExportHelper::getStaticError());
  247. return $this->success('添加导出任务成功,任务完成后请在下载中心进行下载!');
  248. }
  249. }
  250. $is_show_username = Yii::$app->services->setting->mall->get($this->mall_id,'order.is_show_username');
  251. $is_compliance = Yii::$app->services->mall->isOpenComplianceMode($this->mall_id);
  252. $is_electronic_bill = MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_ELECTRONIC_BILL) == 0 ? false : true;
  253. $is_electronic_bill_setting = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_ELECTRONIC_BILL, 'basic');
  254. return $this->render($this->action->id,['is_show_username'=>$is_show_username??0, 'is_compliance' => $is_compliance, 'is_electronic_bill' => ($is_electronic_bill && !empty($is_electronic_bill_setting['is_enable']))]);
  255. }
  256. /**
  257. * 订单改价
  258. * @Author bing
  259. * @DateTime 2021-09-10 19:12:51
  260. * @copyright: Copyright (c) 2020 广东七件事集团
  261. * @return void
  262. */
  263. public function actionChangePrice()
  264. {
  265. // 商品操作
  266. $form = Yii::$app->request->post();
  267. $rules = [[['id', 'shipping_money'], 'required'], [['id'], 'integer'], [['shipping_money'], 'number'], ['detail', 'safe']];
  268. $res = Yii::$app->services->validate->validate($form, $rules);
  269. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  270. $form['mall_id'] = $this->mall['id'];
  271. $form['mch_id'] = $this->admin->mch_id;
  272. $form['operator_id'] = $this->admin->id;
  273. $form['operator_name'] = $this->admin->account;
  274. $res = Order::ChangePrice($form);
  275. if ($res === false) return $this->error(Goods::getStaticError());
  276. return $this->success();
  277. }
  278. /**
  279. * 支付订单
  280. * @Author bing
  281. * @DateTime 2021-09-10 19:12:23
  282. * @copyright: Copyright (c) 2020 广东七件事集团
  283. * @return void
  284. */
  285. public function actionPay()
  286. {
  287. // 商品操作
  288. $form = Yii::$app->request->post();
  289. $rules = [[['id'], 'required'], [['id'], 'integer']];
  290. $res = Yii::$app->services->validate->validate($form, $rules);
  291. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  292. $form['mall_id'] = $this->mall['id'];
  293. $form['mch_id'] = $this->admin->mch_id;
  294. $form['operator_id'] = $this->admin->id;
  295. $form['operator_name'] = $this->admin->account;
  296. $form['is_admin'] = 1;
  297. $service = new MallOrderService(['mall_id' => $this->mall_id]);
  298. $res = $service->adminPay($form);
  299. if ($res === false) return $this->error($service->getError());
  300. return $this->success();
  301. }
  302. /**
  303. * 关闭订单
  304. * @Author bing
  305. * @DateTime 2021-09-10 19:12:23
  306. * @copyright: Copyright (c) 2020 广东七件事集团
  307. * @return void
  308. */
  309. public function actionClose()
  310. {
  311. // 商品操作
  312. $form = Yii::$app->request->post();
  313. $rules = [[['id'], 'required'], [['id'], 'integer']];
  314. $res = Yii::$app->services->validate->validate($form, $rules);
  315. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  316. $form['mall_id'] = $this->mall['id'];
  317. $form['mch_id'] = $this->admin->mch_id;
  318. $form['operator_id'] = $this->admin->id;
  319. $form['operator_name'] = $this->admin->account;
  320. $form['is_admin'] = 1;
  321. $res = Order::close($form);
  322. if ($res === false) return $this->error(Goods::getStaticError());
  323. return $this->success();
  324. }
  325. /**
  326. * 删除订单
  327. * @Author bing
  328. * @DateTime 2021-09-10 19:12:23
  329. * @copyright: Copyright (c) 2020 广东七件事集团
  330. * @return void
  331. */
  332. public function actionDel()
  333. {
  334. // 商品操作
  335. $form = Yii::$app->request->post();
  336. // $rules = [[['id'], 'required'], [['id'], 'integer']];
  337. // $res = Yii::$app->services->validate->validate($form, $rules);
  338. // if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  339. if(!is_array($form['id'])){
  340. $form['mall_id'] = $this->mall_id;
  341. $form['mch_id'] = $this->admin->mch_id;
  342. $form['operator_id'] = $this->admin->id;
  343. $form['operator_name'] = $this->admin->account;
  344. $form['is_admin'] = 1;
  345. $res = Order::del($form);
  346. if ($res === false) return $this->error(Order::getStaticError());
  347. }else{
  348. foreach ($form['id'] as $id){
  349. $params = [];
  350. $params['mall_id'] = $this->mall_id;
  351. $params['mch_id'] = $this->admin->mch_id;
  352. $params['operator_id'] = $this->admin->id;
  353. $params['operator_name'] = $this->admin->account;
  354. $params['id'] = $id;
  355. $params['is_admin'] = 1;
  356. $res = Order::del($params);
  357. if ($res === false) return $this->error(Order::getStaticError());
  358. }
  359. }
  360. return $this->success();
  361. }
  362. /**
  363. * 修改备注
  364. * @Author bing
  365. * @DateTime 2021-09-14 18:40:15
  366. * @copyright: Copyright (c) 2020 广东七件事集团
  367. * @return void
  368. */
  369. public function actionRemark()
  370. {
  371. $form = Yii::$app->request->post();
  372. $rules = [[['id'], 'required'], [['id'], 'integer'], [['remark','seller_remark'], 'string']];
  373. $res = Yii::$app->services->validate->validate($form, $rules);
  374. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  375. $form['mall_id'] = $this->mall['id'];
  376. $form['mch_id'] = $this->admin->mch_id;
  377. $form['operator_id'] = $this->admin->id;
  378. $form['operator_name'] = $this->admin->account;
  379. $res = Order::remark($form);
  380. if ($res === false) return $this->error(Goods::getStaticError());
  381. // 事件
  382. $event = new OrderRemarkEvent($form['mall_id']);
  383. $form['operator_id'] = $this->admin->id;
  384. $form['is_admin'] = 1;
  385. Yii::$app->services->events->dispatch($event,$form,$event->listeners);
  386. return $this->success();
  387. }
  388. /**
  389. * 修改收货地址
  390. * @Author bing
  391. * @DateTime 2021-09-14 18:40:15
  392. * @copyright: Copyright (c) 2020 广东七件事集团
  393. * @return void
  394. */
  395. public function actionChangeAddress()
  396. {
  397. $form = Yii::$app->request->post();
  398. $rules = [
  399. [['id', 'receiver_name', 'mobile', 'province', 'city', 'area', 'address', 'region_name'], 'required'],
  400. [['id', 'province', 'city', 'area', 'zip'], 'integer'],
  401. [['address', 'region_name', 'receiver_name', 'mobile'], 'string']
  402. ];
  403. $res = Yii::$app->services->validate->validate($form, $rules);
  404. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  405. $form['mall_id'] = $this->mall['id'];
  406. $form['mch_id'] = $this->admin->mch_id;
  407. $form['operator_id'] = $this->admin->id;
  408. $form['operator_name'] = $this->admin->account;
  409. $form['is_admin'] = 1;
  410. $res = Order::changeAddress($form);
  411. if ($res === false) return $this->error(Goods::getStaticError());
  412. return $this->success();
  413. }
  414. /**
  415. * 发货
  416. * @Author bing
  417. * @DateTime 2021-09-15 14:29:48
  418. * @copyright: Copyright (c) 2020 广东七件事集团
  419. * @return void
  420. */
  421. public function actionShipping()
  422. {
  423. if (\Yii::$app->request->isAjax) {
  424. if (\Yii::$app->request->isGet) {
  425. // 获取订单发货信息
  426. $jd_mch_code = MallSetting::conf($this->mall_id, 'logistics.jd_mch_code');
  427. $express_list = Express::getExpresses([], [], true, '*');
  428. return $this->success('请求成功', compact('express_list', 'jd_mch_code'));
  429. } else {
  430. // 发货
  431. $form = Yii::$app->request->post();
  432. $rules = [
  433. [['shipping_type', 'id'], 'required'],
  434. [['express_id', 'shipping_type', 'id'], 'integer'],
  435. [['express_name', 'express_no', 'memo', 'memo_arr1', 'memo_arr2', 'memo_arr3'], 'string'],
  436. [['order_detail_ids'], 'each', 'rule' => ['integer']],
  437. [['shipping_change', 'customer_name', 'send_nums'], 'safe']
  438. ];
  439. $res = Yii::$app->services->validate->validate($form, $rules);
  440. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  441. $form['mall_id'] = $this->mall_id;
  442. $form['mch_id'] = $this->admin->mch_id;
  443. $form['operator_id'] = $this->admin->id;
  444. $form['operator_name'] = $this->admin->account;
  445. $form['is_admin'] = 1;
  446. $form['memo'] = json_encode([$form['memo_arr1'],$form['memo_arr2'],$form['memo_arr3']],JSON_UNESCAPED_UNICODE);
  447. if (empty($form['shipping_change'])) {
  448. $res = OrderExpress::delivery($form); // 发货
  449. } else {
  450. $res = OrderExpress::shippingChange($form); // 修改物流
  451. }
  452. if ($res === false) return $this->error(Goods::getStaticError());
  453. return $this->success('发货/修改物流成功');
  454. }
  455. }
  456. }
  457. /**
  458. * 收货
  459. * @param $id
  460. * @param string $member_id
  461. * @throws UnprocessableEntityHttpException
  462. * @throws \yii\web\NotFoundHttpException
  463. */
  464. public function actionTakeDelivery()
  465. {
  466. // 商品操作
  467. $form = Yii::$app->request->post();
  468. $rules = [[['id'], 'required'], [['id'], 'integer']];
  469. $res = Yii::$app->services->validate->validate($form, $rules);
  470. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  471. $form['mall_id'] = $this->mall['id'];
  472. $form['mch_id'] = $this->admin->mch_id;
  473. $form['operator_id'] = $this->admin->id;
  474. $form['operator_name'] = $this->admin->account;
  475. $form['is_admin'] = 1;
  476. $res = Order::takeDelivery($form);
  477. if ($res === false) return $this->error(Goods::getStaticError());
  478. return $this->success();
  479. }
  480. /**
  481. * @notes:取消发货
  482. * @return mixed|null
  483. * @author: lun
  484. * @Time: 2022/10/27 10:20
  485. */
  486. public function actionCancelShipment()
  487. {
  488. // 商品操作
  489. $form = Yii::$app->request->post();
  490. $rules = [[['id', 'order_id'], 'required'], [['id', 'order_id'], 'integer']];
  491. $res = Yii::$app->services->validate->validate($form, $rules);
  492. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  493. $form['mall_id'] = $this->mall['id'];
  494. $form['mch_id'] = $this->admin->mch_id;
  495. $form['operator_id'] = $this->admin->id;
  496. $form['operator_name'] = $this->admin->account;
  497. $res = OrderExpress::cancelExpress($form, true);
  498. if ($res === false) return $this->error(Order::getStaticError());
  499. return $this->success();
  500. }
  501. /**
  502. * 订单详情
  503. * @Author bing
  504. * @DateTime 2021-09-06 14:09:56
  505. * @copyright: Copyright (c) 2020 广东七件事集团
  506. * @return void
  507. */
  508. public function actionDetail()
  509. {
  510. if (\Yii::$app->request->isAjax) {
  511. if (\Yii::$app->request->isGet) {
  512. //商品列表筛选
  513. $get = Yii::$app->request->get();
  514. $order_status_list = OrderStatusEnum::getMap();
  515. $payment_type_list = PayTypeEnum::getMap();
  516. $shipping_type_list = ShippingTypeEnum::getMap();
  517. $rules = [[['id'], 'required']];
  518. $res = Yii::$app->services->validate->validate($get, $rules);
  519. $where = [['mall_id' => $this->mall_id]];
  520. $where[] = ['=', 'id', $get['id']];
  521. $where[] = ['>=', 'status', StatusEnum::DISABLED];
  522. $with = [
  523. 'base_user',
  524. 'express',
  525. 'express_log',
  526. 'detail',
  527. 'reserve'
  528. ];
  529. $params = compact('where', 'with');
  530. $order = Order::getOne($where, true, $with);
  531. if ($order === false) return $this->error(Goods::getStaticError());
  532. $express_log = [];
  533. if ($order['express_log']) {
  534. $time = time();
  535. $hour = Yii::$app->services->setting->mall->get($this->mall_id, 'logistics.update'); // 获取更新物流时间设置
  536. if (empty($hour) && is_array($hour)) $hour = 8; // 默认8小时更新一次
  537. foreach ($order['express_log'] as $key => $item) {
  538. $item['status'] = ExpressEnum::getStatusMap($item['status']);
  539. // 检查物流是否已完成,未完成且距离上次修改时间超过一个小时
  540. if ($item['table_express_status'] == StatusEnum::DISABLED && $item['updated_at'] + $hour * 3600 < $time) {
  541. $item['list'] = OrderExpressLog::execExpressLog($this->mall_id, $item);
  542. }
  543. $express_log[$item['order_express_id']] = $item;
  544. }
  545. }
  546. if (!empty($order['express'])) {
  547. $request_type = Yii::$app->services->setting->mall->get($this->mall_id, 'logistics.request_type');
  548. foreach ($order['express'] as &$key) {
  549. if (isset($express_log[$key['id']])) {
  550. $express_list = $express_log[$key['id']]['list'] ? Json::decode($express_log[$key['id']]['list']) : null;
  551. $key['now_state'] = $express_log[$key['id']]['status'];
  552. // 因为七件事订单物流和快递鸟数据不一致,所以需要处理
  553. if ($request_type == 1) {
  554. $key['express_log'] = is_null($express_list) ? '' : array_reverse($express_list['Traces']);
  555. } else {
  556. $key['express_log'] = is_null($express_list) ? '' : $express_list['Traces'];
  557. }
  558. }
  559. $key['nums'] = json_decode($key['nums'], true) ?: [];
  560. }
  561. }
  562. // 获取插件物流信息
  563. $event = new OrderGetExpressEvent($this->mall_id, $order['express'], $order['id'], $order['order_source']);
  564. Yii::$app->services->events->dispatch($event);
  565. $order['express'] = $event->getResultList($express_log);
  566. if (!empty($order['detail'])) {
  567. // 获取订单营销赠扣信息
  568. $orderDetailIds = array_column($order['detail'], 'id');
  569. $orderMarketing = OrderMarketing::find()
  570. ->where(['status' => StatusEnum::ENABLED, 'order_detail_id' => $orderDetailIds])
  571. ->indexBy('order_detail_id')->asArray()->all();
  572. foreach ($order['detail'] as &$detail) {
  573. $detail['score_money'] = $orderMarketing[$detail['id']]['score_money'] ?? 0; // 积分抵扣金额
  574. $order['total_num'] += $detail['num'];
  575. if (!empty($detail['attr_groups_format'])) {
  576. $attr_groups_format = json_decode($detail['attr_groups_format'], true);
  577. $attr_list = $attr_groups_format[$detail['sign_id']];
  578. $attr_group_name_list = array_column($attr_list, 'attr_group_name');
  579. $attr_name_list = array_column($attr_list, 'attr_name');
  580. $detail['attr_list'] = [];
  581. foreach ($attr_group_name_list as $index => $attr_group_name) {
  582. $detail['attr_list'][] = $attr_group_name . ':' . $attr_name_list[$index];
  583. }
  584. }
  585. $order['is_virtual'] = $detail['is_virtual'];
  586. if (empty($detail['goods_attr_name']) && !empty($detail['goods_attr_id'])) {
  587. if ($detail['order_source'] == 'Reserve') { // 服务订单
  588. $attr_info = GoodsReserveSku::getOne([['=', 'id', $detail['goods_attr_id']]],true, ['goods']);
  589. } else {
  590. $attr_info = GoodsAttr::getOne([['=', 'id', $detail['goods_attr_id']]],true, ['goods']);
  591. }
  592. $detail['goods_attr_name'] = $attr_info ? $attr_info['name'] : '';
  593. }
  594. }
  595. }
  596. $step_arr = OrderStatusEnum::setpArrMap($order['is_virtual'] ? -99 : $order['order_status']); // 订单状态跟踪
  597. $order_action = OrderAction::getOrderAction([['order_id' => $get['id']]]);
  598. $marketing_type_map = MarketingTypeEnum::getMap();
  599. //修改支付out_trade_no
  600. if ($order['pay_status']&& empty($order['out_trade_no'])) {
  601. $order['out_trade_no'] = PaymentTradeOrder::getOutTradeNoOfOrderNo($order['order_no']);
  602. }
  603. $order['show_botton'] = true;
  604. // 公共调用
  605. $order = GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $this->mall_id, [
  606. 'order' => $order,
  607. 'mall_id' => $this->mall_id,
  608. ]) ?: $order;
  609. //云盟店订单
  610. if (!$order['show_botton']) {
  611. foreach ($step_arr as $key => $value) {
  612. if ($value['field'] == 'consign_time') {
  613. if ($order['shipping_type'] == 2) {
  614. $step_arr[$key]['title'] = '买家自提';
  615. $step_arr[$key]['field'] = 'sign_time';
  616. } else if ($order['shipping_type'] == 3){
  617. $step_arr[$key]['title'] = '门店配送';
  618. $step_arr[$key]['field'] = 'sign_time';
  619. }
  620. }
  621. }
  622. }
  623. // 查询交易单号
  624. $trade_id = PaymentTradeOrder::find()
  625. ->where(['order_no' => $order['order_no']])
  626. ->select('trade_id')
  627. ->orderBy('id desc')
  628. ->scalar();
  629. $paymentTrade = PaymentTrade::find()
  630. ->where(['id'=>$trade_id])
  631. ->with(['paidItem'])
  632. ->asArray()
  633. ->one();
  634. $order['payment'] = $paymentTrade;
  635. if(empty($order['out_trade_no'])){
  636. $order['out_trade_no'] = $paymentTrade ? $paymentTrade['out_trade_no'] : '';
  637. }
  638. $order_user_handle = OrderUserHandle::find()->where(['order_id' => $order['id'], 'order_status' => OrderStatusEnum::ACCOMPLISH])->select('id')->scalar();
  639. $order['is_user_handle_finish'] = $order_user_handle ? 1 : 0;
  640. // 获取留言
  641. $leave = OrderExtra::getInfo(['=', 'order_id', $order['id']], 'message');
  642. $order['leave'] = $leave['message'] ?? '';
  643. //获取售后原因
  644. $refund_reason = RefundReasonEnum::getMap();
  645. //return $this->success('操作成功', compact('order', 'order_status_list', 'payment_type_list', 'shipping_type_list', 'step_arr', 'order_action','marketing_type_map'));
  646. return $this->success('操作成功', compact('order', 'order_status_list', 'payment_type_list', 'shipping_type_list', 'step_arr', 'order_action','marketing_type_map','refund_reason'),
  647. ApiStatusEnum::CODE_SUCCESS, JSON_BIGINT_AS_STRING);
  648. }
  649. }
  650. return $this->render($this->action->id);
  651. }
  652. /**
  653. * 订单操作日志
  654. * @return mixed|string|void
  655. */
  656. public function actionOrderAction(){
  657. try {
  658. $request = Yii::$app->request;
  659. if ($request->isAjax) {
  660. if ($request->isGet) {
  661. $params = \Yii::$app->request->get();
  662. $params['where'] = ['mall_id'=>$this->mall_id];
  663. $params['is_page'] = true;
  664. $params['order'] = 'created_at desc';
  665. $list = OrderActionEs::getList($params);
  666. return $this->success('ok', $list);
  667. }
  668. }
  669. } catch (\Exception $e) {
  670. return $this->error($e->getMessage(), []);
  671. }
  672. return $this->render($this->action->id);
  673. }
  674. /**
  675. * 完成订单
  676. * @param $id
  677. * @throws \yii\web\NotFoundHttpException
  678. */
  679. public function actionSalesOrder()
  680. {
  681. // 商品操作
  682. $form = Yii::$app->request->post();
  683. $rules = [[['id'], 'required'], [['id'], 'integer']];
  684. $res = Yii::$app->services->validate->validate($form, $rules);
  685. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  686. $form['mall_id'] = $this->mall_id;
  687. $form['operator_id'] = $this->admin->id;
  688. $form['operator_name'] = $this->admin->account;
  689. $form['is_admin'] = 1;
  690. $res = Order::complete($form);
  691. if ($res == false) return $this->error('操作订单失败:' . Order::getStaticError());
  692. return $this->success('操作成功');
  693. }
  694. /**
  695. * 售后订单列表
  696. * @Author: lun
  697. * @DateTime: 2021/10/8 0008 17:53
  698. * @Copyright: copyright (c) 2021 广东七件事集团
  699. * @return mixed|string|void
  700. */
  701. public function actionRefund()
  702. {
  703. if (\Yii::$app->request->isAjax) {
  704. if (\Yii::$app->request->isGet) {
  705. //商品列表筛选
  706. $get = Yii::$app->request->get();
  707. $refund_status_list = RefundStatusEnum::getMap();
  708. $refund_type_list = RefundTypeEnum::getMap();
  709. $rules = [
  710. [['is_feedback', 'goods_type'], 'integer'],
  711. [['keyword','order_no','type'], 'string'],
  712. [['type','order_no','keyword','refund_status', 'refund_type'], 'safe'],
  713. ];
  714. $res = Yii::$app->services->validate->validate($get, $rules);
  715. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  716. $where = [['mall_id' => $this->mall_id],['mch_id' =>0],['store_id' => 0]];
  717. $where[] = ['=', 'status', StatusEnum::ENABLED];
  718. $where[] = ['!=', 'order_detail_id', 0];
  719. if (!empty($get['refund_type'])) $where[] = ['=', 'type', $get['refund_type']];
  720. if (!empty($get['order_no'])) {
  721. $where[]=[
  722. 'OR',
  723. ['in', 'order_id', OrderRefund::getVagueOrderNo($this->mall_id,$get['order_no'])],
  724. ['like', 'order_no', $get['order_no']]
  725. ];
  726. }
  727. if (isset($get['refund_status'])) {
  728. $where[] = ['in', 'refund_status', explode(',', $get['refund_status'])];
  729. } else {
  730. $where[] = ['in', 'refund_status', [RefundStatusEnum::APPLY, RefundStatusEnum::HANDEL, RefundStatusEnum::FINISH, RefundStatusEnum::RETURN_GOODS, RefundStatusEnum::EXCHANGE_GOODS, RefundStatusEnum::REFUSE]];
  731. }
  732. // 通过商品类型筛选
  733. if (!empty($get['goods_type'])) $where[] = ['goods_type' => $get['goods_type']];
  734. if (!empty($get['type']) && !empty($get['keyword'])) $where[] = OrderRefund::searchByKeyword($this->mall_id, $get['type'], $get['keyword']);
  735. $with = ['base_user', 'orderDetail', 'order', 'lastStep' => function ($query) {
  736. $query->select('id, order_refund_id, created_at');
  737. }];
  738. $order = "id desc";
  739. $params = compact('where', 'with', 'order');
  740. $page_data = OrderRefund::listPage($params, false, true);
  741. if ($page_data === false) return $this->error(OrderRefund::getStaticError());
  742. $compact_params = array_keys($page_data);
  743. extract($page_data);
  744. foreach ($list as &$order) {
  745. $order['goods_unit'] = Goods::getOne([['=', 'mall_id', $this->mall_id], ['=', 'id', $order['orderDetail']['goods_id']]], false, '', '', 'unit')['unit'];
  746. foreach ($order['orderDetail'] as &$detail) {
  747. if (!empty($detail['attr_groups_format'])) {
  748. //规格
  749. $attr_groups_format = Json::decode($detail['attr_groups_format'], true);
  750. $attr_list = $attr_groups_format[$detail['sign_id']];
  751. $attr_group_name_list = array_column($attr_list, 'attr_group_name');
  752. $attr_name_list = array_column($attr_list, 'attr_name');
  753. $detail['attr_list'] = [];
  754. foreach ($attr_group_name_list as $index => $attr_group_name) {
  755. $detail['attr_list'][] = $attr_group_name . ':' . $attr_name_list[$index];
  756. }
  757. }
  758. }
  759. if (!empty($order['order'])) {
  760. $extraInfo = $order['order']['extra_info'];
  761. if (!empty($extraInfo['head_id']) && MallAddons::isInstall($this->mall_id, 'Community')) {
  762. $order['order']['community_addons_data'] = (new HeadService())->pickupInfo($order['mall_id'], $extraInfo['head_id']);
  763. }
  764. }
  765. }
  766. $export_list = OrderRefund::fieldsList();
  767. $commission_type = $this->getCommissionType();
  768. return $this->success('操作成功', compact($compact_params, 'refund_status_list', 'refund_type_list', 'export_list', 'commission_type'));
  769. }
  770. if (\Yii::$app->request->post('flag') == 'EXPORT') {
  771. $post = \Yii::$app->request->post();
  772. $post['mall_id'] = $this->mall_id;
  773. $filename = '售后订单列表-' . date('YmdHis') . '_' . rand(10000, 99999);
  774. $res = CsvExportHelper::exportDownLoadCenter($this->mall_id, $filename, DownloadEnum::TYPE_ORDERS, OrderRefund::class, 'exportHandle', $post);
  775. if ($res === false) return $this->error('加入导出任务失败' . CsvExportHelper::getStaticError());
  776. return $this->success('添加导出任务成功,任务完成后请在下载中心进行下载!');
  777. }
  778. }
  779. return $this->render($this->action->id, ['goods_type' => Json::encode(GoodsTypeEnum::getMap())]);
  780. }
  781. public function actionBatchRefund()
  782. {
  783. $post = Yii::$app->request->post();
  784. if (empty($post['refund_ids'])) return $this->error('请选择需要操作操作的订单!');
  785. $order_ids = explode(',', $post['refund_ids']);
  786. $orderRefundList = OrderRefund::find()->select("id,type")->where(['in', 'id', $order_ids])->all();
  787. $not_matching_ids = [];// 不是仅支付的订单
  788. $refund_type_list = RefundTypeEnum::getMap();
  789. foreach ($orderRefundList as $item) {
  790. if ($item->type != RefundTypeEnum::MONEY) {
  791. $not_matching_ids[] = $item->id;
  792. }
  793. }
  794. if (!empty($not_matching_ids)) {// 拥有不可退款条件
  795. $not_matching_ids = implode(',', $not_matching_ids);
  796. $message = '批量操作中ID:' . trim($not_matching_ids, ',') . '。不符合' . $refund_type_list[RefundTypeEnum::MONEY] . '条件,请重新选择!';
  797. return $this->error($message);
  798. }
  799. //批量操作时进行锁
  800. $key = "order_refund:batch_refund_lock_" . md5($post['refund_ids']);
  801. if (LockHelper::fLock($key, 60)) {
  802. return $this->error("暂时无法操作,请稍后在尝试!");
  803. }
  804. Yii::$app->redis->setex($key, 180, 1);
  805. // 退货地址
  806. $address = ['consignee' => $post['consignee'],'mobile' => $post['mobile'],'address' => $post['address']];
  807. // 换货物流信息
  808. $express = ['saler_express' => $post['saler_express'],'saler_express_no' => $post['saler_express_no'],'customer_name' => $post['customer_name']];
  809. try {
  810. $params = [];
  811. foreach ($orderRefundList as $item) {
  812. $data = [
  813. 'id' => $item->id,
  814. 'step_status' => RefundStatusEnum::STEP_6,
  815. 'address' => $address,
  816. 'express' => $express,
  817. 'refund_reason' => $post['refund_reason'] ?? '',
  818. ];
  819. $params['data'][] = $data;
  820. }
  821. $params['mall_id'] = $this->mall_id;
  822. $params['redis_key'] = $key;
  823. OrderRefund::batchRefundSync($params);
  824. } catch (Exception $e) {
  825. }
  826. return $this->success('售后申请成功,请耐心等候!');
  827. }
  828. /**
  829. * 售后详情
  830. * @Author: lun
  831. * @DateTime: 2021/10/9 0009 11:57
  832. * @Copyright: copyright (c) 2021 广东七件事集团
  833. */
  834. public function actionRefundDetail()
  835. {
  836. if (\Yii::$app->request->isAjax) {
  837. if (\Yii::$app->request->isGet) {
  838. //商品列表筛选
  839. $get = Yii::$app->request->get();
  840. $order_status_list = OrderStatusEnum::getMap();
  841. $payment_type_list = PayTypeEnum::getMap();
  842. $feedback_type_list = OrderStatusEnum::getFeedbackMap();
  843. $address_list = Yii::$app->services->setting->mall->get($this->mall_id, 'return_address.return_address');
  844. $address_list = $address_list ? json_decode($address_list, true) : [];
  845. $rules = [[['id'], 'required']];
  846. $res = Yii::$app->services->validate->validate($get, $rules);
  847. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  848. $where = [['mall_id' => $this->mall_id]];
  849. $where[] = ['=', 'id', $get['id']];
  850. $where[] = ['>=', 'status', StatusEnum::DISABLED];
  851. $with = ['base_user', 'order' => function ($query) {
  852. $query->select('*');
  853. }, 'orderDetail', 'marketing', 'step'];
  854. $params = compact('where', 'with');
  855. $refund = OrderRefund::getOne($where, true, $with);
  856. if ($refund === false) return $this->error(Goods::getStaticError());
  857. foreach ($refund['orderDetail'] as $key => $detail) {
  858. if (!empty($detail['attr_groups_format'])) {
  859. $attr_groups_format = Json::decode($detail['attr_groups_format'], true);
  860. $attr_list = $attr_groups_format[$detail['sign_id']];
  861. $attr_group_name_list = array_column($attr_list, 'attr_group_name');
  862. $attr_name_list = array_column($attr_list, 'attr_name');
  863. $detail['attr_list'] = [];
  864. }
  865. if (empty($detail['goods_attr_name']) && !empty($detail['goods_attr_id'])) {
  866. if ($detail['order_source'] == 'Reserve') { // 服务订单
  867. $attr_info = GoodsReserveSku::getOne([['=', 'id', $detail['goods_attr_id']]],true, ['goods']);
  868. } else {
  869. $attr_info = GoodsAttr::getOne([['=', 'id', $detail['goods_attr_id']]],true, ['goods']);
  870. }
  871. $detail['goods_attr_name'] = $attr_info ? $attr_info['name'] : '';
  872. }
  873. }
  874. // 公共调用订单详情
  875. $refund['order'] = GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $this->mall_id, [
  876. 'order' => $refund['order'],
  877. 'mall_id' => $this->mall_id,
  878. ]) ?: $refund['order'];
  879. // 返还优惠内容
  880. if (!empty($refund['marketing'])) {
  881. $discount = [];
  882. $marketing = $refund['marketing'];
  883. if (!empty($marketing['deduct_score'])) {
  884. if($refund['order']['marketing_type'] == AddonsEnum::ADDONS_NAME_FUN_MALL){
  885. $deduct_currency = (array)json_decode($marketing['deduct_currency'], true);
  886. if(isset($deduct_currency['midou_cy'])) $discount[] = floatval($deduct_currency['midou_cy']['midou_cy']) . $deduct_currency['midou_cy']['name'];
  887. }elseif($refund['order']['marketing_type'] == AddonsEnum::ADDONS_NAME_DIGITAL_MALL){
  888. $deduct_currency = (array)json_decode($marketing['deduct_currency'], true);
  889. if(isset($deduct_currency['digital'])) $discount[] = floatval($deduct_currency['digital']['digital']) . $deduct_currency['digital']['name'];
  890. }else{
  891. $score_name = Yii::$app->services->setting->mall->get($this->mall_id,'score.score_name');
  892. $discount[] = floatval($marketing['deduct_score']) . $score_name;
  893. }
  894. }
  895. $refund['discount'] = implode('+', $discount);
  896. }
  897. $step_status = $refund['step'][0]['step_status'] ?? 0;
  898. $step_arr = RefundStatusEnum::stepNumArr(in_array($step_status, [RefundStatusEnum::STEP_NEGATIVE_1, RefundStatusEnum::STEP_NEGATIVE_2]) ? 1 : $refund['type']);// 进度条
  899. $step_text = RefundStatusEnum::getStepStatusText($step_status);
  900. //退款金额方式
  901. $refund['payment_refund_type'] = '';
  902. if($refund['is_refund']){
  903. $payment_refund = PaymentRefund::findOne(['trade_order_no' => $refund['order']['order_no']]);
  904. $refund['payment_refund_type'] = !empty($payment_refund) && $payment_refund->pay_type != PayTypeEnum::BALANCE ? '原路返回' : '退回余额';
  905. }
  906. // 组合支付
  907. $trade = PaymentTrade::findOne(['out_trade_no' => $refund['order']['out_trade_no']]);
  908. $trade && $trade->isMixedPay() && $refund['refund_items'] = array_map(function ($item) {
  909. return $item->toArray();
  910. }, $trade->getRefundFeeList($refund['id']));
  911. $order_detail = OrderDetail::findOne(['id' => $refund['order_detail_id']]);
  912. $goods = Goods::findOne(['id' => $order_detail->goods_id])->toArray();
  913. $refund_status_list = RefundStatusEnum::getMap();
  914. $q_refund = null;
  915. if ($goods['goods_source'] == 'QiJuhe') {
  916. $q_refund = OrderRefundModel::find()->where(['order_refund_id' => $refund['id']])->orderBy('id desc')->asArray()->one();
  917. }
  918. // 是否显示退货超期,撤销售后
  919. $is_show_revoce = (OrderRefund::findOne(['id' => $refund['id']]))->isReturnTimeoutOfRefund();
  920. return $this->success('操作成功', compact('refund', 'order_status_list', 'payment_type_list', 'feedback_type_list', 'step_arr', 'address_list',
  921. 'step_text', 'is_show_revoce', 'goods', 'refund_status_list', 'q_refund'));
  922. }
  923. }
  924. return $this->render($this->action->id);
  925. }
  926. /**
  927. * 售后处理
  928. * @Author: lun
  929. * @DateTime: 2021/10/12 0012 11:15
  930. * @Copyright: copyright (c) 2021 广东七件事集团
  931. * @return mixed|void
  932. */
  933. public function actionHandleRefund()
  934. {
  935. if (\Yii::$app->request->isAjax) {
  936. if (\Yii::$app->request->isPost) {
  937. //商品列表筛选
  938. $params = Yii::$app->request->post();
  939. $rules = [
  940. [['id','step_status'], 'required'],
  941. [['id','step_status','address_type'], 'integer'],
  942. [['saler_express','saler_express_no','address','consignee','refund_reason','mobile'], 'string'],
  943. [['saler_express','saler_express_no','address_type','customer_name', 'balance_pre', 'score_pre', 'digital_pre','admin_handler_refund','refund_price','refund_remark'], 'safe'],
  944. ];
  945. // //模拟数据
  946. // $params['balance_pre'] = 100;
  947. // $params['admin_handler_refund'] = 1;
  948. if ($params['step_status'] == RefundStatusEnum::STEP_NEGATIVE_1 && empty($params['refund_reason'])) {
  949. return $this->error('请输入拒绝理由');
  950. }
  951. $res = Yii::$app->services->validate->validate($params, $rules);
  952. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  953. // 退货地址
  954. $address = ['consignee' => $params['consignee'],'mobile' => $params['mobile'],'address' => $params['address']];
  955. // 换货物流信息
  956. $express = ['saler_express' => $params['saler_express'],'saler_express_no' => $params['saler_express_no'],'customer_name' => $params['customer_name']];
  957. $data = [
  958. 'id' => $params['id'],
  959. 'step_status' => $params['step_status'],
  960. 'refund_price' => $params['refund_price']??0,
  961. 'refund_remark' => $params['refund_remark']??'',
  962. 'address' => $address,
  963. 'express' => $express,
  964. 'refund_reason' => $params['refund_reason'] ?? '',
  965. 'operator_id' => $this->admin->id,
  966. 'is_admin' => 1
  967. ];
  968. if (!empty($params['balance_pre']) || is_numeric($params['balance_pre'])) $data['refund_pre'] = $params['balance_pre'];
  969. if (!empty($params['score_pre']) || is_numeric($params['score_pre'])) $data['score_pre'] = $params['score_pre'];
  970. if (!empty($params['digital_pre']) || is_numeric($params['digital_pre'])) $data['digital_pre'] = $params['digital_pre'];
  971. if ($params['admin_handler_refund'] == 1) $data['admin_handler_refund'] = UserWalletEnum::ADMIN_HANDLER_REFUND;
  972. // print_r($params);exit;
  973. $logic = new OrderRefundLogic();
  974. $res = $logic->execute($this->mall_id, $data);
  975. if ($res == false) return $this->error($logic->getError());
  976. return $this->success('操作成功');
  977. }
  978. }
  979. }
  980. /**
  981. * 批量发货页面
  982. * @Author: lun
  983. * @DateTime: 2021/11/30 0030 18:51
  984. * @Copyright: copyright (c) 2021 广东七件事集团
  985. */
  986. public function actionBatchDelivery()
  987. {
  988. if (\Yii::$app->request->isAjax) {
  989. if (\Yii::$app->request->isPost) {
  990. $params = Yii::$app->request->post();
  991. // 失败订单导出
  992. if(\Yii::$app->request->post('flag') == 'EXPORT'){
  993. $rules = [[['batch_delivery_id'], 'required'], [['batch_delivery_id'], 'integer']];
  994. $res = Yii::$app->services->validate->validate($params, $rules);
  995. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  996. $download['mall_id'] = $this->mall_id;
  997. $download['batch_delivery_id'] = $params['batch_delivery_id'];
  998. $filename = '批量发货失败-' . date('YmdHis').'_'.rand(10000,99999);
  999. $res = CsvExportHelper::exportDownLoadCenter($this->mall_id,$filename,DownloadEnum::TYPE_ORDERS,OrderBatchDeliveryError::class,'exportHandle',$download);
  1000. if ($res === false) return $this->error('加入导出任务失败'.CsvExportHelper::getStaticError());
  1001. return $this->success('添加导出任务成功,任务完成后请在下载中心进行下载!');
  1002. }
  1003. $rules = [
  1004. [['express_id','express_name','delivery_file', 'isByGoods'], 'required'],
  1005. [['express_id', 'isByGoods'], 'integer'],
  1006. [['delivery_file','express_name'], 'string'],
  1007. ];
  1008. $res = Yii::$app->services->validate->validate($params, $rules);
  1009. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  1010. try {
  1011. $params['operator_id'] = $this->admin->id;
  1012. $params['operator_name'] = $this->admin->account;
  1013. $model = OrderBatchDelivery::setData($this->mall_id, $params);
  1014. if ($model == false) throw new Exception(OrderBatchDelivery::getStaticError());
  1015. // 提交到异步处理
  1016. $isByGoods = !in_array($params['isByGoods'], [0, 1]) ? 0 : $params['isByGoods'];
  1017. $handleAction = ['async_batch_handle', 'async_batch_handle_by_goods'][(int)$isByGoods];
  1018. Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE, ['id' => $model->id], OrderDeliveryListener::class, $handleAction);
  1019. return $this->success('提交成功,正在处理异步处理批量发货');
  1020. } catch (Exception $e) {
  1021. return $this->error('提交失败:' . $e->getMessage());
  1022. }
  1023. }else{
  1024. $params = Yii::$app->request->get();
  1025. $rules = [
  1026. [['delivery_status'], 'integer'],
  1027. [['start_time','end_time','operator_name'], 'string'],
  1028. ];
  1029. $res = Yii::$app->services->validate->validate($params, $rules);
  1030. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  1031. // 条件组合
  1032. $where = [['mall_id' => $this->mall_id]];
  1033. $where[] = ['=', 'status', StatusEnum::ENABLED];
  1034. isset($params['start_time']) && isset($params['end_time']) && $where[] = ['between', 'created_at', strtotime($params['start_time']), strtotime($params['end_time'])];
  1035. isset($params['operator_name']) && $where[] = ['=', 'operator_name', $params['operator_name']];
  1036. isset($params['delivery_status']) && $where[] = ['=', 'delivery_status', $params['delivery_status']];
  1037. $order = "id desc";
  1038. $list_params = compact('where', 'with', 'order');
  1039. $list = OrderBatchDelivery::listPage($list_params, false, true);
  1040. if ($list === false) return $this->error(OrderBatchDelivery::getStaticError());
  1041. return $this->success('操作成功', $list);
  1042. }
  1043. }
  1044. return $this->render($this->action->id);
  1045. }
  1046. public function actionCommissionAndScoreList(){
  1047. $params = Yii::$app->request->get();
  1048. $wallet_type = 'commission';
  1049. $level = UserLevel::find()->select("name,level")->where(['mall_id' => $this->mall_id,'status' => StatusEnum::ENABLED])->asArray()->all();
  1050. $level_data = array_column($level,'name','level');
  1051. $list = [];
  1052. if(!empty($params['wallet_type'])) $wallet_type = $params['wallet_type'];
  1053. if(!in_array($wallet_type, ['score', 'commission'])){
  1054. $list['list'] = [];
  1055. $list['list'] = GlobalInvoke::exec(GlobalFuncEnum::ONE_CAPITAL_LOG_LIST, $this->mall_id, [
  1056. 'list' => $list['list'], 'mall_id' => $this->mall_id, 'wallet_type' => $wallet_type, 'order_id' => $params['order_id']
  1057. ]) ?:$list['list'];
  1058. return $this->success('操作成功',['list'=> $list['list'], 'user_level'=> $level_data]);
  1059. }
  1060. $condition['where'] = [['order_id'=>$params['order_id']]];
  1061. $condition['select'] = 'id';
  1062. $order_detail_list = OrderDetail::lists($condition);
  1063. $order_detail_ids = array_column($order_detail_list,'id');
  1064. $condition = [
  1065. 'where'=>[
  1066. ['source_table'=>[Order::tableName()]],
  1067. ['source_table_id'=>$params['order_id']]
  1068. ],
  1069. ];
  1070. CapitalLog::$capitalType = "{$wallet_type}";
  1071. $extra_list = CapitalLog::getList($condition,0);
  1072. if(!empty($extra_list)) $list = $extra_list;
  1073. $condition = [
  1074. 'where'=>[
  1075. ['source_table'=>['order_detail',OrderDetail::tableName()]],
  1076. ['source_table_id'=>$order_detail_ids]
  1077. ],
  1078. ];
  1079. CapitalLog::$capitalType = "{$wallet_type}";
  1080. $temp_list = CapitalLog::getList($condition,0);
  1081. if(!empty($temp_list)) $list = array_merge($list,$temp_list);
  1082. $level = UserLevel::find()->select("name,level")->where(['mall_id' => $this->mall_id,'status' => StatusEnum::ENABLED])->asArray()->all();
  1083. $level_data = array_column($level,'name','level');
  1084. CapitalLog::$capitalType = "{$wallet_type}_frozen";
  1085. $condition['where'][] = ['status'=>0];
  1086. $frozen_list = CapitalLog::getList($condition,1);
  1087. if(!empty($frozen_list)) $list = array_merge($list,$frozen_list);
  1088. return $this->success('操作成功',['list'=>$list,'user_level'=>$level_data]);
  1089. }
  1090. /**
  1091. * 下载批量发货模板
  1092. * @Author: lun
  1093. * @DateTime: 2021/12/1 0001 14:24
  1094. * @Copyright: copyright (c) 2021 广东七件事集团
  1095. */
  1096. public function actionDownloadDeliveryTemplate()
  1097. {
  1098. $csv = new CsvTool();
  1099. $csv->filename = '批量发货模板';
  1100. $csv->file_dirname = DownloadEnum::getTypeStorageDirMap(DownloadEnum::TYPE_ORDERS);
  1101. $csv->export_mode = CsvTool::EXPORT_MODE_SYNC;
  1102. $csv->header = $this->request->get('isByGoods') ? ['订单号', '物流单号', '商品名称', '商品数量'] : ['订单号', '物流单号'];
  1103. $csv->export(true);
  1104. }
  1105. /**
  1106. * 批量发货错误原因列表
  1107. * @Author: lun
  1108. * @DateTime: 2021/12/2 0002 14:58
  1109. * @Copyright: copyright (c) 2021 广东七件事集团
  1110. * @return mixed|string|void
  1111. */
  1112. public function actionBatchDeliveryError()
  1113. {
  1114. if (\Yii::$app->request->isAjax) {
  1115. if (\Yii::$app->request->isGet) {
  1116. $params = Yii::$app->request->get();
  1117. $rules = [
  1118. [['delivery_id'], 'required'],
  1119. [['delivery_id'], 'integer'],
  1120. ];
  1121. $res = Yii::$app->services->validate->validate($params, $rules);
  1122. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  1123. // 条件组合
  1124. $where = [['mall_id' => $this->mall_id],['batch_delivery_id' => $params['delivery_id']],['=', 'status', StatusEnum::ENABLED]];
  1125. $order = "id desc";
  1126. $select = "id,order_no,express_no,content";
  1127. $list_params = compact('where', 'select', 'order');
  1128. $list = OrderBatchDeliveryError::listPage($list_params, false, true);
  1129. if ($list === false) return $this->error(OrderBatchDeliveryError::getStaticError());
  1130. return $this->success('操作成功', $list);
  1131. }
  1132. }
  1133. return $this->render($this->action->id);
  1134. }
  1135. /**
  1136. * 申请售后-换货-后台确认收货,售后完成
  1137. * @Author: hua
  1138. * @DateTime: 2021/10/9 15:52
  1139. * @Copyright: copyright (c) 2021 广东七件事集团
  1140. * @return mixed|void
  1141. */
  1142. public function actionRefundTakeDelivery()
  1143. {
  1144. $params = \Yii::$app->request->post();
  1145. $res = \Yii::$app->services->validate->validate($params, [
  1146. [['id'], 'required'],
  1147. ]);
  1148. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  1149. $params['mall_id'] = $this->mall_id;
  1150. $res = OrderRefundStep::refundTakeDelivery($params);
  1151. if ($res === false) return $this->error(OrderRefundStep::getStaticError());
  1152. return $this->success('操作成功');
  1153. }
  1154. /**
  1155. * @Author: 广东七件事 ganxiaohao
  1156. * @Date: 2020-05-15
  1157. * @Time: 9:58
  1158. * @Note:开票记录
  1159. * @return string|\yii\web\Response
  1160. */
  1161. public function actionInvoice()
  1162. {
  1163. if (\Yii::$app->request->post('flag') == 'EXPORT') {
  1164. $post = \Yii::$app->request->post();
  1165. $post['mall_id'] = $this->mall_id;
  1166. $filename = '开票记录-' . date('YmdHis') . '_' . rand(10000, 99999);
  1167. $res = CsvExportHelper::exportDownLoadCenter($this->mall_id, $filename, DownloadEnum::TYPE_ORDERS, OrderInvoice::class, 'exportHandle', $post);
  1168. if ($res === false) return $this->error('加入导出任务失败' . CsvExportHelper::getStaticError());
  1169. return $this->success('添加导出任务成功,任务完成后请在下载中心进行下载!');
  1170. }
  1171. if (\Yii::$app->request->isAjax) {
  1172. if (\Yii::$app->request->isGet) {
  1173. $get = \Yii::$app->request->get();
  1174. $params['order'] = 'id desc';
  1175. $params['alias'] = 'b';
  1176. $params['joinWith'] = ['user'];
  1177. if (!empty($get['keyword'])) {
  1178. $user_ids = User::find()
  1179. ->where(['mall_id'=>$this->mall_id])->andWhere([
  1180. 'or',
  1181. ['like', 'nickname', $get['keyword']],
  1182. ['like', 'mobile', $get['keyword']]
  1183. ])->select('id')->asArray()->column();
  1184. $params['where'][] = ['in', 'b.user_id', $user_ids];
  1185. }
  1186. if (!empty($get['user_id'])) {
  1187. $params['where'][] = ['=', 'b.user_id', $get['user_id']];
  1188. }
  1189. if (!empty($get['order_no'])) {
  1190. $params['where'][] = ['=', 'b.order_no', $get['order_no']];
  1191. }
  1192. if ($get['head_type'] != -1) {
  1193. $params['where'][] = ['=', 'b.head_type', $get['head_type']];
  1194. }
  1195. if ($get['invoice_status'] != -1) {
  1196. $params['where'][] = ['=', 'b.invoice_status', $get['invoice_status']];
  1197. }
  1198. $params['where'][] = ['=', 'b.mall_id', $this->mall_id];
  1199. $params['order'] = ['id' => SORT_DESC];
  1200. $params['limit'] = 10;
  1201. $list = OrderInvoice::listPage($params);
  1202. $list['export_list'] = OrderInvoice::exportFieldsList();
  1203. return $this->success('操作成功',$list,ApiStatusEnum::CODE_SUCCESS,JSON_UNESCAPED_UNICODE);
  1204. }
  1205. if (\Yii::$app->request->isPost) {
  1206. $post = \Yii::$app->request->post();
  1207. $invoice = OrderInvoice::findOne($post['id']);
  1208. if(empty($invoice)) return $this->error('数据异常!');
  1209. $invoice->invoice_status = $post['status'];
  1210. $invoice->remark = $post['remark'];
  1211. if(!$invoice->save()) return $this->error('操作失败');
  1212. return $this->success('操作成功');
  1213. }
  1214. }
  1215. return $this->render('invoice');
  1216. }
  1217. /**
  1218. * 手动退款
  1219. * @return mixed|null
  1220. */
  1221. public function actionManualRefund()
  1222. {
  1223. $params = \Yii::$app->request->post();
  1224. $res = \Yii::$app->services->validate->validate($params, [
  1225. [['id', 'refund_amount', 'reason'], 'required'],
  1226. ]);
  1227. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  1228. try {
  1229. $order = Order::findOne(['id' => $params['id']]);
  1230. if (empty($order)) throw new Exception('订单不存在');
  1231. if ($order->order_source != OrderSourceEnum::SOURCE_RESERVE) throw new Exception('当前订单类型不支持手动退款');
  1232. if (empty($order->pay_status)) throw new Exception('当前订单未支付');
  1233. if ($order->order_status < OrderStatusEnum::PAY) throw new Exception('当前订单状态不支持退款');
  1234. $order_detail_id = OrderDetail::find()->where(['order_id' => $params['id']])->select('id')->scalar();
  1235. // 执行退款
  1236. $params = [
  1237. 'order_detail_id' => $order_detail_id,
  1238. 'reason' => $params['reason'],
  1239. 'remark' => '',
  1240. 'type' => RefundTypeEnum::MONEY,
  1241. 'refund_price' => bcmul($params['refund_amount'], 1, 2),
  1242. 'user_id' => $order->user_id,
  1243. 'mall_id' => $order->mall_id,
  1244. ];
  1245. $res = OrderRefund::feedback($params);
  1246. if ($res === false) throw new \Exception(Order::getStaticError());
  1247. $event = new \common\events\order\OrderRefundEvent();
  1248. $event->mall_id = $order->mall_id;
  1249. $order_detail['order_detail_id'] = $order_detail_id;
  1250. $order_detail['id'] = $res->id;
  1251. $order_detail['operator_id'] = $this->admin->id;
  1252. $order_detail['operator_name'] = $this->admin->account;
  1253. $order_detail['is_admin'] = 1;
  1254. $order_detail['is_manual'] = 1;
  1255. Yii::$app->services->events->dispatch($event, $order_detail, $event->listeners);
  1256. // 执行退款操作
  1257. // 退货地址
  1258. $address = ['consignee' => '','mobile' => '','address' => ''];
  1259. // 换货物流信息
  1260. $express = ['saler_express' => '','saler_express_no' => '','customer_name' => ''];
  1261. $data = [
  1262. 'id' => $res->id,
  1263. 'step_status' => RefundStatusEnum::STEP_6, // 直接打款操作
  1264. 'address' => $address,
  1265. 'express' => $express,
  1266. 'refund_reason' => '',
  1267. 'not_dec_fee' => StatusEnum::ENABLED, // 不需要手续费
  1268. 'operator_id' => $this->admin->id,
  1269. 'is_admin' => 1,
  1270. 'is_manual' => 1,
  1271. ];
  1272. $logic = new OrderRefundLogic();
  1273. $res = $logic->execute($this->mall_id, $data);
  1274. if (!$res) throw new \Exception($logic->getError());
  1275. } catch (Exception $e) {
  1276. return $this->error($e->getMessage());
  1277. }
  1278. return $this->success();
  1279. }
  1280. /**
  1281. * 订单批量留言或备注
  1282. * @params order_ids 操作订单id
  1283. * @params order_type 操作类型
  1284. * @params content 数据内容
  1285. * @return void
  1286. */
  1287. public function actionOrderBatch()
  1288. {
  1289. $post = Yii::$app->request->post();
  1290. $rules = [[['order_ids'], 'required'], [['content', 'order_type', 'order_ids', 'user_id', 'is_batch_message'], 'string']];
  1291. $res = Yii::$app->services->validate->validate($post, $rules);
  1292. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  1293. $message = '';
  1294. switch ($post['order_type']) {
  1295. case OrderCommentEnum::BATCH_REMARKS:// 批量备注
  1296. $res = Order::batchRemark($post);
  1297. $message = '备注';
  1298. // 事件
  1299. $orderIds = explode(',', $post['order_ids']);
  1300. $event = new OrderRemarkEvent($this->mall_id);
  1301. foreach ($orderIds as $orderId) {
  1302. $eventData['operator_id'] = $this->admin->id;
  1303. $eventData['seller_remark'] = $post['content'] ?? 0;
  1304. $eventData['is_admin'] = 1;
  1305. $eventData['is_batch'] = 1;
  1306. $eventData['id'] = $orderId;
  1307. Yii::$app->services->events->dispatch($event,$eventData,$event->listeners);
  1308. }
  1309. break;
  1310. case OrderCommentEnum::BATCH_LEAVE:// 批量留言
  1311. $res = OrderExtra::batchLeave($post);
  1312. $message = '留言';
  1313. // 事件
  1314. $orderIds = explode(',', $post['order_ids']);
  1315. $event = new OrderLeaveEvent($this->mall_id);
  1316. foreach ($orderIds as $orderId) {
  1317. $eventData['operator_id'] = $this->admin->id;
  1318. $eventData['message'] = $post['content'] ?? 0;
  1319. $eventData['is_admin'] = 1;
  1320. $eventData['is_batch'] = (int)!empty($post['is_batch_message']);
  1321. $eventData['id'] = $orderId;
  1322. Yii::$app->services->events->dispatch($event,$eventData,$event->listeners);
  1323. }
  1324. break;
  1325. default:
  1326. break;
  1327. }
  1328. if ($res === false) return $this->error(Order::getStaticError());
  1329. return $this->success($message . "操作成功");
  1330. }
  1331. /**
  1332. * 撤销售后订单
  1333. *
  1334. * @return mixed
  1335. */
  1336. public function actionRevoceRefund(int $id)
  1337. {
  1338. $service = new MallRefundService(['mall_id' => $this->mall_id]);
  1339. return $service->revoceRefund($id, ['is_admin' => 1, 'operator_id' => $this->admin->id])
  1340. ? $this->success('撤销售成功')
  1341. : $this->error($service->getError());
  1342. }
  1343. /**
  1344. * 返回售后订单菜单是否需要显示小红点
  1345. *
  1346. * @return void
  1347. */
  1348. public function actionOrderRefundIsShowRedDot()
  1349. {
  1350. $this->success('success', [
  1351. 'is_show' => (bool)OrderRefund::find()
  1352. ->where([
  1353. 'mall_id' => $this->mall_id,
  1354. 'mch_id' => 0,
  1355. 'store_id' => 0,
  1356. 'refund_status' => [
  1357. RefundStatusEnum::APPLY,
  1358. RefundStatusEnum::HANDEL,
  1359. RefundStatusEnum::RETURN_GOODS,
  1360. RefundStatusEnum::EXCHANGE_GOODS,
  1361. ],
  1362. 'status' => StatusEnum::ENABLED,
  1363. ])
  1364. ->count()
  1365. ]);
  1366. }
  1367. public function actionGetGoodsCommissionList(){
  1368. $params = Yii::$app->request->get();
  1369. $condition = [
  1370. 'where'=>[
  1371. ['source_table'=>[Order::tableName()]],
  1372. ['source_table_id'=>$params['order_id']]
  1373. ],
  1374. ];
  1375. $list = [];
  1376. $check_order_detail_refund = OrderDetail::findOne(['order_id' => $params['order_id'], 'is_feedback' => 2]);
  1377. if (empty($check_order_detail_refund)) {
  1378. CapitalLog::$capitalType = "{$params['wallet_type']}";
  1379. $extra_list = CapitalLog::getList($condition,0);
  1380. if(!empty($extra_list)) $list = $extra_list;
  1381. }
  1382. $condition = [
  1383. 'where' => [
  1384. ['source_table' => ['order_detail', OrderDetail::tableName()]],
  1385. ['source_table_id' => $params['goods_id']],
  1386. ['mall_id' => $this->mall_id],
  1387. ['from_type' => ['Agent', 'Area', 'CloudStock', 'Achievement', 'Distribution', 'EqualSubsidy', 'PerformanceDividend']],
  1388. ],
  1389. ];
  1390. // $wallet_type = $params['wallet_type'];
  1391. CapitalLog::$capitalType = "{$params['wallet_type']}";
  1392. $temp_list = CapitalLog::getList($condition,0);
  1393. if(!empty($temp_list)) {
  1394. foreach ($temp_list as &$item) {
  1395. $item['type'] = 'commission';
  1396. }
  1397. $list = array_merge($list,$temp_list);
  1398. }
  1399. $params['wallet_type'] = 'score';
  1400. CapitalLog::$capitalType = "{$params['wallet_type']}";
  1401. $temp_list = CapitalLog::getList($condition,0);
  1402. if (!empty($temp_list)) {
  1403. foreach ($temp_list as &$item) {
  1404. $item['type'] = 'score';
  1405. }
  1406. $list = array_merge($list, $temp_list);
  1407. }
  1408. $digital_list = DigitalLog::lists([
  1409. 'where' => array_merge($condition['where'], [['status' => CapitalLog::STATUS_SEND], ['send_status' => DigitalLog::SEND_STATUS_NORMAL]]),
  1410. 'with' => ['user']
  1411. ]);
  1412. if ($digital_list) {
  1413. $from_type_arr = array_column($digital_list, 'from_type');
  1414. $addons_list = Addons::lists(['where' => [['name' => $from_type_arr]], 'index' => 'name', 'select' => 'name,title']);
  1415. $capital_type_map = GlobalVarMap::getEnumMapByType('CapitalTypeMap', $digital_list[0]['mall_id']);
  1416. foreach ($digital_list as &$item) {
  1417. $item['from_type_text'] = $addons_list[$item['from_type']]['title'] ?? '';
  1418. $item['capital_type_text'] = $capital_type_map[$item['capital_type']] ?? '';
  1419. $item['type'] = 'digital';
  1420. $item['nickname'] = $item['user']['nickname'];
  1421. $item['mobile'] = $item['user']['mobile'];
  1422. $item['level'] = $item['user']['level'];
  1423. $item['avatar_url'] = $item['user']['avatar_url'];
  1424. unset($item['user']);
  1425. }
  1426. $list = array_merge($list, $digital_list);
  1427. }
  1428. return $this->success('操作成功',['list'=>$list]);
  1429. }
  1430. public function actionGetOrderDetail(){
  1431. $params = \Yii::$app->request->get();
  1432. $res = \Yii::$app->services->validate->validate($params, [
  1433. [['order_detail_id'], 'required'],
  1434. ]);
  1435. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  1436. $select = 'id,order_id,user_id,goods_name,sign_id,goods_attr_name,price,num,pic_url,goods_price,order_status,marketing_type,extra_info,adjust_money';
  1437. $order_detail = OrderDetail::getOne([['id' => $params['order_detail_id']], 'mall_id' => $this->mall_id], 1, [], false, $select);
  1438. if (empty($order_detail)) return $this->error('订单不存在');
  1439. // 公共调用
  1440. $order_detail = GlobalInvoke::exec(GlobalInvoke::ORDER_REFUND_SUBMIT, $this->mall_id, [
  1441. 'order_detail' => $order_detail,
  1442. 'mall_id' => $this->mall_id,
  1443. ]) ?: $order_detail;
  1444. //价格等于商品价格加上修改价格
  1445. $order_detail['goods_price'] = round($order_detail['goods_price'] + $order_detail['adjust_money'],2);
  1446. return $this->success('操作成功',[ $order_detail]);
  1447. }
  1448. /**
  1449. * 主动退款提交售后申请
  1450. */
  1451. public function actionDoRefundSubmit()
  1452. {
  1453. $params = \Yii::$app->request->post();
  1454. $res = \Yii::$app->services->validate->validate($params, [
  1455. [['order_detail_id', 'reason', 'refund_price', 'settlement_method', 'balance_pre', 'score_pre', 'digital_pre'], 'required'],
  1456. [['shipping_status', 'pic_list', 'reason', 'refund_price', 'remark', 'type', 'user_id', 'settlement_method', 'balance_pre', 'score_pre', 'digital_pre'], 'safe'],
  1457. ]);
  1458. // if (empty($params['reason']))
  1459. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  1460. $key = sprintf('DoRefundSubmit:%s', $params['user_id']);
  1461. if (LockHelper::fLock($key)) return $this->error('请勿频繁请求');
  1462. // 判断是否安装了代客下单
  1463. if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_VALET_ORDER)) {
  1464. // 判断当前订单是否为代客下单订单
  1465. if (!empty(ValetOrder::find()->where(['mall_id' => $this->mall_id])
  1466. ->andWhere(['order_id' => OrderDetail::find()->where(['id' => $params['order_detail_id']])->select('order_id')->scalar()])
  1467. ->select('id')->scalar())) {
  1468. $config = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_VALET_ORDER, 'basic');
  1469. // 如果插件是开启状态,且可售后是关闭状态
  1470. if (!empty($config['is_enable']) && empty($config['is_enable_order_refund'])) {
  1471. LockHelper::unFLock($key);
  1472. return $this->error("代客下单订单不可申请退款/售后");
  1473. }
  1474. }
  1475. }
  1476. if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_SERVICE_POINT_APPOINTMENT) &&
  1477. (new OrderService())->isReserveByOrderDetailId($this->mall_id, $params['order_detail_id'])) { // 服务点预约
  1478. LockHelper::unFLock($key);
  1479. return $this->error('预约订单含有预约后不可进行售后');
  1480. }
  1481. // 企叮咚
  1482. if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_QI_DING_DONG)) {
  1483. if (!RefundService::hasPic($params['order_detail_id'], $params['pic_list'])) {
  1484. LockHelper::unFLock($key);
  1485. return $this->error('图片不能为空');
  1486. }
  1487. }
  1488. // $params['user_id'] = $params['user_id'];
  1489. $params['mall_id'] = $this->mall_id;
  1490. $where = [
  1491. ['=', 'order_detail_id', $params['order_detail_id']],
  1492. ['=', 'user_id', $params['user_id']],
  1493. ['=', 'mall_id', $this->mall_id],
  1494. ['>', 'step_status', 0],
  1495. ['in', 'status', [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  1496. ['<>', 'refund_status', RefundStatusEnum::REVOKE]
  1497. ];
  1498. $order_refund_model = OrderRefund::getOne($where, true);
  1499. if ($order_refund_model) {
  1500. LockHelper::unFLock($key);
  1501. return $this->error('该订单商品已经申请过售后');
  1502. }
  1503. $res = OrderRefund::feedback($params);
  1504. if ($res === false) {
  1505. LockHelper::unFLock($key);
  1506. return $this->error(Order::getStaticError());
  1507. }
  1508. $event = new \common\events\order\OrderRefundEvent();
  1509. $event->mall_id = $this->mall_id;
  1510. $order_detail['order_detail_id'] = $params['order_detail_id'];
  1511. $order_detail['id'] = $res->id;
  1512. $order_detail['operator_id'] = $this->admin->id;
  1513. $order_detail['operator_name'] = $this->admin->account;
  1514. $order_detail['is_admin'] = 1;
  1515. $order_detail['admin_handler_refund'] = UserWalletEnum::ADMIN_HANDLER_REFUND;
  1516. Yii::$app->services->events->dispatch($event, $order_detail, $event->listeners);
  1517. LockHelper::unFLock($key);
  1518. return $this->success('操作成功', ['id' => $res->id]);
  1519. }
  1520. /**
  1521. * 获取订单所有状态
  1522. * @Author:lun
  1523. * @Date:2024-08-29 16:10
  1524. * @Copyright:copyright(c)2024 广东七件事集团
  1525. * @return mixed|void|null
  1526. */
  1527. public function actionGetOrderStatus()
  1528. {
  1529. $request = Yii::$app->request;
  1530. if ($request->isAjax && $request->isGet) {
  1531. $response = [
  1532. 'order_status_map' => OrderStatusEnum::getMap(),
  1533. 'payment_type_map' => PayTypeEnum::getMap(),
  1534. 'shipping_type_map' => ShippingTypeEnum::getMap(),
  1535. 'marketing_type_map' => MarketingTypeEnum::getMap(),
  1536. 'refund_status_map' => RefundStatusEnum::getMap(),
  1537. 'refund_type_map' => RefundTypeEnum::getMap(),
  1538. ];
  1539. return $this->success('操作成功', $response);
  1540. }
  1541. }
  1542. /**
  1543. * 获取分润明细弹窗需要展示的tab
  1544. *
  1545. * @return array[]
  1546. * @throws \yii\db\Exception
  1547. */
  1548. protected function getCommissionType()
  1549. {
  1550. $addons_commission_arr = GlobalInvoke::exec(GlobalInvoke::INVOKE_COMMISSION_TYPE, $this->mall_id, ['mall_id' => $this->mall_id]);
  1551. //判断积分拓客插件有没有安装
  1552. //获取商城已安装插件列表
  1553. $valid_addons = MallAddons::getValidAddons($this->mall_id);
  1554. if (in_array(AddonsEnum::ADDONS_NAME_SCORE_EXPANSION, $valid_addons)){
  1555. $ScoreExpansionArr = (new ScoreExpansion())->getGoodsModeCommssionType();
  1556. foreach($ScoreExpansionArr as $type){
  1557. $addons_commission_arr[AddonsEnum::ADDONS_NAME_SCORE_EXPANSION][]= $type;
  1558. }
  1559. }
  1560. //判断积分拓客插件有没有安装end
  1561. $commission_type = [
  1562. ['name' => 'commission', 'label' => '佣金'], ['name' => 'score', 'label' => '积分']
  1563. ];
  1564. foreach ($addons_commission_arr as $item){
  1565. foreach($item as $v){
  1566. $commission_type[] = $v;
  1567. }
  1568. }
  1569. return $commission_type;
  1570. }
  1571. /**
  1572. * 分润明细数据(根据order_detail_id)
  1573. *
  1574. * @return mixed|null
  1575. */
  1576. public function actionCommissionAndScoreListByOrderDetailId(){
  1577. $params = Yii::$app->request->get();
  1578. $wallet_type = 'commission';
  1579. $level = UserLevel::find()->select("name,level")->where(['mall_id' => $this->mall_id,'status' => StatusEnum::ENABLED])->asArray()->all();
  1580. $level_data = array_column($level,'name','level');
  1581. $list = [];
  1582. if(!empty($params['wallet_type'])) $wallet_type = $params['wallet_type'];
  1583. if(!in_array($wallet_type, ['score', 'commission'])){
  1584. $list['list'] = [];
  1585. $list['list'] = GlobalInvoke::exec(GlobalFuncEnum::ONE_CAPITAL_LOG_LIST, $this->mall_id, [
  1586. 'list' => $list['list'], 'mall_id' => $this->mall_id, 'wallet_type' => $wallet_type,
  1587. 'order_id' => $params['order_id'],'order_detail_id' => $params['order_detail_id']
  1588. ]) ?:$list['list'];
  1589. return $this->success('操作成功',['list'=> $list['list'], 'user_level'=> $level_data]);
  1590. }
  1591. $condition = [
  1592. 'where'=>[
  1593. ['source_table'=>[Order::tableName()]],
  1594. ['source_table_id'=>$params['order_id']]
  1595. ],
  1596. ];
  1597. CapitalLog::$capitalType = "{$wallet_type}";
  1598. $extra_list = CapitalLog::getList($condition,0);
  1599. if(!empty($extra_list)) $list = $extra_list;
  1600. $condition = [
  1601. 'where'=>[
  1602. ['source_table' => ['order_detail',OrderDetail::tableName()]],
  1603. ['source_table_id' => $params['order_detail_id']]
  1604. ],
  1605. ];
  1606. CapitalLog::$capitalType = "{$wallet_type}";
  1607. $temp_list = CapitalLog::getList($condition,0);
  1608. if(!empty($temp_list)) $list = array_merge($list,$temp_list);
  1609. $level = UserLevel::find()->select("name,level")->where(['mall_id' => $this->mall_id,'status' => StatusEnum::ENABLED])->asArray()->all();
  1610. $level_data = array_column($level,'name','level');
  1611. CapitalLog::$capitalType = "{$wallet_type}_frozen";
  1612. $condition['where'][] = ['status'=>[0, -1]];
  1613. $frozen_list = CapitalLog::getList($condition,1);
  1614. if(!empty($frozen_list)) $list = array_merge($list,$frozen_list);
  1615. return $this->success('操作成功',['list'=>$list,'user_level'=>$level_data]);
  1616. }
  1617. /**
  1618. * 发货时验证物流号是否已经发过了
  1619. *
  1620. * @return void
  1621. */
  1622. public function actionCheckOrderExpressNo()
  1623. {
  1624. // 发货
  1625. $params = Yii::$app->request->get();
  1626. $rules = [
  1627. [['express_no', 'id'], 'required'],
  1628. [['id'], 'integer'],
  1629. [['express_no'], 'string'],
  1630. ];
  1631. $res = Yii::$app->services->validate->validate($params, $rules);
  1632. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  1633. $service = new \backend\modules\mall\services\OrderService(['mall_id' => $this->mall_id]);
  1634. return $this->success('操作成功', ['is_exists' => $service->checkOrderExpressNo($params)]);
  1635. }
  1636. }