orderOnlineService->doComplete($global_order_id, $user_id); $this->separateAccountsService->orderOnlineCompleted($global_order_id, $user_id); Db::commit(); return [ "status" => 200, "code" => 0, "result" => [], "message" => '处理成功' ]; } catch (\Exception $e) { Db::rollBack(); $this->log->event(LogLabel::ORDER_COMPLETE_LOG, ['jsonrpc_order_service_exception_onlineComplete' => $e->getMessage(), 'params' => json_encode([$global_order_id, $user_id])]); return [ "status" => 200, "code" => $e->getCode() ?? ErrorCode::ORDER_COMPLETE_FAIL, "result" => [], "message" => $e->getMessage() ]; } } /** * 线上订单退款,整个订单退,这个是专门用于处理用户的申请退款的同意退款操作 * @param $global_order_id * @param $user_id * @return array */ public function onlineRefund($global_order_id, $user_id) { try { $result = $this->orderOnlineService->doRefund($global_order_id, $user_id); return [ "status" => 200, "code" => 0, "result" => [], "message" => '处理成功' ]; } catch (\Exception $e) { return [ "status" => 200, "code" => $e->getCode(), "result" => [], "message" => $e->getMessage() ]; } } /** * 线上订单单笔退款,主要用于后台强行操作退单退款 * 支持单商品、单店、整单 * 按比例计算红包进行退款 * 比如:两个子订单和子订单商品,分别是2元,98元,使用了10元优惠券 * 退2元商品时,退款金额为 * 红包 :(2/(98+2))*10 = 0.2 * 退款:2-0.2=1.8元 * @param $user_id *用户ID * @param $global_order_id *全局总订单ID * @param $order_child_id *主订单ID, * @param $order_goods_id *订单商品ID * @param $note * @return array */ public function onlineSingleRefund($user_id, $note, $global_order_id, $order_child_id='', $order_goods_id='') { Db::beginTransaction(); try { $params = [ 'user_id' => $user_id, 'note' => $note, 'global_order_id' => $global_order_id, 'order_child_id' => $order_child_id, 'order_goods_id' => $order_goods_id, ]; if (!$user_id || !$global_order_id || !$note) { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => '参数不对', 'params' => json_encode($params) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } // 主订单 $orderMain = OrderMain::query() ->where(['global_order_id' => $global_order_id, 'user_id' => $user_id]) ->whereIn('state', array_merge(OrderState::CAN_REFUND_DIRECT, [OrderState::REFUNDED_DIRECT])) ->first(); if (is_null($orderMain)) { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => '订单不存在', 'params' => json_encode($params) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } // 子订单 $orderChild = null; if ($order_child_id) { $orderChild = Order::query()->with('store')->where(['order_main_id' => $orderMain->global_order_id, 'id' => $order_child_id])->first(); } // 订单商品 $orderGoods = null; if ($order_goods_id) { if (!$order_child_id || is_null($orderChild)) { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => '子订单参数异常[单品]', 'params' => json_encode($params) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } $orderGoods = OrderGoods::query() ->where(['order_id' => $orderChild->id, 'id' => $order_goods_id, 'status' => 1]) ->first(); if (is_null($orderGoods)) { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => '订单商品参数异常[单品]', 'params' => json_encode($params) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } } $totalAmount = $orderMain->total_money; // 订单可退款金额,总订单金额不含配送费和服务费 $preRefundAmount = 0; // 预退款金额 $refundAmount = 0; // 实际退款金额 $refundType = 'main'; // 退款类型, Main整单 Sub子单 Goods单品 if ($orderGoods) { // 1. 如果订单商品存在则说明要退单品 $preRefundAmount = bcmul($orderGoods->price, $orderGoods->number, 2); $refundType = 'goods'; } elseif ($orderChild) { // 2. 否则如果存在子订单说明退子订单 $preRefundAmount = $orderChild->money; $refundType = 'sub'; } else { // 3. 再则如果存在主订单说明退主订单 $preRefundAmount = $orderMain->total_money; $refundType = 'main'; } // 占订单金额的比例 $rate = bcdiv($preRefundAmount, $totalAmount, 6); // 计算优惠券所占金额 $couponMoney = bcmul($orderMain->coupon_money, $rate, 6); // 计算本次退款实际退款金额 $refundAmount = bcsub($preRefundAmount, $couponMoney, 2); if ($refundAmount <= 0) { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => '没有可退款金额[实际退款金额]', 'params' => json_encode($params) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } // 开始退款 $config = config('wxpay'); $app = Factory::payment($config); $app['guzzle_handler'] = CoroutineHandler::class; $result = $app->refund->byOutTradeNumber( $orderMain->global_order_id, $orderMain->global_order_id.$order_child_id.$order_goods_id, bcmul($orderMain->money, 100, 0), bcmul($refundAmount, 100, 0), [ 'refund_desc' => '订单协商退款[' . $refundType . ']', 'notify_url' => config('wechat.notify_url.refund_single'), ] ); if ($result['return_code'] == 'FAIL') { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => $result['return_msg'] . '[微信退款失败]', 'params' => json_encode($result) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } if ($result['result_code'] == 'FAIL') { $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => $result['err_code_des'] . '[微信退款失败]' . $result['err_code'], 'params' => json_encode($result) ]); throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } // 退款申请成功,查询退款状态,此处暂时无法传递和记录单品退的信息,所以直接查询退款状态处理,不做回调 $refundResult = $app->refund->queryByRefundId($result['refund_id']); $this->log->event(LogLabel::ORDER_REFUND_LOG, [ 'jsonrpc_order_service_exception_onlineSingleRefund' => '[微信退款查询]', 'params' => json_encode($refundResult) ]); // 退款成功 if ( !($refundResult['return_code'] == 'SUCCESS' && isset($refundResult['result_code']) && $refundResult['result_code'] == 'SUCCESS') ) { throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL); } $currentTime = time(); // 处理订单状态 $orderMain->state = OrderState::REFUNDED_DIRECT; $orderMain->total_refund_note = $note; $orderMain->refund_time = $currentTime; $orderMain->save(); if ($refundType == 'sub') { $orderChild->status = 3; $orderChild->refund_note = $note; $orderChild->refund_time = $currentTime; $orderChild->save(); } elseif ($refundType == 'goods') { $orderGoods->status = 3; $orderGoods->refund_note = $note; $orderGoods->refund_time = $currentTime; $orderGoods->save(); } // 处理用户和商户流水 $orderChildren = []; if ($refundType == 'main') { # 整单退的话还得处理所有子订单的商户 $orderChildren = Order::query()->with('store:user_id')->where(['order_main_id' => $orderMain->global_order_id])->get(); foreach ($orderChildren as $key => &$order) { // 占订单金额的比例 $rate = bcdiv($order->money, $totalAmount, 6); // 计算优惠券所占金额 $couponMoney = bcmul($orderMain->coupon_money, $rate, 6); // 计算本次退款实际退款金额 $refundStoreAmount = bcsub($order->money, $couponMoney, 2); $this->financialRecordService->storeRefundDirect($order->store->user_id, $order->id, $refundStoreAmount); $this->miniprogramService->subscribeMsgForSingleRefund($order->id, $refundStoreAmount, '', $note); } } elseif ($refundType == 'sub'||$refundType == 'goods') { # 退子订单或者退单品的话,商户只有一个 $orderChildren = Order::query()->with('store:user_id')->where(['id' => $order_child_id])->get(); $this->financialRecordService->storeRefundDirect($orderChild->store->user_id, $orderChild->id, $refundAmount); $orderGoodsId = $order_goods_id ?: ''; $this->miniprogramService->subscribeMsgForSingleRefund($order_child_id, $refundAmount, $orderGoodsId, $note); } $this->financialRecordService->userRefundDirect($orderMain->user_id, $orderMain->global_order_id, $refundAmount); Db::commit(); // 记录badge $orderChildIds = array_values(array_column($orderChildren->toArray(), 'store_id')); $this->badgeService->doByOrder($orderMain->user_id, $orderChildIds, $orderMain->global_order_id, OrderState::REFUNDED); return [ "status" => 200, "code" => 0, "result" => [], "message" => '处理成功' ]; } catch (\Exception $e) { Db::rollBack(); return [ "status" => 200, "code" => $e->getCode(), "result" => [], "message" => '[退款失败]'.$e->getMessage() ]; } } /** * 配送开始的时候,管理后台点击配送并分配配送员 * 做一些处理: * 1、发送订阅消息给用户 * 2、发送订阅消息给骑手 * @param $global_order_id */ public function onlineDeliveryStart($global_order_id) { try { $this->miniprogramService->subscribeMsgForDeliveryStart($global_order_id); return [ "status" => 200, "code" => 0, "result" => [], "message" => '处理成功' ]; } catch (\Exception $e) { return [ "status" => 200, "code" => $e->getCode(), "result" => [], "message" => $e->getMessage() ]; } } }