Преглед изворни кода

Merge branch 'dev-rewardPoints' into dev

bianjunhui пре 6 дана
родитељ
комит
af32c4f3a8

+ 3 - 3
packages/Longyi/RewardPoints/src/Http/Controllers/Admin/TransactionController.php

@@ -62,7 +62,7 @@ class TransactionController extends Controller
         if ($viewType === 'earned') {
             $query->where('amount', '>', 0);
         } elseif ($amountType === 'earned') {
-            $query->where('amount', '>', 0);
+            $query->where('amount', '>', 0)->where('status',1);
         } elseif ($amountType === 'redeemed') {
             $query->where('amount', '<', 0);
         }
@@ -71,11 +71,11 @@ class TransactionController extends Controller
 
         // 统计数据 - 根据视图类型调整
         if ($viewType === 'earned') {
-            $totalEarned = (clone $query)->sum('amount');
+            $totalEarned = (clone $query)->where('status',1)->sum('amount');
             $totalRedeemed = 0;
             $totalTransactions = (clone $query)->count();
         } else {
-            $totalEarned = (clone $query)->where('amount', '>', 0)->sum('amount');
+            $totalEarned = (clone $query)->where('status',1)->where('amount', '>', 0)->sum('amount');
             $totalRedeemed = abs((clone $query)->where('amount', '<', 0)->sum('amount'));
             $totalTransactions = (clone $query)->count();
         }

+ 145 - 135
packages/Longyi/RewardPoints/src/Listeners/CustomerEvents.php

@@ -8,176 +8,70 @@ use Longyi\RewardPoints\Models\RewardActiveRule;
 use Webkul\Customer\Models\Customer;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Cache;
+use Carbon\Carbon;
+
 class CustomerEvents
 {
-    protected $rewardPointRepository;
+    protected RewardPointRepository $rewardPointRepository;
 
     public function __construct(RewardPointRepository $rewardPointRepository)
     {
         $this->rewardPointRepository = $rewardPointRepository;
     }
 
-    public function handleCustomerRegistration($event)
+    public function handleCustomerRegistration($event): void
     {
-
-        // 检查事件参数类型
-        if (is_object($event) && method_exists($event, 'getAttribute')) {
-            $customer = $event;
-        } elseif (is_array($event) && isset($event['customer'])) {
-            $customer = $event['customer'];
-        } elseif (is_array($event) && isset($event['id'])) {
-            $customer = Customer::find($event['id']);
-        } elseif (is_int($event) || is_string($event)) {
-            $customer = Customer::find($event);
-        } else {
-            $customer = $event;
-        }
-
+        $customer = $this->resolveCustomer($event);
         if (!$customer) {
             Log::warning('Customer not found in registration event');
             return;
         }
 
-        // 查询注册规则
-        $registrationRule = RewardActiveRule::where('type_of_transaction', RewardActiveRule::TYPE_REGISTRATION)
-            ->where('status', 1)
-            ->first();
-
-        // 查询订阅规则
-        $subscribeRule = RewardActiveRule::where('type_of_transaction', RewardActiveRule::TYPE_SUBSCRIBE)
-            ->where('status', 1)
-            ->first();
-
-        // 准备批量添加的积分列表
         $pointsList = [];
 
-        // 添加注册积分
-        $registrationPoints = $this->getPointsFromRuleOrConfig(
-            $registrationRule,
-            'rewardpoints.registration.points_per_registration',
-            100
-        );
-
+        // 注册积分
+        $registrationPoints = $this->getRegistrationPoints($customer);
         if ($registrationPoints > 0) {
-            $pointsList[] = [
-                'amount' => $registrationPoints,
-                'type' => RewardActiveRule::TYPE_REGISTRATION,
-                'detail' => 'Registration bonus',
-                'rule' => $registrationRule
-            ];
-        }
-
-        // 检查客户是否订阅了新闻通讯
-        $isSubscribedToNewsletter = false;
-        if (property_exists($customer, 'subscribed_to_news_letter')) {
-            $isSubscribedToNewsletter = $customer->subscribed_to_news_letter;
-        } elseif (method_exists($customer, 'getAttribute')) {
-            $isSubscribedToNewsletter = $customer->getAttribute('subscribed_to_news_letter');
+            $pointsList[] = $this->buildPointsItem($registrationPoints, RewardActiveRule::TYPE_REGISTRATION, 'Registration bonus');
         }
 
-        // 如果用户订阅了新闻通讯,添加订阅积分
-        if ($isSubscribedToNewsletter) {
-            $subscribePoints = $this->getPointsFromRuleOrConfig(
-                $subscribeRule,
-                'rewardpoints.newsletter_subscribe.points_per_subscription',
-                200
-            );
-
+        // 订阅积分(仅当用户订阅了新闻通讯)
+        if ($this->isSubscribedToNewsletter($customer)) {
+            $subscribePoints = $this->getSubscribePoints($customer);
             if ($subscribePoints > 0) {
-                $pointsList[] = [
-                    'amount' => $subscribePoints,
-                    'type' => RewardActiveRule::TYPE_SUBSCRIBE,
-                    'detail' => 'Newsletter subscription bonus',
-                    'rule' => $subscribeRule
-                ];
+                $pointsList[] = $this->buildPointsItem($subscribePoints, RewardActiveRule::TYPE_SUBSCRIBE, 'Newsletter subscription bonus');
             }
         }
 
-        // 如果有积分需要添加,使用批量添加方法
         if (!empty($pointsList)) {
-            $histories = $this->rewardPointRepository->addPointsBatch($customer->id, $pointsList);
-
-            /*Log::info('Points added for customer registration', [
-                'customer_id' => $customer->id,
-                'points_count' => count($pointsList),
-                'points_breakdown' => array_column($pointsList, 'amount'),
-                'total_points' => array_sum(array_column($pointsList, 'amount'))
-            ]);*/
+            $this->rewardPointRepository->addPointsBatch($customer->id, $pointsList);
         }
     }
 
-    /**
-     * 处理客户登录事件,赠送登录积分
-     */
-    public function handleCustomerLogin($event)
+    public function handleCustomerLogin($event): void
     {
-        // 检查事件参数类型
-        if (is_object($event) && method_exists($event, 'getAttribute')) {
-            $customer = $event;
-        } elseif (is_array($event) && isset($event['customer'])) {
-            $customer = $event['customer'];
-        } elseif (is_array($event) && isset($event['id'])) {
-            $customer = Customer::find($event['id']);
-        } elseif (is_int($event) || is_string($event)) {
-            $customer = Customer::find($event);
-        } else {
-            $customer = $event;
-        }
-
+        $customer = $this->resolveCustomer($event);
         if (!$customer) {
             Log::warning('Customer not found in login event');
             return;
         }
 
-        Log::info('Customer identified', [
-            'customer_id' => $customer->id,
-            'customer_email' => $customer->email ?? 'N/A'
-        ]);
-
-        // 检查今天是否已经获得过登录积分(使用 Redis/Cache 标记)
-        $today = \Carbon\Carbon::now()->format('Y-m-d');
-        $cacheKey = "reward_points:login_received:{$customer->id}:{$today}";
-
-        // 尝试从缓存获取标记
-        $alreadyReceivedToday = Cache::has($cacheKey);
-        // 尝试从数据库获取登陆状态
-        if(empty($alreadyReceivedToday)){
-            $alreadyReceivedToday = RewardPointHistory::where('customer_id', $customer->id)
-                ->where('type_of_transaction', RewardActiveRule::TYPE_LOGIN)
-                ->whereDate('transaction_time', $today)
-                ->where('status', RewardPointHistory::STATUS_COMPLETED)
-                ->exists();
-        }
-
-        if ($alreadyReceivedToday) {
-            /*Log::info('Customer already received login points today (from cache), skipping', [
-                'customer_id' => $customer->id,
-                'date' => $today,
-                'cache_store' => config('cache.default')
-            ]);*/
+        // 检查今天是否已获得登录积分
+        if ($this->hasReceivedLoginPointsToday($customer)) {
             return;
         }
 
-
-        // 查询登录规则
-        $loginRule = RewardActiveRule::where('type_of_transaction', RewardActiveRule::TYPE_LOGIN)
-            ->where('status', 1)
-            ->first();
-
-        if (!$loginRule) {
-            Log::info('No active login rule found, skipping login points');
+        $loginRule = RewardActiveRule::active()->ofType(RewardActiveRule::TYPE_LOGIN)->first();
+        if (!$loginRule || !$loginRule->isApplicableToCustomer($customer)) {
             return;
         }
 
-        // 获取登录积分
-        $loginPoints = (int) $loginRule->reward_point;
+        $loginPoints = $this->getLoginPoints($customer, $loginRule);
         if ($loginPoints <= 0) {
-            Log::info('Login points is 0 or negative, skipping login points');
             return;
         }
 
-        // 添加登录积分
-        $history = $this->rewardPointRepository->addPoints(
+        $this->rewardPointRepository->addPoints(
             $customer->id,
             RewardActiveRule::TYPE_LOGIN,
             $loginPoints,
@@ -185,22 +79,138 @@ class CustomerEvents
             'Login bonus'
         );
 
-        /*Log::info('Login points added successfully', [
-            'customer_id' => $customer->id,
-            'points' => $loginPoints,
-            'history_id' => $history->history_id ?? null
-        ]);*/
+        // 设置缓存标记,避免重复发放
+        $this->markLoginPointsReceived($customer);
+    }
+
+    /**
+     * 解析客户对象
+     */
+    protected function resolveCustomer($event): ?Customer
+    {
+        if ($event instanceof Customer) {
+            return $event;
+        }
+
+        if (is_array($event)) {
+            if (isset($event['customer'])) {
+                return $event['customer'] instanceof Customer ? $event['customer'] : null;
+            }
+            if (isset($event['id'])) {
+                return Customer::find($event['id']);
+            }
+        }
+
+        if (is_int($event) || is_string($event)) {
+            return Customer::find($event);
+        }
+
+        return null;
+    }
+
+    /**
+     * 检查是否订阅了新闻通讯
+     */
+    protected function isSubscribedToNewsletter(Customer $customer): bool
+    {
+        return (bool)($customer->subscribed_to_news_letter ?? false);
+    }
+
+    /**
+     * 获取注册积分
+     */
+    protected function getRegistrationPoints(Customer $customer): int
+    {
+        $rule = RewardActiveRule::active()->ofType(RewardActiveRule::TYPE_REGISTRATION)->first();
+        return $this->getPointsFromRuleOrConfig($rule, 'rewardpoints.registration.points_per_registration', 100);
+    }
+
+    /**
+     * 获取订阅积分
+     */
+    protected function getSubscribePoints(Customer $customer): int
+    {
+        $rule = RewardActiveRule::active()->ofType(RewardActiveRule::TYPE_SUBSCRIBE)->first();
+        return $this->getPointsFromRuleOrConfig($rule, 'rewardpoints.newsletter_subscribe.points_per_subscription', 200);
+    }
+
+    /**
+     * 获取登录积分
+     */
+    protected function getLoginPoints(Customer $customer, RewardActiveRule $rule): int
+    {
+        $customerGroupId = $customer->customer_group_id;
+        return $customerGroupId !== null
+            ? $rule->getRewardPointForCustomerGroup($customerGroupId)
+            : (int)$rule->reward_point;
+    }
+
+    /**
+     * 检查今日是否已获得登录积分
+     */
+    protected function hasReceivedLoginPointsToday(Customer $customer): bool
+    {
+        $today = Carbon::now()->format('Y-m-d');
+        $cacheKey = $this->getLoginCacheKey($customer->id, $today);
+
+        if (Cache::has($cacheKey)) {
+            return true;
+        }
+
+        $exists = RewardPointHistory::where('customer_id', $customer->id)
+            ->where('type_of_transaction', RewardActiveRule::TYPE_LOGIN)
+            ->whereDate('transaction_time', $today)
+            ->where('status', RewardPointHistory::STATUS_COMPLETED)
+            ->exists();
+
+        if ($exists) {
+            // 回填缓存
+            Cache::put($cacheKey, true, Carbon::now()->endOfDay());
+        }
+
+        return $exists;
+    }
+
+    /**
+     * 标记今日已获得登录积分
+     */
+    protected function markLoginPointsReceived(Customer $customer): void
+    {
+        $today = Carbon::now()->format('Y-m-d');
+        $cacheKey = $this->getLoginCacheKey($customer->id, $today);
+        Cache::put($cacheKey, true, Carbon::now()->endOfDay());
+    }
+
+    /**
+     * 获取登录积分缓存Key
+     */
+    protected function getLoginCacheKey(int $customerId, string $date): string
+    {
+        return "reward_points:login_received:{$customerId}:{$date}";
+    }
+
+    /**
+     * 构建积分项
+     */
+    protected function buildPointsItem(int $amount, int $type, string $detail): array
+    {
+        return [
+            'amount' => $amount,
+            'type' => $type,
+            'detail' => $detail,
+            'rule' => null,
+        ];
     }
 
     /**
      * 从规则或配置获取积分值
      */
-    private function getPointsFromRuleOrConfig($rule, $configKey, $defaultValue)
+    private function getPointsFromRuleOrConfig($rule, string $configKey, int $defaultValue): int
     {
         if ($rule && $rule->reward_point > 0) {
-            return (int) $rule->reward_point;
+            return (int)$rule->reward_point;
         }
 
-        return (int) config($configKey, $defaultValue);
+        return (int)config($configKey, $defaultValue);
     }
 }

+ 70 - 76
packages/Longyi/RewardPoints/src/Listeners/OrderEvents.php

@@ -6,37 +6,56 @@ use Longyi\RewardPoints\Repositories\RewardPointRepository;
 use Longyi\RewardPoints\Models\RewardActiveRule;
 use Longyi\RewardPoints\Models\RewardPointHistory;
 use Longyi\RewardPoints\Services\GrowthValueService;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+use Webkul\Sales\Models\Order;
 
 class OrderEvents
 {
-    protected $rewardPointRepository;
+    protected RewardPointRepository $rewardPointRepository;
+    protected GrowthValueService $growthValueService;
 
-    protected $growthValueService;
-
-    public function __construct(RewardPointRepository $rewardPointRepository, GrowthValueService $growthValueService)
-    {
+    public function __construct(
+        RewardPointRepository $rewardPointRepository,
+        GrowthValueService $growthValueService
+    ) {
         $this->rewardPointRepository = $rewardPointRepository;
         $this->growthValueService = $growthValueService;
     }
 
-    public function handleOrderPlacement($order)
+    public function handleOrderPlacement(Order $order): void
     {
         if (!$order->customer_id) {
             return;
         }
 
-        $rule = RewardActiveRule::where('type_of_transaction', RewardActiveRule::TYPE_ORDER)
-            ->where('status', 1)
-            ->first();
-
+        $rule = $this->getOrderRule();
         if (!$rule) {
             return;
         }
 
-        $points = $this->calculateOrderPoints($order, $rule);
+        $customer = $order->customer;
+
+        // 1. 检查规则是否适用
+        if (!$rule->isApplicableToCustomer($customer)) {
+            Log::info('Order rule not applicable', [
+                'order_id' => $order->id,
+                'customer_id' => $order->customer_id,
+            ]);
+            return;
+        }
+
+        // 2. 使用统一方法获取积分倍率
+        $pointsPerCurrency = $rule->getPointsForCustomer($customer);
+
+        if ($pointsPerCurrency <= 0) {
+            return;
+        }
+
+        // 3. 计算订单积分
+        $points = (int)floor($order->base_grand_total * $pointsPerCurrency);
 
         if ($points > 0) {
-            // 支付订单后,积分状态为 PENDING(待确认),不计入用户总积分
             $this->rewardPointRepository->addPoints(
                 $order->customer_id,
                 RewardActiveRule::TYPE_ORDER,
@@ -46,22 +65,21 @@ class OrderEvents
                 $rule
             );
 
-            Log::info('Order points added as PENDING (not counted in balance yet)', [
+            Log::info('Order points added as PENDING', [
                 'order_id' => $order->id,
-                'customer_id' => $order->customer_id,
-                'points' => $points
+                'points' => $points,
+                'rate' => $pointsPerCurrency
             ]);
         }
     }
 
-    public function handleOrderCancellation($order)
+    public function handleOrderCancellation(Order $order): void
     {
         if (!$order->customer_id) {
             return;
         }
 
-        \DB::transaction(function () use ($order) {
-            // 查找该订单相关的所有积分记录(包括 PENDING 和 COMPLETED)
+        DB::transaction(function () use ($order) {
             $histories = $this->rewardPointRepository->findWhere([
                 'customer_id' => $order->customer_id,
                 'history_order_id' => $order->id,
@@ -71,79 +89,55 @@ class OrderEvents
                 RewardPointHistory::STATUS_COMPLETED
             ])->get();
 
-            if ($histories->isEmpty()) {
-                return;
-            }
-
             foreach ($histories as $history) {
-                if ($history->amount > 0 && $history->point_remaining > 0) {
-                    // 只有 COMPLETED 状态的积分需要从用户余额中扣减
-                    if ($history->status === RewardPointHistory::STATUS_COMPLETED) {
-                        $result = $this->rewardPointRepository->deductPoints(
-                            $order->customer_id,
-                            $history->point_remaining,
-                            $order->id,
-                            "Points deducted due to order cancellation #{$order->increment_id}"
-                        );
-
-                        if ($result) {
-                            Log::info('Completed points deducted on cancellation', [
-                                'history_id' => $history->history_id,
-                                'order_id' => $order->id,
-                                'points_deducted' => $history->point_remaining
-                            ]);
-                        }
-                    } else {
-                        // PENDING 状态的积分只需更新状态,不需要扣减(因为从未计入余额)
-                        Log::info('Pending points cancelled (no deduction needed)', [
-                            'history_id' => $history->history_id,
-                            'order_id' => $order->id,
-                            'points' => $history->point_remaining
-                        ]);
-                    }
-
-                    // 更新历史记录状态
-                    $history->status = RewardPointHistory::STATUS_CANCELLED;
-                    $history->point_remaining = 0;
-                    $history->save();
-                }
+                $this->processCancellationHistory($history, $order);
             }
         });
     }
 
-    public function handleOrderCompletion($order)
+    public function handleOrderCompletion(Order $order): void
     {
-        if (!$order->customer_id) {
+        if (!$order->customer_id || $order->status !== Order::STATUS_COMPLETED) {
             return;
         }
 
-        if ($order->status !== \Webkul\Sales\Models\Order::STATUS_COMPLETED) {
-            return;
-        }
-
-        // 将该订单的 PENDING 积分确认为 COMPLETED,并计入用户总积分
-        $confirmedPoints = $this->rewardPointRepository->confirmPendingPoints(
-            $order->customer_id,
-            $order->id
-        );
-
-       /* if ($confirmedPoints > 0) {
-            Log::info('Order completed, pending points confirmed', [
-                'order_id' => $order->id,
-                'customer_id' => $order->customer_id,
-                'confirmed_points' => $confirmedPoints
-            ]);
-        }*/
+        // 确认待处理积分
+        $this->rewardPointRepository->confirmPendingPoints($order->customer_id, $order->id);
 
         // 处理成长值
         $this->growthValueService->handleOrderCompleted($order);
     }
 
-    protected function calculateOrderPoints($order, $rule)
+    /**
+     * 获取订单积分规则
+     */
+    protected function getOrderRule(): ?RewardActiveRule
     {
-        $pointsPerCurrency = 10;
-        return floor($order->base_grand_total * $pointsPerCurrency);
+        return RewardActiveRule::active()
+            ->ofType(RewardActiveRule::TYPE_ORDER)
+            ->first();
     }
 
-}
+    /**
+     * 处理取消订单的积分记录
+     */
+    protected function processCancellationHistory(RewardPointHistory $history, Order $order): void
+    {
+        if ($history->amount <= 0 || $history->point_remaining <= 0) {
+            return;
+        }
 
+        if ($history->status === RewardPointHistory::STATUS_COMPLETED) {
+            $this->rewardPointRepository->deductPoints(
+                $order->customer_id,
+                $history->point_remaining,
+                $order->id,
+                "Points deducted due to order cancellation #{$order->increment_id}"
+            );
+        }
+
+        $history->status = RewardPointHistory::STATUS_CANCELLED;
+        $history->point_remaining = 0;
+        $history->save();
+    }
+}

+ 128 - 13
packages/Longyi/RewardPoints/src/Listeners/ReviewEvents.php

@@ -4,30 +4,145 @@ namespace Longyi\RewardPoints\Listeners;
 
 use Longyi\RewardPoints\Repositories\RewardPointRepository;
 use Longyi\RewardPoints\Models\RewardActiveRule;
+use Webkul\Customer\Models\Customer;
+use Illuminate\Support\Facades\Log;
 
 class ReviewEvents
 {
-    protected $rewardPointRepository;
+    protected RewardPointRepository $rewardPointRepository;
 
     public function __construct(RewardPointRepository $rewardPointRepository)
     {
         $this->rewardPointRepository = $rewardPointRepository;
     }
 
-    public function handleReviewCreation($review)
+    public function handleReviewCreation($review): void
     {
-        $rule = RewardActiveRule::where('type_of_transaction', RewardActiveRule::TYPE_REVIEW)
-            ->where('status', 1)
-            ->first();
+        // 验证基础条件
+        if (!$this->isValidReview($review)) {
+            return;
+        }
+
+        // 获取评价规则
+        $rule = $this->getReviewRule();
+        if (!$rule) {
+            return;
+        }
+
+        // 获取客户信息
+        $customer = $this->getCustomer($review->customer_id);
+        if (!$customer) {
+            Log::warning('Customer not found for review points', [
+                'review_id' => $review->id,
+                'customer_id' => $review->customer_id
+            ]);
+            return;
+        }
+
+        // 【简化】只需要调用 isApplicableToCustomer,它会内部处理所有适用性检查
+        if (!$rule->isApplicableToCustomer($customer)) {
+            Log::info('Review rule not applicable', [
+                'review_id' => $review->id,
+                'customer_id' => $customer->id,
+            ]);
+            return;
+        }
+
+        // 【简化】使用统一方法获取积分值
+        $points = $rule->getPointsForCustomer($customer);
+
+        if ($points <= 0) {
+            Log::info('Review points is 0, skipping', [
+                'review_id' => $review->id,
+                'points' => $points
+            ]);
+            return;
+        }
+
+        // 检查是否已经为该评价发放过积分
+        if ($this->hasReceivedReviewPoints($review->id, $customer->id)) {
+            Log::info('Review points already granted', [
+                'review_id' => $review->id,
+                'customer_id' => $customer->id
+            ]);
+            return;
+        }
+
+        // 添加评价积分
+        $this->rewardPointRepository->addPoints(
+            $review->customer_id,
+            RewardActiveRule::TYPE_REVIEW,
+            $points,
+            null,
+            $this->getReviewPointsDescription($review),
+            $rule
+        );
+
+        Log::info('Review points added', [
+            'review_id' => $review->id,
+            'customer_id' => $customer->id,
+            'points' => $points
+        ]);
+    }
+
+    /**
+     * 验证评价是否有效
+     */
+    protected function isValidReview($review): bool
+    {
+        if (!$review || !is_object($review)) {
+            return false;
+        }
 
-        if ($rule && $rule->reward_point > 0 && $review->customer_id) {
-            $this->rewardPointRepository->addPoints(
-                $review->customer_id,
-                RewardActiveRule::TYPE_REVIEW,
-                $rule->reward_point,
-                null,
-                "Points earned for product review"
-            );
+        if (empty($review->customer_id)) {
+            Log::info('Review has no customer_id', [
+                'review_id' => $review->id ?? null
+            ]);
+            return false;
         }
+
+        return true;
+    }
+
+    /**
+     * 获取评价积分规则
+     */
+    protected function getReviewRule(): ?RewardActiveRule
+    {
+        return RewardActiveRule::active()
+            ->ofType(RewardActiveRule::TYPE_REVIEW)
+            ->first();
+    }
+
+    /**
+     * 获取客户信息
+     */
+    protected function getCustomer(int $customerId): ?Customer
+    {
+        return Customer::find($customerId);
+    }
+
+    /**
+     * 检查是否已经为该评价发放过积分
+     */
+    protected function hasReceivedReviewPoints(int $reviewId, int $customerId): bool
+    {
+        // 通过备注字段判断(需要存储评价ID)
+        return \Longyi\RewardPoints\Models\RewardPointHistory::where('customer_id', $customerId)
+            ->where('type_of_transaction', RewardActiveRule::TYPE_REVIEW)
+            ->where('description', 'LIKE', "%Review ID: {$reviewId}%")
+            ->exists();
+    }
+
+    /**
+     * 获取评价积分描述
+     */
+    protected function getReviewPointsDescription($review): string
+    {
+        $productInfo = !empty($review->product_id)
+            ? " for product #{$review->product_id}"
+            : '';
+
+        return "Points earned for product review{$productInfo} (Review ID: {$review->id})";
     }
 }

+ 159 - 38
packages/Longyi/RewardPoints/src/Models/RewardActiveRule.php

@@ -3,82 +3,186 @@
 namespace Longyi\RewardPoints\Models;
 
 use Illuminate\Database\Eloquent\Model;
+use Webkul\Customer\Models\Customer;
 
 class RewardActiveRule extends Model
 {
     // 定义交易类型常量
-    const TYPE_REGISTRATION = 2;   // 注册
-    const TYPE_SIGN_IN = 1;        // 签到
-    const TYPE_ORDER = 3;          // 订单
-    const TYPE_REVIEW = 4;         // 评价
-    const TYPE_REFERRAL = 5;       // 推荐
-    const TYPE_BIRTHDAY = 6;       // 生日
-    const TYPE_SHARE  = 7;         // 分享
-    const TYPE_SUBSCRIBE  = 8;         // 关注
-    const TYPE_LOGIN = 9;        // 登录
-    protected $table = 'mw_reward_active_rules';
+    const TYPE_SIGN_IN = 1;
+    const TYPE_REGISTRATION = 2;
+    const TYPE_ORDER = 3;
+    const TYPE_REVIEW = 4;
+    const TYPE_REFERRAL = 5;
+    const TYPE_BIRTHDAY = 6;
+    const TYPE_SHARE = 7;
+    const TYPE_SUBSCRIBE = 8;
+    const TYPE_LOGIN = 9;
 
+    protected $table = 'mw_reward_active_rules';
     protected $primaryKey = 'rule_id';
-
     public $timestamps = false;
 
     protected $fillable = [
-        'rule_name',
-        'type_of_transaction',
-        'store_view',
-        'customer_group_ids',
-        'enable_different_points_by_group',
-        'default_expired',
-        'expired_day',
-        'date_event',
-        'comment',
-        'coupon_code',
-        'reward_point',
-        'status',
+        'rule_name', 'type_of_transaction', 'store_view', 'customer_group_ids',
+        'enable_different_points_by_group', 'default_expired', 'expired_day',
+        'date_event', 'comment', 'coupon_code', 'reward_point', 'status',
+        'group_points'  // 添加群组积分配置字段
     ];
 
     protected $casts = [
         'type_of_transaction' => 'integer',
         'status' => 'boolean',
         'expired_day' => 'integer',
+        'enable_different_points_by_group' => 'boolean',
+        'group_points' => 'array',  // 自动 JSON 转换
     ];
 
     /**
-     * 获取客户群组积分设置
+     * 获取客户群组积分配置
+     * 假设数据库中 group_points 字段存储 JSON,格式:{"1": 100, "2": 150}
      */
-    public function getCustomerGroupPointsAttribute()
+    public function getCustomerGroupPointsAttribute(): array
     {
-        if ($this->enable_different_points_by_group) {
-            $groupPoints = json_decode($this->customer_group_ids, true);
-            return is_array($groupPoints) ? $groupPoints : [];
+        // 如果使用 group_points 字段(推荐)
+        if (isset($this->attributes['group_points'])) {
+            $value = $this->attributes['group_points'];
+            if (is_string($value)) {
+                return json_decode($value, true) ?: [];
+            }
+            return is_array($value) ? $value : [];
         }
+
+        // 兼容其他可能的字段名
+        if (isset($this->attributes['customer_group_points'])) {
+            $value = $this->attributes['customer_group_points'];
+            if (is_string($value)) {
+                return json_decode($value, true) ?: [];
+            }
+            return is_array($value) ? $value : [];
+        }
+
         return [];
     }
 
     /**
-     * 设置客户群组积分设置
+     * 【核心方法】统一获取客户应得的积分值
+     * 整合了所有积分获取逻辑,避免重复代码
+     */
+    public function getPointsForCustomer($customer): int
+    {
+        // 获取客户群组ID
+        $customerGroupId = $this->extractCustomerGroupId($customer);
+
+        // 如果无法获取群组ID,返回0(注册、订阅等场景应该单独处理)
+        if ($customerGroupId === null) {
+            return 0;
+        }
+
+        // 启用群组差异化:从配置中获取该群组的积分
+        if ($this->enable_different_points_by_group) {
+            $groupPoints = $this->getCustomerGroupPointsAttribute();
+            return (int)($groupPoints[$customerGroupId] ?? 0);
+        }
+
+        // 不启用差异化:检查群组是否在允许列表中
+        if ($this->isGroupAllowed($customerGroupId)) {
+            return (int)$this->reward_point;
+        }
+
+        return 0;
+    }
+
+    /**
+     * 获取特定客户群组的积分值(保留向后兼容)
      */
-    public function setCustomerGroupPointsAttribute($value)
+    public function getRewardPointForCustomerGroup($customerGroupId): int
     {
         if ($this->enable_different_points_by_group) {
-            $this->attributes['customer_group_ids'] = json_encode($value);
+            $groupPoints = $this->getCustomerGroupPointsAttribute();
+            return (int)($groupPoints[$customerGroupId] ?? 0);
         }
+
+        if ($this->isGroupAllowed($customerGroupId)) {
+            return (int)$this->reward_point;
+        }
+
+        return 0;
     }
 
     /**
-     * 获取特定客户群组的积分值
+     * 检查规则是否适用于指定客户
      */
-    public function getRewardPointForCustomerGroup($customerGroupId)
+    public function isApplicableToCustomer($customer): bool
     {
+        // 检查 store_view
+        if (!$this->isStoreViewMatched()) {
+            return false;
+        }
+
+        $customerGroupId = $this->extractCustomerGroupId($customer);
+
+        if ($customerGroupId === null) {
+            return false;
+        }
+
+        // 启用群组差异化:检查是否有为该群组配置积分
         if ($this->enable_different_points_by_group) {
             $groupPoints = $this->getCustomerGroupPointsAttribute();
-            return isset($groupPoints[$customerGroupId]) ? (int)$groupPoints[$customerGroupId] : 0;
+            return !empty($groupPoints) && isset($groupPoints[$customerGroupId]);
         }
 
-        // 如果不启用不同群组不同积分,则返回统一的积分值
-        return (int)$this->reward_point;
+        // 不启用差异化:检查群组是否在允许列表中
+        return $this->isGroupAllowed($customerGroupId);
     }
-     public function getTransactionTypeTextAttribute()
+
+    /**
+     * 检查 store_view 是否匹配
+     */
+    protected function isStoreViewMatched(): bool
+    {
+        if (empty($this->store_view) || $this->store_view === '0') {
+            return true;
+        }
+
+        $storeViews = explode(',', $this->store_view);
+        $currentChannelCode = core()->getCurrentChannelCode();
+
+        return in_array($currentChannelCode, $storeViews);
+    }
+
+    /**
+     * 检查群组是否允许
+     */
+    protected function isGroupAllowed($customerGroupId): bool
+    {
+        if (empty($this->customer_group_ids) || trim($this->customer_group_ids) === '') {
+            return true;
+        }
+
+        $allowedGroups = array_map('trim', explode(',', $this->customer_group_ids));
+        return in_array((string)$customerGroupId, $allowedGroups);
+    }
+
+    /**
+     * 提取客户群组ID
+     */
+    protected function extractCustomerGroupId($customer): ?string
+    {
+        if ($customer instanceof Customer) {
+            return $customer->customer_group_id;
+        }
+
+        if (is_object($customer) && property_exists($customer, 'customer_group_id')) {
+            return $customer->customer_group_id;
+        }
+
+        return null;
+    }
+
+    /**
+     * 获取交易类型文本
+     */
+    public function getTransactionTypeTextAttribute(): string
     {
         $types = [
             self::TYPE_ORDER => 'Order',
@@ -88,9 +192,26 @@ class RewardActiveRule extends Model
             self::TYPE_REFERRAL => 'Referral',
             self::TYPE_BIRTHDAY => 'Birthday',
             self::TYPE_SHARE => 'Share',
-            self::TYPE_SUBSCRIBE => 'Subscription'
+            self::TYPE_SUBSCRIBE => 'Subscription',
+            self::TYPE_SIGN_IN => 'Sign In',
         ];
 
         return $types[$this->type_of_transaction] ?? 'Unknown';
     }
+
+    /**
+     * 作用域:获取启用的规则
+     */
+    public function scopeActive($query)
+    {
+        return $query->where('status', 1);
+    }
+
+    /**
+     * 作用域:按交易类型查询
+     */
+    public function scopeOfType($query, $type)
+    {
+        return $query->where('type_of_transaction', $type);
+    }
 }

+ 13 - 7
packages/Longyi/RewardPoints/src/Repositories/RewardPointRepository.php

@@ -350,27 +350,33 @@ class RewardPointRepository extends Repository
                         ->first();
 
                     if ($customerPoints) {
-                        $customerPoints->increment('mw_reward_point', $history->point_remaining);
-                        $customerPoints->save();
+                        $pointsToAdd = $history->point_remaining;
+
+                        // 增加积分
+                        $customerPoints->increment('mw_reward_point', $pointsToAdd);
+                        $customerPoints->refresh(); // 刷新获取最新值
+                        $newBalance = (int) $customerPoints->mw_reward_point;
 
-                        // 更新历史记录状态
+                        // 直接更新原记录的状态和余额
                         $history->status = RewardPointHistory::STATUS_COMPLETED;
-                        $history->balance = (int) $customerPoints->mw_reward_point;
+                        $history->balance = $newBalance;
                         $history->save();
 
-                        $totalConfirmedPoints += $history->point_remaining;
+                        $totalConfirmedPoints += $pointsToAdd;
 
                         Log::info('Pending points confirmed', [
                             'history_id' => $history->history_id,
                             'customer_id' => $customerId,
                             'order_id' => $orderId,
-                            'points' => $history->point_remaining,
-                            'new_balance' => $customerPoints->mw_reward_point
+                            'points' => $pointsToAdd,
+                            'old_balance' => $history->getOriginal('balance'),
+                            'new_balance' => $newBalance
                         ]);
                     }
                 }
 
                 return $totalConfirmedPoints;
+
             });
         } catch (\Exception $e) {
             Log::error('Error confirming pending points', [