文件
yjyf/server/application/admin/controller/Settle.php
MiAn fafddceaf2 feat: 新增发票抬头、晒单、钱包日志等模型及后台管理功能
- 新增 invoice_title、showcase、wallet_log 模型及对应语言包
- 新增后台控制器、视图及搜索字段配置
- 修复服务类目删除保护逻辑
- 优化后台登录页面文案及样式
- 新增前端角色切换逻辑及页面拦截
- 新增 SVG 图标及样式变量
- 修复接口权限及下拉框默认值问题
2026-11-11 17:02:35 +08:00

224 行
7.7 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace app\admin\controller;
use app\common\controller\Backend;
use think\Db;
use think\exception\PDOException;
/**
* 结算单管理
*
* 结算单由订单核销完工自动生成,后台负责对账审计及异常挂起单的人工结算归档
*
* @icon fa fa-calculator
*/
class Settle extends Backend
{
/**
* Settle模型对象
* @var \app\admin\model\Settle
*/
protected $model = null;
protected $relationSearch = true;
protected $searchFields = 'id,order.order_no,master.realname,master.mobile';
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Settle;
$this->view->assign("statusList", $this->model->getStatusList());
}
/**
* 结算单列表
*/
public function index()
{
$this->request->filter(['strip_tags', 'trim']);
if (false === $this->request->isAjax()) {
return $this->view->fetch();
}
if ($this->request->request('keyField')) {
return $this->selectpage();
}
[$where, $sort, $order, $offset, $limit] = $this->buildparams();
$list = $this->model
->with(['order', 'master'])
->where($where)
->order($sort, $order)
->paginate($limit);
$result = ['total' => $list->total(), 'rows' => $list->items()];
return json($result);
}
/**
* 结算对账详情(关联订单费用明细、师傅钱包快照与入账流水)
*/
public function detail($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
$this->assignSettleContext($row);
return $this->view->fetch();
}
/**
* 待结算单财务处理(严禁篡改结算金额,仅允许对 wait 状态执行线上入账或线下归档)
*/
public function edit($ids = null)
{
$row = $this->model->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
if (false === $this->request->isPost()) {
$this->assignSettleContext($row);
return $this->view->fetch();
}
if ($row['status'] !== 'wait') {
$this->error('该结算单已归档完结,禁止重复结算或修改账务数据');
}
$targetStatus = (string)$this->request->post('row.status', '');
if (!in_array($targetStatus, ['settled', 'offline'], true)) {
$this->error('请选择有效的结算归档方式(线上划拨入账 / 线下特殊结算)');
}
$masterId = (int)$row['master_id'];
$orderId = (int)$row['order_id'];
$settleAmount = round((float)$row['settle_amount'], 2);
$now = time();
Db::startTrans();
try {
// 乐观锁防并发重复点击结算
$affected = Db::name('settle')
->where('id', (int)$row['id'])
->where('status', 'wait')
->update([
'status' => $targetStatus,
'settle_time' => $now,
]);
if (!$affected) {
throw new \Exception('结算单状态已变更,请刷新列表后重试');
}
$master = Db::name('master')->where('id', $masterId)->lock(true)->find();
if (!$master) {
throw new \Exception('关联结算师傅不存在');
}
$orderNo = $orderId > 0 ? (string)Db::name('order')->where('id', $orderId)->value('order_no') : '';
if ($targetStatus === 'settled') {
// 幂等校验:防止该订单此前已产生过 settle 流水
$existsLog = $orderId > 0 && Db::name('wallet_log')
->where('user_type', 'master')
->where('user_id', $masterId)
->where('order_id', $orderId)
->where('type', 'settle')
->find();
if ($existsLog) {
throw new \Exception('检测到该订单已存在线上结算入账流水,请核对后再操作');
}
$newMoney = round((float)$master['money'] + $settleAmount, 2);
Db::name('master')->where('id', $masterId)->update([
'money' => $newMoney,
'updatetime' => $now,
]);
Db::name('wallet_log')->insert([
'user_type' => 'master',
'user_id' => $masterId,
'type' => 'settle',
'amount' => $settleAmount,
'balance' => $newMoney,
'order_id' => $orderId,
'remark' => '后台财务确认结算入账' . ($orderNo !== '' ? '(订单 ' . $orderNo . ')' : ''),
'createtime' => $now,
]);
$msgText = ($orderNo !== '' ? '订单 ' . $orderNo . ' ' : '') . '服务佣金 ¥' . number_format($settleAmount, 2, '.', '') . ' 已结算至您的平台钱包余额。';
} else {
$msgText = ($orderNo !== '' ? '订单 ' . $orderNo . ' ' : '') . '服务佣金 ¥' . number_format($settleAmount, 2, '.', '') . ' 已由财务完成线下特殊结算归档。';
}
if ($orderId > 0) {
Db::name('order')->where('id', $orderId)->update([
'settle_status' => 1,
'settle_amount' => $settleAmount,
'updatetime' => $now,
]);
}
Db::name('message')->insert([
'receive_type' => 'master',
'receive_id' => $masterId,
'type' => 'order',
'title' => '服务佣金结算通知',
'content' => mb_substr($msgText, 0, 500),
'order_id' => $orderId,
'is_read' => 0,
'createtime' => $now,
]);
Db::commit();
} catch (PDOException|\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success();
}
/**
* 结算单由订单核销系统生成,禁止手动添加
*/
public function add()
{
$this->error('结算单由完工核销自动生成,后台不可手工录入');
}
/**
* 财务结算凭证禁止删除
*/
public function del($ids = null)
{
$this->error('财务结算单据禁止删除');
}
/**
* 禁止跳过钱包流水的批量修改状态
*/
public function multi($ids = null)
{
$this->error('结算单涉及资金划拨,不支持批量修改状态,请逐单核对处理');
}
/**
* 组装结算单对账上下文
*/
protected function assignSettleContext($row)
{
$order = (int)$row['order_id'] > 0 ? Db::name('order')->where('id', (int)$row['order_id'])->find() : null;
$master = (int)$row['master_id'] > 0 ? Db::name('master')->where('id', (int)$row['master_id'])->find() : null;
$walletLogs = ((int)$row['master_id'] > 0 && (int)$row['order_id'] > 0)
? Db::name('wallet_log')
->where('user_type', 'master')
->where('user_id', (int)$row['master_id'])
->where('order_id', (int)$row['order_id'])
->order('id desc')
->select()
: [];
$this->view->assign([
'row' => $row,
'order' => $order ?: [],
'master' => $master ?: [],
'walletLogs' => $walletLogs,
]);
}
}