ShopPurchaseLimit.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. namespace App\Module\Shop\Models;
  3. use App\Module\Shop\Enums\PURCHASE_LIMIT_PERIOD;
  4. use App\Module\Shop\Enums\PURCHASE_LIMIT_TYPE;
  5. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  6. use Illuminate\Database\Eloquent\Relations\HasMany;
  7. use UCore\ModelCore;
  8. /**
  9. * 商店限购配置模型
  10. *
  11. * field start
  12. * @property int $id 限购配置ID,主键
  13. * @property int $shop_item_id 商品ID,外键关联kku_shop_items表
  14. * @property \App\Module\Shop\Enums\PURCHASE_LIMIT_TYPE $limit_type 限购类型(1:单次购买限制, 2:周期性购买限制)
  15. * @property \App\Module\Shop\Enums\PURCHASE_LIMIT_PERIOD $limit_period 限购周期(0:永久, 1:每日, 2:每周, 3:每月, 4:每年)
  16. * @property int $max_quantity 最大购买数量
  17. * @property string $name 限购规则名称
  18. * @property string $description 限购规则描述
  19. * @property bool $is_active 是否激活(0:否, 1:是)
  20. * @property int $sort_order 排序权重
  21. * @property \Carbon\Carbon $created_at 创建时间
  22. * @property \Carbon\Carbon $updated_at 更新时间
  23. * field end
  24. */
  25. class ShopPurchaseLimit extends ModelCore
  26. {
  27. /**
  28. * 与模型关联的表名
  29. *
  30. * @var string
  31. */
  32. protected $table = 'shop_purchase_limits';
  33. /**
  34. * 可批量赋值的属性
  35. *
  36. * @var array
  37. */
  38. protected $fillable = [
  39. 'shop_item_id',
  40. 'limit_type',
  41. 'limit_period',
  42. 'max_quantity',
  43. 'name',
  44. 'description',
  45. 'is_active',
  46. 'sort_order',
  47. ];
  48. /**
  49. * 应该被转换为原生类型的属性
  50. *
  51. * @var array
  52. */
  53. protected $casts = [
  54. 'is_active' => 'boolean',
  55. 'limit_type' => PURCHASE_LIMIT_TYPE::class,
  56. 'limit_period' => PURCHASE_LIMIT_PERIOD::class,
  57. ];
  58. /**
  59. * 获取关联的商品
  60. *
  61. * @return BelongsTo
  62. */
  63. public function shopItem(): BelongsTo
  64. {
  65. return $this->belongsTo(ShopItem::class, 'shop_item_id');
  66. }
  67. /**
  68. * 获取用户购买计数记录
  69. *
  70. * @return HasMany
  71. */
  72. public function userCounters(): HasMany
  73. {
  74. return $this->hasMany(ShopUserPurchaseCounter::class, 'limit_id');
  75. }
  76. /**
  77. * 获取用户在此限购规则下的购买计数
  78. *
  79. * @param int $userId 用户ID
  80. * @return int 购买计数
  81. */
  82. public function getUserPurchaseCount(int $userId): int
  83. {
  84. $counter = $this->userCounters()
  85. ->where('user_id', $userId)
  86. ->first();
  87. if (!$counter) {
  88. return 0;
  89. }
  90. // 检查是否需要重置计数
  91. if ($this->limit_period->shouldReset($counter->last_reset_time)) {
  92. $counter->resetCount();
  93. return 0;
  94. }
  95. return $counter->current_count;
  96. }
  97. /**
  98. * 增加用户购买计数
  99. *
  100. * @param int $userId 用户ID
  101. * @param int $quantity 购买数量
  102. * @return bool
  103. */
  104. public function incrementUserPurchaseCount(int $userId, int $quantity = 1): bool
  105. {
  106. $counter = ShopUserPurchaseCounter::firstOrCreate(
  107. [
  108. 'limit_id' => $this->id,
  109. 'user_id' => $userId,
  110. ],
  111. [
  112. 'current_count' => 0,
  113. 'last_reset_time' => now(),
  114. ]
  115. );
  116. // 检查是否需要重置计数
  117. if ($this->limit_period->shouldReset($counter->last_reset_time)) {
  118. $counter->resetCount();
  119. }
  120. $counter->current_count += $quantity;
  121. return $counter->save();
  122. }
  123. /**
  124. * 检查用户是否可以购买指定数量
  125. *
  126. * @param int $userId 用户ID
  127. * @param int $quantity 购买数量
  128. * @return array [是否可购买, 错误消息, 剩余可购买数量]
  129. */
  130. public function canUserPurchase(int $userId, int $quantity): array
  131. {
  132. if (!$this->is_active) {
  133. return [true, '', $this->max_quantity]; // 限购规则未激活,不限制
  134. }
  135. $currentCount = $this->getUserPurchaseCount($userId);
  136. $remainingQuantity = $this->max_quantity - $currentCount;
  137. if ($quantity > $remainingQuantity) {
  138. $periodName = $this->limit_period->getName($this->limit_period->value);
  139. $typeName = $this->limit_type->getName($this->limit_type->value);
  140. $message = match ($this->limit_type) {
  141. PURCHASE_LIMIT_TYPE::SINGLE_PURCHASE => "单次购买数量不能超过{$this->max_quantity}个",
  142. PURCHASE_LIMIT_TYPE::PERIODIC_PURCHASE => "{$periodName}内最多购买{$this->max_quantity}个,剩余可购买{$remainingQuantity}个",
  143. };
  144. return [false, $message, $remainingQuantity];
  145. }
  146. return [true, '', $remainingQuantity];
  147. }
  148. /**
  149. * 获取限购类型文本
  150. *
  151. * @return string
  152. */
  153. public function getLimitTypeTextAttribute(): string
  154. {
  155. return $this->limit_type->getName($this->limit_type->value);
  156. }
  157. /**
  158. * 获取限购周期文本
  159. *
  160. * @return string
  161. */
  162. public function getLimitPeriodTextAttribute(): string
  163. {
  164. return $this->limit_period->getName($this->limit_period->value);
  165. }
  166. }