bianjunhui 3 ماه پیش
والد
کامیت
4cb24342cb

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

@@ -8,189 +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
-            ];
+            $pointsList[] = $this->buildPointsItem($registrationPoints, RewardActiveRule::TYPE_REGISTRATION, 'Registration bonus');
         }
 
-        // 检查客户是否订阅了新闻通讯
-        $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');
-        }
-
-        // 如果用户订阅了新闻通讯,添加订阅积分
-        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;
         }
 
-        // 检查规则是否适用于该客户
-        if (!$loginRule->isApplicableToCustomer($customer)) {
-            Log::info('Login rule not applicable to this customer group', [
-                'customer_id' => $customer->id,
-                'customer_group_id' => $customer->customer_group_id ?? null
-            ]);
-            return;
-        }
-
-        // 获取登录积分(根据客户群组)
-        $customerGroupId = $customer->customer_group_id ?? null;
-        $loginPoints = $customerGroupId !== null
-            ? $loginRule->getRewardPointForCustomerGroup($customerGroupId)
-            : (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,
@@ -198,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);
     }
 }

+ 64 - 77
packages/Longyi/RewardPoints/src/Listeners/OrderEvents.php

@@ -6,36 +6,37 @@ 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 $growthValueService;
+    protected RewardPointRepository $rewardPointRepository;
+    protected GrowthValueService $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;
         }
+
         $customer = $order->customer;
-        // 检查规则是否适用于该客户
         if (!$rule->isApplicableToCustomer($customer)) {
-            Log::info('Order rule not applicable to this customer group', [
+            Log::info('Order rule not applicable', [
                 'order_id' => $order->id,
                 'customer_id' => $order->customer_id,
                 'customer_group_id' => $customer->customer_group_id ?? null
@@ -46,7 +47,6 @@ class OrderEvents
         $points = $this->calculateOrderPoints($order, $rule, $customer);
 
         if ($points > 0) {
-            // 支付订单后,积分状态为 PENDING(待确认),不计入用户总积分
             $this->rewardPointRepository->addPoints(
                 $order->customer_id,
                 RewardActiveRule::TYPE_ORDER,
@@ -56,7 +56,7 @@ 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
@@ -64,14 +64,13 @@ class OrderEvents
         }
     }
 
-    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,
@@ -81,87 +80,53 @@ 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) {
-            return;
-        }
-
-        if ($order->status !== \Webkul\Sales\Models\Order::STATUS_COMPLETED) {
+        if (!$order->customer_id || $order->status !== 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, $customer)
+    /**
+     * 获取订单积分规则
+     */
+    protected function getOrderRule(): ?RewardActiveRule
+    {
+        return RewardActiveRule::active()
+            ->ofType(RewardActiveRule::TYPE_ORDER)
+            ->first();
+    }
+
+    /**
+     * 计算订单积分
+     */
+    protected function calculateOrderPoints(Order $order, RewardActiveRule $rule, $customer): int
     {
-        // 获取积分倍率
         $pointsPerCurrency = $this->getPointsPerCurrency($rule, $customer);
 
         if ($pointsPerCurrency <= 0) {
             return 0;
         }
 
-        return floor($order->base_grand_total * $pointsPerCurrency);
+        return (int)floor($order->base_grand_total * $pointsPerCurrency);
     }
 
-    protected function getPointsPerCurrency($rule, $customer)
+    /**
+     * 获取积分倍率
+     */
+    protected function getPointsPerCurrency(RewardActiveRule $rule, $customer): int
     {
         if ($rule->enable_different_points_by_group && $customer) {
             $customerGroupId = $customer->customer_group_id ?? null;
@@ -170,9 +135,31 @@ class OrderEvents
             }
         }
 
-        // 不使用群组差异化时,直接返回默认积分值
         return (int)$rule->reward_point;
     }
 
-}
+    /**
+     * 处理取消订单的积分记录
+     */
+    protected function processCancellationHistory(RewardPointHistory $history, Order $order): void
+    {
+        if ($history->amount <= 0 || $history->point_remaining <= 0) {
+            return;
+        }
 
+        // 只有 COMPLETED 状态需要扣减余额
+        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();
+    }
+}

+ 161 - 22
packages/Longyi/RewardPoints/src/Listeners/ReviewEvents.php

@@ -4,50 +4,189 @@ namespace Longyi\RewardPoints\Listeners;
 
 use Longyi\RewardPoints\Repositories\RewardPointRepository;
 use Longyi\RewardPoints\Models\RewardActiveRule;
+use Longyi\RewardPoints\Models\RewardPointHistory;
+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 (!$rule || !$review->customer_id) {
+        // 验证基础条件
+        if (!$this->isValidReview($review)) {
+            return;
+        }
+
+        // 获取评价规则
+        $rule = $this->getReviewRule();
+        if (!$rule) {
             return;
         }
+
         // 获取客户信息
-        $customer = \Webkul\Customer\Models\Customer::find($review->customer_id);
+        $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;
         }
 
         // 检查规则是否适用于该客户
         if (!$rule->isApplicableToCustomer($customer)) {
+            Log::info('Review rule not applicable to this customer group', [
+                'review_id' => $review->id,
+                'customer_id' => $customer->id,
+                'customer_group_id' => $customer->customer_group_id ?? null
+            ]);
+            return;
+        }
+
+        // 检查是否已经为该评价发放过积分(防止重复发放)
+        if ($this->hasReceivedReviewPoints($review->id, $customer->id)) {
+            Log::info('Review points already granted, skipping', [
+                'review_id' => $review->id,
+                'customer_id' => $customer->id
+            ]);
+            return;
+        }
+
+        // 获取积分值
+        $points = $this->getReviewPoints($customer, $rule);
+        if ($points <= 0) {
+            Log::info('Review points is 0 or negative, skipping', [
+                'review_id' => $review->id,
+                'customer_id' => $customer->id,
+                'points' => $points
+            ]);
             return;
         }
 
-        // 获取积分(根据客户群组)
-        $customerGroupId = $customer->customer_group_id ?? null;
-        $points = $customerGroupId !== null
-            ? $rule->getRewardPointForCustomerGroup($customerGroupId)
-            : (int) $rule->reward_point;
-
-        if ($points > 0) {
-            $this->rewardPointRepository->addPoints(
-                $review->customer_id,
-                RewardActiveRule::TYPE_REVIEW,
-                $points,
-                null,
-                "Points earned for product review",
-                $rule
-            );
+        // 添加评价积分
+        $history = $this->rewardPointRepository->addPoints(
+            $review->customer_id,
+            RewardActiveRule::TYPE_REVIEW,
+            $points,
+            null,
+            $this->getReviewPointsDescription($review),
+            $rule
+        );
+
+        Log::info('Review points added successfully', [
+            'review_id' => $review->id,
+            'customer_id' => $customer->id,
+            'points' => $points,
+            'history_id' => $history->history_id ?? null
+        ]);
+    }
+
+    /**
+     * 验证评价是否有效
+     */
+    protected function isValidReview($review): bool
+    {
+        if (!$review || !is_object($review)) {
+            return false;
+        }
+
+        // 检查是否有客户ID
+        if (empty($review->customer_id)) {
+            Log::info('Review has no customer_id, skipping points', [
+                'review_id' => $review->id ?? null
+            ]);
+            return false;
+        }
+
+        // 可选:检查评价状态是否已批准(如果评价系统有审核机制)
+        // if (isset($review->status) && $review->status !== 'approved') {
+        //     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 getReviewPoints(Customer $customer, RewardActiveRule $rule): int
+    {
+        $customerGroupId = $customer->customer_group_id;
+
+        if ($customerGroupId !== null) {
+            return $rule->getRewardPointForCustomerGroup($customerGroupId);
+        }
+
+        return (int)$rule->reward_point;
+    }
+
+    /**
+     * 检查是否已经为该评价发放过积分
+     */
+    protected function hasReceivedReviewPoints(int $reviewId, int $customerId): bool
+    {
+        // 方案1:通过订单ID字段关联(如果评价有对应的订单ID)
+        // return RewardPointHistory::where('customer_id', $customerId)
+        //     ->where('type_of_transaction', RewardActiveRule::TYPE_REVIEW)
+        //     ->where('history_order_id', $reviewId)
+        //     ->exists();
+
+        // 方案2:通过备注字段判断(需要存储评价ID)
+        return 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 = '';
+
+        if (!empty($review->product_id)) {
+            $productInfo = " for product #{$review->product_id}";
+        }
+
+        return "Points earned for product review{$productInfo} (Review ID: {$review->id})";
+    }
+
+    /**
+     * 批量处理多个评价(如果是一次性创建多个评价的场景)
+     */
+    public function handleMultipleReviewsCreation(array $reviews): void
+    {
+        foreach ($reviews as $review) {
+            $this->handleReviewCreation($review);
         }
     }
 }

+ 107 - 101
packages/Longyi/RewardPoints/src/Models/RewardActiveRule.php

@@ -3,154 +3,160 @@
 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',
     ];
 
     protected $casts = [
         'type_of_transaction' => 'integer',
         'status' => 'boolean',
         'expired_day' => 'integer',
+        'enable_different_points_by_group' => 'boolean',
+    ];
+
+    // 交易类型文本映射
+    protected const TRANSACTION_TYPES = [
+        self::TYPE_ORDER => 'Order',
+        self::TYPE_REGISTRATION => 'Registration',
+        self::TYPE_REVIEW => 'Product Review',
+        self::TYPE_LOGIN => 'Login',
+        self::TYPE_REFERRAL => 'Referral',
+        self::TYPE_BIRTHDAY => 'Birthday',
+        self::TYPE_SHARE => 'Share',
+        self::TYPE_SUBSCRIBE => 'Subscription',
+        self::TYPE_SIGN_IN => 'Sign In',
     ];
 
     /**
      * 获取特定客户群组的积分值
      */
-    public function getRewardPointForCustomerGroup($customerGroupId)
+    public function getRewardPointForCustomerGroup($customerGroupId): int
     {
         if ($this->enable_different_points_by_group) {
             $groupPoints = $this->getCustomerGroupPointsAttribute();
-            return isset($groupPoints[$customerGroupId]) ? (int)$groupPoints[$customerGroupId] : 0;
+            return (int)($groupPoints[$customerGroupId] ?? 0);
         }
 
-        // 如果不启用不同群组不同积分,则检查 customer_group_ids 是否为空或包含当前群组
-        // 如果 customer_group_ids 为空,表示适用于所有群组
-        if (empty($this->customer_group_ids)) {
+        // 不启用群组差异化时,检查群组是否允许
+        if ($this->isGroupAllowed($customerGroupId)) {
             return (int)$this->reward_point;
         }
 
-        // 检查当前群组是否在允许的群组列表中
-        $allowedGroups = explode(',', $this->customer_group_ids);
-        if (in_array((string)$customerGroupId, $allowedGroups)) {
-            return (int)$this->reward_point;
-        }
-
-        // 如果群组不在允许列表中,返回 0(不赠送积分)
         return 0;
     }
 
     /**
      * 检查规则是否适用于指定客户
      */
-    public function isApplicableToCustomer($customer)
+    public function isApplicableToCustomer($customer): bool
     {
-        // 检查 store_view 是否匹配
-        if ($this->store_view && $this->store_view !== '0') {
-            $storeViews = explode(',', $this->store_view);
-            $currentChannelCode = core()->getCurrentChannelCode();
-            if (!in_array($currentChannelCode, $storeViews)) {
-                return false;
-            }
+        // 检查 store_view
+        if (!$this->isStoreViewMatched()) {
+            return false;
         }
 
-        // 如果不启用不同群组不同积分,检查 customer_group_ids
-        if (!$this->enable_different_points_by_group) {
-            // 如果 customer_group_ids 为空或空字符串,表示适用于所有群组
-            if (empty($this->customer_group_ids) || trim($this->customer_group_ids) === '') {
-                return true;
-            }
-
-            // 检查客户群组是否在允许列表中
-            $allowedGroups = array_map('trim', explode(',', $this->customer_group_ids));
-
-            // 获取客户群组ID
-            if ($customer instanceof \Webkul\Customer\Models\Customer) {
-                $customerGroupId = $customer->customer_group_id;
-            } elseif (is_object($customer) && property_exists($customer, 'customer_group_id')) {
-                $customerGroupId = $customer->customer_group_id;
-            } else {
-                return false;
-            }
-
-            if ($customerGroupId === null || $customerGroupId === '') {
-                return false;
-            }
-
-            return in_array((string)$customerGroupId, $allowedGroups);
+        $customerGroupId = $this->extractCustomerGroupId($customer);
+        if ($customerGroupId === null) {
+            return false;
         }
 
-        // 如果启用不同群组不同积分,检查是否有为该群组配置积分
+        // 启用群组差异化时,检查是否有积分配置
         if ($this->enable_different_points_by_group) {
             $groupPoints = $this->getCustomerGroupPointsAttribute();
+            return !empty($groupPoints) && isset($groupPoints[$customerGroupId]);
+        }
+
+        // 不启用差异化时,检查群组是否在允许列表中
+        return $this->isGroupAllowed($customerGroupId);
+    }
+
+    /**
+     * 检查 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;
+        }
 
-            if (empty($groupPoints)) {
-                return false;
-            }
-
-            // 获取客户群组ID
-            if ($customer instanceof \Webkul\Customer\Models\Customer) {
-                $customerGroupId = $customer->customer_group_id;
-            } elseif (is_object($customer) && property_exists($customer, 'customer_group_id')) {
-                $customerGroupId = $customer->customer_group_id;
-            } else {
-                return false;
-            }
-
-            if ($customerGroupId === null || $customerGroupId === '') {
-                return false;
-            }
-
-            // 检查是否为该群组配置了积分(即使为 0 也算配置了)
-            return isset($groupPoints[(string)$customerGroupId]) || isset($groupPoints[$customerGroupId]);
+        $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;
         }
 
-        return true;
+        if (is_object($customer) && property_exists($customer, 'customer_group_id')) {
+            return $customer->customer_group_id;
+        }
+
+        return null;
     }
 
-    public function getTransactionTypeTextAttribute()
+    /**
+     * 获取交易类型文本
+     */
+    public function getTransactionTypeTextAttribute(): string
+    {
+        return self::TRANSACTION_TYPES[$this->type_of_transaction] ?? 'Unknown';
+    }
+
+    /**
+     * 作用域:获取启用的规则
+     */
+    public function scopeActive($query)
     {
-        $types = [
-            self::TYPE_ORDER => 'Order',
-            self::TYPE_REGISTRATION => 'Registration',
-            self::TYPE_REVIEW => 'Product Review',
-            self::TYPE_LOGIN => 'Login',
-            self::TYPE_REFERRAL => 'Referral',
-            self::TYPE_BIRTHDAY => 'Birthday',
-            self::TYPE_SHARE => 'Share',
-            self::TYPE_SUBSCRIBE => 'Subscription'
-        ];
-
-        return $types[$this->type_of_transaction] ?? 'Unknown';
+        return $query->where('status', 1);
     }
 
+    /**
+     * 作用域:按交易类型查询
+     */
+    public function scopeOfType($query, $type)
+    {
+        return $query->where('type_of_transaction', $type);
+    }
 }