db->beginTransaction(); try { $refund = OrderRefund::findOne(['id' => $params['id'], 'mall_id' => $mallId]); if(empty($refund)) throw new Exception("售后订单不存在或已删除"); if ($refund->isRefundFinish()) throw new Exception('当前订单已售后'); switch ($params['step_status']) { case RefundStatusEnum::STEP_2:// 退货退款:已同意退货申请,等待买家处理 $refund->saler_address = Json::encode($params['address']); $refund->refund_status = RefundStatusEnum::HANDEL; break; case RefundStatusEnum::STEP_4:// 退货退款:退货完成 $refund->refund_status = RefundStatusEnum::FINISH; break; case RefundStatusEnum::STEP_6:// 仅退款:退款完成 $refund->refund_status = RefundStatusEnum::FINISH; break; case RefundStatusEnum::STEP_8:// 换货:已同意换货申请,等待买家处理 $refund->saler_address = Json::encode($params['address']); $refund->refund_status = RefundStatusEnum::HANDEL; break; case RefundStatusEnum::STEP_10:// 换货:已重新发货 $refund->saler_express = $params['express']['saler_express']; $refund->saler_express_no = $params['express']['saler_express_no']; $refund->customer_name = $params['express']['customer_name'] ?? ''; $refund->refund_status = RefundStatusEnum::EXCHANGE_GOODS; $refund->saler_express_at = time();// 重新发货时间 break; case RefundStatusEnum::STEP_NEGATIVE_1:// 拒绝售后 $refund->refund_status = RefundStatusEnum::FINISH; break; case RefundStatusEnum::STEP_NEGATIVE_2:// 拒绝收货 $refund->refund_status = RefundStatusEnum::REFUSE; break; } $refund_price = $refund->refund_price; // 自动维护主订单 OrderDetail::updateAll(['is_feedback' => OrderStatusEnum::getIsFeedbackStatus($params['step_status']), 'updated_at' => time()], ['id' => $refund->order_detail_id]); $order = Order::getOne([['id' => $refund->order_id]]); $order_status = $order->order_status; $is_install = MallAddons::isInstall($mallId, AddonsEnum::ADDONS_NAME_STORE); Order::autoUpdateStatus($order); if($is_install){ $store_order = StoreOrder::findOne(['order_no'=>$order['order_no']]); if(!empty($store_order)){ $order['out_trade_no'] = $store_order['out_trade_no']; StoreOrderDetail::updateAll(['is_feedback' => OrderStatusEnum::getIsFeedbackStatus($params['step_status']), 'updated_at' => time()], ['main_order_detail_id' => $refund->order_detail_id]); StoreOrder::autoUpdateStatus($store_order); } } // 操作退款-退货退款,仅退款 if (in_array($params['step_status'], [RefundStatusEnum::STEP_4, RefundStatusEnum::STEP_6]) && $order->marketing_type != AddonsEnum::ADDONS_NAME_WECHAT_VIDEO_SHOP) { // 判断是否为预约订单 if (in_array($order->order_source, [OrderSourceEnum::SOURCE_RESERVE, OrderSourceEnum::SOURCE_STORE_RESERVE]) && empty($params['not_dec_fee'])) { // 如果是预约订单那么就需要判断是否需要扣点 $orderDetail = OrderDetail::findOne(['id' => $refund->order_detail_id]); if ($order->order_source == OrderSourceEnum::SOURCE_STORE_RESERVE) { $goodsReserve = StoreGoodsReserve::findOne(['goods_id' => $orderDetail->goods_id]); } else { $goodsReserve = GoodsReserve::findOne(['goods_id' => $orderDetail->goods_id]); } $cancel_rule = !empty($goodsReserve->cancel_rule) ? Json::decode($goodsReserve->cancel_rule) : []; if (!empty($cancel_rule['cancel_fee_percent']) && in_array($order_status, [OrderStatusEnum::SHIPMENTS, OrderStatusEnum::SING])) { // 判断是否需要扣点 - 待服务/服务中 $refund->refund_price -= bcmul(bcmul($refund->refund_price, $cancel_rule['cancel_fee_percent'], 2), 0.01, 2); } } $wallet_type = UserWalletService::WALLET_TYPE_BALANCE; if ($order->payment_type == PayTypeEnum::SCORE) $wallet_type = UserWalletService::WALLET_TYPE_SCORE; if ($refund->refund_price > 0) {// 只有退款金额大于0的情况下才可以进入 // 是否为代客下单订单 $is_refund_balance = MallAddons::isInstall($refund->mall_id, AddonsEnum::ADDONS_NAME_VALET_ORDER) && (new OrderService())->refund($order->id); $out_trade_no = $order['out_trade_no']; //是否为组合支付 $payment_trade = PaymentTrade::findOne(['out_trade_no' => $out_trade_no]); if(!empty($payment_trade->is_pay_group)){ $payment_group_trade_list = PaymentTrade::find()->where(['is_pay'=>1,'is_pay_group'=>1,'parent_trade_id'=>$payment_trade->id])->orderBy('id asc')->all(); }else{ $payment_group_trade_list[] = $payment_trade; } $all_refund_price = $refund->refund_price; foreach($payment_group_trade_list as $payment_group_trade){ if($all_refund_price > $payment_group_trade->pay_fee){ $refund_price = $payment_group_trade->pay_fee; }else{ $refund_price = $all_refund_price; } if(in_array($payment_group_trade->pay_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE]) || $is_refund_balance){ // 本地支付 $wallet_type = $payment_group_trade->pay_type == PayTypeEnum::SCORE ? UserWalletService::WALLET_TYPE_SCORE : UserWalletService::WALLET_TYPE_BALANCE; // 如果是代付,那么就需要原路退回 $extra_refund_price = 0;//额外抵扣金额 if($wallet_type == UserWalletService::WALLET_TYPE_BALANCE){ //判断是否有卡券插件 if (MallAddons::isInstall($refund->mall_id, AddonsEnum::ADDONS_NAME_CARD_COUPONS)) { $card_refund_price = $refund->refund_price - $payment_group_trade->pay_fee; $extra_refund_price = CardCouponsScoreGive::setOrderRefund([ 'refund_price' => $card_refund_price, 'trade_id' => $payment_group_trade->id, 'refund_id' => $refund->id ]); } } $insert_wallet = []; $insert_wallet[] = [ 'mall_id' => $refund->mall_id, 'user_id' => $refund->user_id, 'is_frozen' => false, 'wallet_type' => $wallet_type,// 暂定退回余额或积分 'money' => $refund_price, 'desc' => '订单售后退款', 'source_table' => OrderRefund::tableName(), 'source_table_id' => $refund->id, 'from_type' => UserWalletEnum::REFUND, 'capital_type' => UserWalletEnum::REFUND_ORDER, 'order_no' => $order->order_no, 'not_add_total' => false ]; $res = UserWalletService::batchHandleByQueue($insert_wallet); if (empty($res)) throw new \Exception(UserWalletService::getStaticError()); $refund_price += $extra_refund_price; } elseif(in_array($payment_group_trade->pay_type,[PayTypeEnum::JOINPAY,PayTypeEnum::ALI,PayTypeEnum::JOINPAY_FAST_PAY,PayTypeEnum::WECHAT,PayTypeEnum::SANDPAY_FAST_PAY])){ //原路返回 $res = Yii::$app->services->pay->refund($refund->refund_price,$refund_price, $payment_group_trade->out_trade_no, $order, '订单售后退款'); if ($res === false) throw new \Exception('退款失败'); } elseif ($order->payment_type == PayTypeEnum::OFFLINE) { // 此支付方式为后台管理员直接支付不做任何处理 } elseif ( // 当res返回为false 说明没有相对于的退款方式 $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_ORDER_REFUND, $mallId, [ 'id' => $refund->id, 'mall_id' => $refund->mall_id, 'refund' => $refund, 'params' => $params, 'order_no' => $order['order_no'], 'refund_order_no' => $refund['order_no'], 'payment_trade_id' => $payment_group_trade->id, 'refund_price' => $refund_price, 'pay_type' => $order->payment_type, ]) ) { // 当res不为空 进此判断 list($boolean, $msg) = $res; if ($boolean === false) { $this->setError($msg); return false; } } else { } $all_refund_price -= $refund_price; $refund->reality_refund_price += $refund_price; if($all_refund_price <= 0) break; } } $refund->is_refund = StatusEnum::ENABLED; $refund->refund_at = time(); $refund->refund_price = $refund_price; //$refund->reality_refund_price = $refund->refund_price; $order_detail_ids = array_column($order->detail,'id'); // 订单营销扣减返还 if(empty($order['store_id'])){ $res = OrderMarketing::deductBack($order['id'],$order_detail_ids,[$refund['order_detail_id']],$refund->mall_id,$refund->user_id,'订单退款',UserWalletEnum::REFUND,UserWalletEnum::REFUND_ORDER); if ($res == false) throw new Exception(OrderMarketing::getStaticError()); }else{ if(MallAddons::isInstall($order['mall_id'],AddonsEnum::ADDONS_NAME_STORE)){ $store_order = StoreOrder::findOne(['order_no'=>$order['order_no']]); $store_order_detail_ids = array_column($store_order->detail,'id'); $store_order_detail_arr = array_column($store_order->detail,'id','main_order_detail_id'); $store_order_detail_id = $store_order_detail_arr[$refund['order_detail_id']]??0; $res = StoreOrderMarketing::deductBack($store_order,$store_order_detail_ids,[$store_order_detail_id],$refund->mall_id,$refund->user_id,'订单退款',UserWalletEnum::REFUND,UserWalletEnum::REFUND_ORDER); if ($res == false) throw new Exception(StoreOrderMarketing::getStaticError()); } } } // 保存步骤 $params['payment_type'] = $order->payment_type; $step_status = self::saveStep($refund, $params); // 修改售后信息 $refund->step_status = $step_status; if (!$refund->save()) throw new Exception("保存失败,msg=" . $refund->getErrorMessage()); $trans->commit(); // 触发售后统计 if (in_array($params['step_status'], [RefundStatusEnum::STEP_4, RefundStatusEnum::STEP_6]) && empty($params['is_async'])) { $refund_event = ['id' =>$refund->id, 'type' => RefundTypeEnum::EVENT_FINISH]; StatisticsHandle::execute(EventNameEnum::ORDER_REFUND, $refund_event); //触发订单售后完成 $event = new OrderRefundFinishEvent($refund->mall_id); $data = []; $data['id'] = $refund->id; $data['source_table'] = 'order_detail'; $data['source_table_id'] = $refund['order_detail_id']; $data['step_status'] = $params['step_status']; Yii::$app->services->events->dispatch($event, $data, $event->listeners); } if($params['step_status']==RefundStatusEnum::STEP_2){ Yii::error('退货申请审核通过开始'); try { $send_data = [ 'mall_id' => $order['mall_id'], 'user_id' => $order['user_id'], 'order_id' => $order['id'], 'refund_id' => $refund->id, 'created_at' => $order['created_at'], 'order_no' => $order['order_no'], 'mobile' => $order['mobile'], 'address' => $order['region_name'].$order['address'], 'receiver_name' => $order['receiver_name'], ]; $obj = new WechatMessageLogic(); $obj->orderRefundAgree($send_data); }catch (\Exception $e){ Yii::error('退货申请审核通过Exception:'.$e->getMessage()); } Yii::error('退货申请审核通过结束'); } // 拒绝 - 需要处理ERP if ($params['step_status'] == RefundStatusEnum::REFUSE && MallAddons::isInstall($order['mall_id'],AddonsEnum::ADDONS_NAME_WANG_DIAN_TONG)) { (new OrderRefundRejectService())->sync($order['mall_id'], $refund->id); } // 是否需要触发更新事件 if (!empty($params['is_trigger_update_event'])) { // 退款ID & 退款状态 $event = new OrderRefundUpdateEvent($refund->mall_id); $data = []; $data['id'] = $refund->id; $data['step_status'] = $params['step_status']; Yii::$app->services->events->dispatch($event, $data, $event->listeners); } $event = new OrderRefundChangeEvent($refund->mall_id); $data = []; $data['id'] = $refund->id; $data['step_status'] = $params['step_status']; Yii::$app->services->events->dispatch($event, $data, $event->listeners); return true; } catch (Exception $e) { $trans->rollBack(); $this->setError($e->getMessage()); return false; } } /** * 保存步骤 * @Author: lun * @DateTime: 2021/10/11 0011 15:55 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $refund * @param $stepStatus * @param array $params */ public static function saveStep($refund, $params = []) { $return_address = $params['address']['address'] .' '. $params['address']['consignee'] .' '. $params['address']['mobile']; $step_text = RefundStatusEnum::getStepStatusText($params['step_status']); $payment_map = PayTypeEnum::getMap(); switch ($params['step_status']) { case RefundStatusEnum::STEP_2: $content = [ $step_text['desc'], '退货地址:' . $return_address ]; break; case RefundStatusEnum::STEP_4: $content = [ $step_text['desc'], '申请退款金额:¥' . $refund->refund_price, '实际退款金额:¥' . $refund->reality_refund_price, '退款方式:' . $payment_map[$params['payment_type']], ]; break; case RefundStatusEnum::STEP_6: $content = [ $step_text['desc'], '申请退款金额:¥' . $refund->refund_price, '实际退款金额:¥' . $refund->reality_refund_price, '退款方式:' . $payment_map[$params['payment_type']], ]; break; case RefundStatusEnum::STEP_8: $content = [ $step_text['desc'], '退货地址:' . $return_address ]; break; case RefundStatusEnum::STEP_10: $content = [ $step_text['desc'], '物流公司:' . $refund->saler_express, '物流编号:' . $refund->saler_express_no, ]; break; case RefundStatusEnum::STEP_NEGATIVE_1: case RefundStatusEnum::STEP_NEGATIVE_2: $content = [ $step_text['desc'], '拒绝理由:' . $params['refund_reason'] ?? '', ]; break; } $step = new OrderRefundStep(); $step->order_refund_id = $refund->id; $step->role = $step_text['role']; $step->content = Json::encode($content); $step->step_num = RefundStatusEnum::getStepNumByStatus($params['step_status']); $step->step_status = $params['step_status']; if (!$step->save()) throw new Exception("退款步骤保存失败,msg=" . $refund->getErrorMessage()); return $params['step_status']; } /** * 商家拒绝售后(暂供应链订单使用) * * @param integer $mall_id * @param integer $id * @param string $reason * @return void */ public static function refuseRefundForChain(int $mall_id, int $id, string $reason = '拒绝售后') { // 售后订单 $refund = OrderRefund::find()->where(['mall_id' => $mall_id, 'id' => $id])->one(); if ($refund->isRefundFinish()) throw new Exception('当前订单已售后'); $refund->refund_status = RefundStatusEnum::FINISH; // 自动维护主订单 OrderDetail::updateAll( [ 'is_feedback' => OrderStatusEnum::getIsFeedbackStatus(RefundStatusEnum::STEP_NEGATIVE_1), 'updated_at' => time() ], ['id' => $refund->order_detail_id] ); $order = Order::getOne([['id' => $refund->order_id]]); $order->is_feedback = OrderStatusEnum::getIsFeedbackStatus(RefundStatusEnum::STEP_NEGATIVE_1); $order->save(); // 保存步骤 $step_status = self::saveStep($refund, [ 'payment_type' => $order->payment_type, 'address' => [ 'address' => '', 'consignee' => '', 'mobile' => '', ], 'step_status' => RefundStatusEnum::STEP_NEGATIVE_1, 'refund_reason' => $reason, ]); // 修改售后信息 $refund->step_status = $step_status; if (!$refund->save()) throw new Exception("保存失败,msg=" . $refund->getErrorMessage()); // 拒绝 - 需要处理ERP if (MallAddons::isInstall($order['mall_id'],AddonsEnum::ADDONS_NAME_WANG_DIAN_TONG)) { (new OrderRefundRejectService())->sync($order['mall_id'], $refund->id); } $event = new OrderRefundChangeEvent($refund->mall_id); $data = []; $data['id'] = $refund->id; $data['step_status'] = RefundStatusEnum::STEP_NEGATIVE_1; Yii::$app->services->events->dispatch($event, $data, $event->listeners); } }