- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\Admin;
use app\admin\model\shopro\user\User;
class Action extends Common
{
protected $name = 'shopro_order_action';
protected $type = [
];
// 追加属性
protected $append = [
'oper'
];
public static function add($order, $item = null, $oper = null, $type = 'user', $remark = '')
{
$oper_id = $oper ? $oper['id'] : 0;
$self = new self();
$self->order_id = $order->id;
$self->order_item_id = is_null($item) ? 0 : $item->id;
$self->oper_type = $type;
$self->oper_id = $oper_id;
$self->order_status = $order->status;
$self->dispatch_status = is_null($item) ? 0 : $item->dispatch_status;
$self->comment_status = is_null($item) ? 0 : $item->comment_status;
$self->aftersale_status = is_null($item) ? 0 : $item->aftersale_status;
$self->refund_status = is_null($item) ? 0 : $item->refund_status;
$self->remark = $remark;
$self->save();
return $self;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
class Address extends Common
{
protected $name = 'shopro_order_address';
protected $type = [
];
// 追加属性
protected $append = [
];
}

View File

@@ -0,0 +1,286 @@
<?php
namespace app\admin\model\shopro\order;
use traits\model\SoftDelete;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
class Aftersale extends Common
{
use SoftDelete;
protected $name = 'shopro_order_aftersale';
protected $deleteTime = 'deletetime';
// 追加属性
protected $append = [
'type_text',
'btns',
'dispatch_status_text',
'aftersale_status_text',
'aftersale_status_desc',
'refund_status_text'
];
// 发货状态
const DISPATCH_STATUS_REFUSE = -1; // 拒收
const DISPATCH_STATUS_NOSEND = 0; // 未发货
const DISPATCH_STATUS_SENDED = 1; // 已发货
const DISPATCH_STATUS_GETED = 2; // 已收货
// 售后状态
const AFTERSALE_STATUS_CANCEL = -2; // 已取消
const AFTERSALE_STATUS_REFUSE = -1; // 拒绝
const AFTERSALE_STATUS_NOOPER = 0; // 未处理
const AFTERSALE_STATUS_ING = 1; // 申请售后
const AFTERSALE_STATUS_COMPLETED = 2; // 售后完成
// 退款状态
const REFUND_STATUS_NOREFUND = 0; // 未退款
const REFUND_STATUS_AGREE = 1; // 已同意
public function typeList()
{
return [
'refund' => '仅退款',
'return' => '退货退款',
'other' => '其他'
];
}
public function dispatchStatusList()
{
return [
self::DISPATCH_STATUS_REFUSE => '已拒收',
self::DISPATCH_STATUS_NOSEND => '未发货',
self::DISPATCH_STATUS_SENDED => '已发货',
self::DISPATCH_STATUS_GETED => '已收货'
];
}
public function aftersaleStatusList()
{
return [
self::AFTERSALE_STATUS_CANCEL => '已取消',
self::AFTERSALE_STATUS_REFUSE => '拒绝',
self::AFTERSALE_STATUS_NOOPER => '未处理',
self::AFTERSALE_STATUS_ING => '申请售后',
self::AFTERSALE_STATUS_COMPLETED => '售后完成'
];
}
public function aftersaleStatusDescList()
{
return [
self::AFTERSALE_STATUS_CANCEL => '买家取消了售后申请',
self::AFTERSALE_STATUS_REFUSE => '卖家拒绝了售后申请',
self::AFTERSALE_STATUS_NOOPER => '买家申请了售后,请及时处理',
self::AFTERSALE_STATUS_ING => '售后正在处理中',
self::AFTERSALE_STATUS_COMPLETED => '售后已完成'
];
}
public function refundStatusList()
{
return [
self::REFUND_STATUS_NOREFUND => '未退款',
self::REFUND_STATUS_AGREE => '同意退款',
];
}
// 已取消
public function scopeCancel($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_CANCEL);
}
// 已拒绝
public function scopeRefuse($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_REFUSE);
}
public function scopeNoOper($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_NOOPER);
}
// 处理中
public function scopeIng($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_ING);
}
// 处理完成
public function scopeCompleted($query)
{
return $query->where('aftersale_status', self::AFTERSALE_STATUS_COMPLETED);
}
// 需要处理的,包含未处理,和处理中的,个人中心显示售后数量
public function scopeNeedOper($query)
{
return $query->whereIn('aftersale_status', [self::AFTERSALE_STATUS_NOOPER, self::AFTERSALE_STATUS_ING]);
}
/**
* 后台售后列表,主表是 order 表时不用用 scope 了
*
* @param [type] $scope
* @return void
*/
public static function getScopeWhere($scope)
{
$where = [];
switch ($scope) {
case 'cancel':
$where['aftersale_status'] = self::AFTERSALE_STATUS_CANCEL;
break;
case 'refuse':
$where['aftersale_status'] = self::AFTERSALE_STATUS_REFUSE;
break;
case 'nooper':
$where['aftersale_status'] = self::AFTERSALE_STATUS_NOOPER;
break;
case 'ing':
$where['aftersale_status'] = self::AFTERSALE_STATUS_ING;
break;
case 'completed':
$where['aftersale_status'] = self::AFTERSALE_STATUS_COMPLETED;
break;
}
return $where;
}
// 可以取消
public function scopeCanCancel($query)
{
// 未处理,处理中,可以取消
return $query->where('aftersale_status', 'in', [
self::AFTERSALE_STATUS_NOOPER,
self::AFTERSALE_STATUS_ING
]);
}
// 可以操作
public function scopeCanOper($query)
{
// 未处理,处理中,可以 操作退款,拒绝,完成
return $query->where('aftersale_status', 'in', [
self::AFTERSALE_STATUS_NOOPER,
self::AFTERSALE_STATUS_ING
]);
}
// 可以删除
public function scopeCanDelete($query)
{
// 取消,拒绝,完成可以删除
return $query->where('aftersale_status', 'in', [
self::AFTERSALE_STATUS_CANCEL,
self::AFTERSALE_STATUS_REFUSE,
self::AFTERSALE_STATUS_COMPLETED
]);
}
public function getDispatchStatusTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_status'] ?? null);
$list = $this->dispatchStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getBtnsAttr($value, $data)
{
$btns = [];
switch ($data['aftersale_status']) {
case self::AFTERSALE_STATUS_NOOPER:
case self::AFTERSALE_STATUS_ING:
$btns[] = 'cancel';
break;
case self::AFTERSALE_STATUS_CANCEL:
case self::AFTERSALE_STATUS_REFUSE:
case self::AFTERSALE_STATUS_COMPLETED:
$btns[] = 'delete';
break;
}
return $btns;
}
public function getAftersaleStatusTextAttr($value, $data)
{
$value = $value ?: ($data['aftersale_status'] ?? null);
$list = $this->aftersaleStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getAftersaleStatusDescAttr($value, $data)
{
$value = $value ?: ($data['aftersale_status'] ?? null);
$list = $this->aftersaleStatusDescList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getRefundStatusTextAttr($value, $data)
{
$value = $value ?: ($data['refund_status'] ?? null);
$list = $this->refundStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 获取建议退款金额,不考虑剩余可退款金额是否够退
*
* @param string $value
* @param array $data
* @return string
*/
public function getSuggestRefundFeeAttr($value, $data)
{
$current_goods_amount = bcmul($data['goods_price'], (string)$data['goods_num'], 2);
$total_amount = bcadd($current_goods_amount, $data['dispatch_fee'], 2);
$suggest_refund_fee = bcsub($total_amount, $data['discount_fee'], 2); // (商品金额 + 运费金额) - 总优惠(活动,优惠券,包邮优惠)
return $suggest_refund_fee;
}
public function logs()
{
return $this->hasMany(AftersaleLog::class, 'order_aftersale_id', 'id')->order('id', 'desc');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function order()
{
return $this->belongsTo(Order::class, 'order_id');
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\Admin;
use app\admin\model\shopro\user\User;
class AftersaleLog extends Common
{
protected $name = 'shopro_order_aftersale_log';
protected $type = [
'images' => 'json',
];
protected $append = [
'log_type_text'
];
public function logTypeList()
{
return [
'apply_aftersale' => '售后服务单申请成功,等待售后处理',
'cancel' => '用户取消申请售后',
'delete' => '用户删除售后单',
'completed' => '售后订单已完成',
'refuse' => '卖家拒绝售后',
'refund' => '卖家同意退款',
'add_log' => '卖家留言'
];
}
public static function add($order = null, $aftersale = null, $oper = null, $type = 'user', $data = [])
{
$oper_id = $oper ? $oper['id'] : 0;
$images = $data['images'] ?? [];
$self = new self();
$self->order_id = $order ? $order->id : ($aftersale ? $aftersale->id : 0);
$self->order_aftersale_id = $aftersale ? $aftersale->id : 0;
$self->oper_type = $type;
$self->oper_id = $oper_id;
$self->dispatch_status = $aftersale ? $aftersale->dispatch_status : 0;
$self->aftersale_status = $aftersale ? $aftersale->aftersale_status : 0;
$self->refund_status = $aftersale ? $aftersale->refund_status : 0;
$self->log_type = $data['log_type'];
$self->content = $data['content'] ?? '';
$self->images = $images;
$self->save();
// 售后单变动行为
$data = ['aftersale' => $aftersale, 'order' => $order, 'aftersaleLog' => $self];
\think\Hook::listen('order_aftersale_change', $data);
return $self;
}
/**
* log 类型获取器
*
* @param string $value
* @param array $data
* @return string
*/
public function getLogTypeTextAttr($value, $data)
{
$value = $value ?: ($data['log_type'] ?? null);
$list = $this->logTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
class Express extends Common
{
protected $name = 'shopro_order_express';
protected $type = [
'ext' => 'json'
];
// 追加属性
protected $append = [
'status_text'
];
public function statusList()
{
return [
'noinfo' => '暂无信息',
'collect' => '已揽件',
'transport' => '运输中',
'delivery' => '派送中',
'signfor' => '已签收',
'refuse' => '用户拒收',
'difficulty' => '问题件',
'invalid' => '无效件',
'timeout' => '超时单',
'fail' => '签收失败',
'back' => '退回',
];
}
public function items()
{
return $this->hasMany(OrderItem::class, 'order_express_id', 'id');
}
public function logs()
{
return $this->hasMany(ExpressLog::class, 'order_express_id', 'id')->order('id', 'desc');
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
class ExpressLog extends Common
{
protected $name = 'shopro_order_express_log';
protected $type = [
];
// 追加属性
protected $append = [
'status_text'
];
public function statusList()
{
return [
'noinfo' => '',
'collect' => '已揽件',
'transport' => '运输中',
'delivery' => '派送中',
'signfor' => '已签收',
'refuse' => '用户拒收',
'difficulty' => '问题件',
'invalid' => '无效件',
'timeout' => '超时单',
'fail' => '签收失败',
'back' => '退回',
];
}
}

View File

@@ -0,0 +1,184 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\user\Invoice as UserInvoiceModel;
class Invoice extends Common
{
protected $name = 'shopro_order_invoice';
protected $type = [
'download_urls' => 'array',
'finish_time' => 'timestamp'
];
protected $hidden = [
'order_items'
];
// 追加属性
protected $append = [
'type_text',
'status_text'
];
public function typeList()
{
return (new UserInvoiceModel)->typeList();
}
/**
* 状态
*
* @return array
*/
public function statusList()
{
return [
'cancel' => '已取消',
'unpaid' => '未支付',
'waiting' => '等待开票',
'finish' => '已开具',
];
}
public function getOrderStatusAttr($value, $data)
{
$order = $this->order;
$order_status = 'normal';
if (!$order) {
$order_status = 'order_deleted';
} else if (in_array($order->status, [Order::STATUS_PAID, Order::STATUS_COMPLETED])) {
$items = $this->order_items;
$refund_num = 0;
$aftersale_num = 0;
foreach ($items as $item) {
if (in_array($item->refund_status, [
OrderItem::REFUND_STATUS_AGREE,
OrderItem::REFUND_STATUS_COMPLETED
])) {
$refund_num += 1;
}
if (in_array($item->aftersale_status, [
OrderItem::AFTERSALE_STATUS_REFUSE,
OrderItem::AFTERSALE_STATUS_ING,
OrderItem::AFTERSALE_STATUS_COMPLETED
])) {
$aftersale_num += 1;
}
}
if ($refund_num) {
$order_status = 'refund';
if ($refund_num == count($items)) {
$order_status = 'refund_all';
}
} else if ($aftersale_num) {
$order_status = 'aftersale';
}
} else if ($order->isOffline($order)) {
$order_status = 'offline_unpaid';
}
return $order_status;
}
public function getOrderStatusTextAttr($value, $data)
{
$order_status = $this->order_status;
switch($order_status) {
case 'order_deleted':
$order_status_text = '该订单已被删除';
break;
case 'refund_all':
$order_status_text = '该订单已全部退款';
break;
case 'refund':
$order_status_text = '该订单已部分退款';
break;
case 'aftersale':
$order_status_text = '该订单已申请售后';
break;
case 'offline_unpaid':
$order_status_text = '该订单货到付款-未付款';
break;
default :
$order_status_text = '';
}
return $order_status_text;
}
public function getOrderFeeAttr($value, $data)
{
$order = $this->order;
if ($order && $order->pay_fee != $order->original_pay_fee) {
return [
'pay_fee' => $order->pay_fee,
'original_pay_fee' => $order->original_pay_fee,
];
}
return null;
}
public function scopeCancel($query)
{
return $query->where('status', 'cancel');
}
public function scopeWaiting($query)
{
return $query->where('status', 'waiting');
}
public function scopeFinish($query)
{
return $query->where('status', 'finish');
}
/**
* 不展示 未支付的
*/
public function scopeShow($query)
{
return $query->whereIn('status', ['cancel', 'waiting', 'finish']);
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function order()
{
return $this->belongsTo(Order::class, 'order_id', 'id');
}
public function orderItems()
{
return $this->hasMany(OrderItem::class, 'order_id', 'order_id');
}
}

View File

@@ -0,0 +1,361 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use traits\model\SoftDelete;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\Pay as PayModel;
use app\admin\model\shopro\activity\Activity;
use app\admin\model\shopro\order\traits\OrderScope;
use app\admin\model\shopro\order\traits\OrderStatus;
use app\admin\model\shopro\activity\Order as ActivityOrder;
class Order extends Common
{
use SoftDelete, OrderScope, OrderStatus;
protected $name = 'shopro_order';
protected $deleteTime = 'deletetime';
protected $type = [
'ext' => 'json',
'paid_time' => 'timestamp',
];
// 追加属性
protected $append = [
'type_text',
'status_code',
'status_text',
'status_desc',
'apply_refund_status_text',
'btns',
'platform_text',
'activity_type_text',
'promo_types_text',
'wechat_extra_data'
];
// 订单状态
const STATUS_CLOSED = 'closed';
const STATUS_CANCEL = 'cancel';
const STATUS_UNPAID = 'unpaid';
const STATUS_PAID = 'paid';
const STATUS_COMPLETED = 'completed';
const STATUS_PENDING = 'pending'; // 待定 后付款
const APPLY_REFUND_STATUS_NOAPPLY = 0;
const APPLY_REFUND_STATUS_APPLY = 1;
const APPLY_REFUND_STATUS_FINISH = 2;
const APPLY_REFUND_STATUS_REFUSE = -1;
public function statusList()
{
return [
'closed' => '交易关闭',
'cancel' => '已取消',
'unpaid' => '未支付',
'pending' => '待定', // 货到付款未付款状态
'paid' => '已支付',
'completed' => '已完成'
];
}
public function applyRefundStatusList()
{
return [
self::APPLY_REFUND_STATUS_NOAPPLY => '未申请',
self::APPLY_REFUND_STATUS_APPLY => '申请退款',
self::APPLY_REFUND_STATUS_FINISH => '退款完成',
self::APPLY_REFUND_STATUS_REFUSE => '拒绝申请'
];
}
/**
* 订单列表状态搜索
*/
public function searchStatusList()
{
return [
'unpaid' => '待付款',
'paid' => '已支付', // 包括刚支付的,发货中,和已退款的,以及已完成的所有付过款的订单,不包含货到付款还未真实付款的订单
'nosend' => '待发货',
'noget' => '待收货',
'refuse' => '已拒收',
'nocomment' => '待评价',
'completed' => '已完成',
'aftersale' => '售后',
'applyRefundIng' => '申请退款',
'refund' => '已退款',
'cancel' => '已取消',
'closed' => '交易关闭', // 包含货到付款,拒收的商品
];
}
public function typeList()
{
return [
'goods' => '商城订单',
'score' => '积分订单'
];
}
public function platformList()
{
return [
'H5' => 'H5',
'WechatOfficialAccount' => '微信公众号',
'WechatMiniProgram' => '微信小程序',
'App' => 'App',
];
}
public function getExtAttr($value, $data)
{
$ext = (isset($data['ext']) && $data['ext']) ? json_decode($data['ext'], true) : [];
// 每类活动优惠金额聚合(可能订单购买多个商品,然后同时参与了两种满减,金额累加)
$ext['promo_discounts'] = [
'full_reduce' => 0,
'full_discount' => 0,
'free_shipping' => 0,
'full_gift' => 0
];
if ($ext && isset($ext['promo_infos']) && $ext['promo_infos']) {
foreach ($ext['promo_infos'] as $key => $info) {
if ($info['activity_type'] == 'full_gift') {
$ext['promo_discounts']['full_gift'] = 1;
continue;
}
$ext['promo_discounts'][$info['activity_type']] = bcadd((string)$ext['promo_discounts'][$info['activity_type']], (string)$info['promo_discount_money'], 2);
}
}
// 格式化
$ext['promo_discounts'] = array_map(function ($value) {
return number_format(floatval($value), 2, '.', '');
}, $ext['promo_discounts']);
// 处理时间
if (isset($ext['closed_time']) && $ext['closed_time']) {
$ext['closed_date'] = date('Y-m-d H:i:s', $ext['closed_time']);
}
if (isset($ext['cancel_time']) && $ext['cancel_time']) {
$ext['cancel_date'] = date('Y-m-d H:i:s', $ext['cancel_time']);
}
if (isset($ext['pending_time']) && $ext['pending_time']) {
$ext['pending_date'] = date('Y-m-d H:i:s', $ext['pending_time']);
}
if (isset($ext['apply_refund_time']) && $ext['apply_refund_time']) {
$ext['apply_refund_date'] = date('Y-m-d H:i:s', $ext['apply_refund_time']);
}
if (isset($ext['send_time']) && $ext['send_time']) {
$ext['send_date'] = date('Y-m-d H:i:s', $ext['send_time']);
}
if (isset($ext['confirm_time']) && $ext['confirm_time']) {
$ext['confirm_date'] = date('Y-m-d H:i:s', $ext['confirm_time']);
}
if (isset($ext['comment_time']) && $ext['comment_time']) {
$ext['comment_date'] = date('Y-m-d H:i:s', $ext['comment_time']);
}
if (isset($ext['completed_time']) && $ext['completed_time']) {
$ext['completed_date'] = date('Y-m-d H:i:s', $ext['completed_time']);
}
if (isset($ext['refund_time']) && $ext['refund_time']) {
$ext['refund_date'] = date('Y-m-d H:i:s', $ext['refund_time']);
}
return $ext;
}
public function getPlatformTextAttr($value, $data)
{
$value = $value ?: ($data['platform'] ?? null);
$list = $this->platformList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 微信小程序发货信息管理所需参数
*
* @param string|null $value
* @param array $data
* @return array
*/
public function getWechatExtraDataAttr($value, $data)
{
$extraData = [];
if (strpos(request()->url(), 'addons/shopro') !== false && $data['platform'] == 'WechatMiniProgram') {
// 前端接口,并且是 微信小程序订单,才返这个参数
$pays = $this->pays;
foreach ($pays as $pay) {
if ($pay->status != PayModel::PAY_STATUS_UNPAID && $pay->pay_type == 'wechat') {
$extraData['merchant_trade_no'] = $pay->pay_sn;
$extraData['transaction_id'] = $pay->transaction_id;
}
}
}
return $extraData;
}
/**
* 申请退款状态
*
* @param string $value
* @param array $data
* @return string
*/
public function getApplyRefundStatusTextAttr($value, $data)
{
$value = $value ?: ($data['apply_refund_status'] ?? null);
$list = $this->applyRefundStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getActivityTypeTextAttr($value, $data)
{
$value = $value ?: ($data['activity_type'] ?? null);
$ext = $this->ext;
$list = (new Activity)->typeList();
$text = isset($list[$value]) ? $list[$value] : '';
if (in_array($value, ['groupon', 'groupon_ladder'])) {
// 订单已支付的,或者线下支付(货到付款)的
if ((in_array($data['status'], [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data))
&& (!isset($ext['groupon_id']) || !$ext['groupon_id']))
{
// 已支付,并且没有团 id,就是单独购买
$text .= '-单独购买';
}
}
return $text;
}
public function getPromoTypesTextAttr($value, $data)
{
$value = $value ?: ($data['promo_types'] ?? null);
$promoTypes = array_filter(explode(',', $value));
$texts = [];
$list = (new Activity)->typeList();
foreach ($promoTypes as $type) {
$text = isset($list[$type]) ? $list[$type] : '';
if ($text) {
$texts[] = $text;
}
}
return $texts;
}
/**
* 已支付订单,支付类型
*
* @param string $value
* @param array $data
* @return void
*/
public function getPayTypesAttr($value, $data)
{
$status = $data['status'] ?? '';
$payTypes = [];
// 订单已支付的,或者线下支付(货到付款)的
if (in_array($status, [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data)) {
$payTypes = PayModel::typeOrder()->where('order_id', $data['id'])->where('status', '<>', PayModel::PAY_STATUS_UNPAID)->group('pay_type')->column('pay_type');
}
return $payTypes;
}
/**
* 已支付订单,支付类型文字
*
* @param string $value
* @param array $data
* @return void
*/
public function getPayTypesTextAttr($value, $data)
{
$payTypes = $this->pay_types;
$list = (new PayModel)->payTypeList();
$texts = [];
foreach ($payTypes as $pay_type) {
$text = isset($list[$pay_type]) ? $list[$pay_type] : '';
if ($text) {
$texts[] = $text;
}
}
return $texts;
}
public function getExpressAttr($value, $data)
{
return Express::with(['items', 'logs'])->where('order_id', $data['id'])->select();
}
public function items()
{
return $this->hasMany(OrderItem::class, 'order_id', 'id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function aftersales()
{
return $this->hasMany(Aftersale::class, 'order_id')->order('id', 'desc');
}
public function address()
{
return $this->hasOne(Address::class, 'order_id', 'id');
}
public function invoice()
{
return $this->hasOne(Invoice::class, 'order_id', 'id');
}
public function pays()
{
return $this->hasMany(PayModel::class, 'order_id', 'id')->typeOrder()->order('id', 'desc');
}
public function activityOrders()
{
return $this->hasMany(ActivityOrder::class, 'order_id');
}
}

View File

@@ -0,0 +1,227 @@
<?php
namespace app\admin\model\shopro\order;
use app\admin\model\shopro\Common;
use app\admin\model\shopro\order\traits\OrderItemStatus;
use app\admin\model\shopro\activity\Activity;
use app\admin\model\shopro\user\User;
class OrderItem extends Common
{
use OrderItemStatus;
protected $name = 'shopro_order_item';
protected $type = [
'ext' => 'json'
];
// 追加属性
protected $append = [
'dispatch_status_text',
'dispatch_type_text',
'aftersale_status_text',
'refund_status_text',
'comment_status_text',
'status_code',
'status_text',
'status_desc',
'btns',
'activity_type_text',
'promo_types_text'
];
// 发货状态
const DISPATCH_STATUS_REFUSE = -1; // 已拒收
const DISPATCH_STATUS_NOSEND = 0; // 未发货
const DISPATCH_STATUS_SENDED = 1; // 已发货
const DISPATCH_STATUS_GETED = 2; // 已收货
// 售后状态
const AFTERSALE_STATUS_REFUSE = -1; // 拒绝
const AFTERSALE_STATUS_NOAFTER = 0; // 未申请
const AFTERSALE_STATUS_ING = 1; // 申请售后
const AFTERSALE_STATUS_COMPLETED = 2; // 售后完成
// 退款状态
const REFUND_STATUS_NOREFUND = 0; // 退款状态 未申请
const REFUND_STATUS_AGREE = 1; // 已同意
const REFUND_STATUS_COMPLETED = 2; // 退款完成
// 评价状态
const COMMENT_STATUS_NO = 0; // 待评价
const COMMENT_STATUS_OK = 1; // 已评价
public function dispatchStatusList()
{
return [
self::DISPATCH_STATUS_REFUSE => '已拒收',
self::DISPATCH_STATUS_NOSEND => '待发货',
self::DISPATCH_STATUS_SENDED => '待收货',
self::DISPATCH_STATUS_GETED => '已收货'
];
}
public function dispatchTypeList()
{
return [
'express' => '快递物流',
'autosend' => '自动发货',
'custom' => '手动发货'
];
}
public function aftersaleStatusList()
{
return [
self::AFTERSALE_STATUS_REFUSE => '售后驳回',
self::AFTERSALE_STATUS_NOAFTER => '未申请',
self::AFTERSALE_STATUS_ING => '申请售后',
self::AFTERSALE_STATUS_COMPLETED => '已完成'
];
}
public function refundStatusList()
{
return [
self::REFUND_STATUS_NOREFUND => '未退款',
self::REFUND_STATUS_AGREE => '退款完成',
self::REFUND_STATUS_COMPLETED => '退款完成',
];
}
public function commentStatusList()
{
return [
self::COMMENT_STATUS_NO => '待评价',
self::COMMENT_STATUS_OK => '已评价',
];
}
public function getActivityTypeTextAttr($value, $data)
{
$value = $value ?: ($data['activity_type'] ?? null);
$list = (new Activity)->typeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getDispatchTypeTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_type'] ?? null);
$list = $this->dispatchTypeList();
if (strpos(request()->url(), 'addons/shopro') !== false) {
$list['custom'] = '商家发货';
}
return isset($list[$value]) ? $list[$value] : '';
}
public function getPromoTypesTextAttr($value, $data)
{
$value = $value ?: ($data['promo_types'] ?? null);
$promoTypes = array_filter(explode(',', $value));
$texts = [];
$list = (new Activity)->typeList();
foreach ($promoTypes as $type) {
$text = isset($list[$type]) ? $list[$type] : '';
if ($text) {
$texts[] = $text;
}
}
return $texts;
}
public function getDispatchStatusTextAttr($value, $data)
{
$value = $value ?: ($data['dispatch_status'] ?? null);
$list = $this->dispatchStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getAftersaleStatusTextAttr($value, $data)
{
$value = $value ?: ($data['aftersale_status'] ?? null);
$list = $this->aftersaleStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getRefundStatusTextAttr($value, $data)
{
$value = $value ?: ($data['refund_status'] ?? null);
$list = $this->refundStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getCommentStatusTextAttr($value, $data)
{
$value = $value ?: ($data['comment_status'] ?? null);
$list = $this->commentStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 获取建议退款金额,不考虑剩余可退款金额是否够退
*
* @param string $value
* @param array $data
* @return string
*/
public function getSuggestRefundFeeAttr($value, $data)
{
$current_goods_amount = bcmul($data['goods_price'], (string)$data['goods_num'], 2);
$total_amount = bcadd($current_goods_amount, $data['dispatch_fee'], 2);
$suggest_refund_fee = bcsub($total_amount, $data['discount_fee'], 2); // (商品金额 + 运费金额) - 总优惠(活动,优惠券,包邮优惠)
return $suggest_refund_fee;
}
/**
* 可以确认收货
*
* @param \think\db\Query $query
* @return void
*/
public function scopeCanConfirm($query)
{
return $query->where('dispatch_status', OrderItem::DISPATCH_STATUS_SENDED) // 已发货
->whereNotIn('refund_status', [OrderItem::REFUND_STATUS_AGREE, OrderItem::REFUND_STATUS_COMPLETED]); // 没有退款完成
}
/**
* 可以评价
*
* @param \think\db\Query $query
* @return void
*/
public function scopeCanComment($query)
{
return $query->where('dispatch_status', OrderItem::DISPATCH_STATUS_GETED) // 已收货
->where('comment_status', OrderItem::COMMENT_STATUS_NO) // 未评价
->whereNotIn('refund_status', [OrderItem::REFUND_STATUS_AGREE, OrderItem::REFUND_STATUS_COMPLETED]); // 没有退款完成
}
public function express()
{
return $this->belongsTo(Express::class, 'order_express_id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}

View File

@@ -0,0 +1,268 @@
<?php
namespace app\admin\model\shopro\order\traits;
use app\admin\model\shopro\order\OrderItem;
trait OrderItemStatus
{
public function getStatus($data, $type)
{
$btns = [];
$backendBtns = [];
$status_text = '';
$status_desc = '';
$ext = $this->ext;
$aftersale_id = (isset($ext['aftersale_id']) && !empty($ext['aftersale_id'])) ? $ext['aftersale_id'] : 0;
$status_code = $this->status_code;
$item_code = 'null'; // 有售后的时候,第二状态
if (strpos($status_code, '|') !== false) {
$codes = explode('|', $status_code);
$status_code = $codes[0] ?? 'null';
$item_code = $codes[1] ?? 'null';
}
switch ($status_code) {
case 'null':
case 'cancel':
case 'closed':
case 'unpaid':
// 未支付的返回空
break;
case 'refuse': // 拒收
$status_text = '已拒收';
$status_desc = '用户拒绝收货';
break;
case 'nosend':
$status_text = '待发货';
$status_desc = '等待卖家发货';
$backendBtns[] = 'send';
$backendBtns[] = 'refund'; // 退款
// $btns[] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id , 待发货商品,不用申请售后,直接用订单退款
break;
case 'noget':
$status_text = '待收货';
$status_desc = '等待买家收货';
// $btns[] = 'get'; // 确认收货,总订单上才有
$btns[] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
$backendBtns[] = 'send_cancel'; // 取消发货
$backendBtns[] = 'refund';
break;
case 'nocomment':
$status_text = '待评价';
$status_desc = '等待买家评价';
$btns[] = 'comment'; // 评价,总订单上才有(前端通过这个判断待评价商品)
$btns[] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
$backendBtns[] = 'refund'; // 退款
break;
case 'commented':
$status_text = '已评价';
$status_desc = '订单已评价';
$btns[] = 'buy_again';
$backendBtns[] = 'refund'; // 退款
$backendBtns[] = 'comment_view'; // 查看评价
break;
case 'refund_completed':
$status_text = '退款完成';
$status_desc = '订单退款完成';
break;
case 'refund_agree': // 不需要申请退款(状态不会出现)
$status_text = '退款完成';
$status_desc = '卖家已同意退款';
break;
case 'aftersale_ing':
$status_text = '售后中';
$status_desc = '售后处理中';
if ($item_code == 'noget') {
if (in_array($data['dispatch_type'], ['express'])) { // 除了 自提扫码核销外,都可确认收货
$backendBtns[] = 'send_cancel'; // 取消发货
}
} else if ($item_code == 'nocomment') {
// 售后中也可以评价订单
$btns[] = 'comment'; // 评价,总订单上才有(前端通过这个判断待评价商品)
}
break;
case 'aftersale_refuse':
case 'aftersale_completed':
switch ($status_code) {
case 'aftersale_refuse':
$status_text = '售后拒绝';
$status_desc = '售后申请拒绝';
if ($item_code != 'commented') {
$btns[] = 're_aftersale'; // 售后
}
break;
case 'aftersale_completed':
$status_text = '售后完成';
$status_desc = '售后完成';
break;
}
// 售后拒绝,或者完成的时候,还可以继续操作订单
switch ($item_code) {
case 'nosend':
if (in_array($data['dispatch_type'], ['express'])) { // 除了 自提扫码核销外,都可确认收货
$backendBtns[] = 'send'; // 发货
}
break;
case 'noget':
if (in_array($data['dispatch_type'], ['express'])) { // 除了 自提扫码核销外,都可确认收货
// $btns[] = 'get'; // 确认收货,总订单上才有
$backendBtns[] = 'send_cancel'; // 取消发货
}
break;
case 'nocomment':
$btns[] = 'comment'; // 评价,总订单上才有(前端通过这个判断待评价商品)
break;
case 'commented':
$btns[] = 'buy_again';
$backendBtns[] = 'comment_view'; // 查看评价
break;
}
break;
}
// 如果有售后id 就显示售后详情按钮,退款中可能是售后退的款
if ($aftersale_id) {
$btns[] = 'aftersale_info';
$backendBtns[] = 'aftersale_info';
}
$return = null;
switch($type) {
case 'status_text':
$return = $status_text;
break;
case 'btns':
$return = $btns;
break;
case 'status_desc':
$return = $status_desc;
break;
case 'backend_btns':
$return = $backendBtns;
break;
}
return $return;
}
public function getStatusTextAttr($value, $data)
{
return $this->getStatus($data, 'status_text');
}
public function getStatusDescAttr($value, $data)
{
return $this->getStatus($data, 'status_desc');
}
public function getBtnsAttr($value, $data)
{
$btn_name = strpos(request()->url(), 'addons/shopro') !== false ? 'btns' : 'backend_btns';
return $this->getStatus($data, $btn_name);
}
// 获取订单 item status_code 状态,不进行订单是否支付判断,在这里查询数据库特别慢,
// 需要处理情况订单列表要正确显示item 状态,直接获取 item 的状态
public function getStatusCodeAttr($value, $data)
{
// $status_code = 'null';
// $order = Order::withTrashed()->where('id', $data['order_id'])->find();
// if (!$order) {
// return $status_code;
// }
// // 判断是否支付
// if (!in_array($order->status, [Order::STATUS_PAYED, Order::STATUS_FINISH])) {
// return $order->status_code;
// }
// 获取 item status_code
return $this->getBaseStatusCode($data);
}
/**
* $data 当前 item 数据
* $from 当前 model 调用,还是 order 调用
*/
public function getBaseStatusCode($data, $from = 'item')
{
$status_code = 'null';
if ($data['refund_status'] == OrderItem::REFUND_STATUS_AGREE) {
// 退款已同意
return 'refund_agree';
}
if ($data['refund_status'] == OrderItem::REFUND_STATUS_COMPLETED) {
// 退款完成
return 'refund_completed';
}
if ($data['aftersale_status']) {
// 只申请了售后,没有退款
// status_code
$status_code = $this->getNormalStatusCode($data);
// item 要原始状态,总订单还要原来的未退款状态
if ($from == 'item') {
switch ($data['aftersale_status']) {
case OrderItem::AFTERSALE_STATUS_REFUSE:
$status_code = 'aftersale_refuse' . '|' . $status_code;
break;
case OrderItem::AFTERSALE_STATUS_ING:
$status_code = 'aftersale_ing' . '|' . $status_code;
break;
case OrderItem::AFTERSALE_STATUS_COMPLETED:
$status_code = 'aftersale_completed' . '|' . $status_code;
break;
}
}
} else {
// status_code
$status_code = $this->getNormalStatusCode($data);
}
return $status_code;
}
public function getNormalStatusCode($data)
{
// 获取未申请售后和退款时候的 status_code
$status_code = 'null';
switch ($data['dispatch_status']) {
case OrderItem::DISPATCH_STATUS_REFUSE:
$status_code = 'refuse';
break;
case OrderItem::DISPATCH_STATUS_NOSEND:
$status_code = 'nosend';
break;
case OrderItem::DISPATCH_STATUS_SENDED:
$status_code = 'noget';
break;
case OrderItem::DISPATCH_STATUS_GETED:
if ($data['comment_status'] == OrderItem::COMMENT_STATUS_NO) {
$status_code = 'nocomment';
} else {
$status_code = 'commented';
}
break;
}
return $status_code; // status_code
}
}

View File

@@ -0,0 +1,211 @@
<?php
namespace app\admin\model\shopro\order\traits;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
trait OrderScope
{
// 已关闭
public function scopeClosed($query)
{
return $query->where('status', Order::STATUS_CLOSED);
}
// 已取消
public function scopeCancel($query)
{
return $query->where('status', Order::STATUS_CANCEL);
}
// 未支付
public function scopeUnpaid($query)
{
return $query->where('status', Order::STATUS_UNPAID);
}
// 可以取消,未支付&货到付款未发货的订单
public function scopeCanCancel($query)
{
return $query->where(function ($query) {
$query->where('status', Order::STATUS_UNPAID)->whereOr(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->where('pay_mode', 'offline')->where('status', Order::STATUS_PENDING)->whereExists(function ($query) use ($self_name, $item_name) {
// 货到付款订单,未发货未退款,可以申请售后
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_NOSEND) // 未发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成;
});
});
});
}
// 已支付
public function scopePaid($query)
{
return $query->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED]);
}
// 线下支付(货到付款) pending 时
public function scopeOffline($query)
{
return $query->where('pay_mode', 'offline')->where('status', Order::STATUS_PENDING);
}
/**
* 是否线下支付(货到付款),暂未付款
*
* @param object|array $order
* @return boolean
*/
public function isOffline($order)
{
return ($order['status'] == Order::STATUS_PENDING && $order['pay_mode'] == 'offline') ? true : false;
}
// 已支付的,或者是线下付款的未支付订单,后续可以,发货,收货,评价
public function scopePretendPaid($query)
{
return $query->where(function ($query) {
$query->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED])->whereOr(function($query) {
$query->where('pay_mode', 'offline')->where('status', Order::STATUS_PENDING);
});
});
}
// 已完成
public function scopeCompleted($query)
{
return $query->where('status', Order::STATUS_COMPLETED);
}
// 未申请全额退款,或者已拒绝
public function scopeNoApplyRefund($query)
{
return $query->whereIn('apply_refund_status', [
Order::APPLY_REFUND_STATUS_NOAPPLY,
Order::APPLY_REFUND_STATUS_REFUSE
]);
}
// 申请全额退款中
public function scopeApplyRefundIng($query)
{
return $query->where('apply_refund_status', Order::APPLY_REFUND_STATUS_APPLY);
}
// 未发货
public function scopeNosend($query)
{
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$is_express = (request()->action() == 'exportdelivery') ? 1 : 0; // 是否是 express将只查快递物流的代发货
return $query->noApplyRefund()->whereExists(function ($query) use ($self_name, $item_name, $is_express) {
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_NOSEND) // 未发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成
if ($is_express) { // 只查快递物流的代发货
$query->where('dispatch_type', 'express');
}
})->whereNotExists(function ($query) use ($self_name, $item_name, $is_express) {
// 不是 正在售后的商品
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('aftersale_status', OrderItem::AFTERSALE_STATUS_ING) // 但是售后中
->where('dispatch_status', OrderItem::DISPATCH_STATUS_NOSEND) // 未发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成;
if ($is_express) { // 只查快递物流的代发货
$query->where('dispatch_type', 'express');
}
});
}
// 待收货
public function scopeNoget($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_SENDED) // 已发货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成
});
}
// 已拒收
public function scopeRefuse($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_REFUSE) // 已拒收
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND); // 没有退款完成
});
}
// 待评价
public function scopeNocomment($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('dispatch_status', OrderItem::DISPATCH_STATUS_GETED) // 已收货
->where('refund_status', OrderItem::REFUND_STATUS_NOREFUND) // 没有退款完成
->where('comment_status', OrderItem::COMMENT_STATUS_NO); // 未评价
});
}
// 售后 (后台要用,虽然有专门的售后单列表)
public function scopeAftersale($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('aftersale_status', '<>', OrderItem::AFTERSALE_STATUS_NOAFTER);
});
}
// 退款
public function scopeRefund($query)
{
return $query->whereExists(function ($query) {
$self_name = (new Order())->getQuery()->getTable();
$item_name = (new OrderItem())->getQuery()->getTable();
$query->table($item_name)->where('order_id=' . $self_name . '.id')
->where('refund_status', '<>', OrderItem::REFUND_STATUS_NOREFUND);
});
}
public function scopeCanAftersale($query)
{
return $query->where('status', 'in', [Order::STATUS_PAID, Order::STATUS_COMPLETED]);
}
public function scopeCanDelete($query)
{
return $query->where('status', 'in', [
Order::STATUS_CANCEL,
Order::STATUS_CLOSED,
Order::STATUS_COMPLETED
]);
}
}

View File

@@ -0,0 +1,417 @@
<?php
namespace app\admin\model\shopro\order\traits;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
use app\admin\model\shopro\activity\Groupon;
use app\admin\model\shopro\Config;
trait OrderStatus
{
protected function getStatus($data, $type)
{
$btns = []; // 前端订单操作按钮
$backendBtns = [];
$status_text = '';
$status_desc = '';
$ext = $this->ext;
switch ($this->status_code) {
case 'cancel':
$status_text = '已取消';
$status_desc = '买家已取消';
$btns[] = 'delete'; // 删除订单
break;
case 'closed':
$status_text = '交易关闭';
if (isset($ext['closed_type']) && $ext['closed_type'] == 'refuse') {
$status_desc = '买家拒绝收货';
} else {
$status_desc = '买家未在规定时间内付款';
}
$btns[] = 'delete'; // 删除订单
break;
case 'unpaid':
$status_text = '待付款';
$status_desc = '等待买家付款';
$btns[] = 'cancel'; // 取消订单
$btns[] = 'pay'; // 支付
$backendBtns[] = 'change_fee'; // 订单改价
break;
// 已支付的
case 'apply_refund':
$status_text = '申请退款中';
$status_desc = '等待卖家处理退款';
$backendBtns[] = 'apply_refund_oper'; // 处理申请退款按钮
$backendBtns[] = 'refund'; // 只能退款,或者在列表上拒绝申请退款
break;
case 'commented':
$status_text = '已评价';
$status_desc = '订单已评价';
$dispatchType = $this->getItemDispatchTypes();
if (in_array('express', $dispatchType)) {
$btns[] = 'express'; // 查看物流
}
$backendBtns[] = 'refund';
break;
case 'nocomment':
$status_text = '待评价';
$status_desc = '等待买家评价';
$dispatchType = $this->getItemDispatchTypes();
if (in_array('express', $dispatchType)) {
$btns[] = 'express'; // 查看物流
}
$btns[] = 'comment';
$backendBtns[] = 'refund';
break;
case 'noget':
$status_text = '待收货';
$status_desc = '等待买家收货';
$dispatchType = $this->getItemDispatchTypes();
if (in_array('express', $dispatchType)) {
$btns[] = 'express'; // 查看物流
}
if ($this->isOffline($data)) {
$status_desc = '卖家已发货,等待包裹运达';
// 用户可以拒收,后台确认收货
$btns[] = 'refuse'; // 用户拒收
$backendBtns[] = 'confirm';
}else {
// 计算自动确认收货时间
$send_time = $ext['send_time'] ?? 0;
$auto_confirm = Config::getConfigField('shop.order.auto_confirm');
$auto_confirm_unix = $auto_confirm * 86400;
if ($send_time && $auto_confirm_unix) {
$auto_confirm_time = $send_time + $auto_confirm_unix;
if ($auto_confirm_time > time()) {
$status_desc .= ',还剩' . diff_in_time($auto_confirm_time, null, true, true) . '自动确认';
}
}
$btns[] = 'confirm'; // 确认收货
$backendBtns[] = 'refund';
}
break;
case 'nosend':
$status_text = '待发货';
$status_desc = '等待卖家发货';
$statusCodes = $this->getItemStatusCode();
if (in_array('noget', $statusCodes)) { // 只要存在待收货的item
$btns[] = 'confirm'; // 确认收货 (部分发货时也可以收货)
}
if ($this->isOffline($data)) {
// 发货之前用户可以取消
$btns[] = 'cancel'; // 用户取消订单
} else {
$backendBtns[] = 'refund';
}
$backendBtns[] = 'send';
if (!isset($ext['need_address']) || $ext['need_address']) { // 自动发货这些不需要收货地址的,没有 edit_consignee
$backendBtns[] = 'edit_consignee'; //修改收货地址
}
break;
case 'refund_completed':
$status_text = '退款完成';
$status_desc = '订单退款完成';
break;
case 'refund_agree':
$status_text = '退款完成';
$status_desc = '订单退款完成';
break;
case 'groupon_ing':
$status_text = '等待成团';
$status_desc = '等待拼团成功';
if ($this->isOffline($data)) {
// 货到付款未付款,不能退款,等待拼团时还未发货,用户可取消订单
$btns[] = 'cancel'; // 用户取消订单
} else {
$backendBtns[] = 'refund'; // 全部退款 直接不申请退款
}
break;
case 'groupon_invalid':
$status_text = '拼团失败';
$status_desc = '拼团失败';
break;
// 已支付的结束
case 'completed':
$status_text = '交易完成';
$status_desc = '交易已完成';
$btns[] = 'delete'; // 删除订单
break;
}
// 有活动
if (in_array($data['activity_type'], ['groupon', 'groupon_ladder', 'groupon_lucky'])) {
// 是拼团订单
if (isset($ext['groupon_id']) && $ext['groupon_id']) {
$btns[] = 'groupon'; // 拼团详情
}
}
if (in_array($this->status_code, ['nosend', 'groupon_ing']) && !$this->isOffline($data)) { // 线下付款订单,不可申请全额退款
if (in_array($data['apply_refund_status'], [Order::APPLY_REFUND_STATUS_NOAPPLY, Order::APPLY_REFUND_STATUS_REFUSE])) {
// 获取所有的 item 状态
$statusCodes = $this->getItemStatusCode();
if (count($statusCodes) == 1 && current($statusCodes) == 'nosend') {
// items 只有 未发货,就显示 申请退款按钮
if ($data['apply_refund_status'] == Order::APPLY_REFUND_STATUS_REFUSE) {
$btns[] = 're_apply_refund'; // 重新申请退款
} else {
$btns[] = 'apply_refund'; // 申请退款
}
}
}
}
if ($data['invoice_status'] == 1) {
$btns[] = 'invoice'; // 查看发票
} else if ($data['invoice_status'] == 0) {
if (in_array($this->status_code, ['commented', 'nocomment', 'noget', 'nosend', 'completed'])) {
$btns[] = 'apply_invoice'; // 申请发票
}
}
$return = null;
switch ($type) {
case 'status_text':
$return = $status_text;
break;
case 'btns':
$return = $btns;
break;
case 'status_desc':
$return = $status_desc;
break;
case 'backend_btns':
if (in_array('refund', $backendBtns)) {
// 判断是否有退款,如果存在退款就移除 refund 按钮
$refundCount = OrderItem::where('order_id', $data['id'])->where('refund_status', '<>', OrderItem::REFUND_STATUS_NOREFUND)->count();
if ($refundCount && ($key = array_search('refund', $backendBtns))) {
unset($backendBtns[$key]);
}
$backendBtns = array_values($backendBtns);
}
$return = $backendBtns;
break;
}
return $return;
}
/**
* 获取支付成功之后的子状态
*/
public function getPayedStatusCode($data)
{
$status_code = '';
// 获取所有的 item 状态
$statusCodes = $this->getItemStatusCode();
if (in_array('nosend', $statusCodes)) {
// 存在待发货就是待发货
$status_code = 'nosend';
} else if (in_array('noget', $statusCodes)) {
// 存在待收货,就是待收货
$status_code = 'noget';
} else if (in_array('nocomment', $statusCodes)) {
// 存在待评价,就是待评价
$status_code = 'nocomment';
} else if (in_array('commented', $statusCodes)) {
// 存在已评价,就是已评价
$status_code = 'commented';
} else if (in_array('refund_completed', $statusCodes)) {
// 所有商品退款完成,或者退款中(不可能存在待发货或者收货的商品,上面已判断过)
$status_code = 'refund_completed';
} else if (in_array('refund_agree', $statusCodes)) {
// 所有商品都同意退款了 (不可能存在待发货或者收货的商品,上面已判断过)
$status_code = 'refund_agree';
} // 售后都不在总状态显示
if ($data['apply_refund_status'] == Order::APPLY_REFUND_STATUS_APPLY && !in_array($status_code, ['refund_completed', 'refund_agree'])) {
return $status_code = 'apply_refund'; // 申请退款中,并且还没退款
}
$ext = $this->ext;
// 是拼团订单
if (
in_array($data['activity_type'], ['groupon', 'groupon_ladder', 'groupon_lucky']) &&
isset($ext['groupon_id']) && $ext['groupon_id']
) {
$groupon = Groupon::where('id', $ext['groupon_id'])->find();
if ($groupon) {
if ($groupon['status'] == 'ing') {
// 尚未成团
$status_code = $statusCodes[0] ?? ''; // 拼团订单只能有一个商品
$status_code = in_array($status_code, ['refund_agree', 'refund_completed']) ? $status_code : 'groupon_ing'; // 如果订单已退款,则是退款状态,不显示拼团中
} else if ($groupon['status'] == 'invalid') {
$status_code = 'groupon_invalid';
}
}
}
return $status_code;
}
/**
* 获取订单items状态
*
* @param string $type
* @return array
*/
private function getItemStatusCode($type = 'order')
{
// 循环判断 item 状态
$itemStatusCode = [];
foreach ($this->items as $key => $item) {
// 获取 item status
$itemStatusCode[] = (new OrderItem)->getBaseStatusCode($item, $type);
}
// 取出不重复不为空的 status_code
$statusCodes = array_values(array_unique(array_filter($itemStatusCode)));
return $statusCodes;
}
private function getItemDispatchTypes()
{
$dispatchType = [];
foreach ($this->items as $key => $item) {
// 获取 item status
$dispatchType[] = $item['dispatch_type'];
}
$dispatchType = array_unique(array_filter($dispatchType)); // 过滤重复,过滤空值
return $dispatchType;
}
public function getStatusTextAttr($value, $data)
{
return $this->getStatus($data, 'status_text');
}
public function getStatusDescAttr($value, $data)
{
return $this->getStatus($data, 'status_desc');
}
public function getBtnsAttr($value, $data)
{
$btn_name = strpos(request()->url(), 'addons/shopro') !== false ? 'btns' : 'backend_btns';
return $this->getStatus($data, $btn_name);
}
// 获取订单状态
public function getStatusCodeAttr($value, $data)
{
$status_code = '';
switch ($data['status']) {
case Order::STATUS_CLOSED:
$status_code = 'closed'; // 订单交易关闭
break;
case Order::STATUS_CANCEL:
$status_code = 'cancel'; // 订单已取消
break;
case Order::STATUS_UNPAID:
$status_code = 'unpaid'; // 订单等待支付
break;
case Order::STATUS_PENDING:
$status_code = $this->getPayedStatusCode($data); // 订单线下付款
break;
case Order::STATUS_PAID:
// 根据 item 获取支付后的状态信息
$status_code = $this->getPayedStatusCode($data);
break;
case Order::STATUS_COMPLETED:
$status_code = 'completed';
break;
}
return $status_code;
}
/**
* 处理未支付 item status_code
* 查询列表 item status_code 不关联订单表,使用这个方法进行处理
*/
public function setOrderItemStatusByOrder($order)
{
$order = $order instanceof \think\Model ? $order->toArray() : $order;
foreach ($order['items'] as $key => &$item) {
if ((!in_array($order['status'], [Order::STATUS_PAID, Order::STATUS_COMPLETED]) && !$this->isOffline($order)) // 没有支付,并且也不是货到付款
|| $order['apply_refund_status'] == Order::APPLY_REFUND_STATUS_APPLY) {
// 未支付status_code = 订单的 status_code
$item['status_code'] = $order['status_code'];
$item['status_text'] = '';
$item['status_desc'] = '';
$item['btns'] = [];
} else {
if (strpos(request()->url(), 'addons/shopro') !== false) {
// 前端
if (strpos($item['status_code'], 'nosend') !== false) {
if (!$this->isOffline($order) && !array_intersect(['re_apply_refund', 'apply_refund'], $order['btns'])) {
// 不能申请全额退款了(有部分发货,或者退款)的待发货的 item 要显示申请售后的按钮
$aftersale_id = (isset($item['ext']['aftersale_id']) && !empty($item['ext']['aftersale_id'])) ? $item['ext']['aftersale_id'] : 0;
if (strpos($item['status_code'], 'aftersale_ing') === false && strpos($item['status_code'], 'aftersale_completed') === false) {
// 不是售后中,也不是售后完成
if (strpos($item['status_code'], 'aftersale_refuse') !== false && $aftersale_id) {
// 如果申请过退款,被拒绝了,则为重新申请售后
$item['btns'][] = 're_aftersale';
} else {
// 取消售后是 re_aftersale ,未申请过是 aftersale
$item['btns'][] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
}
}
}
} else if (strpos($item['status_code'], 'noget') !== false) {
// 如果是货到付款的 待收货
if ($this->isOffline($order)) {
foreach($item['btns'] as $btnk => $btn) {
if (in_array($btn, ['re_aftersale', 'aftersale'])) {
unset($item['btns'][$btnk]);
}
}
}
}
} else {
// 后端,如果是货到付款, 并且还没收货,不显示退款按钮
if ($this->isOffline($order) && (strpos($item['status_code'], 'nosend') !== false || strpos($item['status_code'], 'noget') !== false)) {
$refund_key = array_search('refund', $item['btns']);
if ($refund_key !== false) {
unset($item['btns'][$refund_key]);
}
}
}
}
}
return $order;
}
}