|
|
@@ -0,0 +1,319 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace Longyi\RewardPoints\Services;
|
|
|
+
|
|
|
+use Longyi\RewardPoints\Models\GrowthValueCustomer;
|
|
|
+use Longyi\RewardPoints\Models\GrowthValueHistory;
|
|
|
+use Longyi\RewardPoints\Models\GrowthValueLevel;
|
|
|
+use Longyi\RewardPoints\Models\RewardPointSetting;
|
|
|
+use Carbon\Carbon;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
+
|
|
|
+class GrowthValueService
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 处理订单完成事件,增加成长值并检查升级
|
|
|
+ */
|
|
|
+ public function handleOrderCompleted($order)
|
|
|
+ {
|
|
|
+ if (!$order->customer_id) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ DB::transaction(function () use ($order) {
|
|
|
+ $customerId = $order->customer_id;
|
|
|
+ $orderAmount = $order->grand_total;
|
|
|
+
|
|
|
+ $growthValueCustomer = GrowthValueCustomer::firstOrCreate(
|
|
|
+ ['customer_id' => $customerId],
|
|
|
+ [
|
|
|
+ 'growth_value' => 0,
|
|
|
+ 'growth_level' => 'V0',
|
|
|
+ 'level_updated_at' => now(),
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ $levelBefore = $growthValueCustomer->growth_level;
|
|
|
+ $hasFirstOrder = !is_null($growthValueCustomer->first_order_completed_at);
|
|
|
+
|
|
|
+ if (!$hasFirstOrder) {
|
|
|
+ $growthValueCustomer->first_order_completed_at = now();
|
|
|
+ }
|
|
|
+
|
|
|
+ $earnedGrowthValue = $this->calculateGrowthValue($orderAmount);
|
|
|
+
|
|
|
+ $currentGrowthValue = $growthValueCustomer->growth_value;
|
|
|
+ $newGrowthValue = $currentGrowthValue + $earnedGrowthValue;
|
|
|
+
|
|
|
+ $validityDays = $this->getValidityDays();
|
|
|
+ $expiresAt = $validityDays > 0 ? Carbon::now()->addDays($validityDays) : null;
|
|
|
+
|
|
|
+ $growthValueCustomer->growth_value = $newGrowthValue;
|
|
|
+
|
|
|
+ if ($validityDays > 0) {
|
|
|
+ $growthValueCustomer->growth_value_expires_at = $expiresAt;
|
|
|
+ }
|
|
|
+
|
|
|
+ $newLevel = GrowthValueLevel::getLevelByGrowthValue($newGrowthValue, true);
|
|
|
+ $levelAfter = $newLevel ? $newLevel->level_code : 'V0';
|
|
|
+
|
|
|
+ if ($levelBefore !== $levelAfter) {
|
|
|
+ $growthValueCustomer->growth_level = $levelAfter;
|
|
|
+ $growthValueCustomer->level_updated_at = now();
|
|
|
+ }
|
|
|
+
|
|
|
+ $growthValueCustomer->save();
|
|
|
+
|
|
|
+ GrowthValueHistory::create([
|
|
|
+ 'customer_id' => $customerId,
|
|
|
+ 'order_id' => $order->id,
|
|
|
+ 'order_amount' => $orderAmount,
|
|
|
+ 'growth_value_earned' => $earnedGrowthValue,
|
|
|
+ 'total_growth_value' => $newGrowthValue,
|
|
|
+ 'level_before' => $levelBefore,
|
|
|
+ 'level_after' => $levelAfter,
|
|
|
+ 'event_type' => GrowthValueHistory::EVENT_TYPE_ORDER,
|
|
|
+ 'description' => "订单 #{$order->increment_id} 完成,获得 {$earnedGrowthValue} 成长值",
|
|
|
+ 'expires_at' => $expiresAt,
|
|
|
+ 'created_at' => now(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ Log::info('Growth value added and level checked', [
|
|
|
+ 'customer_id' => $customerId,
|
|
|
+ 'order_id' => $order->id,
|
|
|
+ 'order_amount' => $orderAmount,
|
|
|
+ 'earned_growth_value' => $earnedGrowthValue,
|
|
|
+ 'new_total' => $newGrowthValue,
|
|
|
+ 'level_before' => $levelBefore,
|
|
|
+ 'level_after' => $levelAfter,
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error adding growth value', [
|
|
|
+ 'customer_id' => $order->customer_id,
|
|
|
+ 'order_id' => $order->id,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'trace' => $e->getTraceAsString(),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算订单应获得的成长值
|
|
|
+ */
|
|
|
+ protected function calculateGrowthValue($orderAmount)
|
|
|
+ {
|
|
|
+ $ratio = $this->getGrowthValueRatio();
|
|
|
+
|
|
|
+ return max(1, floor($orderAmount * $ratio));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取成长值计算比例(每元获得的成长值)
|
|
|
+ */
|
|
|
+ protected function getGrowthValueRatio()
|
|
|
+ {
|
|
|
+ $setting = RewardPointSetting::where('code', 'growth_value_ratio')->first();
|
|
|
+
|
|
|
+ if ($setting && $setting->value) {
|
|
|
+ return floatval($setting->value);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取成长值有效期(天)
|
|
|
+ */
|
|
|
+ protected function getValidityDays()
|
|
|
+ {
|
|
|
+ $setting = RewardPointSetting::where('code', 'growth_value_validity_days')->first();
|
|
|
+
|
|
|
+ if ($setting && $setting->value) {
|
|
|
+ return intval($setting->value);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 365;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查并处理过期的成长值
|
|
|
+ */
|
|
|
+ public function checkExpiredGrowthValues()
|
|
|
+ {
|
|
|
+ $expiredRecords = GrowthValueCustomer::whereNotNull('growth_value_expires_at')
|
|
|
+ ->where('growth_value_expires_at', '<', now())
|
|
|
+ ->where('growth_value', '>', 0)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($expiredRecords as $record) {
|
|
|
+ try {
|
|
|
+ DB::transaction(function () use ($record) {
|
|
|
+ $levelBefore = $record->growth_level;
|
|
|
+
|
|
|
+ GrowthValueHistory::create([
|
|
|
+ 'customer_id' => $record->customer_id,
|
|
|
+ 'order_id' => null,
|
|
|
+ 'order_amount' => 0,
|
|
|
+ 'growth_value_earned' => -$record->growth_value,
|
|
|
+ 'total_growth_value' => 0,
|
|
|
+ 'level_before' => $levelBefore,
|
|
|
+ 'level_after' => 'V0',
|
|
|
+ 'event_type' => GrowthValueHistory::EVENT_TYPE_EXPIRATION,
|
|
|
+ 'description' => '成长值过期清零',
|
|
|
+ 'expires_at' => null,
|
|
|
+ 'created_at' => now(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $record->growth_value = 0;
|
|
|
+ $record->growth_level = 'V0';
|
|
|
+ $record->level_updated_at = now();
|
|
|
+ $record->growth_value_expires_at = null;
|
|
|
+ $record->save();
|
|
|
+
|
|
|
+ Log::info('Growth value expired and level reset', [
|
|
|
+ 'customer_id' => $record->customer_id,
|
|
|
+ 'expired_value' => $record->growth_value,
|
|
|
+ 'level_before' => $levelBefore,
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error processing expired growth value', [
|
|
|
+ 'customer_id' => $record->customer_id,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取客户成长值信息
|
|
|
+ */
|
|
|
+ public function getCustomerGrowthValue($customerId)
|
|
|
+ {
|
|
|
+ $growthValueCustomer = GrowthValueCustomer::with('levelConfig')->where('customer_id', $customerId)->first();
|
|
|
+ $customer = \Webkul\Customer\Models\Customer::find($customerId);
|
|
|
+
|
|
|
+ if (!$growthValueCustomer) {
|
|
|
+ $defaultLevel = GrowthValueLevel::where('level_code', 'V0')->first();
|
|
|
+ return [
|
|
|
+ 'growth_value' => 0,
|
|
|
+ 'growth_level' => 'V0',
|
|
|
+ 'level_name' => $defaultLevel ? $defaultLevel->level_name : '普通会员',
|
|
|
+ 'level_icon' => $defaultLevel ? $defaultLevel->icon : null,
|
|
|
+ 'discount_rate' => $defaultLevel ? $defaultLevel->discount_rate : 0,
|
|
|
+ 'benefits' => $defaultLevel ? $defaultLevel->benefits : [],
|
|
|
+ 'next_level' => null,
|
|
|
+ 'points_to_next_level' => null,
|
|
|
+ 'expires_at' => null,
|
|
|
+ 'first_order_completed' => false,
|
|
|
+ 'customer_group' => $customer ? $customer->group : null,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ $levelConfig = $growthValueCustomer->levelConfig;
|
|
|
+
|
|
|
+ $nextLevel = GrowthValueLevel::getNextLevel(
|
|
|
+ $growthValueCustomer->growth_level,
|
|
|
+ !is_null($growthValueCustomer->first_order_completed_at)
|
|
|
+ );
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'growth_value' => $growthValueCustomer->growth_value,
|
|
|
+ 'growth_level' => $growthValueCustomer->growth_level,
|
|
|
+ 'level_name' => $levelConfig ? $levelConfig->level_name : '普通会员',
|
|
|
+ 'level_icon' => $levelConfig ? $levelConfig->icon : null,
|
|
|
+ 'discount_rate' => $levelConfig ? $levelConfig->discount_rate : 0,
|
|
|
+ 'benefits' => $levelConfig ? $levelConfig->benefits : [],
|
|
|
+ 'next_level' => $nextLevel ? [
|
|
|
+ 'level_code' => $nextLevel->level_code,
|
|
|
+ 'level_name' => $nextLevel->level_name,
|
|
|
+ 'min_growth_value' => $nextLevel->min_growth_value,
|
|
|
+ 'icon' => $nextLevel->icon,
|
|
|
+ ] : null,
|
|
|
+ 'points_to_next_level' => $nextLevel ? ($nextLevel->min_growth_value - $growthValueCustomer->growth_value) : null,
|
|
|
+ 'expires_at' => $growthValueCustomer->growth_value_expires_at,
|
|
|
+ 'first_order_completed' => !is_null($growthValueCustomer->first_order_completed_at),
|
|
|
+ 'customer_group' => $customer ? $customer->group : null,
|
|
|
+ 'level_updated_at' => $growthValueCustomer->level_updated_at,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 手动调整成长值(管理员操作)
|
|
|
+ */
|
|
|
+ public function adjustGrowthValue($customerId, $amount, $description = '管理员调整')
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ return DB::transaction(function () use ($customerId, $amount, $description) {
|
|
|
+ $growthValueCustomer = GrowthValueCustomer::firstOrCreate(
|
|
|
+ ['customer_id' => $customerId],
|
|
|
+ [
|
|
|
+ 'growth_value' => 0,
|
|
|
+ 'growth_level' => 'V0',
|
|
|
+ 'level_updated_at' => now(),
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ $levelBefore = $growthValueCustomer->growth_level;
|
|
|
+ $currentGrowthValue = $growthValueCustomer->growth_value;
|
|
|
+ $newGrowthValue = max(0, $currentGrowthValue + $amount);
|
|
|
+
|
|
|
+ $hasFirstOrder = !is_null($growthValueCustomer->first_order_completed_at);
|
|
|
+ $newLevel = GrowthValueLevel::getLevelByGrowthValue($newGrowthValue, $hasFirstOrder);
|
|
|
+ $levelAfter = $newLevel ? $newLevel->level_code : 'V0';
|
|
|
+
|
|
|
+ if ($levelBefore !== $levelAfter) {
|
|
|
+ $growthValueCustomer->growth_level = $levelAfter;
|
|
|
+ $growthValueCustomer->level_updated_at = now();
|
|
|
+ }
|
|
|
+
|
|
|
+ $growthValueCustomer->growth_value = $newGrowthValue;
|
|
|
+ $growthValueCustomer->save();
|
|
|
+
|
|
|
+ $history = GrowthValueHistory::create([
|
|
|
+ 'customer_id' => $customerId,
|
|
|
+ 'order_id' => null,
|
|
|
+ 'order_amount' => 0,
|
|
|
+ 'growth_value_earned' => $amount,
|
|
|
+ 'total_growth_value' => $newGrowthValue,
|
|
|
+ 'level_before' => $levelBefore,
|
|
|
+ 'level_after' => $levelAfter,
|
|
|
+ 'event_type' => GrowthValueHistory::EVENT_TYPE_ADMIN_ADJUST,
|
|
|
+ 'description' => $description,
|
|
|
+ 'expires_at' => null,
|
|
|
+ 'created_at' => now(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ Log::info('Growth value adjusted by admin', [
|
|
|
+ 'customer_id' => $customerId,
|
|
|
+ 'amount' => $amount,
|
|
|
+ 'new_total' => $newGrowthValue,
|
|
|
+ 'level_before' => $levelBefore,
|
|
|
+ 'level_after' => $levelAfter,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $history;
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error adjusting growth value', [
|
|
|
+ 'customer_id' => $customerId,
|
|
|
+ 'amount' => $amount,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有等级配置
|
|
|
+ */
|
|
|
+ public function getAllLevels()
|
|
|
+ {
|
|
|
+ return GrowthValueLevel::where('is_active', true)
|
|
|
+ ->orderBy('sort_order')
|
|
|
+ ->get();
|
|
|
+ }
|
|
|
+}
|