From f9d3511ed6804e044262744ce3e3914cf1e1183f Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Thu, 27 Mar 2025 10:47:31 +0800 Subject: [PATCH] feat : refund --- app/Amqp/Consumer/OrderGoodStockConsumer.php | 92 +++++++++++++++++-- app/Model/RefundOrder.php | 5 +- .../Amqp/Refund/BaseRefundOrderService.php | 6 ++ .../Refund/RefundGoodOrderFinishService.php | 19 +++- app/Service/Api/Order/PlaceOrderService.php | 1 - app/Service/Api/Order/RefundOrderService.php | 22 +++-- app/Service/ServiceTrait/Api/OrderTrait.php | 6 +- 7 files changed, 128 insertions(+), 23 deletions(-) diff --git a/app/Amqp/Consumer/OrderGoodStockConsumer.php b/app/Amqp/Consumer/OrderGoodStockConsumer.php index 224ba81..2ac1ecb 100644 --- a/app/Amqp/Consumer/OrderGoodStockConsumer.php +++ b/app/Amqp/Consumer/OrderGoodStockConsumer.php @@ -4,12 +4,14 @@ declare(strict_types=1); namespace App\Amqp\Consumer; +use App\Cache\Redis\Api\ApiRedisKey; use App\Constants\Common\OrderCode; use App\Lib\Log; use App\Model\Order; use App\Model\OrderGood; use App\Model\Sku; use App\Service\ServiceTrait\Api\OrderTrait; +use App\Service\ServiceTrait\Common\CycleTrait; use App\Service\ServiceTrait\Common\StockTrait; use Exception; use Hyperf\Amqp\Message\Type; @@ -18,6 +20,7 @@ use Hyperf\Amqp\Annotation\Consumer; use Hyperf\Amqp\Message\ConsumerMessage; use Hyperf\DbConnection\Db; use Hyperf\Di\Annotation\Inject; +use Hyperf\Redis\Redis; use PhpAmqpLib\Message\AMQPMessage; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -27,6 +30,7 @@ use Throwable; class OrderGoodStockConsumer extends ConsumerMessage { use StockTrait; + use CycleTrait; /** * @var Type|string 消息类型 @@ -51,6 +55,18 @@ class OrderGoodStockConsumer extends ConsumerMessage #[Inject] protected Sku $skuModel; + /** + * @var Order + */ + #[Inject] + protected Order $orderModel; + + /** + * @var Order + */ + protected Order $orderInfo; + + /** * @var array */ @@ -66,6 +82,11 @@ class OrderGoodStockConsumer extends ConsumerMessage */ private array $updateArr; + /** + * @var array + */ + private array $reduceStockCache = []; + /** * @param $data * @param AMQPMessage $message @@ -81,9 +102,22 @@ class OrderGoodStockConsumer extends ConsumerMessage } $orderId = (int)$data['order_id']; + $this->orderInfo = $this->orderModel->getInfoById($orderId); + + if ($this->orderInfo->cycle_id != $this->initTodayCycleId()) { + $this->log->error('OrderGoodStockConsumer:error:cycleIdError:'.json_encode([ + 'order_id' => $orderId, + 'cycle_id' => $this->initTodayCycleId(), + 'order' => $this->orderInfo->toArray(), + ])); + return Result::ACK; + } + $this->orderGoodArr = []; $this->skuArr = []; + + $this->orderGoodArr = $this->orderGoodModel->getGoodIdsByOrderId($orderId); // $this->log->debug('OrderGoodStockConsumer:'.json_encode($this->orderGoodArr)); if (empty($this->orderGoodArr)) { @@ -101,11 +135,11 @@ class OrderGoodStockConsumer extends ConsumerMessage $this->updateArr = []; try { - //todo 是否做个优化 截单后 不再增加库存 + // 是否做个优化 截单后 不再增加库存 match ($data['type']) { OrderCode::WAIT_PAY => $this->waitPaySubStock(), OrderCode::CANCEL => $this->cancelAddStock(), -// OrderCode::FINISH_REFUND,OrderCode::UNCOMPLETED_REFUND => $this->RefundUpdateData($data),//todo 退款后 库存不回收 因为存在退款一部分 无法核查 + OrderCode::FINISH_REFUND => $this->RefundUpdateData(),// 用户退款后 库存回收 后台操作不回收 因为存在退款一部分 无法核查 default => throw new Exception('OrderGoodStockConsumer:error:无效的订单类型') }; @@ -131,13 +165,53 @@ class OrderGoodStockConsumer extends ConsumerMessage return Result::ACK; } + + + return Result::ACK; } catch (Exception $e) { + if (!empty($this->rollbackStockCache)) { + foreach ($this->rollbackStockCache as $goodId => $stock) { + $this->redis->zIncrBy($this->stockKey,-$stock,$goodId); + } + } + $this->log->error($e->getMessage()); return Result::ACK; } } + /** + * @var Redis + */ + #[Inject] + protected Redis $redis; + + /** + * @var array + */ + private array $rollbackStockCache = []; + + /** + * @var string + */ + private string $stockKey; + + private function stockCacheAction() + { + $this->stockKey = ApiRedisKey::goodStockKey($this->orderInfo->cycle_id,$this->orderInfo->kitchen_id); + if (empty($this->reduceStockCache)) return; + + $this->rollbackStockCache = []; + + foreach ($this->reduceStockCache as $goodId => $stock) { + $this->rollbackStockCache[$goodId] = $stock; + if (!($this->redis->zIncrBy($this->stockKey,$stock,$goodId))) { + throw new Exception('cache error'); + } + } + } + /** * @return void */ @@ -154,21 +228,19 @@ class OrderGoodStockConsumer extends ConsumerMessage } /** - * @param $data * @return void - * @throws Exception */ - private function RefundUpdateData($data): void + private function RefundUpdateData(): void { - if (empty($data['refund_goods'])) throw new Exception('OrderGoodStockConsumer:error:UpdateSkuDataFail:'.json_encode($data)); - - foreach ($data['refund_goods'] as $orderGood) { + foreach ($this->orderGoodArr as $orderGood) { $this->updateArr[] = [ 'id' => $orderGood['sku_id'], - 'refund_num' => ($this->skuArr[$orderGood['sku_id']]['refund_num'] ?? 0) + $orderGood['quantity'], + 'refund_num' => ($this->skuArr[$orderGood['sku_id']]['cancel_num'] ?? 0) + $orderGood['quantity'], 'order_num' => ($this->skuArr[$orderGood['sku_id']]['order_num'] ?? 0) - $orderGood['quantity'], 'surplus_stock' => ($this->skuArr[$orderGood['sku_id']]['surplus_stock'] ?? 0) + $orderGood['quantity'], ]; + + $this->reduceStockCache[$orderGood['sku_id']] = $orderGood['quantity'] + ($this->reduceStockCache[$orderGood['sku_id']] ?? 0); } } @@ -184,6 +256,8 @@ class OrderGoodStockConsumer extends ConsumerMessage 'order_num' => ($this->skuArr[$orderGood['sku_id']]['order_num'] ?? 0) - $orderGood['quantity'], 'surplus_stock' => ($this->skuArr[$orderGood['sku_id']]['surplus_stock'] ?? 0) + $orderGood['quantity'], ]; + + $this->reduceStockCache[$orderGood['sku_id']] = $orderGood['quantity'] + ($this->reduceStockCache[$orderGood['sku_id']] ?? 0); } } } diff --git a/app/Model/RefundOrder.php b/app/Model/RefundOrder.php index 5a1887d..3e78b93 100644 --- a/app/Model/RefundOrder.php +++ b/app/Model/RefundOrder.php @@ -11,7 +11,8 @@ use Hyperf\DbConnection\Model\Model; /** * @property int $id - * @property int $user_id + * @property int $user_id + * @property int $action_admin_id * @property int $order_type * @property int $type * @property int $order_id @@ -48,7 +49,7 @@ class RefundOrder extends Model /** * The attributes that should be cast to native types. */ - protected array $casts = ['id' => 'integer', 'user_id' => 'integer', 'order_type' => 'integer', 'order_id' => 'integer', 'pay_id' => 'integer', 'refund_status' => 'integer', 'refund_type' => 'integer', 'admin_id' => 'integer']; + protected array $casts = ['id' => 'integer', 'user_id' => 'integer','action_admin_id' => 'integer', 'order_type' => 'integer', 'order_id' => 'integer', 'pay_id' => 'integer', 'refund_status' => 'integer', 'refund_type' => 'integer', 'admin_id' => 'integer']; const string CREATED_AT = 'create_time'; const string UPDATED_AT = 'update_time'; diff --git a/app/Service/Amqp/Refund/BaseRefundOrderService.php b/app/Service/Amqp/Refund/BaseRefundOrderService.php index 5ef9b49..b0a3566 100644 --- a/app/Service/Amqp/Refund/BaseRefundOrderService.php +++ b/app/Service/Amqp/Refund/BaseRefundOrderService.php @@ -44,6 +44,11 @@ abstract class BaseRefundOrderService */ public int $type; + /** + * @var int + */ + public int $adminId = 0; + /** * @var array */ @@ -213,6 +218,7 @@ abstract class BaseRefundOrderService $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; diff --git a/app/Service/Amqp/Refund/RefundGoodOrderFinishService.php b/app/Service/Amqp/Refund/RefundGoodOrderFinishService.php index 9afa89a..bc5f18f 100644 --- a/app/Service/Amqp/Refund/RefundGoodOrderFinishService.php +++ b/app/Service/Amqp/Refund/RefundGoodOrderFinishService.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace App\Service\Amqp\Refund; +use App\Constants\Common\RefundCode; use App\Event\RefundGoodOrderFinishEvent; use App\Lib\Log; use App\Model\Order; @@ -103,11 +104,23 @@ class RefundGoodOrderFinishService $this->manageSubCateringLog(); }); - if ($this->rollBackStockFlag) { - $this->sendStockMq($this->orderInfo->id,$this->orderInfo->status); - } $this->eventDispatcher->dispatch(new RefundGoodOrderFinishEvent($this->orderInfo->id, $this->payInfo->id, $this->refundInfo->id)); } + + /** + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + private function rollBackStock(): void + { + if (!$this->rollBackStockFlag) return; + + //判断是不是用户行为才退库存 + if ($this->refundInfo->action_admin_id != 0) return; + + $this->sendStockMq($this->orderInfo->id,$this->orderInfo->status); + } } \ No newline at end of file diff --git a/app/Service/Api/Order/PlaceOrderService.php b/app/Service/Api/Order/PlaceOrderService.php index c6443e3..391ab5c 100644 --- a/app/Service/Api/Order/PlaceOrderService.php +++ b/app/Service/Api/Order/PlaceOrderService.php @@ -97,7 +97,6 @@ class PlaceOrderService extends BaseOrderService foreach ($this->cartFirstData as $goodId => $stock) { $this->rollbackStockCache[$goodId] = $stock; if (!($this->redis->zIncrBy($this->stockKey,-$stock,$goodId))) { - echo '123'; throw new Exception('cache error'); } } diff --git a/app/Service/Api/Order/RefundOrderService.php b/app/Service/Api/Order/RefundOrderService.php index 5c03e89..e7e7e04 100644 --- a/app/Service/Api/Order/RefundOrderService.php +++ b/app/Service/Api/Order/RefundOrderService.php @@ -15,8 +15,10 @@ use App\Constants\Common\RefundCode; use App\Exception\ErrException; use App\Model\Order; use App\Model\PayOrder; +use App\Service\Amqp\Refund\FullRefundOrderService; use App\Service\Api\BaseService; use App\Service\ServiceTrait\Common\OrderChangeStatusTrait; +use Exception; use Hyperf\Di\Annotation\Inject; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -46,18 +48,26 @@ class RefundOrderService extends BaseService { //todo 考虑是否枷锁 $orderId = (int)$this->request->input('order_id'); - $type = (int)$this->request->input('order_type'); $orderInfo = $this->orderModel->getInfoById($orderId); + if ($orderInfo->user_id != $this->userId) throw new ErrException('该订单不是您的订单,请勿操作'); + if ($orderInfo->status != OrderCode::PAYED) throw new ErrException('该订单状态已变更,请勿重复操作,刷新后无法退款请联系客服'); - $payInfo = $this->payOrderModel->getInfoByOrderIdAndType($orderInfo->id,OrderCode::ORDER_TYPE_GOOD); - if (empty($payInfo)) throw new ErrException('订单支付信息不存在'); + try { + $orderId = (int)$this->request->input('order_id'); - //立即取消 - $this->joinRefundQueue($orderId, RefundCode::FULL_GOOD_REFUND, '用户主动取消订单'); + $service = new FullRefundOrderService(); + $service->orderId = $orderId; + $service->reason = '用户主动退款订单'; + $service->type = RefundCode::FULL_GOOD_REFUND; - return $this->return->success(); + $service->handle(); + + return $this->return->success(); + }catch (Exception $e) { + throw new ErrException($e->getMessage()); + } } } \ No newline at end of file diff --git a/app/Service/ServiceTrait/Api/OrderTrait.php b/app/Service/ServiceTrait/Api/OrderTrait.php index 2956f27..ec6f15c 100644 --- a/app/Service/ServiceTrait/Api/OrderTrait.php +++ b/app/Service/ServiceTrait/Api/OrderTrait.php @@ -365,15 +365,17 @@ trait OrderTrait /** * @param int $orderId * @param int $orderStatus + * @param array $refundGoodIds * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ - protected function sendStockMq(int $orderId,int $orderStatus): void + protected function sendStockMq(int $orderId,int $orderStatus,array $refundGoodIds = []): void { $message = new OrderGoodStockProducer([ 'order_id' => $orderId, - 'type' => $orderStatus + 'type' => $orderStatus, + 'refund_goods' => $refundGoodIds ]); $producer = ApplicationContext::getContainer()->get(Producer::class); $producer->produce($message);