Quellcode durchsuchen

优化礼品卡,删掉多余无用代码

llp vor 5 Tagen
Ursprung
Commit
b7db8e7104

+ 33 - 15
packages/Longyi/Gift/src/Listeners/OrderCancelHandler.php

@@ -16,37 +16,55 @@ class OrderCancelHandler
      */
     public function afterCancelOrder($order)
     {
-        if (!$order) {
+        if (! $order || ! $order->giftcard_number) {
             return;
         }
 
-        // 检查订单是否使用了礼品卡
-        if (!$order->giftcard_number || !$order->giftcard_amount || $order->giftcard_amount <= 0) {
+        // 以订单固化的 base 金额回补,缺失时退回用当前币种转换(保持兼容)
+        $refundAmount = (float) ($order->base_giftcard_amount ?? 0);
+        if ($refundAmount <= 0) {
+            $refundAmount = (float) core()->convertToBasePrice($order->giftcard_amount ?? 0);
+        }
+
+        if ($refundAmount <= 0) {
             return;
         }
 
         $giftCardNumber = $order->giftcard_number;
-        $refundAmount = core()->convertToBasePrice($order->giftcard_amount);
 
-        // 查找礼品卡
         $giftCard = GiftCards::where('giftcard_number', $giftCardNumber)->first();
 
-        if (!$giftCard) {
+        if (! $giftCard) {
             return;
         }
-        // 记录退款前余额
-        $balanceBefore = $giftCard->remaining_giftcard_amount;
-        // 恢复礼品卡余额
-        $giftCard->used_giftcard_amount = max(0, $giftCard->used_giftcard_amount - $refundAmount);
-        $giftCard->remaining_giftcard_amount += $refundAmount;
 
-        // 恢复状态为未使用
-        if ($giftCard->remaining_giftcard_amount > 0) {
-            $giftCard->giftcard_status = 1; // 未使用
+        // 幂等:同一订单已经退过款就不再重复回补(force 取消 / 重试场景)
+        $alreadyRefunded = GiftCardUsageLog::where('order_id', $order->id)
+            ->where('giftcard_number', $giftCardNumber)
+            ->where('action_type', GiftCardUsageLog::ACTION_REFUND)
+            ->exists();
+
+        if ($alreadyRefunded) {
+            return;
+        }
+
+        $balanceBefore = (float) $giftCard->remaining_giftcard_amount;
+
+        $giftCard->used_giftcard_amount = max(0, (float) $giftCard->used_giftcard_amount - $refundAmount);
+        // 回补封顶到卡面额,防止重复/异常退款把余额补超
+        $giftCard->remaining_giftcard_amount = min(
+            (float) $giftCard->giftcard_amount,
+            (float) $giftCard->remaining_giftcard_amount + $refundAmount
+        );
+
+        if ((float) $giftCard->remaining_giftcard_amount > 0) {
+            $giftCard->giftcard_status = $giftCard->isExpired()
+                ? GiftCards::STATUS_EXPIRED
+                : GiftCards::STATUS_UNUSED;
         }
 
         $giftCard->save();
-        // 记录退款日志
+
         GiftCardUsageLog::create([
             'giftcard_number' => $giftCardNumber,
             'customer_id' => $giftCard->customer_id,

+ 24 - 20
packages/Longyi/Gift/src/Listeners/OrderPlacedHandler.php

@@ -16,37 +16,41 @@ class OrderPlacedHandler
      */
     public function afterPlaceOrder($order)
     {
-        if (!$order || !$order->cart) {
+        if (! $order || ! $order->giftcard_number) {
             return;
         }
-        $cart = $order->cart;
-        // 检查订单是否使用了礼品卡
-        if (!$cart->giftcard_number || !$cart->giftcard_amount || $cart->giftcard_amount <= 0) {
+
+        // 以订单固化的 base 金额扣款(不再事后重查购物车),避免 cart 与 order 不同步时错账
+        $giftCardNumber = $order->giftcard_number;
+        $usedAmount = (float) ($order->base_giftcard_amount ?? 0);
+
+        if ($usedAmount <= 0) {
             return;
         }
-        $giftCardNumber = $cart->giftcard_number;
-        $usedAmount = core()->convertToBasePrice($cart->giftcard_amount);
 
-        // 查找礼品卡
-        $giftCard = GiftCards::where('giftcard_number', $giftCardNumber)->first();
-        if (!$giftCard) {
+        // 行锁:防止同一张卡并发下单被双花(checkout.order.save.after 在订单事务内派发)
+        $giftCard = GiftCards::where('giftcard_number', $giftCardNumber)->lockForUpdate()->first();
+
+        if (! $giftCard) {
             return;
         }
-        // 检查余额是否足够
-        if ($giftCard->remaining_giftcard_amount < $usedAmount) {
+
+        // 余额不足则放弃抵扣(极端并发下的兜底)
+        if ((float) $giftCard->remaining_giftcard_amount < $usedAmount) {
             return;
         }
-        // 记录使用前余额
-        $balanceBefore = $giftCard->remaining_giftcard_amount;
-        // 扣除礼品卡余额
-        $giftCard->used_giftcard_amount += $usedAmount;
-        $giftCard->remaining_giftcard_amount -= $usedAmount;
-        // 如果余额为0,标记为已使用
-        if ($giftCard->remaining_giftcard_amount <= 0) {
-            $giftCard->giftcard_status = 2; // 已使用
+
+        $balanceBefore = (float) $giftCard->remaining_giftcard_amount;
+
+        $giftCard->used_giftcard_amount = (float) $giftCard->used_giftcard_amount + $usedAmount;
+        $giftCard->remaining_giftcard_amount = (float) $giftCard->remaining_giftcard_amount - $usedAmount;
+
+        if ((float) $giftCard->remaining_giftcard_amount <= 0) {
+            $giftCard->giftcard_status = GiftCards::STATUS_USED;
         }
+
         $giftCard->save();
-        // 记录使用日志
+
         GiftCardUsageLog::create([
             'giftcard_number' => $giftCardNumber,
             'customer_id' => $giftCard->customer_id,

+ 3 - 22
packages/Longyi/Gift/src/Services/GiftCardService.php

@@ -10,10 +10,8 @@ class GiftCardService
     /**
      * 激活礼品卡
      */
-    public function activate(string $code, ?int $customerId = null): void
+    public function activate(string $code, int $customerId): void
     {
-        $customerId = $customerId ?? auth()->user()?->id;
-
         if (! $customerId) {
             throw new \Exception('Customer not authenticated.');
         }
@@ -49,27 +47,10 @@ class GiftCardService
      */
     public function remove(?int $customerId = null): void
     {
-        $customerId = $customerId ?? auth()->user()?->id;
-
-        $cart = Cart::getCart();
-
+        // 移除只是清掉购物车上的卡标记,不回补余额:余额在下单时才扣,
+        // 下单前移除无需回补,否则会把历史已用余额清零。
         GiftCards::removeGiftCardCode();
 
         Cart::collectTotals();
-
-        if ($cart->giftcard_number && $customerId) {
-            $giftCard = GiftCards::where(
-                'giftcard_number',
-                $cart->giftcard_number
-            )
-            ->where('customer_id', $customerId)
-            ->first();
-
-            if ($giftCard) {
-                $giftCard->used_giftcard_amount = 0;
-                $giftCard->remaining_giftcard_amount = $giftCard->giftcard_amount;
-                $giftCard->save();
-            }
-        }
     }
 }

+ 14 - 5
packages/Webkul/BagistoApi/src/State/SaveCheckoutCartProcessor.php

@@ -202,15 +202,24 @@ class SaveCheckoutCartProcessor implements ProcessorInterface
             return;
         }
 
-        if (Cart::getCart()?->giftcard_number === $code) {
-            return;
-        }
-
         if (! $customerId) {
             throw new OperationFailedException(__('bagistoapi::app.graphql.checkout.customer-not-found'));
         }
 
-        $this->giftCardService->activate($code, $customerId);
+        if (Cart::getCart()?->giftcard_number === $code) {
+            // 卡已应用,仍校验其当前是否可用(可能已过期/被删/没余额),不可用则移除
+            $giftCard = GiftCards::where('giftcard_number', $code)
+                ->where('customer_id', $customerId)
+                ->first();
+
+            if (! $giftCard || $giftCard->isExpired() || (float) $giftCard->remaining_giftcard_amount <= 0) {
+                $this->giftCardService->remove($customerId);
+            }
+
+            return;
+        }
+
+        $this->giftCardService->activate($code, (int) $customerId);
     }
 
     /**

+ 9 - 2
packages/Webkul/BagistoApi/src/Transformers/ExpressOrderResource.php

@@ -36,8 +36,10 @@ class ExpressOrderResource extends JsonResource
         $baseSubTotal = (float) ($this->base_sub_total ?? $subTotal);
         $discount = (float) ($this->discount_amount ?? 0);
         $baseDiscount = (float) ($this->base_discount_amount ?? $discount);
-        $grandTotal = max(0, $subTotal - $discount);
-        $baseGrandTotal = max(0, $baseSubTotal - $baseDiscount);
+        $giftcard = (float) ($this->giftcard_amount ?? 0);
+        $baseGiftcard = (float) ($this->base_giftcard_amount ?? $giftcard);
+        $grandTotal = max(0, $subTotal - $discount - $giftcard);
+        $baseGrandTotal = max(0, $baseSubTotal - $baseDiscount - $baseGiftcard);
 
         return [
             'cart_id'                  => $this->id,
@@ -69,6 +71,11 @@ class ExpressOrderResource extends JsonResource
             'applied_cart_rule_ids'    => $this->applied_cart_rule_ids,
             'discount_amount'          => $discount,
             'base_discount_amount'     => $baseDiscount,
+            $this->mergeWhen($this->giftcard_number, [
+                'giftcard_number'      => $this->giftcard_number,
+                'giftcard_amount'      => $giftcard,
+                'base_giftcard_amount' => $baseGiftcard,
+            ]),
             $this->mergeWhen($this->shipping_insurance_amount && $this->shipping_insurance_amount > 0, [
                 'shipping_insurance_amount'      => $this->shipping_insurance_amount,
                 'base_shipping_insurance_amount' => $this->base_shipping_insurance_amount,