| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- <?php
- namespace addons\UpgradeGift\common\logic\order;
- use addons\Store\common\models\StoreGoodsReserve;
- use addons\Store\common\models\StoreOrder;
- use addons\Store\common\models\StoreOrderDetail;
- use addons\Store\common\models\StoreOrderMarketing;
- use addons\ValetOrder\common\service\OrderService;
- use addons\WangDianTong\common\service\OrderRefundRejectService;
- use addons\CardCoupons\common\models\CardCouponsScoreGive;
- use common\enums\AddonsEnum;
- use common\enums\EventNameEnum;
- use common\enums\OrderSourceEnum;
- use common\enums\OrderStatusEnum;
- use common\enums\PaymentTradeOrderEnum;
- use common\enums\RefundStatusEnum;
- use common\enums\RefundTypeEnum;
- use common\enums\StatusEnum;
- use common\enums\UserWalletEnum;
- use common\events\order\OrderRefundChangeEvent;
- use common\events\order\OrderRefundFinishEvent;
- use common\events\order\OrderRefundUpdateEvent;
- use common\logic\statistics\StatisticsHandle;
- use common\logic\wechat\WechatMessageLogic;
- use common\models\common\PaymentTrade;
- use common\models\common\PaymentTradeOrder;
- use common\models\goods\GoodsReserve;
- use common\models\mall\MallAddons;
- use common\models\order\Order;
- use common\models\order\OrderDetail;
- use common\models\order\OrderMarketing;
- use common\models\order\OrderRefund;
- use common\models\order\OrderRefundStep;
- use common\models\common\Addons;
- use common\traits\ErrorTrait;
- use Yii;
- use Exception;
- use services\common\UserWalletService;
- use yii\helpers\Json;
- use common\enums\PayTypeEnum;
- use common\globals\GlobalInvoke;
- use services\common\ThirdPartyRefundService;
- /**
- * 售后订单处理
- * Class OrderRefundLogic
- * @Author: lun
- * @DateTime: 2021/10/11 0011 14:11
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @package addons\UpgradeGift\common\logic\order
- */
- class OrderRefundLogic
- {
- use ErrorTrait;
- /**
- * 售后处理
- * @Author: lun
- * @DateTime: 2021/10/11 0011 15:55
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $mallId
- * @param $refundId
- * @param $stepStatus
- * @return string
- */
- public function execute($mallId, $params)
- {
- $trans = Yii::$app->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);
- }
- }
|