476 lines
11 KiB
PHP
476 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Constants\OrderStatus;
|
|
use App\Enums\PayWay;
|
|
use App\Models\Store\Store;
|
|
use Dcat\Admin\Traits\HasDateTimeFormatter;
|
|
use EloquentFilter\Filterable;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class Order extends Model
|
|
{
|
|
use Filterable;
|
|
use HasDateTimeFormatter;
|
|
|
|
/**
|
|
* 订单状态
|
|
*/
|
|
public const STATUS_PENDING = 0; // 待付款
|
|
public const STATUS_PAID = 1; // 已付款
|
|
public const STATUS_COMPLETED = 9; // 已完成
|
|
public const STATUS_CANCELLED = 10; // 已取消
|
|
|
|
/**
|
|
* 发货状态
|
|
*/
|
|
public const SHIPPING_STATE_PENDING = 0; // 待发货
|
|
public const SHIPPING_STATE_PROCESSING = 1; // 发货中
|
|
public const SHIPPING_STATE_PROCESSED = 2; // 已完成
|
|
|
|
/**
|
|
* 支付方式
|
|
*/
|
|
public const PAY_WAY_WXPAY = 'wxpay'; // 微信支付
|
|
public const PAY_WAY_ALIPAY = 'alipay'; // 支付宝
|
|
public const PAY_WAY_WALLET = 'wallet'; // 钱包
|
|
public const PAY_WAY_BALANCE = 'balance'; // 余额
|
|
public const PAY_WAY_OFFLINE = 'offline'; // 现金支付
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $attributes = [
|
|
'reduced_amount' => 0,
|
|
'is_change' => false,
|
|
'status' => self::STATUS_PENDING,
|
|
'point_discount_amount' => 0,
|
|
];
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $casts = [
|
|
'pay_way' => PayWay::class,
|
|
'pay_at' => 'datetime',
|
|
'completed_at' => 'datetime',
|
|
'auto_complete_at' => 'datetime',
|
|
'profit_paid' => 'datetime',
|
|
'status' => 'int',
|
|
'is_change' => 'bool',
|
|
// 订单分账
|
|
// status: Y/N, 分账状态, Y: 开始分账, N: 已经完结(解冻资金)
|
|
// share_sn: 20230xxxxx, 分账订单号
|
|
// finish_sn: 20230xxxxx, 完结分账订单号
|
|
'wx_share' => 'json',
|
|
];
|
|
|
|
/**
|
|
* @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',
|
|
'out_trade_no',
|
|
'consignee_name',
|
|
'consignee_telephone',
|
|
'consignee_zone',
|
|
'consignee_address',
|
|
'shipping_state',
|
|
'status',
|
|
'completed_at',
|
|
'auto_complete_at',
|
|
'is_change',
|
|
'sales_value',
|
|
'bargain_amount',
|
|
'profit',
|
|
'source_type',
|
|
'source_id',
|
|
'store_id',
|
|
'inviter_id',
|
|
'market_price',
|
|
'cost_price',
|
|
'profit_paid',
|
|
'point_discount_amount',
|
|
'wx_share',
|
|
];
|
|
|
|
/**
|
|
* 仅查询支付过期的订单
|
|
*/
|
|
public function scopeExpired($query)
|
|
{
|
|
return $query->where('status', static::STATUS_PENDING)
|
|
->where('created_at', '<=', now()->subSeconds(app_settings('app.order_payment_expires_at')));
|
|
}
|
|
|
|
/**
|
|
* 仅查询可自动完成的订单
|
|
*/
|
|
public function scopeCompletable($query)
|
|
{
|
|
return $query->where('status', static::STATUS_PAID)
|
|
->where('shipping_state', static::SHIPPING_STATE_PROCESSED)
|
|
->where('auto_complete_at', '<=', now());
|
|
}
|
|
|
|
/**
|
|
* 仅查询待发货的订单
|
|
*/
|
|
public function scopeNeedShipping($query)
|
|
{
|
|
return $query->where('status', static::STATUS_PAID)
|
|
->where('shipping_state', '<', static::SHIPPING_STATE_PROCESSED);
|
|
}
|
|
|
|
/**
|
|
* 下单人
|
|
*
|
|
* @return void
|
|
*/
|
|
public function user()
|
|
{
|
|
return $this->belongsTo(User::class, 'user_id');
|
|
}
|
|
|
|
/**
|
|
* 下单人信息
|
|
*/
|
|
public function userInfo()
|
|
{
|
|
return $this->belongsTo(UserInfo::class, 'user_id', 'user_id');
|
|
}
|
|
|
|
|
|
public function inviter()
|
|
{
|
|
return $this->belongsTo(User::class, 'inviter_id');
|
|
}
|
|
|
|
public function inviterInfo()
|
|
{
|
|
return $this->belongsTo(UserInfo::class, 'inviter_id', 'user_id');
|
|
}
|
|
|
|
/**
|
|
* 门店
|
|
*/
|
|
public function store()
|
|
{
|
|
return $this->belongsTo(Store::class, 'store_id');
|
|
}
|
|
|
|
/**
|
|
* 使用的优惠券
|
|
*
|
|
* @return void
|
|
*/
|
|
public function userCoupon()
|
|
{
|
|
return $this->hasOne(UserCoupon::class, 'id', 'user_coupon_id');
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的商品
|
|
*/
|
|
public function products()
|
|
{
|
|
return $this->hasMany(OrderProduct::class);
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的发货包裹
|
|
*/
|
|
public function packages()
|
|
{
|
|
return $this->hasMany(OrderPackage::class);
|
|
}
|
|
|
|
/**
|
|
* 此订单的最新包裹
|
|
*
|
|
*/
|
|
public function lastPackage()
|
|
{
|
|
return $this->hasOne(OrderPackage::class)->where('is_failed', false)->latestOfMany();
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的退款任务
|
|
*/
|
|
public function refundLogs()
|
|
{
|
|
return $this->hasMany(OrderRefundLog::class);
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的标签
|
|
*/
|
|
public function tags()
|
|
{
|
|
return $this->belongsToMany(Tag::class, 'taggables', 'taggable_id', 'tag_id')->wherePivot('taggable_type', self::class)->withTimestamps();
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的支付记录
|
|
*/
|
|
public function payLogs()
|
|
{
|
|
return $this->morphMany(PayLog::class, 'payable');
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的售后单
|
|
*/
|
|
public function afterSales()
|
|
{
|
|
return $this->hasMany(AfterSale::class, 'order_id');
|
|
}
|
|
|
|
/**
|
|
* 属于此订单的返利记录
|
|
*/
|
|
public function profits()
|
|
{
|
|
return $this->hasMany(OrderProfit::class, 'order_id');
|
|
}
|
|
|
|
/**
|
|
* 订单来源
|
|
*/
|
|
public function source()
|
|
{
|
|
return $this->morphTo();
|
|
}
|
|
|
|
/**
|
|
* 此订单是否待付款
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isPending(): bool
|
|
{
|
|
return $this->status === static::STATUS_PENDING;
|
|
}
|
|
|
|
/**
|
|
* 确认此订单是否已付款
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isPaid(): bool
|
|
{
|
|
return $this->status === static::STATUS_PAID;
|
|
}
|
|
|
|
/**
|
|
* 确认此订单是否是待发货
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isWaitShipping(): bool
|
|
{
|
|
return $this->status === static::STATUS_PAID
|
|
&& $this->shipping_state === static::SHIPPING_STATE_PENDING;
|
|
}
|
|
|
|
/**
|
|
* 确认此订单是否是发货中
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isShipping(): bool
|
|
{
|
|
return $this->status === static::STATUS_PAID
|
|
&& $this->shipping_state === static::SHIPPING_STATE_PROCESSING;
|
|
}
|
|
|
|
/**
|
|
* 确认此订单是否是已发货
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isShipped(): bool
|
|
{
|
|
return $this->status === static::STATUS_PAID
|
|
&& $this->shipping_state === static::SHIPPING_STATE_PROCESSED;
|
|
}
|
|
|
|
/**
|
|
* 确认此订单是否是已完成
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isCompleted(): bool
|
|
{
|
|
return $this->status === static::STATUS_COMPLETED;
|
|
}
|
|
|
|
/**
|
|
* 确认此订单是否是已取消
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isCancelled(): bool
|
|
{
|
|
return $this->status === static::STATUS_CANCELLED;
|
|
}
|
|
|
|
/**
|
|
* 获取订单券优惠金额
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getCouponDiscountAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['coupon_discount_amount'], 100, 2));
|
|
}
|
|
|
|
/**
|
|
* 获取订单会员折扣金额
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getVipDiscountAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['vip_discount_amount'], 100, 2));
|
|
}
|
|
|
|
/**
|
|
* 获取订单减免金额
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getReducedAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['reduced_amount'], 100, 2));
|
|
}
|
|
|
|
/**
|
|
* 获取订单邮费
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getShippingFeeFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['shipping_fee'], 100, 2));
|
|
}
|
|
|
|
/**
|
|
* 获取订单支付金额
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTotalAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['total_amount'], 100, 2));
|
|
}
|
|
|
|
/**
|
|
* 获取订单商品总额
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getProductsTotalAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['products_total_amount'], 100, 2));
|
|
}
|
|
|
|
/**
|
|
* 待支付订单过期时间
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getExpiresAtAttribute()
|
|
{
|
|
$seconds = 0;
|
|
|
|
if ($this->isPending()) {
|
|
$seconds = now()->diffInSeconds(
|
|
$this->created_at->addSeconds(app_settings('app.order_payment_expires_at', 1800)), false
|
|
);
|
|
}
|
|
|
|
return $seconds > 0 ? $seconds : 0;
|
|
}
|
|
|
|
/**
|
|
* 获取订单状态
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getOrderStatusAttribute(): int
|
|
{
|
|
// 待付款
|
|
if ($this->isPending()) {
|
|
return OrderStatus::PENDING;
|
|
}
|
|
|
|
// 待发货
|
|
if ($this->isWaitShipping()) {
|
|
return OrderStatus::WAIT_SHIPPING;
|
|
}
|
|
|
|
// 发货中
|
|
if ($this->isShipping()) {
|
|
return OrderStatus::SHIPPING;
|
|
}
|
|
|
|
// 已发货
|
|
if ($this->isShipped()) {
|
|
return OrderStatus::SHIPPED;
|
|
}
|
|
|
|
// 已完成
|
|
if ($this->isCompleted()) {
|
|
return OrderStatus::COMPLETED;
|
|
}
|
|
|
|
// 已取消
|
|
if ($this->isCancelled()) {
|
|
return OrderStatus::CANCELLED;
|
|
}
|
|
|
|
// 其它
|
|
return OrderStatus::UNKNOWN;
|
|
}
|
|
|
|
/**
|
|
* 获取订单状态
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getOrderStatusTextAttribute(): string
|
|
{
|
|
return OrderStatus::$statusTexts[$this->order_status] ?? OrderStatus::$statusTexts[OrderStatus::UNKNOWN];
|
|
}
|
|
|
|
/**
|
|
* 获取订单砍价优惠
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getBargainAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['bargain_amount'], 100, 2));
|
|
}
|
|
|
|
public function getPointDiscountAmountFormatAttribute()
|
|
{
|
|
return trim_trailing_zeros(bcdiv($this->attributes['point_discount_amount'], 100, 2));
|
|
}
|
|
}
|