orderInfo = match ($this->orderType) { OrderCode::ORDER_TYPE_GOOD => $this->orderModel->getInfoById($this->orderId), // OrderCode::ORDER_TYPE_BALANCE => $this->orderModel->getInfoById($this->orderId), default => null, }; } /** * @var array */ protected array $orderGoodList; /** * @var string */ protected string $totalGoodsPrice = '0'; /** * @return void * @throws Exception */ protected function checkGoodOrder(): void { if (empty($this->orderInfo)) throw new Exception('订单信息不存在:'.json_encode(['order_id' => $this->orderId,'order_type' => $this->type])); if (!in_array($this->orderInfo->status,OrderCode::CAN_REFUND_STATUS)) throw new Exception('订单状态不能退款:'.json_encode($this->orderInfo->toArray())); //余额订单必须退款全部金额 // if ($this->type == OrderCode::ORDER_TYPE_BALANCE && $this->refundAmount != $this->orderInfo->actual_price) throw new Exception('余额订单必须退款全部金额:'.json_encode($this->orderInfo->toArray())); if ($this->type != RefundCode::PARTIAL_GOOD_REFUND) return; if (empty($this->orderGoodIds)) throw new Exception('商品信息不存在:'.json_encode(['order_id' => $this->orderId,'order_type' => $this->type,'goods_list' => $this->orderGoodIds])); $orderGoodList = $this->orderGoodModel->whereIn('id',$this->orderGoodIds)->where('order_id',$this->orderId)->get(); if ($orderGoodList->isEmpty()) throw new Exception('该订单没有这些商品信息:'.json_encode(['order_id' => $this->orderId,'order_type' => $this->type,'goods_list' => $this->orderGoodIds])); $this->orderGoodList = $orderGoodList->toArray(); unset($orderGoodList); //todo 优惠券信息没有看 foreach ($this->orderGoodList as $orderGood) { if (!in_array($orderGood['status'],OrderCode::CAN_REFUND_STATUS)) throw new Exception('商品状态不能退款:'.json_encode(['order_info' => $this->orderInfo->toArray(),'order_good' => $orderGood,'goods_list' => $this->orderGoodIds])); $oneGoodTotalPrice = bcmul((string)$orderGood['unit_price'],(string)$orderGood['quantity'],2); $this->totalGoodsPrice = bcadd($this->totalGoodsPrice, $oneGoodTotalPrice,2) ; } } /** * @return void * @throws Exception */ protected function getPayOrder(): void { $this->payInfo = $this->payOrderModel->getInfoByOrderIdAndType($this->orderId, $this->orderType); if (empty($this->payInfo)) throw new Exception('支付信息不存在'); } /** * @return void * @throws Exception */ protected function getRefundAmount(): void { $this->refundAmount = match ($this->type) { RefundCode::BALANCE_REFUND => $this->getBalanceRefundAmount(), RefundCode::FULL_GOOD_REFUND => $this->getFullGoodRefundAmount(), RefundCode::PARTIAL_GOOD_REFUND => $this->getPartialGoodAmount(), default => throw new Exception('退款类型错误'), }; if ($this->refundAmount <= 0) throw new Exception('退款金额不能为0'); } /** * @var RefundOrder */ #[Inject] protected RefundOrder $refundOrderModel; private function getBalanceRefundAmount(): float { $isRefundMoney = $this->refundOrderModel->getAllMoneyByOrderId($this->orderInfo->id,OrderCode::ORDER_TYPE_GOOD); return $this->payInfo->pay_money - $isRefundMoney; } /** * @return float */ private function getFullGoodRefundAmount(): float { $isRefundMoney = $this->refundOrderModel->getAllMoneyByOrderId($this->orderInfo->id,OrderCode::ORDER_TYPE_GOOD); // 部分退款会验证 pay_money != order_money throw error 所以不需要判断 return $this->payInfo->pay_money - $isRefundMoney; } protected UserCoupon $userCouponModel; /** * @return float * @throws Exception */ private function getPartialGoodAmount(): float { if ($this->totalGoodsPrice <= 0) throw new Exception('商品退款价格不能为0'); // 部分退款 不支持 价格不一致 if ($this->payInfo->pay_money != $this->orderInfo->actual_price) throw new Exception('价格不一致的订单无法部分退款'); $isRefundMoney = $this->refundOrderModel->getSuccessMoneyByOrderId($this->orderInfo->id,OrderCode::ORDER_TYPE_GOOD); return floatval(min($this->payInfo->pay_money - $isRefundMoney,$this->totalGoodsPrice)); } /** * @var RefundOrder */ protected RefundOrder $refundInfo; /** * @return void * @throws Exception */ protected function insertRefundOrder(): void { $this->refundInfo = new RefundOrder(); $this->refundInfo->user_id = $this->orderInfo->user_id; $this->refundInfo->action_admin_id = $this->adminId; $this->refundInfo->order_type = OrderCode::ORDER_TYPE_GOOD; $this->refundInfo->order_id = $this->orderId; $this->refundInfo->pay_id = $this->payInfo->id; $this->refundInfo->type = $this->type; if ($this->type == RefundCode::PARTIAL_GOOD_REFUND) $this->refundInfo->good_ids = json_encode($this->orderGoodIds); $this->refundInfo->refund_status = RefundCode::WAIT_REFUND; $this->refundInfo->refund_money = $this->refundAmount; $this->refundInfo->refund_type = $this->payInfo->recharge_type; $this->refundInfo->refund_order_sno = $this->generateRefundOrderNo(OrderCode::ORDER_TYPE_GOOD, $this->orderInfo->user_id); $this->refundInfo->reason = $this->reason; if (!$this->refundInfo->save()) throw new Exception('退款订单创建失败'); } /** * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function refund(): void { $rechargeService = match ($this->refundInfo->refund_type) { PayCode::ALIPAY => $this->setAliPayRefund(), PayCode::WECHAT_PAY => $this->setWechatPayRefund(), }; $rechargeService->setConfig(); $rechargeService->setRefundNotify(); $rechargeService->refund( $this->refundAmount, (float)$this->payInfo->pay_money, $this->orderInfo->order_sno, $this->refundInfo->refund_order_sno, ); } /** * @return void * @throws Exception */ protected function updateRefund(): void { $status = RefundCode::WAIT_BY_PAY_TOOL; $errMsg = '等待支付工具退款'; $this->refundInfo->refund_status = $status; $this->refundInfo->remark = $errMsg; if (!$this->refundInfo->save()) throw new Exception('退款订单更新失败'); } /** * @param string $errMsg * @return void * @throws Exception */ protected function updateError(string $errMsg = ''): void { if (empty($this->refundInfo)) return; $status = RefundCode::REFUND_FAIL; $errMsg = empty($errMsg) ? '未知错误' : $errMsg; $this->refundInfo->refund_status = $status; $this->refundInfo->remark = $errMsg; if (!$this->refundInfo->save()) throw new Exception('退款订单更新失败'); } /** * @return null */ protected function setAliPayRefund(): null { return null; } /** * @return WxJsRechargeOrderService */ protected function setWechatPayRefund(): WxJsRechargeOrderService { return new WxJsRechargeOrderService(); } }