Order.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <?php
  2. namespace App\Models;
  3. use App\Casts\money;
  4. use App\Observers\OrderObserver;
  5. use App\Utils\Helpers;
  6. use Auth;
  7. use Illuminate\Database\Eloquent\Attributes\ObservedBy;
  8. use Illuminate\Database\Eloquent\Builder;
  9. use Illuminate\Database\Eloquent\Model;
  10. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  11. use Illuminate\Database\Eloquent\Relations\HasOne;
  12. use Kyslik\ColumnSortable\Sortable;
  13. /**
  14. * 订单.
  15. */
  16. #[ObservedBy([OrderObserver::class])]
  17. class Order extends Model
  18. {
  19. use Sortable;
  20. public array $sortable = ['id', 'sn', 'expired_at', 'created_at'];
  21. protected $table = 'order';
  22. protected $guarded = [];
  23. protected $casts = ['origin_amount' => money::class, 'amount' => money::class, 'expired_at' => 'datetime'];
  24. public function user(): BelongsTo
  25. {
  26. return $this->belongsTo(User::class);
  27. }
  28. public function goods(): BelongsTo
  29. {
  30. return $this->belongsTo(Goods::class)->withTrashed();
  31. }
  32. public function coupon(): BelongsTo
  33. {
  34. return $this->belongsTo(Coupon::class)->withTrashed();
  35. }
  36. public function payment(): HasOne
  37. {
  38. return $this->hasOne(Payment::class);
  39. }
  40. public function scopeUid(Builder $query, ?int $uid = null): Builder
  41. {
  42. return $query->whereUserId($uid ?? Auth::id());
  43. }
  44. public function scopeRecentUnPay(Builder $query, int $minutes = 0): Builder
  45. {
  46. if (! $minutes) {
  47. $minutes = (int) config('tasks.close.orders');
  48. }
  49. return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-$minutes minutes")));
  50. }
  51. public function scopeUserPrepay(Builder $query, ?int $uid = null): Builder
  52. {
  53. return $query->uid($uid)->whereStatus(3)->oldest();
  54. }
  55. public function scopeActive(Builder $query): Builder
  56. {
  57. return $query->whereIsExpire(0)->whereStatus(2);
  58. }
  59. public function scopeActivePlan(Builder $query): Builder
  60. {
  61. return $query->active()->isPlan();
  62. }
  63. public function scopeIsPlan(Builder $query): Builder
  64. {
  65. return $query->with('goods')->whereHas('goods', function ($query) {
  66. $query->whereType(2);
  67. });
  68. }
  69. public function scopeActivePackage(Builder $query): Builder
  70. {
  71. return $query->active()->with('goods')->whereHas('goods', static function ($query) {
  72. $query->whereType(1);
  73. });
  74. }
  75. public function scopeUserActivePlan(Builder $query, ?int $uid = null): Builder
  76. {
  77. return $query->uid($uid)->activePlan();
  78. }
  79. public function scopeUserActivePackage(Builder $query, ?int $uid = null): Builder
  80. {
  81. return $query->uid($uid)->activePackage();
  82. }
  83. public function close(): bool
  84. { // 关闭订单
  85. return $this->update(['status' => -1]);
  86. }
  87. public function paid(): bool
  88. { // 支付需要确认的订单
  89. return $this->update(['status' => 1]);
  90. }
  91. public function complete(): bool
  92. { // 完成订单
  93. return $this->update(['status' => 2]);
  94. }
  95. public function prepay(): bool
  96. { // 预支付订单
  97. return $this->update(['status' => 3]);
  98. }
  99. public function expired(): bool
  100. { // 预支付订单
  101. return $this->update(['is_expire' => 1]);
  102. }
  103. public function getStatusLabelAttribute(): string
  104. { // 订单状态
  105. return $this->statusTags($this->status, $this->is_expire);
  106. }
  107. public function statusTags(int $status, bool $expire, bool $isHtml = true): string
  108. {
  109. switch ($status) {
  110. case -1:
  111. $label = trans('common.order.status.canceled');
  112. break;
  113. case 0:
  114. $tag = 1;
  115. $label = trans('common.payment.status.wait');
  116. break;
  117. case 1:
  118. $tag = 2;
  119. $label = trans('common.order.status.review');
  120. break;
  121. case 2:
  122. if ($this->goods_id === null) {
  123. $label = trans('common.order.status.completed');
  124. } elseif ($expire) {
  125. $label = trans('common.status.expire');
  126. } else {
  127. $tag = 3;
  128. $label = trans('common.order.status.ongoing');
  129. }
  130. break;
  131. case 3:
  132. $tag = 2;
  133. $label = trans('common.order.status.prepaid');
  134. break;
  135. default:
  136. $tag = 4;
  137. $label = trans('common.status.unknown');
  138. }
  139. if ($isHtml) {
  140. $label = '<span class="badge badge-'.['default', 'danger', 'info', 'success', 'warning'][$tag ?? 0].'">'.$label.'</span>';
  141. }
  142. return $label;
  143. }
  144. public function getOriginAmountTagAttribute(): string
  145. {
  146. return Helpers::getPriceTag($this->origin_amount);
  147. }
  148. public function getAmountTagAttribute(): string
  149. {
  150. return Helpers::getPriceTag($this->amount);
  151. }
  152. // 支付渠道
  153. public function getPayTypeLabelAttribute(): string
  154. {
  155. return match ($this->pay_type) {
  156. 0 => trans('common.payment.credit'),
  157. 1 => trans('common.payment.alipay'),
  158. 2 => trans('common.payment.qq'),
  159. 3 => trans('common.payment.wechat'),
  160. 4 => trans('common.payment.crypto'),
  161. 5 => 'PayPal',
  162. 6 => 'Stripe',
  163. 7 => trans('common.payment.manual'),
  164. default => '',
  165. };
  166. }
  167. // 支付图标
  168. public function getPayTypeIconAttribute(): string
  169. {
  170. return '/assets/images/payment/'.config('common.payment.icon')[$this->pay_type] ?? 'coin.png';
  171. }
  172. // 支付方式
  173. public function getPayWayLabelAttribute(): string
  174. {
  175. return config('common.payment.labels')[$this->pay_way] ?? trans('common.status.unknown');
  176. }
  177. }