文件
xionggeshop/application/admin/controller/shopro/order/Aftersale.php

442 行
17 KiB
PHP

<?php
namespace app\admin\controller\shopro\order;
use addons\shopro\model\OrderAftersaleLog;
use app\admin\model\shopro\order\Order;
use app\admin\model\shopro\order\OrderItem;
use app\admin\model\shopro\order\Aftersale as OrderAftersale;
use app\common\controller\Backend;
use think\db;
/**
* 订单商品明细
*
* @icon fa fa-circle-o
*/
class Aftersale extends Backend
{
/**
* Aftersale模型对象
* @var \app\admin\model\shopro\order\Aftersale
*/
protected $model = null;
protected $orderModel = null;
public function _initialize()
{
parent::_initialize();
// 手动加载语言包
$this->loadlang('shopro/order/order');
$this->model = new \app\admin\model\shopro\order\Aftersale;
$this->orderModel = new \app\admin\model\shopro\order\Order;
$this->view->assign("dispatchStatusList", $this->model->getDispatchStatusList());
$this->view->assign("aftersaleStatusList", $this->model->getAftersaleStatusList());
$this->view->assign("refundStatusList", $this->model->getRefundStatusList());
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
/**
* 查看
*/
public function index()
{
//当前是否为关联查询
$this->relationSearch = false;
//设置过滤方法
$this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) {
//如果发送的来源是Selectpage,则转发到Selectpage
if ($this->request->request('keyField')) {
return $this->selectpage();
}
// list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id');
$order = $this->request->get("order", "DESC");
$offset = $this->request->get("offset", 0);
$limit = $this->request->get("limit", 0);
$search = $this->request->get("search", ''); // 关键字
$status = $this->request->get("status", 'all');
$total = $this->buildSearchOrder()// 返回的是 orderModel
->order($sort, $order)
->count();
$list = $this->buildSearchOrder()// 返回的是 orderModel
->with(['aftersale' => function ($query) {
$query->removeOption('soft_delete')->alias('a')->field('a.*, u.nickname as user_nickname, u.mobile as user_mobile')->join('user u', 'u.id = a.user_id', 'LEFT');
}])
->order($sort, $order)
->limit($offset, $limit)
->select();
// foreach ($list as $row) {
// $row->visible(['id','aftersale_sn','user_id','type','order_id','order_item_id','goods_id','goods_sku_price_id','goods_sku_text','goods_title','goods_image','goods_original_price','discount_fee','goods_price','goods_num','dispatch_status','dispatch_fee','aftersale_status','refund_status','refund_fee','createtime','updatetime','deletetime', 'user', 'activity_type']);
// }
$list = collection($list)->toArray();
$result = array("total" => $total, "rows" => $list);
return $this->success('获取成功', null, $result);
}
return $this->view->fetch();
}
/**
* 详情
*/
public function detail($id)
{
if ($this->request->isAjax()) {
$row = $this->model->withTrashed()->with(['user', 'order' => function ($query) {
$query->removeOption('soft_delete');
}, 'logs'])->where('id', $id)->find();
if (!$row) {
$this->error(__('No Results were found'));
}
$result = [
'detail' => $row,
'logs' => $row->logs,
'order' => $row->order,
];
return $this->success('获取成功', null, $result);
}
$this->assignconfig('id', $id);
return $this->view->fetch();
}
public function newAftersale($id)
{
if ($this->request->isAjax()) {
$aftersale = $this->model->withTrashed()->where('id', $id)->find();
if (!$aftersale) {
$this->error('售后单不存在或不可完成');
}
$order = Order::withTrashed()->where('id', $aftersale->order_id)->find();
$orderItem = OrderItem::where('id', $aftersale->order_item_id)->find();
if (!$order || !$orderItem) {
$this->error('订单或订单商品不存在');
}
Db::transaction(function () use ($aftersale, $order, $orderItem) {
$orderItem->aftersale_status = 0;
$orderItem->refund_status = 1;
$orderItem->save();
$aftersale->aftersale_status = 1; // 售后重启
$aftersale->save();
});
return $this->success('操作成功');
}
}
/**
* 完成售后
*/
public function finish($id)
{
if ($this->request->isAjax()) {
$aftersale = $this->model->withTrashed()->canOper()->where('id', $id)->find();
if (!$aftersale) {
$this->error('售后单不存在或不可完成');
}
$order = Order::withTrashed()->where('id', $aftersale->order_id)->find();
$orderItem = OrderItem::where('id', $aftersale->order_item_id)->find();
if (!$order || !$orderItem) {
$this->error('订单或订单商品不存在');
}
Db::transaction(function () use ($aftersale, $order, $orderItem) {
// 售后单完成前
$data = ['aftersale' => $aftersale, 'order' => $order, 'item' => $orderItem];
\think\Hook::listen('aftersale_finish_before', $data);
$aftersale->aftersale_status = \app\admin\model\shopro\order\Aftersale::AFTERSALE_STATUS_OK; // 售后完成
$aftersale->save();
// 增加售后单变动记录、
OrderAftersaleLog::operAdd($order, $aftersale, $this->auth->getUserInfo(), 'admin', [
'reason' => '卖家完成售后',
'content' => '售后订单已完成',
'images' => []
]);
$orderItem->aftersale_status = OrderItem::AFTERSALE_STATUS_OK;
$orderItem->save();
\addons\shopro\model\OrderAction::operAdd($order, $orderItem, $this->auth->getUserInfo(), 'admin', '管理员完成售后');
// 售后单完成之后
$data = ['aftersale' => $aftersale, 'order' => $order, 'item' => $orderItem];
\think\Hook::listen('aftersale_finish_after', $data);
});
return $this->success('操作成功');
}
}
/**
* 拒绝售后
*/
public function refuse($id = 0)
{
if ($this->request->isAjax()) {
$refuse_msg = $this->request->post('refuse_msg', '');
if (!$refuse_msg) {
$this->error('请输入拒绝原因');
}
$aftersale = $this->model->withTrashed()->canOper()->where('id', $id)->find();
if (!$aftersale) {
$this->error('售后单不存在或不可拒绝');
}
$order = Order::withTrashed()->where('id', $aftersale->order_id)->find();
$orderItem = OrderItem::where('id', $aftersale->order_item_id)->find();
if (!$order || !$orderItem) {
$this->error('订单或订单商品不存在');
}
Db::transaction(function () use ($aftersale, $order, $orderItem, $refuse_msg) {
// 售后单拒绝前
$data = ['aftersale' => $aftersale, 'order' => $order, 'item' => $orderItem];
\think\Hook::listen('aftersale_refuse_before', $data);
$aftersale->aftersale_status = \app\admin\model\shopro\order\Aftersale::AFTERSALE_STATUS_REFUSE; // 售后拒绝
$aftersale->save();
// 增加售后单变动记录
OrderAftersaleLog::operAdd($order, $aftersale, $this->auth->getUserInfo(), 'admin', [
'reason' => '卖家拒绝售后',
'content' => $refuse_msg,
'images' => []
]);
$orderItem->aftersale_status = OrderItem::AFTERSALE_STATUS_REFUSE; // 拒绝售后
$orderItem->save();
\addons\shopro\model\OrderAction::operAdd($order, $orderItem, $this->auth->getUserInfo(), 'admin', '管理员拒绝订单售后:' . $refuse_msg);
// 售后单拒绝后
$data = ['aftersale' => $aftersale, 'order' => $order, 'item' => $orderItem];
\think\Hook::listen('aftersale_refuse_after', $data);
});
return $this->success('操作成功');
}
}
/**
* 同意退款
*/
public function refund($id = 0)
{
if ($this->request->isAjax()) {
$refund_money = round($this->request->post('refund_money', 0), 2);
if ($refund_money <= 0) {
$this->error('退款金额必须大于 0');
}
$aftersale = $this->model->withTrashed()->canOper()->where('id', $id)->find();
if (!$aftersale) {
$this->error('售后单不存在或不可退款');
}
$order = Order::withTrashed()->with('item')->where('id', $aftersale->order_id)->find();
if (!$order) {
$this->error('订单不存在');
}
$lockKey = 'lock:refund:aftersale:' . $id;
if (\think\Cache::get($lockKey)) {
$this->error('退款正在处理中,请勿重复操作');
}
\think\Cache::set($lockKey, 1, 10);
try {
Db::transaction(function () use ($id, $refund_money, $order) {
// 行级排他锁锁定售后单与订单商品,防止并发重复退款
$aftersale = $this->model->withTrashed()->where('id', $id)->lock(true)->find();
if (!$aftersale || $aftersale['refund_status'] == \app\admin\model\shopro\order\Aftersale::REFUND_STATUS_FINISH) {
throw new \Exception('售后单已退款,不能重复退款');
}
$orderItem = OrderItem::where('id', $aftersale['order_item_id'])->lock(true)->find();
if (!$orderItem || in_array($orderItem['refund_status'], [
\app\admin\model\shopro\order\OrderItem::REFUND_STATUS_OK,
\app\admin\model\shopro\order\OrderItem::REFUND_STATUS_FINISH,
])) {
throw new \Exception('订单商品已退款,不能重复退款');
}
// 实时剩余可退金额硬校验(防多退)
$refund_surplus_money = bcsub($orderItem->pay_price, $orderItem->refund_fee, 2);
if (bccomp($refund_money, $refund_surplus_money, 2) === 1) {
throw new \Exception('退款金额不能大于' . $refund_surplus_money . '元');
}
$data = ['aftersale' => $aftersale, 'order' => $order, 'item' => $orderItem];
\think\Hook::listen('aftersale_finish_before', $data);
$aftersale->aftersale_status = \app\admin\model\shopro\order\Aftersale::AFTERSALE_STATUS_OK; // 售后同意
$aftersale->refund_status = \app\admin\model\shopro\order\Aftersale::REFUND_STATUS_FINISH; // 售后同意退款
$aftersale->refund_fee = bcadd($refund_money, $aftersale->refund_fee, 2); // 已退款金额
$aftersale->save();
// 增加售后单变动记录
OrderAftersaleLog::operAdd($order, $aftersale, $this->auth->getUserInfo(), 'admin', [
'reason' => '卖家同意退款',
'content' => '售后订单已退款',
'images' => []
]);
$orderItem->aftersale_status = OrderItem::AFTERSALE_STATUS_OK;
$orderItem->save();
\addons\shopro\model\OrderAction::operAdd($order, $orderItem, $this->auth->getUserInfo(), 'admin', '管理员同意售后退款');
// 退款
\app\admin\model\shopro\order\Order::startRefund($order, $orderItem, $refund_money, $this->auth->getUserInfo(), '管理员同意售后退款');
$data = ['aftersale' => $aftersale, 'order' => $order, 'item' => $orderItem];
\think\Hook::listen('aftersale_finish_after', $data);
});
} catch (\Throwable $e) {
\think\Cache::rm($lockKey);
$this->error($e->getMessage());
}
\think\Cache::rm($lockKey);
return $this->success('操作成功');
}
}
/**
* 留言
*/
public function addLog($id = 0)
{
if ($this->request->isAjax()) {
$reason = $this->request->post('reason', '卖家留言');
$content = $this->request->post('content', '');
$images = $this->request->post('images', []);
if (!$content) {
$this->error('留言内容不能为空');
}
$aftersale = $this->model->withTrashed()->where('id', $id)->find();
if (!$aftersale) {
$this->error('售后单不存在');
}
$order = Order::withTrashed()->with('item')->where('id', $aftersale->order_id)->find();
if (!$order) {
$this->error('订单不存在');
}
Db::transaction(function () use ($order, $aftersale, $reason, $content, $images) {
if ($aftersale['aftersale_status'] == 0) {
$aftersale->aftersale_status = \app\admin\model\shopro\order\Aftersale::AFTERSALE_STATUS_AFTERING; // 售后处理中
$aftersale->save();
}
// 增加售后单变动记录
OrderAftersaleLog::operAdd($order, $aftersale, $this->auth->getUserInfo(), 'admin', [
'reason' => $reason,
'content' => $content,
'images' => $images
]);
});
return $this->success('操作成功');
}
}
private function buildSearchOrder()
{
$search = $this->request->get("search", ''); // 关键字
$status = $this->request->get("status", 'all');
$orders = $this->orderModel->withTrashed();
$orders = $orders->whereExists(function ($query) use ($search, $status) {
extract($this->getModelTable());
$aftersales = $query->table($aftersaleName)->where($aftersaleName . '.order_id=' . $orderName . '.id');
$aftersales = $this->aftersaleSearch($aftersales, $search, $status);
return $aftersales;
});
return $orders;
}
private function aftersaleSearch($aftersales, $search, $status)
{
extract($this->getModelTable());
if ($search) {
// 模糊搜索字段
$searcharr = ['goods_title', 'goods_sku_text', 'aftersale_sn'];
foreach ($searcharr as $k => &$v) {
$v = stripos($v, ".") === false ? $aftersaleName . '.' . $v : $v;
}
unset($v);
$aftersales = $aftersales->where(function ($query) use ($searcharr, $search, $aftersaleName) {
$query->where(implode("|", $searcharr), "LIKE", "%{$search}%")
->whereOr(function ($query) use ($search, $aftersaleName) { // 用户
$query->whereExists(function ($query) use ($search, $aftersaleName) {
$userTableName = (new \app\admin\model\User())->getQuery()->getTable();
$query->table($userTableName)->where($userTableName . '.id=' . $aftersaleName . '.user_id')
->where(function ($query) use ($search) {
$query->where('nickname', 'like', "%{$search}%")
->whereOr('mobile', 'like', "%{$search}%");
});
});
});
});
}
// 售后单状态
if ($status != 'all') {
if (in_array($status, ['cancel', 'refuse', 'nooper', 'ing', 'finish'])) {
$aftersales = $aftersales->where(OrderAftersale::getScopeWhere($status));
}
}
return $aftersales;
}
private function getModelTable()
{
$orderName = $this->orderModel->getQuery()->getTable();
$aftersaleName = $this->model->getQuery()->getTable();
return compact("orderName", "aftersaleName");
}
}