feat: 重构后台服务字典与商品独立定价体系及前后端交互优化

这个提交包含在:
2026-11-10 11:01:05 +08:00
父节点 3ebd795cbb
当前提交 e2b0044b64
共有 66 个文件被更改,包括 6628 次插入 和 2137 次删除

查看文件

@@ -248,33 +248,92 @@ class Merchant extends Base
}
/**
* 开票记录
* 开票记录与可开票额度(个人用户与认证商家通用)
*/
public function invoices()
{
$merchant = $this->requireMerchant();
$list = Db::name('invoice')->where('merchant_id', $merchant['id'])->order('id desc')->limit(30)->select();
$merchant = $this->merchantInfo();
$isPassMerchant = ($merchant && $merchant['verify_status'] === 'pass');
if ($isPassMerchant) {
$uids = $this->merchantUserIds($merchant);
$mid = (int)$merchant['id'];
$list = Db::name('invoice')
->where(function ($q) use ($mid, $uids) {
$q->where('merchant_id', $mid)->whereOr('user_id', 'in', $uids);
})
->order('id desc')
->limit(30)
->select();
$paid = (float)Db::name('order')->where('user_id', 'in', $uids)->where('pay_status', 1)->sum('pay_amount');
$used = (float)Db::name('invoice')
->where(function ($q) use ($mid, $uids) {
$q->where('merchant_id', $mid)->whereOr('user_id', 'in', $uids);
})
->where('status', 'in', ['wait', 'issued'])
->sum('amount');
$issued = (float)Db::name('invoice')
->where(function ($q) use ($mid, $uids) {
$q->where('merchant_id', $mid)->whereOr('user_id', 'in', $uids);
})
->where('status', 'issued')
->sum('amount');
} else {
$uid = $this->uid();
$list = Db::name('invoice')->where('user_id', $uid)->order('id desc')->limit(30)->select();
$paid = (float)Db::name('order')->where('user_id', $uid)->where('pay_status', 1)->sum('pay_amount');
$used = (float)Db::name('invoice')->where('user_id', $uid)->where('status', 'in', ['wait', 'issued'])->sum('amount');
$issued = (float)Db::name('invoice')->where('user_id', $uid)->where('status', 'issued')->sum('amount');
}
$statusText = ['wait' => '开票中', 'issued' => '已开票', 'reject' => '已驳回'];
foreach ($list as &$row) {
$row['amount'] = (float)$row['amount'];
$row['status_text'] = isset($statusText[$row['status']]) ? $statusText[$row['status']] : $row['status'];
$row['type_text'] = $row['type'] === 'special' ? '专用发票' : '普通发票';
$row['title_type'] = !empty($row['tax_no']) ? 'enterprise' : 'personal';
$row['title_type_text'] = !empty($row['tax_no']) ? '企业单位' : '个人/非企业';
$row['time_text'] = date('Y-m-d H:i', (int)$row['createtime']);
}
unset($row);
$this->success('', ['list' => $list]);
$userRow = Db::name('user')->where('id', $this->uid())->field('nickname,mobile')->find();
$personalDefaultTitle = ($userRow && !empty($userRow['nickname'])) ? (string)$userRow['nickname'] : '个人';
$this->success('', [
'list' => $list,
'quota' => [
'available' => round(max(0, $paid - $used), 2),
'paid_amount' => round($paid, 2),
'used_amount' => round($used, 2),
'issued_amount' => round($issued, 2),
'is_merchant' => $isPassMerchant,
'default_title_type' => $isPassMerchant ? 'enterprise' : 'personal',
'default_title' => $isPassMerchant ? ($merchant['invoice_title'] ?: $merchant['name']) : $personalDefaultTitle,
'default_tax_no' => $isPassMerchant ? (string)$merchant['invoice_tax_no'] : '',
'enterprise_title' => $merchant ? (string)($merchant['invoice_title'] ?: $merchant['name']) : '',
'enterprise_tax_no' => $merchant ? (string)$merchant['invoice_tax_no'] : '',
'personal_title' => $personalDefaultTitle,
],
]);
}
/**
* 申请开票
* 申请开票(支持个人用户与认证商家)
* @ApiMethod (POST)
*/
public function invoice()
{
$merchant = $this->requireMerchant();
$merchant = $this->merchantInfo();
$isPassMerchant = ($merchant && $merchant['verify_status'] === 'pass');
$amount = round((float)$this->request->post('amount'), 2);
$type = $this->request->post('type', 'normal');
$email = trim((string)$this->request->post('email'));
$titleType = trim((string)$this->request->post('title_type', ''));
$title = trim((string)$this->request->post('title', ''));
$taxNo = strtoupper(trim((string)$this->request->post('tax_no', '')));
$email = trim((string)$this->request->post('email', ''));
$remark = trim((string)$this->request->post('remark', ''));
if ($amount <= 0) {
$this->error('请填写开票金额');
@@ -283,21 +342,64 @@ class Merchant extends Base
$this->error('发票类型错误');
}
$paid = (float)Db::name('order')->where('user_id', 'in', $this->merchantUserIds($merchant))->where('pay_status', 1)->sum('pay_amount');
$used = (float)Db::name('invoice')->where('merchant_id', $merchant['id'])->where('status', 'in', ['wait', 'issued'])->sum('amount');
if (!in_array($titleType, ['personal', 'enterprise'], true)) {
$titleType = ($isPassMerchant || $taxNo !== '' || $type === 'special') ? 'enterprise' : 'personal';
}
if ($titleType === 'personal') {
if ($type === 'special') {
$this->error('个人抬头仅支持开具普通发票');
}
if ($title === '') {
$userRow = Db::name('user')->where('id', $this->uid())->field('nickname')->find();
$title = ($userRow && !empty($userRow['nickname'])) ? (string)$userRow['nickname'] : '个人';
}
$taxNo = '';
} else {
if ($title === '' && $isPassMerchant) {
$title = (string)($merchant['invoice_title'] ?: $merchant['name']);
}
if ($taxNo === '' && $isPassMerchant) {
$taxNo = strtoupper(trim((string)$merchant['invoice_tax_no']));
}
if ($title === '') {
$this->error('请填写企业发票抬头');
}
if ($taxNo === '') {
$this->error('请填写纳税人识别号(税号)');
}
}
if ($isPassMerchant) {
$uids = $this->merchantUserIds($merchant);
$mid = (int)$merchant['id'];
$paid = (float)Db::name('order')->where('user_id', 'in', $uids)->where('pay_status', 1)->sum('pay_amount');
$used = (float)Db::name('invoice')
->where(function ($q) use ($mid, $uids) {
$q->where('merchant_id', $mid)->whereOr('user_id', 'in', $uids);
})
->where('status', 'in', ['wait', 'issued'])
->sum('amount');
} else {
$uid = $this->uid();
$paid = (float)Db::name('order')->where('user_id', $uid)->where('pay_status', 1)->sum('pay_amount');
$used = (float)Db::name('invoice')->where('user_id', $uid)->where('status', 'in', ['wait', 'issued'])->sum('amount');
}
$available = round(max(0, $paid - $used), 2);
if ($amount > $available) {
$this->error('可开票金额不足,当前可开 ¥' . $available);
}
Db::name('invoice')->insert([
'merchant_id' => (int)$merchant['id'],
'merchant_id' => $isPassMerchant ? (int)$merchant['id'] : 0,
'user_id' => $this->uid(),
'amount' => $amount,
'type' => $type,
'title' => $merchant['invoice_title'] ?: $merchant['name'],
'tax_no' => $merchant['invoice_tax_no'],
'title' => $title,
'tax_no' => $taxNo,
'email' => $email,
'remark' => $remark,
'status' => 'wait',
'createtime' => time(),
'updatetime' => time(),