ShopItem.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <?php
  2. namespace App\Module\Shop\Models;
  3. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  4. use Illuminate\Database\Eloquent\Relations\BelongsToMany;
  5. use Illuminate\Database\Eloquent\Relations\HasMany;
  6. use Illuminate\Support\Facades\DB;
  7. use UCore\ModelCore;
  8. use App\Module\GameItems\Models\Item;
  9. use App\Module\Shop\Models\ShopCategory;
  10. use App\Module\Shop\Models\ShopPromotion;
  11. use App\Module\Shop\Models\ShopPromotionItem;
  12. /**
  13. * 商店物品模型
  14. *
  15. * field start
  16. * field end
  17. */
  18. class ShopItem extends ModelCore
  19. {
  20. /**
  21. * 与模型关联的表名
  22. *
  23. * @var string
  24. */
  25. protected $table = 'shop_items';
  26. /**
  27. * 可批量赋值的属性
  28. *
  29. * @var array
  30. */
  31. protected $fillable = [
  32. 'name',
  33. 'description',
  34. 'category_id',
  35. 'item_id',
  36. 'item_quantity',
  37. 'price',
  38. 'currency_id',
  39. 'max_buy',
  40. 'is_active',
  41. 'sort_order',
  42. 'image',
  43. 'start_time',
  44. 'end_time',
  45. ];
  46. /**
  47. * 应该被转换为日期的属性
  48. *
  49. * @var array
  50. */
  51. protected $dates = [
  52. 'start_time',
  53. 'end_time',
  54. 'created_at',
  55. 'updated_at',
  56. ];
  57. /**
  58. * 应该被转换为原生类型的属性
  59. *
  60. * @var array
  61. */
  62. protected $casts = [
  63. 'is_active' => 'boolean',
  64. ];
  65. /**
  66. * 获取关联的物品
  67. *
  68. * @return BelongsTo
  69. */
  70. public function item(): BelongsTo
  71. {
  72. return $this->belongsTo(Item::class, 'item_id');
  73. }
  74. /**
  75. * 获取关联的分类
  76. *
  77. * @return BelongsTo
  78. */
  79. public function category(): BelongsTo
  80. {
  81. return $this->belongsTo(ShopCategory::class, 'category_id');
  82. }
  83. /**
  84. * 获取用户已购买数量
  85. *
  86. * @param int $userId 用户ID
  87. * @return int 已购买数量
  88. */
  89. public function getUserBoughtCount(int $userId): int
  90. {
  91. return ShopPurchaseLog::where('user_id', $userId)
  92. ->where('shop_item_id', $this->id)
  93. ->sum('quantity');
  94. }
  95. /**
  96. * 获取该商品关联的促销活动
  97. *
  98. * @return BelongsToMany
  99. */
  100. public function promotions(): BelongsToMany
  101. {
  102. return $this->belongsToMany(
  103. ShopPromotion::class,
  104. 'shop_promotion_items',
  105. 'shop_item_id',
  106. 'promotion_id'
  107. )->withPivot('custom_discount_value')
  108. ->withTimestamps();
  109. }
  110. /**
  111. * 获取商品的促销关联记录
  112. *
  113. * @return HasMany
  114. */
  115. public function promotionItems(): HasMany
  116. {
  117. return $this->hasMany(ShopPromotionItem::class, 'shop_item_id');
  118. }
  119. /**
  120. * 获取当前有效的促销活动
  121. *
  122. * @return ShopPromotion|null
  123. */
  124. public function getActivePromotion(): ?ShopPromotion
  125. {
  126. $now = now();
  127. return $this->promotions()
  128. ->where('is_active', true)
  129. ->where(function ($query) use ($now) {
  130. $query->whereNull('start_time')
  131. ->orWhere('start_time', '<=', $now);
  132. })
  133. ->where(function ($query) use ($now) {
  134. $query->whereNull('end_time')
  135. ->orWhere('end_time', '>=', $now);
  136. })
  137. ->orderBy('sort_order')
  138. ->first();
  139. }
  140. /**
  141. * 获取折扣后的价格
  142. *
  143. * @return int
  144. */
  145. public function getDiscountedPrice(): int
  146. {
  147. $promotion = $this->getActivePromotion();
  148. if (!$promotion) {
  149. return $this->price;
  150. }
  151. $promotionItem = $this->promotionItems()
  152. ->where('promotion_id', $promotion->id)
  153. ->first();
  154. $customDiscountValue = $promotionItem ? $promotionItem->custom_discount_value : null;
  155. return $promotion->calculateDiscountedPrice($this->price, $customDiscountValue);
  156. }
  157. /**
  158. * 记录购买记录
  159. *
  160. * @param int $userId 用户ID
  161. * @param int $quantity 购买数量
  162. * @param int $totalPrice 总价
  163. * @return ShopPurchaseLog 购买记录
  164. */
  165. public function recordPurchase(int $userId, int $quantity, int $totalPrice): ShopPurchaseLog
  166. {
  167. $log = new ShopPurchaseLog([
  168. 'user_id' => $userId,
  169. 'shop_item_id' => $this->id,
  170. 'item_id' => $this->item_id,
  171. 'quantity' => $quantity,
  172. 'price' => $this->price,
  173. 'total_price' => $totalPrice,
  174. 'currency_id' => $this->currency_id,
  175. 'purchase_time' => now(),
  176. 'ip_address' => request()->ip(),
  177. 'device_info' => request()->userAgent(),
  178. ]);
  179. $log->save();
  180. return $log;
  181. }
  182. }