feat: 完善协议管理、师傅资质认证、分账配置并完成测试环境全量部署与同步

这个提交包含在:
2026-11-12 17:19:49 +08:00
父节点 fafddceaf2
当前提交 72cea8445f
共有 179 个文件被更改,包括 29242 次插入 和 3340 次删除

查看文件

@@ -2,6 +2,8 @@
namespace app\api\controller;
use app\common\library\CommissionService;
use app\common\library\FinanceConfigService;
use app\common\library\InvoiceService;
use app\common\library\OrderStatus;
use think\Db;
@@ -645,6 +647,12 @@ class Merchant extends Base
$this->error("第 {$rowNo} 条订单计算金额异常");
}
$resolvedProvince = mb_substr(trim((string)(isset($item['province']) && $item['province'] !== '' ? $item['province'] : ($merchant['province'] ?: ''))), 0, 50);
$resolvedCity = mb_substr(trim((string)(isset($item['city']) && $item['city'] !== '' ? $item['city'] : ($merchant['city'] ?: ''))), 0, 50);
if ($resolvedProvince === '' || $resolvedCity === '') {
$this->error("第 {$rowNo} 条订单缺少服务省份或城市信息,请在Excel或表格中填写后再提交");
}
$preparedRows[] = [
'svc' => $svc,
'service_id' => (int)$svc['id'],
@@ -655,8 +663,8 @@ class Merchant extends Base
'goods_num' => $goodsNum,
'contact' => mb_substr($contact ?: '买家', 0, 50),
'mobile' => $mobile,
'province' => mb_substr(trim((string)(isset($item['province']) && $item['province'] !== '' ? $item['province'] : ($merchant['province'] ?: '贵州省'))), 0, 50),
'city' => mb_substr(trim((string)(isset($item['city']) && $item['city'] !== '' ? $item['city'] : ($merchant['city'] ?: '贵阳市'))), 0, 50),
'province' => $resolvedProvince,
'city' => $resolvedCity,
'district' => mb_substr(trim((string)(isset($item['district']) ? $item['district'] : ($merchant['district'] ?: ''))), 0, 50),
'address' => mb_substr($address, 0, 255),
'floor' => $floor,
@@ -678,6 +686,9 @@ class Merchant extends Base
$isMonthly = false;
$batchNo = 'MB' . date('YmdHis') . mt_rand(1000, 9999);
$now = time();
// 事务外一次性预加载生效抽佣规则与默认兜底配置,循环内纯内存匹配快照(零额外 SQL)
$activeCommRules = CommissionService::getActiveRules();
$commDefaults = FinanceConfigService::getCommissionDefaults();
Db::startTrans();
try {
@@ -697,6 +708,13 @@ class Merchant extends Base
$calc = $pRow['calc'];
$payAmt = round((float)$calc['pay_amount'], 2);
$unitPrice = round((float)$calc['base_amount'] / max(1, (int)$pRow['goods_num']), 2);
$commMatch = CommissionService::matchOrderSnapshot([
'price_type' => 'fixed',
'customer_type' => 'merchant',
'cat_id' => (int)$pRow['cat_id'],
'urgent' => (int)$pRow['urgent'],
'order_amount' => $payAmt,
], $activeCommRules, $commDefaults);
$orderId = (int)Db::name('order')->insertGetId([
'order_no' => $orderNo,
@@ -724,9 +742,11 @@ class Merchant extends Base
'floor_amount' => $calc['floor_amount'],
'urgent_amount' => $calc['urgent_amount'],
'discount_amount' => 0.00,
'total_amount' => $calc['total_amount'],
'pay_amount' => $payAmt,
'status' => $initStatus,
'total_amount' => $calc['total_amount'],
'pay_amount' => $payAmt,
'commission_rate' => $commMatch['commission_rate'],
'commission_snapshot' => $commMatch['commission_snapshot'],
'status' => $initStatus,
'pay_status' => $initPayStatus,
'pay_type' => $initPayType,
'pay_time' => $initPayTime,
@@ -825,124 +845,13 @@ class Merchant extends Base
}
/**
* 商户端:预付商家按批次号支付待支付批量订单
* 商户端:预付商家按批次号支付待支付批量订单(严禁模拟免付兜底,预付订单须逐笔走真实微信支付)
* @ApiMethod (POST)
*/
public function payBatch()
{
$merchant = $this->requireMerchant();
$batchNo = trim((string)$this->request->post('batch_no', ''));
$payType = trim((string)$this->request->post('pay_type', 'wechat'));
if ($payType === '') {
$payType = 'mock';
}
if ($batchNo === '') {
$this->error('缺少批次号 batch_no');
}
$batchLinks = Db::name('merchant_order')->where('batch_no', $batchNo)->select();
if (empty($batchLinks)) {
$this->error('批次订单不存在');
}
$batchOrderIds = [];
foreach ($batchLinks as $link) {
if ((int)$link['merchant_id'] !== (int)$merchant['id']) {
$this->error('无权操作该批次订单', null, 403);
}
$oid = (int)$link['order_id'];
if ($oid > 0) {
$batchOrderIds[] = $oid;
}
}
$batchOrderIds = array_values(array_unique($batchOrderIds));
if (empty($batchOrderIds)) {
$this->error('该批次下无有效订单');
}
$paidCount = 0;
$paidTotal = 0.00;
$paidOrderIds = [];
$now = time();
Db::startTrans();
try {
$lockedMerchant = Db::name('merchant')->where('id', (int)$merchant['id'])->lock(true)->find();
$orders = Db::name('order')
->where('id', 'in', $batchOrderIds)
->lock(true)
->select();
foreach ($orders as $ord) {
if ((int)$ord['pay_status'] === 1 || (int)$ord['status'] !== OrderStatus::PENDING_PAY) {
continue;
}
$oid = (int)$ord['id'];
$amt = round((float)$ord['pay_amount'], 2);
$txId = 'BATCH' . date('YmdHis', $now) . mt_rand(1000, 9999);
Db::name('order')->where('id', $oid)->update([
'status' => OrderStatus::PENDING_ACCEPT,
'pay_status' => 1,
'pay_type' => $payType,
'pay_time' => $now,
'transaction_id' => $txId,
'updatetime' => $now,
]);
$this->addLog($oid, OrderStatus::PENDING_ACCEPT, "企业批次支付完成(批次 {$batchNo}),订单已进入接单大厅", 'user', $this->uid());
$paidCount++;
$paidTotal = round($paidTotal + $amt, 2);
$paidOrderIds[] = $oid;
}
if ($paidCount === 0) {
throw new \InvalidArgumentException('该批次没有待支付的订单,请勿重复支付');
}
if ($lockedMerchant) {
Db::name('merchant')->where('id', (int)$lockedMerchant['id'])->update([
'order_count' => (int)$lockedMerchant['order_count'] + $paidCount,
'total_amount' => round((float)$lockedMerchant['total_amount'] + $paidTotal, 2),
'updatetime' => $now,
]);
}
Db::commit();
} catch (\think\exception\HttpResponseException $e) {
Db::rollback();
throw $e;
} catch (\InvalidArgumentException $e) {
Db::rollback();
$this->error($e->getMessage());
return;
} catch (\Exception $e) {
Db::rollback();
\think\Log::error('[Merchant::payBatch] ' . $e->getMessage());
$this->error('批次支付失败:' . $e->getMessage());
return;
}
try {
$masters = Db::name('master')
->where('verify_status', 'pass')
->where('work_status', 'on')
->where('user_id', '<>', $this->uid())
->limit(20)
->select();
foreach ($masters as $m) {
$this->notify('master', (int)$m['id'], '企业批量新工单就绪', "同城有 {$paidCount} 笔企业批量工单进入接单大厅,请尽快前往查看抢单!", 'order', (int)$paidOrderIds[0]);
}
} catch (\Exception $e) {
\think\Log::error('[Merchant::payBatch broadcast] ' . $e->getMessage());
}
$this->success('批次支付成功,订单已进入接单大厅', [
'batch_no' => $batchNo,
'count' => $paidCount,
'paid_count' => $paidCount,
'total_amount' => round($paidTotal, 2),
'order_ids' => $paidOrderIds,
]);
$this->requireMerchant();
$this->error('系统已全面禁用模拟支付通道,企业预付工单请逐笔使用真实微信支付完成付款(月结授信企业导单时已直接授信进入大厅)');
}
protected function merchantInfo()