This commit is contained in:
Your Name
2026-05-11 16:10:06 +08:00
parent 62d15efbaf
commit 15cf6324f6
8 changed files with 2349 additions and 19 deletions
@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\stats;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\logic\stats\YejiStatsLogic;
/**
* 提成结算业绩(独立于业绩看板 yejiStats 接口)
*
* - GET stats.commissionSettlement/overview
* - GET stats.commissionSettlement/orderLines
* - GET stats.commissionSettlement/confirmStatus
* - POST stats.commissionSettlement/saveReconcile
* - POST stats.commissionSettlement/confirmFinalize
* - GET stats.commissionSettlement/deptOptions
* - GET stats.commissionSettlement/channelOptions
*/
class CommissionSettlementController extends BaseAdminController
{
public function overview()
{
@set_time_limit(120);
$params = $this->request->get();
return $this->data(YejiStatsLogic::commissionSettlementOverview($params, $this->adminId, $this->adminInfo));
}
public function orderLines()
{
@set_time_limit(120);
return $this->data(YejiStatsLogic::commissionSettlementOrderLines($this->request->get(), $this->adminId, $this->adminInfo));
}
public function confirmStatus()
{
return $this->data(YejiStatsLogic::commissionSettlementConfirmStatus($this->request->get(), $this->adminId, $this->adminInfo));
}
public function saveReconcile()
{
return $this->data(YejiStatsLogic::commissionSettlementSaveReconcile($this->request->post(), $this->adminId, $this->adminInfo));
}
public function confirmFinalize()
{
@set_time_limit(120);
return $this->data(YejiStatsLogic::commissionSettlementConfirmFinalize($this->request->post(), $this->adminId, $this->adminInfo));
}
public function deptOptions()
{
return $this->data(YejiStatsLogic::deptOptions($this->adminId, $this->adminInfo));
}
public function channelOptions()
{
return $this->data(YejiStatsLogic::channelOptions(false));
}
}
@@ -916,6 +916,8 @@ class YejiStatsLogic
/**
* 渠道下拉(按 source_group_name 分组),同时附带客户/成本统计便于排序展示
*
* @param bool $includeTagCustomerCounts 为 false 时跳过标签客户数统计(qywx_external_contact_tag 大表聚合较慢);提成结算等仅需筛选项时可关闭以提速。
*
* @return array{
* groups: array<int, array{
* group_name: string,
@@ -928,7 +930,7 @@ class YejiStatsLogic
* total: int
* }
*/
public static function channelOptions(): array
public static function channelOptions(bool $includeTagCustomerCounts = true): array
{
$rows = Db::name('qywx_media_channel')
->where('status', 1)
@@ -939,24 +941,26 @@ class YejiStatsLogic
return ['groups' => [], 'total' => 0];
}
// 顺路给 tag_* 渠道带上「打了该标签的客户数」(直接用 contact_tag 表
$tagIds = [];
foreach ($rows as $r) {
$code = (string) $r['channel_code'];
if (str_starts_with($code, 'tag_')) {
$tagIds[] = substr($code, 4);
}
}
// 顺路给 tag_* 渠道带上「打了该标签的客户数」(qywx_external_contact_tag 数据量大时聚合较慢,可按需关闭
$tagToCount = [];
if ($tagIds !== []) {
$cntRows = Db::name('qywx_external_contact_tag')
->whereIn('tag_id', $tagIds)
->fieldRaw('tag_id, COUNT(DISTINCT external_userid) AS c')
->group('tag_id')
->select()
->toArray();
foreach ($cntRows as $cr) {
$tagToCount[(string) $cr['tag_id']] = (int) $cr['c'];
if ($includeTagCustomerCounts) {
$tagIds = [];
foreach ($rows as $r) {
$code = (string) $r['channel_code'];
if (str_starts_with($code, 'tag_')) {
$tagIds[] = substr($code, 4);
}
}
if ($tagIds !== []) {
$cntRows = Db::name('qywx_external_contact_tag')
->whereIn('tag_id', $tagIds)
->fieldRaw('tag_id, COUNT(DISTINCT external_userid) AS c')
->group('tag_id')
->select()
->toArray();
foreach ($cntRows as $cr) {
$tagToCount[(string) $cr['tag_id']] = (int) $cr['c'];
}
}
}
@@ -4920,4 +4924,923 @@ class YejiStatsLogic
return $out;
}
/**
* 提成结算统计:渠道收窄条件应用到业务订单查询(与 sumPerformance「scoped」同源)。
*/
private static function applyCommissionSettlementChannelFilter(Query $query, array $c): void
{
if (empty($c['channelFilterActive'])) {
return;
}
/** @var array<int, mixed> $appointmentChannelValues */
$appointmentChannelValues = $c['appointmentChannelValues'] ?? [];
$tagDiagIds = $c['tagDiagIds'] ?? null;
$tagAssistantIds = $c['tagAssistantIds'] ?? null;
$tagFallback = !empty($c['tagFallback']);
$channelInfo = $c['channelInfo'] ?? null;
if ($appointmentChannelValues !== []) {
$norm = self::normalizeAppointmentChannelValues($appointmentChannelValues);
$pack = self::buildChannelScopedAppointmentExistsSqlAndBindings('o.diagnosis_id', $norm, $channelInfo);
if ($pack === null) {
$query->whereRaw('0 = 1');
return;
}
$query->whereRaw($pack[0], $pack[1]);
return;
}
if ($tagDiagIds !== null && $tagDiagIds === []) {
$query->whereRaw('0 = 1');
return;
}
if ($tagAssistantIds !== null && $tagAssistantIds === [] && $tagFallback) {
$query->whereRaw('0 = 1');
return;
}
$att = self::sqlPerformanceAttributionAdminExpr();
$narrowed = false;
if ($tagDiagIds !== null) {
$idsSan = array_values(array_unique(array_filter(array_map('intval', $tagDiagIds), static fn (int $x): bool => $x > 0)));
if ($idsSan === []) {
$query->whereRaw('0 = 1');
return;
}
$narrowed = true;
$chunks = array_chunk($idsSan, 800);
if (\count($chunks) === 1) {
$query->whereIn('o.diagnosis_id', $chunks[0]);
} else {
$query->where(function ($qq) use ($chunks): void {
foreach ($chunks as $i => $chunk) {
if ($i === 0) {
$qq->whereIn('o.diagnosis_id', $chunk);
} else {
$qq->whereOr(function ($q2) use ($chunk): void {
$q2->whereIn('o.diagnosis_id', $chunk);
});
}
}
});
}
}
if ($tagAssistantIds !== null) {
$ids = array_map('intval', array_keys($tagAssistantIds));
if ($ids === []) {
$query->whereRaw('0 = 1');
return;
}
$in = implode(',', $ids);
$query->whereRaw("({$att}) IN ({$in})");
$narrowed = true;
}
if (!$narrowed) {
$query->whereRaw('0 = 1');
}
}
/**
* 提成结算:部门筛选规范化键(与确认/结转 scope 一致)。
*
* @param int[]|string|null $deptIds
*/
private static function commissionSettlementDeptIdsKey($deptIds): string
{
if ($deptIds === null || $deptIds === '' || $deptIds === []) {
return '*';
}
if (is_array($deptIds)) {
$ids = array_map('intval', $deptIds);
} else {
$ids = array_map('intval', explode(',', (string) $deptIds));
}
$ids = array_values(array_unique(array_filter($ids, static function (int $x): bool {
return $x > 0;
})));
sort($ids);
return $ids === [] ? '*' : implode(',', $ids);
}
/**
* @return int[]
*/
private static function commissionSettlementCarryOrderIdsForTarget(string $targetSettlementMonth, string $scopeChannelCode, string $scopeDeptKey): array
{
$ids = Db::name('commission_settlement_carry')
->where('target_settlement_month', $targetSettlementMonth)
->where('scope_channel_code', $scopeChannelCode)
->where('scope_dept_ids_key', $scopeDeptKey)
->column('prescription_order_id');
return array_values(array_unique(array_filter(array_map('intval', $ids), static function (int $x): bool {
return $x > 0;
})));
}
private static function commissionSettlementNextMonth(string $monthRaw): string
{
$t = strtotime($monthRaw . '-01 12:00:00');
return date('Y-m', strtotime('+1 month', $t !== false ? $t : time()));
}
/**
* @return array<string, mixed>|null
*/
private static function commissionSettlementGetConfirmRow(string $settlementMonth, string $scopeChannelCode, string $scopeDeptKey): ?array
{
$row = Db::name('commission_settlement_confirm')
->where('settlement_month', $settlementMonth)
->where('scope_channel_code', $scopeChannelCode)
->where('scope_dept_ids_key', $scopeDeptKey)
->find();
if (!$row) {
return null;
}
$r = is_array($row) ? $row : $row->toArray();
return [
'status' => (int) ($r['status'] ?? 0),
'reconcile_note' => (string) ($r['reconcile_note'] ?? ''),
'confirmed_admin_id' => (int) ($r['confirmed_admin_id'] ?? 0),
'confirmed_admin_name' => (string) ($r['confirmed_admin_name'] ?? ''),
'confirmed_at' => (int) ($r['confirmed_at'] ?? 0),
'confirmed_at_text' => !empty($r['confirmed_at']) ? date('Y-m-d H:i:s', (int) $r['confirmed_at']) : '',
'totals_json' => (string) ($r['totals_json'] ?? ''),
];
}
/**
* @return array<string, mixed>
*/
private static function commissionSettlementResolveBasePack(array $params, int $viewerAdminId, array $viewerAdminInfo): array
{
$monthRaw = trim((string) ($params['settlement_month'] ?? ''));
if (!preg_match('/^\d{4}-\d{2}$/', $monthRaw)) {
throw new \think\Exception('请传入有效的结算月 settlement_month(格式 YYYY-MM');
}
$anchor = strtotime($monthRaw . '-01 12:00:00');
if ($anchor === false) {
throw new \think\Exception('结算月日期无效');
}
$prevMonthAnchor = strtotime('-1 month', $anchor);
$orderCreateStartTs = (int) strtotime(date('Y-m-01 00:00:00', $prevMonthAnchor));
$orderCreateEndTs = (int) strtotime(date('Y-m-t 23:59:59', $prevMonthAnchor));
$cutoffTs = (int) strtotime(date('Y-m-07 23:59:59', $anchor));
$orderMonthLabel = date('Y-m', $prevMonthAnchor);
$ctxParams = array_merge($params, [
'start_date' => date('Y-m-d', $orderCreateStartTs),
'end_date' => date('Y-m-d', $orderCreateEndTs),
]);
$c = self::resolveYejiContext($ctxParams);
if ($viewerAdminId > 0) {
self::applyYejiDataScope($c, $viewerAdminId, $viewerAdminInfo);
}
$deptKey = self::commissionSettlementDeptIdsKey($params['dept_ids'] ?? null);
$scopeChannelCode = (string) ($c['channelCode'] ?? '');
$carryOrderIds = self::commissionSettlementCarryOrderIdsForTarget($monthRaw, $scopeChannelCode, $deptKey);
$diagTable = self::tableWithPrefix('tcm_diagnosis');
$rxTable = self::tableWithPrefix('tcm_prescription');
$att = self::sqlPerformanceAttributionAdminExpr();
return [
'monthRaw' => $monthRaw,
'cutoffTs' => $cutoffTs,
'orderCreateStartTs' => $orderCreateStartTs,
'orderCreateEndTs' => $orderCreateEndTs,
'orderMonthLabel' => $orderMonthLabel,
'nextSettlementMonth' => self::commissionSettlementNextMonth($monthRaw),
'deptKey' => $deptKey,
'scopeChannelCode' => $scopeChannelCode,
'carryOrderIds' => $carryOrderIds,
'c' => $c,
'tableRowDeptIds' => $c['tableRowDeptIds'],
'deptById' => $c['deptById'],
'adminToPrimary' => $c['adminToPrimary'],
'diagTable' => $diagTable,
'rxTable' => $rxTable,
'att' => $att,
];
}
/**
* @param int[] $ids
*
* @return array<int, string>
*/
private static function commissionSettlementBatchAdminNames(array $ids): array
{
$ids = array_values(array_unique(array_filter(array_map('intval', $ids))));
if ($ids === []) {
return [];
}
$rows = Db::name('admin')
->whereIn('id', $ids)
->whereNull('delete_time')
->column('name', 'id');
$out = [];
foreach ($rows as $id => $name) {
$out[(int) $id] = (string) $name;
}
return $out;
}
/**
* 签收 / 尾款时间:对物流与支付关联做 GROUP BY 后 LEFT JOIN,避免 SELECT 中逐行相关子查询导致 overview 超时。
*/
private static function commissionSettlementAttachExpressPayAggregates(Query $query): void
{
$etTable = self::tableWithPrefix('express_tracking');
$linkTbl = self::tableWithPrefix('tcm_prescription_order_pay_order');
$payTbl = self::tableWithPrefix('order');
$etAggSql = "(SELECT et.order_id, MAX(et.sign_time) AS cs_sign_ts FROM {$etTable} et "
. "WHERE et.order_type = 'prescription' AND et.delete_time IS NULL GROUP BY et.order_id) cs_et_sig";
$payAggSql = "(SELECT l.prescription_order_id AS cs_pay_oid, "
. 'MAX(CASE WHEN pay.order_type IN (5, 7) THEN UNIX_TIMESTAMP(pay.payment_time) END) AS cs_pay_tail_ts, '
. 'MAX(UNIX_TIMESTAMP(pay.payment_time)) AS cs_pay_any_ts '
. "FROM {$linkTbl} l INNER JOIN {$payTbl} pay ON pay.id = l.pay_order_id AND pay.delete_time IS NULL "
. 'WHERE pay.status = 2 GROUP BY l.prescription_order_id) cs_pay_agg';
// 须传入带子查询别名的字符串;ThinkPHP parseJoin 对 Db::raw 整段 JOIN 表会直接传给 parseTable,触发类型错误
$query->leftJoin($etAggSql, 'cs_et_sig.order_id = o.id');
$query->leftJoin($payAggSql, 'cs_pay_agg.cs_pay_oid = o.id');
}
/**
* @return array<int, mixed>
*/
private static function commissionSettlementSignPayFieldRawList(): array
{
return [
Db::raw('IFNULL(cs_et_sig.cs_sign_ts, 0) AS sign_ts'),
Db::raw('COALESCE(cs_pay_agg.cs_pay_tail_ts, cs_pay_agg.cs_pay_any_ts, 0) AS pay_ts'),
];
}
/**
* @param array<string, mixed> $pack commissionSettlementResolveBasePack 返回值
*/
private static function commissionSettlementBuildFilteredOrderQuery(array $pack): Query
{
$c = $pack['c'];
$diagTable = $pack['diagTable'];
$rxTable = $pack['rxTable'];
$att = $pack['att'];
$query = Db::name('tcm_prescription_order')
->alias('o')
->join("{$diagTable} dg", 'dg.id = o.diagnosis_id AND dg.delete_time IS NULL', 'INNER')
->join("{$rxTable} rx", 'rx.id = o.prescription_id AND rx.delete_time IS NULL AND IFNULL(rx.is_system_auto, 0) = 1', 'INNER');
self::commissionSettlementAttachExpressPayAggregates($query);
$query->whereNull('o.delete_time')
->where('o.fulfillment_status', 3)
->where('o.diagnosis_id', '>', 0)
->whereRaw("({$att}) > 0", []);
$query->where(function ($qq) use ($pack) {
$qq->whereBetween('o.create_time', [$pack['orderCreateStartTs'], $pack['orderCreateEndTs']]);
if ($pack['carryOrderIds'] !== []) {
$qq->whereOr(function ($q2) use ($pack) {
$q2->whereIn('o.id', $pack['carryOrderIds']);
});
}
});
self::applyCommissionSettlementChannelFilter($query, $c);
return $query;
}
/**
* 提成结算业绩看板:上月(相对结算月)系统处方对应的已完成业务单,按签收与尾款支付是否在结算月 7 日 24 点前拆分「计入本期提成 / 顺延下期」。
*
* 规则摘要:
* - 订单池:结算月上一自然月内创建;关联处方 is_system_auto=1(系统代开);履约已完成 fulfillment_status=3;未软删。
* - 签收时间:express_tracking.order_type=prescription 下 MAX(sign_time)。
* - 尾款支付时间:关联支付单 status=2,优先 order_type∈(5,7),否则回退为任意已支付关联单的 MAX(payment_time)。
* - 计入本期:签收与尾款时间均已成立且不晚于结算月 7 日 23:59:59。
* - 其余已完成单计入「顺延下期」(含签收或支付缺失、或晚于截止)。
*
* @param array{settlement_month?: string, dept_ids?: int[]|string, channel_code?: string, tag_id?: string} $params
*
* @return array<string, mixed>
*/
public static function commissionSettlementOverview(array $params, int $viewerAdminId = 0, array $viewerAdminInfo = []): array
{
$pack = self::commissionSettlementResolveBasePack($params, $viewerAdminId, $viewerAdminInfo);
$monthRaw = $pack['monthRaw'];
$cutoffTs = $pack['cutoffTs'];
$orderMonthLabel = $pack['orderMonthLabel'];
$c = $pack['c'];
$tableRowDeptIds = $pack['tableRowDeptIds'];
$deptById = $pack['deptById'];
$adminToPrimary = $pack['adminToPrimary'];
$carryFlip = array_flip($pack['carryOrderIds']);
$confirm = self::commissionSettlementGetConfirmRow($monthRaw, $pack['scopeChannelCode'], $pack['deptKey']);
$emptyTotal = [
'completed_order_count' => 0,
'completed_order_amount' => 0.0,
'current_period_count' => 0,
'current_period_amount' => 0.0,
'deferred_period_count' => 0,
'deferred_period_amount' => 0.0,
'carry_in_order_count' => 0,
];
if ($tableRowDeptIds === [] || $adminToPrimary === []) {
return [
'settlement_month' => $monthRaw,
'order_month' => $orderMonthLabel,
'cutoff_end' => date('Y-m-d H:i:s', $cutoffTs),
'rule_note' => '订单创建月为结算月的上一自然月;统计系统代开处方对应的已完成业务订单;签收与尾款均在结算月 7 日 24 点前完成的金额计入本期提成,否则计入顺延下期。上期「确定业绩」写入的顺延订单会在本期并入统计。',
'channel_code' => $c['channelCode'],
'channel_name' => $c['channelInfo'] ? (string) $c['channelInfo']['channel_name'] : '',
'scope_dept_ids_key' => $pack['deptKey'],
'carry_in_order_count' => 0,
'confirm' => $confirm,
'rows' => [],
'assistant_rows' => [],
'doctor_rows' => [],
'total' => $emptyTotal,
];
}
$query = self::commissionSettlementBuildFilteredOrderQuery($pack);
$att = $pack['att'];
$signPayFields = self::commissionSettlementSignPayFieldRawList();
$rowsRaw = $query->field(array_merge([
'o.id',
'o.order_no',
'o.diagnosis_id',
'o.create_time',
'o.amount',
Db::raw("({$att}) AS assistant_id"),
Db::raw('IFNULL(rx.creator_id, 0) AS doctor_id'),
], $signPayFields))->select()->toArray();
$curAgg = [];
$defAgg = [];
$totAgg = [];
$cntByAsst = [];
$curCntByAsst = [];
$defCntByAsst = [];
$carryInCnt = 0;
$carryInByAssist = [];
$carryInByDoctor = [];
$totByDoctor = [];
$curByDoctor = [];
$defByDoctor = [];
$cntDoctorTot = [];
$cntDoctorCur = [];
$cntDoctorDef = [];
foreach ($rowsRaw as $r) {
$oid = (int) ($r['id'] ?? 0);
$isCarry = $oid > 0 && isset($carryFlip[$oid]);
if ($isCarry) {
$carryInCnt++;
}
$aid = (int) ($r['assistant_id'] ?? 0);
$doctorId = (int) ($r['doctor_id'] ?? 0);
$signTs = (int) ($r['sign_ts'] ?? 0);
$payTs = (int) ($r['pay_ts'] ?? 0);
$amt = round((float) ($r['amount'] ?? 0), 2);
if ($aid <= 0 || $amt < 0) {
continue;
}
$totAgg[$aid] = ($totAgg[$aid] ?? 0.0) + $amt;
$cntByAsst[$aid] = ($cntByAsst[$aid] ?? 0) + 1;
$eligible = $signTs > 0 && $payTs > 0 && $signTs <= $cutoffTs && $payTs <= $cutoffTs;
if ($eligible) {
$curAgg[$aid] = ($curAgg[$aid] ?? 0.0) + $amt;
$curCntByAsst[$aid] = ($curCntByAsst[$aid] ?? 0) + 1;
} else {
$defAgg[$aid] = ($defAgg[$aid] ?? 0.0) + $amt;
$defCntByAsst[$aid] = ($defCntByAsst[$aid] ?? 0) + 1;
}
if ($isCarry) {
$carryInByAssist[$aid] = ($carryInByAssist[$aid] ?? 0) + 1;
$carryInByDoctor[$doctorId] = ($carryInByDoctor[$doctorId] ?? 0) + 1;
}
$totByDoctor[$doctorId] = ($totByDoctor[$doctorId] ?? 0.0) + $amt;
$cntDoctorTot[$doctorId] = ($cntDoctorTot[$doctorId] ?? 0) + 1;
if ($eligible) {
$curByDoctor[$doctorId] = ($curByDoctor[$doctorId] ?? 0.0) + $amt;
$cntDoctorCur[$doctorId] = ($cntDoctorCur[$doctorId] ?? 0) + 1;
} else {
$defByDoctor[$doctorId] = ($defByDoctor[$doctorId] ?? 0.0) + $amt;
$cntDoctorDef[$doctorId] = ($cntDoctorDef[$doctorId] ?? 0) + 1;
}
}
$foldAmt = static function (array $byAssistant): array {
$outRows = [];
foreach ($byAssistant as $aid => $amt) {
$aid = (int) $aid;
if ($aid <= 0) {
continue;
}
$outRows[] = ['assistant_id' => $aid, 'amt' => round((float) $amt, 2)];
}
return $outRows;
};
$foldCnt = static function (array $byAssistant): array {
$outRows = [];
foreach ($byAssistant as $aid => $v) {
$aid = (int) $aid;
if ($aid <= 0) {
continue;
}
$outRows[] = ['assistant_id' => $aid, 'cnt' => (int) $v];
}
return $outRows;
};
$byDeptAmtTot = self::foldPerformanceRowsToDeptByTable($foldAmt($totAgg), $adminToPrimary, $tableRowDeptIds, $deptById, 'amt');
$byDeptAmtCur = self::foldPerformanceRowsToDeptByTable($foldAmt($curAgg), $adminToPrimary, $tableRowDeptIds, $deptById, 'amt');
$byDeptAmtDef = self::foldPerformanceRowsToDeptByTable($foldAmt($defAgg), $adminToPrimary, $tableRowDeptIds, $deptById, 'amt');
$byDeptCntTot = self::foldPerformanceRowsToDeptByTable($foldCnt($cntByAsst), $adminToPrimary, $tableRowDeptIds, $deptById, 'cnt');
$byDeptCntCur = self::foldPerformanceRowsToDeptByTable($foldCnt($curCntByAsst), $adminToPrimary, $tableRowDeptIds, $deptById, 'cnt');
$byDeptCntDef = self::foldPerformanceRowsToDeptByTable($foldCnt($defCntByAsst), $adminToPrimary, $tableRowDeptIds, $deptById, 'cnt');
$rows = [];
$sumCompletedCnt = 0;
$sumCompletedAmt = 0.0;
$sumCurCnt = 0;
$sumCurAmt = 0.0;
$sumDefCnt = 0;
$sumDefAmt = 0.0;
foreach ($tableRowDeptIds as $deptId) {
$deptId = (int) $deptId;
$cCnt = (int) ($byDeptCntTot[$deptId] ?? 0);
$cAmt = round((float) ($byDeptAmtTot[$deptId] ?? 0), 2);
$kCnt = (int) ($byDeptCntCur[$deptId] ?? 0);
$kAmt = round((float) ($byDeptAmtCur[$deptId] ?? 0), 2);
$dCnt = (int) ($byDeptCntDef[$deptId] ?? 0);
$dAmt = round((float) ($byDeptAmtDef[$deptId] ?? 0), 2);
$rows[] = [
'dept_id' => $deptId,
'dept_name' => self::formatYejiDeptRowDisplayName($deptId, $deptById),
'completed_order_count' => $cCnt,
'completed_order_amount' => $cAmt,
'current_period_count' => $kCnt,
'current_period_amount' => $kAmt,
'deferred_period_count' => $dCnt,
'deferred_period_amount' => $dAmt,
];
$sumCompletedCnt += $cCnt;
$sumCompletedAmt += $cAmt;
$sumCurCnt += $kCnt;
$sumCurAmt += $kAmt;
$sumDefCnt += $dCnt;
$sumDefAmt += $dAmt;
}
$assistantRows = [];
foreach (array_keys($totAgg) as $aid) {
$aid = (int) $aid;
if ($aid <= 0) {
continue;
}
$pid = (int) ($adminToPrimary[$aid] ?? 0);
$assistantRows[] = [
'assistant_id' => $aid,
'assistant_name' => '',
'primary_dept_id' => $pid,
'primary_dept_name' => $pid > 0 ? self::formatYejiDeptRowDisplayName($pid, $deptById) : '',
'carry_in_order_count' => (int) ($carryInByAssist[$aid] ?? 0),
'completed_order_count' => (int) ($cntByAsst[$aid] ?? 0),
'completed_order_amount' => round((float) ($totAgg[$aid] ?? 0), 2),
'current_period_count' => (int) ($curCntByAsst[$aid] ?? 0),
'current_period_amount' => round((float) ($curAgg[$aid] ?? 0), 2),
'deferred_period_count' => (int) ($defCntByAsst[$aid] ?? 0),
'deferred_period_amount' => round((float) ($defAgg[$aid] ?? 0), 2),
];
}
$assistNameMap = self::commissionSettlementBatchAdminNames(array_column($assistantRows, 'assistant_id'));
foreach ($assistantRows as &$ar) {
$aid = (int) ($ar['assistant_id'] ?? 0);
$ar['assistant_name'] = (string) ($assistNameMap[$aid] ?? ('#' . $aid));
}
unset($ar);
usort($assistantRows, static function (array $a, array $b): int {
$cmp = ($b['completed_order_amount'] ?? 0) <=> ($a['completed_order_amount'] ?? 0);
return $cmp !== 0 ? $cmp : (($b['assistant_id'] ?? 0) <=> ($a['assistant_id'] ?? 0));
});
$doctorRows = [];
foreach (array_keys($totByDoctor) as $did) {
$did = (int) $did;
$pid = $did > 0 ? (int) ($adminToPrimary[$did] ?? 0) : 0;
$doctorRows[] = [
'doctor_id' => $did,
'doctor_name' => '',
'primary_dept_id' => $pid,
'primary_dept_name' => $pid > 0 ? self::formatYejiDeptRowDisplayName($pid, $deptById) : '',
'carry_in_order_count' => (int) ($carryInByDoctor[$did] ?? 0),
'completed_order_count' => (int) ($cntDoctorTot[$did] ?? 0),
'completed_order_amount' => round((float) ($totByDoctor[$did] ?? 0), 2),
'current_period_count' => (int) ($cntDoctorCur[$did] ?? 0),
'current_period_amount' => round((float) ($curByDoctor[$did] ?? 0), 2),
'deferred_period_count' => (int) ($cntDoctorDef[$did] ?? 0),
'deferred_period_amount' => round((float) ($defByDoctor[$did] ?? 0), 2),
];
}
$doctorNameIds = array_values(array_filter(array_column($doctorRows, 'doctor_id'), static fn ($id) => (int) $id > 0));
$doctorNameMap = self::commissionSettlementBatchAdminNames($doctorNameIds);
foreach ($doctorRows as &$dr) {
$did = (int) ($dr['doctor_id'] ?? 0);
$dr['doctor_name'] = $did > 0 ? (string) ($doctorNameMap[$did] ?? ('#' . $did)) : '未关联开方人';
}
unset($dr);
usort($doctorRows, static function (array $a, array $b): int {
$za = (int) ($a['doctor_id'] ?? 0) === 0 ? 1 : 0;
$zb = (int) ($b['doctor_id'] ?? 0) === 0 ? 1 : 0;
if ($za !== $zb) {
return $za <=> $zb;
}
$cmp = ($b['completed_order_amount'] ?? 0) <=> ($a['completed_order_amount'] ?? 0);
return $cmp !== 0 ? $cmp : (($b['doctor_id'] ?? 0) <=> ($a['doctor_id'] ?? 0));
});
return [
'settlement_month' => $monthRaw,
'order_month' => $orderMonthLabel,
'cutoff_end' => date('Y-m-d H:i:s', $cutoffTs),
'rule_note' => '订单创建月为结算月的上一自然月;仅统计系统代开处方(is_system_auto=1)对应的履约已完成业务订单。签收时间取物流表签收时间最大值;尾款时间取关联支付单已支付记录(优先类型为尾款/全部)。签收与尾款均不晚于结算月 7 日 24 点的计入「本期提成」,其余已完成订单计入「顺延下期」。上期同渠道同部门范围内「确定业绩」产生的顺延订单,会计入本期订单池。「按医助下发」按业绩归属医助聚合;「按医生下发」按处方开方人(creator_id)聚合。',
'channel_code' => $c['channelCode'],
'channel_name' => $c['channelInfo'] ? (string) $c['channelInfo']['channel_name'] : '',
'scope_dept_ids_key' => $pack['deptKey'],
'carry_in_order_count' => $carryInCnt,
'confirm' => $confirm,
'rows' => $rows,
'assistant_rows' => $assistantRows,
'doctor_rows' => $doctorRows,
'total' => [
'completed_order_count' => $sumCompletedCnt,
'completed_order_amount' => round($sumCompletedAmt, 2),
'current_period_count' => $sumCurCnt,
'current_period_amount' => round($sumCurAmt, 2),
'deferred_period_count' => $sumDefCnt,
'deferred_period_amount' => round($sumDefAmt, 2),
'carry_in_order_count' => $carryInCnt,
],
];
}
/**
* 提成核对:订单明细(分页)。
*
* @param array{settlement_month?: string, dept_ids?: int[]|string, channel_code?: string, page?: int|string, page_size?: int|string, bucket?: string} $params bucket: 空|current|deferred
*
* @return array<string, mixed>
*/
public static function commissionSettlementOrderLines(array $params, int $viewerAdminId = 0, array $viewerAdminInfo = []): array
{
$pack = self::commissionSettlementResolveBasePack($params, $viewerAdminId, $viewerAdminInfo);
$cutoffTs = $pack['cutoffTs'];
$tableRowDeptIds = $pack['tableRowDeptIds'];
$deptById = $pack['deptById'];
$adminToPrimary = $pack['adminToPrimary'];
$carryFlip = array_flip($pack['carryOrderIds']);
$bucket = trim((string) ($params['bucket'] ?? ''));
$page = max(1, (int) ($params['page'] ?? 1));
$pageSize = min(100, max(10, (int) ($params['page_size'] ?? 20)));
if ($tableRowDeptIds === [] || $adminToPrimary === []) {
return ['list' => [], 'count' => 0, 'page' => $page, 'page_size' => $pageSize];
}
$query = self::commissionSettlementBuildFilteredOrderQuery($pack);
$att = $pack['att'];
$signPayFields = self::commissionSettlementSignPayFieldRawList();
$baseRows = $query->field(array_merge([
'o.id',
'o.order_no',
'o.diagnosis_id',
'o.create_time',
'o.amount',
Db::raw("({$att}) AS assistant_id"),
Db::raw('IFNULL(rx.creator_id, 0) AS doctor_id'),
], $signPayFields))->order('o.id', 'desc')->select()->toArray();
$mapped = [];
foreach ($baseRows as $r) {
$signTs = (int) ($r['sign_ts'] ?? 0);
$payTs = (int) ($r['pay_ts'] ?? 0);
$eligible = $signTs > 0 && $payTs > 0 && $signTs <= $cutoffTs && $payTs <= $cutoffTs;
$b = $eligible ? 'current' : 'deferred';
if ($bucket === 'current' && $b !== 'current') {
continue;
}
if ($bucket === 'deferred' && $b !== 'deferred') {
continue;
}
$oid = (int) ($r['id'] ?? 0);
$aid = (int) ($r['assistant_id'] ?? 0);
$doctorId = (int) ($r['doctor_id'] ?? 0);
$foldRows = [['assistant_id' => $aid, 'cnt' => 1]];
$byDept = self::foldPerformanceRowsToDeptByTable($foldRows, $adminToPrimary, $tableRowDeptIds, $deptById, 'cnt');
$primaryDeptId = 0;
foreach ($byDept as $did => $_c) {
$primaryDeptId = (int) $did;
break;
}
$mapped[] = [
'id' => $oid,
'order_no' => (string) ($r['order_no'] ?? ''),
'diagnosis_id' => (int) ($r['diagnosis_id'] ?? 0),
'amount' => round((float) ($r['amount'] ?? 0), 2),
'create_time' => (int) ($r['create_time'] ?? 0),
'create_time_text' => !empty($r['create_time']) ? date('Y-m-d H:i:s', (int) $r['create_time']) : '',
'sign_ts' => $signTs,
'sign_time_text' => $signTs > 0 ? date('Y-m-d H:i:s', $signTs) : '',
'pay_ts' => $payTs,
'pay_time_text' => $payTs > 0 ? date('Y-m-d H:i:s', $payTs) : '',
'assistant_id' => $aid,
'doctor_id' => $doctorId,
'assistant_name' => '',
'doctor_name' => '',
'bucket' => $b,
'is_carry_in' => $oid > 0 && isset($carryFlip[$oid]) ? 1 : 0,
'primary_dept_id' => $primaryDeptId,
'primary_dept_name' => $primaryDeptId > 0 ? self::formatYejiDeptRowDisplayName($primaryDeptId, $deptById) : '',
];
}
$nameIds = [];
foreach ($mapped as $row) {
$na = (int) ($row['assistant_id'] ?? 0);
if ($na > 0) {
$nameIds[$na] = true;
}
$nd = (int) ($row['doctor_id'] ?? 0);
if ($nd > 0) {
$nameIds[$nd] = true;
}
}
$adminNames = self::commissionSettlementBatchAdminNames(array_map('intval', array_keys($nameIds)));
foreach ($mapped as &$row) {
$na = (int) ($row['assistant_id'] ?? 0);
$nd = (int) ($row['doctor_id'] ?? 0);
$row['assistant_name'] = $na > 0 ? (string) ($adminNames[$na] ?? ('#' . $na)) : '—';
$row['doctor_name'] = $nd > 0 ? (string) ($adminNames[$nd] ?? ('#' . $nd)) : '未关联开方人';
}
unset($row);
$total = count($mapped);
$slice = array_slice($mapped, ($page - 1) * $pageSize, $pageSize);
return [
'list' => $slice,
'count' => $total,
'page' => $page,
'page_size' => $pageSize,
];
}
/**
* 当前筛选条件下的核对 / 确定状态。
*
* @param array{settlement_month?: string, dept_ids?: int[]|string, channel_code?: string} $params
*
* @return array<string, mixed>
*/
public static function commissionSettlementConfirmStatus(array $params, int $viewerAdminId = 0, array $viewerAdminInfo = []): array
{
$pack = self::commissionSettlementResolveBasePack($params, $viewerAdminId, $viewerAdminInfo);
$row = self::commissionSettlementGetConfirmRow($pack['monthRaw'], $pack['scopeChannelCode'], $pack['deptKey']);
return [
'settlement_month' => $pack['monthRaw'],
'scope_channel_code' => $pack['scopeChannelCode'],
'scope_dept_ids_key' => $pack['deptKey'],
'confirm' => $row,
];
}
/**
* 保存核对备注(未确定前可反复保存)。
*
* @param array{settlement_month?: string, dept_ids?: int[]|string, channel_code?: string, reconcile_note?: string} $params
*/
public static function commissionSettlementSaveReconcile(array $params, int $viewerAdminId, array $viewerAdminInfo): array
{
if ($viewerAdminId <= 0) {
throw new \think\Exception('未登录');
}
$pack = self::commissionSettlementResolveBasePack($params, $viewerAdminId, $viewerAdminInfo);
$note = mb_substr(trim((string) ($params['reconcile_note'] ?? '')), 0, 500);
$t = time();
$exists = Db::name('commission_settlement_confirm')
->where('settlement_month', $pack['monthRaw'])
->where('scope_channel_code', $pack['scopeChannelCode'])
->where('scope_dept_ids_key', $pack['deptKey'])
->find();
if ($exists) {
$ex = is_array($exists) ? $exists : $exists->toArray();
if ((int) ($ex['status'] ?? 0) === 1) {
throw new \think\Exception('已确定业绩的记录不可修改核对备注,如需更正请联系管理员处理数据');
}
Db::name('commission_settlement_confirm')->where('id', (int) $ex['id'])->update([
'reconcile_note' => $note,
'update_time' => $t,
]);
} else {
Db::name('commission_settlement_confirm')->insert([
'settlement_month' => $pack['monthRaw'],
'scope_channel_code' => $pack['scopeChannelCode'],
'scope_dept_ids_key' => $pack['deptKey'],
'status' => 0,
'reconcile_note' => $note,
'totals_json' => '',
'confirmed_admin_id' => 0,
'confirmed_admin_name' => '',
'confirmed_at' => 0,
'create_time' => $t,
'update_time' => $t,
]);
}
return ['ok' => true];
}
/**
* 确定本期业绩:写入快照,并将「顺延下期」订单结转至下一结算月同 scope。
*
* @param array{settlement_month?: string, dept_ids?: int[]|string, channel_code?: string, reconcile_note?: string} $params
*/
public static function commissionSettlementConfirmFinalize(array $params, int $viewerAdminId, array $viewerAdminInfo): array
{
if ($viewerAdminId <= 0) {
throw new \think\Exception('未登录');
}
$pack = self::commissionSettlementResolveBasePack($params, $viewerAdminId, $viewerAdminInfo);
$tableRowDeptIds = $pack['tableRowDeptIds'];
$adminToPrimary = $pack['adminToPrimary'];
if ($tableRowDeptIds === [] || $adminToPrimary === []) {
throw new \think\Exception('当前账号无可操作的展示部门,无法确定业绩');
}
$exists = Db::name('commission_settlement_confirm')
->where('settlement_month', $pack['monthRaw'])
->where('scope_channel_code', $pack['scopeChannelCode'])
->where('scope_dept_ids_key', $pack['deptKey'])
->find();
if ($exists) {
$ex = is_array($exists) ? $exists : $exists->toArray();
if ((int) ($ex['status'] ?? 0) === 1) {
throw new \think\Exception('该结算月在同渠道同部门筛选下已确定业绩,请勿重复提交');
}
}
$overview = self::commissionSettlementOverview($params, $viewerAdminId, $viewerAdminInfo);
$total = $overview['total'] ?? [];
$query = self::commissionSettlementBuildFilteredOrderQuery($pack);
$att = $pack['att'];
$signPayFields = self::commissionSettlementSignPayFieldRawList();
$cutoffTs = $pack['cutoffTs'];
$rowsRaw = $query->field(array_merge([
'o.id',
'o.create_time',
Db::raw("({$att}) AS assistant_id"),
], $signPayFields))->select()->toArray();
$deferredIds = [];
foreach ($rowsRaw as $r) {
$signTs = (int) ($r['sign_ts'] ?? 0);
$payTs = (int) ($r['pay_ts'] ?? 0);
$eligible = $signTs > 0 && $payTs > 0 && $signTs <= $cutoffTs && $payTs <= $cutoffTs;
if (!$eligible) {
$deferredIds[] = (int) ($r['id'] ?? 0);
}
}
$deferredIds = array_values(array_unique(array_filter($deferredIds, static fn (int $x): bool => $x > 0)));
$adminName = (string) (Db::name('admin')->where('id', $viewerAdminId)->whereNull('delete_time')->value('name') ?: '');
$note = mb_substr(trim((string) ($params['reconcile_note'] ?? '')), 0, 500);
$t = time();
$next = $pack['nextSettlementMonth'];
$totalsJson = json_encode([
'total' => $total,
'deferred_ids' => $deferredIds,
'next_carry_month' => $next,
], JSON_UNESCAPED_UNICODE);
Db::startTrans();
try {
Db::name('commission_settlement_carry')
->where('source_settlement_month', $pack['monthRaw'])
->where('scope_channel_code', $pack['scopeChannelCode'])
->where('scope_dept_ids_key', $pack['deptKey'])
->delete();
foreach ($deferredIds as $poId) {
$dup = Db::name('commission_settlement_carry')
->where('prescription_order_id', $poId)
->where('target_settlement_month', $next)
->where('scope_channel_code', $pack['scopeChannelCode'])
->where('scope_dept_ids_key', $pack['deptKey'])
->find();
if ($dup) {
continue;
}
Db::name('commission_settlement_carry')->insert([
'prescription_order_id' => $poId,
'target_settlement_month' => $next,
'source_settlement_month' => $pack['monthRaw'],
'scope_channel_code' => $pack['scopeChannelCode'],
'scope_dept_ids_key' => $pack['deptKey'],
'create_time' => $t,
]);
}
if ($exists) {
$ex = is_array($exists) ? $exists : $exists->toArray();
Db::name('commission_settlement_confirm')->where('id', (int) $ex['id'])->update([
'status' => 1,
'reconcile_note' => $note !== '' ? $note : (string) ($ex['reconcile_note'] ?? ''),
'totals_json' => (string) $totalsJson,
'confirmed_admin_id' => $viewerAdminId,
'confirmed_admin_name' => mb_substr($adminName, 0, 64),
'confirmed_at' => $t,
'update_time' => $t,
]);
} else {
Db::name('commission_settlement_confirm')->insert([
'settlement_month' => $pack['monthRaw'],
'scope_channel_code' => $pack['scopeChannelCode'],
'scope_dept_ids_key' => $pack['deptKey'],
'status' => 1,
'reconcile_note' => $note,
'totals_json' => (string) $totalsJson,
'confirmed_admin_id' => $viewerAdminId,
'confirmed_admin_name' => mb_substr($adminName, 0, 64),
'confirmed_at' => $t,
'create_time' => $t,
'update_time' => $t,
]);
}
Db::commit();
} catch (\Throwable $e) {
Db::rollback();
throw $e;
}
return [
'ok' => true,
'next_settlement_month' => $next,
'deferred_carry_count' => count($deferredIds),
];
}
}
@@ -0,0 +1,31 @@
-- 提成结算:核对记录 + 顺延结转(上期「确定业绩」时写入,下期统计自动并入订单池)
CREATE TABLE IF NOT EXISTS `zyt_commission_settlement_confirm` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`settlement_month` char(7) NOT NULL COMMENT '结算月 YYYY-MM',
`scope_channel_code` varchar(128) NOT NULL DEFAULT '' COMMENT '与查询渠道一致,空为全渠道',
`scope_dept_ids_key` varchar(255) NOT NULL DEFAULT '*' COMMENT '部门筛选键:* 或排序后的 id 逗号串',
`status` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0已保存核对 1已确定业绩',
`reconcile_note` varchar(500) NOT NULL DEFAULT '' COMMENT '核对备注',
`totals_json` text COMMENT '确定时汇总快照 JSON',
`confirmed_admin_id` int unsigned NOT NULL DEFAULT 0,
`confirmed_admin_name` varchar(64) NOT NULL DEFAULT '',
`confirmed_at` int unsigned NOT NULL DEFAULT 0 COMMENT '确定业绩时间戳',
`create_time` int unsigned NOT NULL DEFAULT 0,
`update_time` int unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_scope` (`settlement_month`,`scope_channel_code`(64),`scope_dept_ids_key`(128))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='提成结算核对/确定';
CREATE TABLE IF NOT EXISTS `zyt_commission_settlement_carry` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`prescription_order_id` int unsigned NOT NULL COMMENT '业务订单 tcm_prescription_order.id',
`target_settlement_month` char(7) NOT NULL COMMENT '计入哪个月结算池',
`source_settlement_month` char(7) NOT NULL COMMENT '从哪个月确定顺延出来',
`scope_channel_code` varchar(128) NOT NULL DEFAULT '',
`scope_dept_ids_key` varchar(255) NOT NULL DEFAULT '*',
`create_time` int unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_carry` (`prescription_order_id`,`target_settlement_month`,`scope_channel_code`(64),`scope_dept_ids_key`(64)),
KEY `idx_target_scope` (`target_settlement_month`,`scope_channel_code`(32),`scope_dept_ids_key`(64)),
KEY `idx_source_scope` (`source_settlement_month`,`scope_channel_code`(32),`scope_dept_ids_key`(64))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='提成顺延结转';
@@ -0,0 +1,101 @@
-- 提成结算业绩:独立页面 fans/commission-settlement + stats.commissionSettlement/* 接口权限
-- 与业绩看板 yeji 同父菜单(pid = 业绩看板菜单 id 293);幂等
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
y.pid,
'C',
'提成结算业绩',
'',
96,
'fans/commission-settlement',
'/fans/commission-settlement',
'fans/commission-settlement',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT pid FROM `zyt_system_menu` WHERE id = 293 LIMIT 1) AS y
WHERE EXISTS (SELECT 1 FROM `zyt_system_menu` WHERE id = 293)
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m WHERE m.component = 'fans/commission-settlement'
);
SET @commission_cs_pid := (
SELECT id FROM `zyt_system_menu` WHERE component = 'fans/commission-settlement' ORDER BY id DESC LIMIT 1
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-汇总',
'',
1,
'stats.commissionSettlement/overview',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/overview'
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-部门下拉',
'',
2,
'stats.commissionSettlement/deptOptions',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/deptOptions'
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-渠道下拉',
'',
3,
'stats.commissionSettlement/channelOptions',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/channelOptions'
);
@@ -0,0 +1,101 @@
-- 提成结算:核对/确定业绩接口权限(挂在 fans/commission-settlement 页面菜单下)
SET @commission_cs_pid := (
SELECT id FROM `zyt_system_menu` WHERE component = 'fans/commission-settlement' ORDER BY id DESC LIMIT 1
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-核对明细',
'',
11,
'stats.commissionSettlement/orderLines',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/orderLines'
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-确认状态',
'',
12,
'stats.commissionSettlement/confirmStatus',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/confirmStatus'
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-保存核对',
'',
13,
'stats.commissionSettlement/saveReconcile',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/saveReconcile'
);
INSERT INTO `zyt_system_menu`
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
SELECT
@commission_cs_pid,
'A',
'提成结算-确定业绩',
'',
14,
'stats.commissionSettlement/confirmFinalize',
'',
'',
'',
'',
1,
0,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP()
FROM (SELECT 1 AS `_`) AS `_exec`
WHERE @commission_cs_pid IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM `zyt_system_menu` m
WHERE m.pid = @commission_cs_pid AND m.perms = 'stats.commissionSettlement/confirmFinalize'
);