0, 'status' => self::STATUS_PENDING, ]; /** * @var array */ protected $casts = [ 'completed_at' => 'datetime', 'status' => 'int', ]; /** * @var array */ protected $fillable = [ 'user_id', 'sn', 'user_coupon_id', 'coupon_discount_amount', 'vip_discount_amount', 'reduced_amount', 'shipping_fee', 'products_total_amount', 'total_amount', 'note', 'remark', 'pay_sn', 'pay_way', 'pay_at', 'consignee_name', 'consignee_telephone', 'consignee_zone', 'consignee_address', 'status', 'completed_at', ]; /** * @var array */ public static $payWayTexts = [ self::PAY_WAY_ALIPAY => '支付宝', self::PAY_WAY_WXPAY => '微信支付', self::PAY_WAY_BALANCE => '余额', ]; /** * 仅查询已过期的订单 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeExpired($query) { return $query->where('status', static::STATUS_PENDING) ->where('created_at', '<=', now()->subSeconds(static::expiresAt())); } /** * 仅查询待付款的订单 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopePending($query) { return $query->where('status', static::STATUS_PENDING) ->where('created_at', '>', now()->subSeconds(static::expiresAt())); } /** * 仅查询待收货的订单 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeUnreceived($query) { return $query->where('status', [static::STATUS_PAID, static::STATUS_SHIPPED]); } /** * 仅查询已完成的订单 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeCompleted($query) { return $query->where('status', static::STATUS_COMPLETED); } /** * 仅查询已取消的订单 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeCancelled($query) { return $query->where(function ($query) { $query->expired(); })->orWhere('status', static::STATUS_CANCELLED); } /** * 属于此订单的商品 */ public function products() { return $this->hasMany(OrderProduct::class); } /** * 确认此订单是否可以被确认 * * @return bool */ public function isConfirmable(): bool { return in_array($this->status, [static::STATUS_PAID, static::STATUS_SHIPPED]); } /** * 确认此订单是否可以被取消 * * @return bool */ public function isCancelable(): bool { return in_array($this->status, [static::STATUS_PENDING, static::STATUS_PAID]); } /** * 确认此订单是否是待付款 * * @return bool */ public function isPending(): bool { return $this->status === static::STATUS_PENDING; } /** * 获取订单券优惠金额 * * @return int */ public function getStatusAttribute() { if ($this->attributes['status'] === static::STATUS_PENDING && $this->created_at->lte(now()->subSeconds(static::expiresAt())) ) { return static::STATUS_CANCELLED; } return $this->attributes['status']; } /** * 获取订单券优惠金额 * * @return string */ public function getCouponDiscountAmountFormatAttribute() { return Numeric::trimTrailingZero(bcdiv($this->attributes['coupon_discount_amount'], 100, 2)); } /** * 获取订单会员折扣金额 * * @return string */ public function getVipDiscountAmountFormatAttribute() { return Numeric::trimTrailingZero(bcdiv($this->attributes['vip_discount_amount'], 100, 2)); } /** * 获取订单减免金额 * * @return string */ public function getReducedAmountFormatAttribute() { return Numeric::trimTrailingZero(bcdiv($this->attributes['reduced_amount'], 100, 2)); } /** * 获取订单邮费 * * @return string */ public function getShippingFeeFormatAttribute() { return Numeric::trimTrailingZero(bcdiv($this->attributes['shipping_fee'], 100, 2)); } /** * 获取订单支付金额 * * @return string */ public function getTotalAmountFormatAttribute() { return Numeric::trimTrailingZero(bcdiv($this->attributes['total_amount'], 100, 2)); } /** * 获取订单商品总额 * * @return string */ public function getProductsTotalAmountFormatAttribute() { return Numeric::trimTrailingZero(bcdiv($this->attributes['products_total_amount'], 100, 2)); } /** * 待支付订单过期时间 * * @return int */ public function getExpiresAtAttribute() { if (! $this->isPending()) { return 0; } return 1800; } /** * 待付款订单的过期时间(单位:秒) * * @return int */ public static function expiresAt(): int { return 1800; } }