This commit is contained in:
Your Name
2026-05-12 17:26:11 +08:00
parent c644f2554f
commit 796ca12fb8
10 changed files with 172 additions and 68 deletions
@@ -77,6 +77,23 @@ class CustomerLists extends BaseAdminDataLists implements ListsSearchInterface
}
}
// 添加时间:与 lists 排序口径一致(external_first_add_time 优先,0 则 create_time
$addStart = trim((string) ($this->params['add_time_start'] ?? ''));
$addEnd = trim((string) ($this->params['add_time_end'] ?? ''));
$effExpr = 'COALESCE(NULLIF(external_first_add_time, 0), create_time)';
if ($addStart !== '') {
$t = strtotime($addStart . ' 00:00:00');
if ($t !== false) {
$query->whereRaw($effExpr . ' > 0 AND ' . $effExpr . ' >= ?', [$t]);
}
}
if ($addEnd !== '') {
$t = strtotime($addEnd . ' 23:59:59');
if ($t !== false) {
$query->whereRaw($effExpr . ' > 0 AND ' . $effExpr . ' <= ?', [$t]);
}
}
return $query;
}
@@ -107,7 +107,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$this->applyCreatorOrOwnPrescriptionVisibility($query);
$this->applyDataScopeForPrescriptionOrder($query);
}
// 业绩看板侧栏等:不展示履约已取消(4),与 stats 业绩统计口径一致
// 业绩看板侧栏等:不展示履约 4/9/10,与 stats 业绩口径一致
if ((int) ($this->params['exclude_fulfillment_cancelled'] ?? 0) === 1) {
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($query, '');
}
@@ -378,7 +378,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$this->applyDataScopeForPrescriptionOrder($query);
}
}
// 与看板「合计业绩」一致:NULL 安全剔除履约已取消(4),勿用 `<>` 以免误丢 NULL 状态行
// 与看板「合计业绩」一致:NULL 安全剔除履约 4/9/10
if ((int) ($this->params['exclude_fulfillment_cancelled'] ?? 0) === 1) {
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($query, '');
}
@@ -570,13 +570,13 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
'stats_order_amount' => $s['order_amount'],
'stats_order_amount_not_cancelled' => $s['order_amount_not_cancelled'],
'stats_order_amount_cancelled' => $s['order_amount_cancelled'],
/** 业绩:业务订单金额,剔除履约已取消(fulfillment_status=4),其余状态全部计入 */
'stats_order_amount_performance' => $s['order_amount_not_cancelled'],
/** 业绩:业务订单金额,剔除履约已取消/拒收/退款(4/9/10)NULL 与其它状态计入 */
'stats_order_amount_performance' => $s['order_amount_performance'] ?? $s['order_amount_not_cancelled'],
'stats_linked_pay_amount' => $s['linked_pay_amount'],
'stats_linked_pay_amount_not_cancelled' => $s['linked_pay_amount_not_cancelled'],
'stats_linked_pay_amount_cancelled' => $s['linked_pay_amount_cancelled'],
/** 业绩-关联实付:剔除履约已取消订单的关联支付金额 */
'stats_linked_pay_amount_performance' => $s['linked_pay_amount_not_cancelled'],
/** 业绩-关联实付:剔除履约 4/9/10 订单的关联支付金额 */
'stats_linked_pay_amount_performance' => $s['linked_pay_amount_performance'] ?? $s['linked_pay_amount_not_cancelled'],
'stats_time_start' => $s['label_start'],
'stats_time_end' => $s['label_end'],
/** 统计口径:all=支付审核白名单全量;assistant=医助仅诊单协助业绩;restricted=与列表同域 */
@@ -693,7 +693,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$t1 = $tmp;
}
$q = $this->buildBaseQueryForStats(false)->whereBetween('create_time', [$t0, $t1]);
// 全量「合计业绩」与看板列同口径:始终剔除履约已取消(4),不依赖 exclude 参数
// 全量「合计业绩」与看板列同口径:始终剔除履约 4/9/10,不依赖 exclude 参数
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($q, '');
$amount = round((float) (clone $q)->sum('amount'), 2);
$count = (int) (clone $q)->count();
@@ -715,7 +715,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($pendingRxQuery, '');
return [
// 处方审核待处理(不含履约已取消
// 处方审核待处理(不含履约 4/9/10
'pending_rx' => (int) $pendingRxQuery->where('prescription_audit_status', 0)->count(),
// 支付审核待处理(前提:处方已通过)
'pending_pay' => (int) (clone $query)->where('prescription_audit_status', 1)->where('payment_slip_audit_status', 0)->count(),
@@ -761,8 +761,8 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
}
$q = $this->buildBaseQueryForStats()->whereBetween('create_time', [$t0, $t1]);
$orderTotal = round((float) (clone $q)->sum('amount'), 2);
$orderCancelled = round((float) (clone $q)->where('fulfillment_status', 4)->sum('amount'), 2);
$orderTotal = round((float) (clone $q)->sum('amount'), 2);
$orderCancelled = round((float) (clone $q)->where('fulfillment_status', 4)->sum('amount'), 2);
$orderNotCancelled = round($orderTotal - $orderCancelled, 2);
$idsAll = (clone $q)->column('id');
@@ -770,7 +770,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
return $id > 0;
}));
if ($idsAll === []) {
return $this->statsExtendPayload(
$empty = $this->statsExtendPayload(
$orderTotal,
$orderNotCancelled,
$orderCancelled,
@@ -780,6 +780,12 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$l0,
$l1
);
$qPerfEmpty = clone $q;
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($qPerfEmpty, '');
$empty['order_amount_performance'] = round((float) $qPerfEmpty->sum('amount'), 2);
$empty['linked_pay_amount_performance'] = 0.0;
return $empty;
}
$idsCancel = (clone $q)->where('fulfillment_status', 4)->column('id');
$idsCancel = array_values(array_filter(array_map('intval', $idsCancel), static function (int $id): bool {
@@ -791,7 +797,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$linkedNotCancelled = $this->sumLinkedPayForPrescriptionOrderIds($idsNotCancelled);
$linkedCancelled = $this->sumLinkedPayForPrescriptionOrderIds($idsCancel);
return $this->statsExtendPayload(
$base = $this->statsExtendPayload(
$orderTotal,
$orderNotCancelled,
$orderCancelled,
@@ -801,6 +807,21 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$l0,
$l1
);
$qPerf = clone $q;
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($qPerf, '');
$base['order_amount_performance'] = round((float) $qPerf->sum('amount'), 2);
$idsExcludedPerf = (clone $q)
->whereIn('fulfillment_status', YejiStatsLogic::PRESCRIPTION_ORDER_FULFILLMENT_EXCLUDED_FROM_PERFORMANCE)
->column('id');
$idsExcludedPerf = array_values(array_filter(array_map('intval', $idsExcludedPerf), static function (int $id): bool {
return $id > 0;
}));
$idsPerf = array_values(array_diff($idsAll, $idsExcludedPerf));
$base['linked_pay_amount_performance'] = $this->sumLinkedPayForPrescriptionOrderIds($idsPerf);
return $base;
}
/**
@@ -808,7 +829,11 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
*/
private function statsZeroPayload(): array
{
return $this->statsExtendPayload(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, '', '');
$z = $this->statsExtendPayload(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, '', '');
$z['order_amount_performance'] = 0.0;
$z['linked_pay_amount_performance'] = 0.0;
return $z;
}
/**
+3 -2
View File
@@ -14,6 +14,7 @@
namespace app\adminapi\logic\dept;
use app\adminapi\logic\stats\YejiStatsLogic;
use app\common\logic\BaseLogic;
use app\common\model\auth\Admin;
use app\common\model\auth\AdminDept;
@@ -212,8 +213,8 @@ class DeptLogic extends BaseLogic
->join('tcm_diagnosis dg', 'dg.id = o.diagnosis_id AND dg.delete_time IS NULL', 'INNER')
->whereNull('o.delete_time')
->where('o.diagnosis_id', '>', 0)
->where('dg.assistant_id', '>', 0)
->whereRaw('NOT (o.fulfillment_status <=> ?)', [4]);
->where('dg.assistant_id', '>', 0);
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($q, 'o');
if ($orderStartTs !== null && $orderEndTs !== null) {
$q->where('o.create_time', 'between', [$orderStartTs, $orderEndTs]);
}
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace app\adminapi\logic\stats;
use app\adminapi\logic\dept\DeptLogic;
use app\adminapi\logic\stats\YejiStatsLogic;
use app\adminapi\logic\tcm\DiagnosisLogic;
use app\common\model\finance\AccountCost;
use app\common\service\DataScope\DataScopeService;
@@ -1041,8 +1042,9 @@ class ConversionLogic
->alias('po')
->leftJoin('tcm_diagnosis dg', 'dg.id = po.diagnosis_id')
->whereNull('po.delete_time')
->where('po.create_time', 'between', [$startTimestamp, $endTimestamp])
->where('po.fulfillment_status', '<>', 4)
->where('po.create_time', 'between', [$startTimestamp, $endTimestamp]);
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($businessQuery, 'po');
$businessQuery
->fieldRaw("{$businessSourceExpr} AS source_admin_id, SUM(po.amount) AS total_amount")
->group($businessSourceExpr);
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace app\adminapi\logic\stats;
use app\adminapi\logic\stats\YejiStatsLogic;
use app\common\model\auth\Admin;
use app\common\service\DataScope\DataScopeService;
use think\facade\Db;
@@ -14,7 +15,7 @@ use think\facade\Db;
* 医生范围:<b>admin_role.role_id = 1</b> 且管理员 <b>未软删</b>delete_time 为空);再按账号「数据范围」收窄。
*
* - 系统/手动开方:tcm_prescription.prescription_date ∈ [start,end];渠道/标签与业绩渠道列同源 EXISTS / 诊单标签
* - 成交:订单 create_time、排除履约(4),按处方 creator_id;渠道/标签同 sumPerformance 口径
* - 成交:订单 create_time、排除履约 4/9/10,按处方 creator_id;渠道/标签同 sumPerformance 口径
* - 挂号:appointment_date ∈ [start,end];选渠道时挂号 channels 命中字典值;标签渠道时 patient_id ∈ 标签诊单集
*/
class DoctorDailyStatsLogic
@@ -300,9 +301,9 @@ class DoctorDailyStatsLogic
->alias('o')
->join('tcm_prescription rx', 'rx.id = o.prescription_id AND rx.delete_time IS NULL', 'INNER')
->whereNull('o.delete_time')
->whereBetween('o.create_time', [$startTs, $endTs])
->whereRaw('NOT (o.fulfillment_status <=> 4)')
->whereIn('rx.creator_id', $doctorIds)
->whereBetween('o.create_time', [$startTs, $endTs]);
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($q, 'o');
$q->whereIn('rx.creator_id', $doctorIds)
->where('o.diagnosis_id', '>', 0);
$normCh = self::normalizeAppointmentChannelInts($appointmentChannelValues);
@@ -22,15 +22,15 @@ use think\facade\Db;
* · **二中心及其组织下级在选定渠道下计 0**(与进线一致)
* - 复诊统计 = 仅**名称含「二中心」的部门及其组织架构下级**:区间内业务单按患者 create_time 排序,第 1 笔不计,第 2 笔起分列「复诊2」「复诊3」…;口径同业绩单条件;按**订单创建人**所在部门在组织树内 rollup(含下级),与排行榜复诊一致
* - 已完成挂号 = status=3 挂号条数(appointment_date),列「已完成挂号」;部门归属:有效医助→接诊医生→展示行映射。
* - 接诊诊单 = 列名对应**业务订单条数**(非取消、create_time 区间),按**订单创建人**人事部门落在该行子树即计入;多行命中时取**最深的展示部门行**。与处方列表按 assistant_dept_id 筛选不同(列表保留旧口径:诊单医助 ∪ 创建人)。
* - {渠道}成交单 = 选定渠道时与 {渠道}业绩同源:区间内 **非取消业务订单条数**剔除 fulfillment_status=4;NULL 与其它状态计入,按 create_time 归日);dict(channels) 与 tag 口径均按订单计(按订单创建人归属),非挂号条数。
* - 合计业绩 = 区间内业务订单 amount 求和(排除已取消(4) 与软删),**部门列**与「接诊诊单」一致:**订单创建人**人事部门落在该展示行子树则计入,多行命中取最深展示行;与排行榜诊金同口径。
* - 接诊诊单 = 列名对应**业务订单条数**(剔除履约 4/9/10、create_time 区间),按**订单创建人**人事部门落在该行子树即计入;多行命中时取**最深的展示部门行**。与处方列表按 assistant_dept_id 筛选不同(列表保留旧口径:诊单医助 ∪ 创建人)。
* - {渠道}成交单 = 选定渠道时与 {渠道}业绩同源:区间内 **计入业绩的业务订单条数**(剔除 fulfillment_status ∈ {4,9,10};NULL 与其它状态计入,按 create_time 归日);dict(channels) 与 tag 口径均按订单计(按订单创建人归属),非挂号条数。
* - 合计业绩 = 区间内业务订单 amount 求和(排除已取消/拒收/退款(4,9,10) 与软删),**部门列**与「接诊诊单」一致:**订单创建人**人事部门落在该展示行子树则计入,多行命中取最深展示行;与排行榜诊金同口径。
* 无法归入任一展示部门的金额单列「未归属中心」行;**底栏「合计业绩」「接诊诊单」= 当前表内各行业绩列相加**(含未归属行),与弹窗摊分口径一致。
* · 时间窗与 stats_order_amount_performance 一致;列表若另有患者筛选或账号数据域收窄,金额可能仍不同
* · 选定渠道时「{渠道}业绩」列仍按比例展示;合计列全量与渠道列含未归属补差;**二中心及其组织下级展示部门不参与该渠道进线/业绩/成交单/ROI 分子**(与同模块 DeptLogic::getErCenterSubtreeDeptIdSet 一致)
* - {渠道}业绩 = 与「处方订单列表」业绩同口径(≠4):按 **o.create_time** 落入区间,按**订单创建人**归部门;
* - {渠道}业绩 = 与「处方订单列表」业绩同口径(剔除 4/9/10:按 **o.create_time** 落入区间,按**订单创建人**归部门;
* 渠道判定仅用 EXISTS:"患者有任一已完成挂号 (status=3) 且 channels 命中字典",**不限挂号时点**;无字典映射时回退 tag/creator 口径
* - 成交单数 = 区间内非取消业务订单 **条数**;按**订单创建人**映射到「中心」;无法归属计入「未归属中心」;合计=全表 COUNT。
* - 成交单数 = 区间内计入业绩的业务订单 **条数**(剔除 4/9/10;按**订单创建人**映射到「中心」;无法归属计入「未归属中心」;合计=全表 COUNT。
* - 投放成本 = zyt_account_cost 在日期区间内 **amount** 合计(选定渠道时 `media_channel_code = channel_code` 过滤)。
* · **各部门行投放成本** = 总投放成本 × (该部门进线 ÷ 各展示部门进线合计)。相当于先算 **单进线成本** = 总成本 ÷ 总进线,再乘部门进线。
* · **二中心及其组织下级**不参与均摊投放成本(进线分摊分母对其计 0,与选定渠道下进线清零规则独立);其余部门按进线占比分摊。合计行成本 = 账务汇总总额。
@@ -53,6 +53,9 @@ use think\facade\Db;
*/
class YejiStatsLogic
{
/** 不计入业绩的履约状态:已取消(4)、拒收(9)、退款(10);NULL 与其它值仍计业绩 */
public const PRESCRIPTION_ORDER_FULFILLMENT_EXCLUDED_FROM_PERFORMANCE = [4, 9, 10];
/**
* overview / assistantLeaderboards 共用的筛选与时间上下文。
*
@@ -557,7 +560,7 @@ class YejiStatsLogic
. ($dataScopeRestricted
? ' 当前账号受数据范围限制时,底栏合计业绩与列表同域。'
: '');
$baseNoteNoChannel = '业绩口径:除履约已取消(4)外全部计入。部门行「合计业绩」「接诊诊单」「复诊」均按**订单创建人人事部门 ∈ 该展示行子树**归属(多行命中取最深展示行),与医助排行榜诊金一致;与处方订单列表 assistant_dept_id 默认筛选(诊单医助 ∪ 创建人)不同——侧栏点击会自动收窄为创建人口径。多表「本月」区间为当月1日至服务器当日。**投放成本**按进线占比分摊,**二中心子树展示部门进线在分摊中计 0**(与部门 ErCenter 子树一致)。';
$baseNoteNoChannel = '业绩口径:除履约已取消(4)、拒收(9)、退款(10),其余(含 NULL计入。部门行「合计业绩」「接诊诊单」「复诊」均按**订单创建人人事部门 ∈ 该展示行子树**归属(多行命中取最深展示行),与医助排行榜诊金一致;与处方订单列表 assistant_dept_id 默认筛选(诊单医助 ∪ 创建人)不同——侧栏点击会自动收窄为创建人口径。多表「本月」区间为当月1日至服务器当日。**投放成本**按进线占比分摊,**二中心子树展示部门进线在分摊中计 0**(与部门 ErCenter 子树一致)。';
return [
'start_date' => $startDate,
@@ -567,9 +570,9 @@ class YejiStatsLogic
'channel_name' => $channelInfo ? (string) $channelInfo['channel_name'] : '',
'channel_group' => $channelInfo ? (string) $channelInfo['source_group_name'] : '',
'channel_filter_note' => $channelCode !== ''
? ('{渠道}业绩:按订单 create_time 归日、剔除履约已取消(4)(NULL 与其它状态均计入);渠道判定用"该患者是否有挂号 channels 命中 dict + status=3"(不限挂号时点)。部门归属按**订单创建人**人事部门 ∈ 子树。'
. ' {渠道}成交单数:与{渠道}业绩同源,剔除已取消(4)的订单条数(非挂号条数),按订单创建人归部门。'
. ' 「已完成挂号」列同 admin 挂号已完成列表;「接诊诊单」列为业务订单条数(非取消),同样按订单创建人归部门。**二中心及其组织下级**(与部门模块 ErCenter 子树一致)**不计入**该渠道进线、业绩与成交单。**投放成本**按各部门进线条数占展示部门进线合计的比例分摊,**二中心子树进线在分摊中计 0**(未选渠道时仍显示进线数,仅不参与均摊)。ROI = 渠道业绩(不含二中心子树)÷ 总投放成本。进线按所选标签客户精确过滤。'
? ('{渠道}业绩:按订单 create_time 归日、剔除履约 4/9/10(NULL 与其它状态均计入);渠道判定用"该患者是否有挂号 channels 命中 dict + status=3"(不限挂号时点)。部门归属按**订单创建人**人事部门 ∈ 子树。'
. ' {渠道}成交单数:与{渠道}业绩同源,剔除 4/9/10 的订单条数(非挂号条数),按订单创建人归部门。'
. ' 「已完成挂号」列同 admin 挂号已完成列表;「接诊诊单」列为业务订单条数(同业绩剔除口径),同样按订单创建人归部门。**二中心及其组织下级**(与部门模块 ErCenter 子树一致)**不计入**该渠道进线、业绩与成交单。**投放成本**按各部门进线条数占展示部门进线合计的比例分摊,**二中心子树进线在分摊中计 0**(未选渠道时仍显示进线数,仅不参与均摊)。ROI = 渠道业绩(不含二中心子树)÷ 总投放成本。进线按所选标签客户精确过滤。'
. ($tagFallback
? ' ⚠ 当前业务尚未回填 tcm_diagnosis.external_userid 与 user_auth.unionid,已自动退化为「该标签客户的跟进医助 → 区间内接诊/业绩」口径,仅用于趋势观察。'
: '')
@@ -1799,7 +1802,7 @@ class YejiStatsLogic
/**
* 接诊诊单聚合:返回两组按部门归属的接诊计数。
* - all: 区间内 status=3 挂号条数按部门归属(与列表计数一致),不含「仅 role_id=2」等额外限制。
* - scoped: 选定渠道时「{渠道}成交单」= **非取消业务订单条数**(与 {渠道}业绩同源):dict 下 EXISTS 与侧栏一致(channels channel_source);有展示行时按列表部门摊行;否则走归因折叠。
* - scoped: 选定渠道时「{渠道}成交单」= **计入业绩的业务订单条数**(与 {渠道}业绩同源,剔除 4/9/10):dict 下 EXISTS 与侧栏一致(channels channel_source);有展示行时按列表部门摊行;否则走归因折叠。
* 未选渠道时 scoped == all(不再额外查一次)。
*
* @param int[] $appointmentChannelValues dict_data value 整型列表(通常 1=自媒体1)
@@ -2996,7 +2999,7 @@ class YejiStatsLogic
}
/**
* 与 sumPerformanceByAdmin 对应:按订单创建人统计成交单数(非取消业务订单条数),全量/渠道分支一致。
* 与 sumPerformanceByAdmin 对应:按订单创建人统计成交单数(剔除履约 4/9/10),全量/渠道分支一致。
*
* @param int[] $appointmentChannelValues
*
@@ -3296,18 +3299,19 @@ class YejiStatsLogic
}
/**
* 业绩/成交单统计:排除履约已取消 fulfillment_status = 4,其余(含 NULL 与任意其它状态)全部计入。
* 与看板「合计业绩」、处方列表业绩 extend 口径一致;勿用 `<> 4`,以免误排除 NULL
* 业绩/成交单统计:排除履约已取消/拒收/退款」(fulfillment_status 4、9、10)NULL 与其它状态计入。
* 与看板「合计业绩」、处方列表业绩 extend 口径一致。
*
* @param \think\db\BaseQuery|\think\Model $query Db::name / Model::where 等查询实例
* @param string $tableAlias 主表别名(如 Db 侧 `alias('o')` 传 `o`);无别名时传空字符串
*/
public static function applyPrescriptionOrderNotCancelledForPerformanceQuery($query, string $tableAlias = ''): void
{
$inList = implode(',', array_map(static fn (int $v): string => (string) $v, self::PRESCRIPTION_ORDER_FULFILLMENT_EXCLUDED_FROM_PERFORMANCE));
if ($tableAlias !== '') {
$query->whereRaw("NOT ({$tableAlias}.fulfillment_status <=> ?)", [4]);
$query->whereRaw("({$tableAlias}.fulfillment_status IS NULL OR {$tableAlias}.fulfillment_status NOT IN ({$inList}))");
} else {
$query->whereRaw('NOT (fulfillment_status <=> ?)', [4]);
$query->whereRaw("(fulfillment_status IS NULL OR fulfillment_status NOT IN ({$inList}))");
}
}
@@ -3609,7 +3613,7 @@ class YejiStatsLogic
/**
* 业绩聚合:返回两组按部门归属的业绩金额。
* 口径与 /tcm.prescriptionOrder/lists 的 stats_*_performance 完全一致:
* 业绩 = SUM(amount) WHERE NOT (fulfillment_status <=> 4) AND delete_time IS NULL
* 业绩 = SUM(amount) WHERE fulfillment_status 为 NULL 或 NOT IN (4,9,10),且 delete_time IS NULL
*
* - all: 部门全量业绩(不限渠道)。用于「合计业绩」列展示。
* - scoped: 「{渠道}业绩」:患者渠道 EXISTS 与侧栏/抽屉一致(channels channel_source);有展示行时部门列与「合计业绩」同为列表部门摊行。
@@ -3725,7 +3729,7 @@ class YejiStatsLogic
}
/**
* 渠道业绩:与「处方订单列表」业绩完全同口径 —— 按 o.create_time 归日、剔除已取消(4)(含 NULL);
* 渠道业绩:与「处方订单列表」业绩完全同口径 —— 按 o.create_time 归日、剔除履约 4/9/10(NULL 与其它状态计入);
* EXISTS 仅用于"该患者属于此渠道"的判定(有任一挂号 channels 命中 + status=3**不限挂号时点**);
* 部门归属按业绩归属表达式(订单创建人 o.creator_id)。
*/
@@ -3812,7 +3816,7 @@ class YejiStatsLogic
/**
* 单次业绩聚合:与 aggregatePerformanceAmountsByAdmin / aggregateDealOrderCount 同源 ——
* INNER 诊单,按业绩归属医助 SUM(amount) 后映射到展示「中心」。
* WHERE: delete_time IS NULL、NOT(fulfillment <=> 4)、create_time 区间、diagnosis_id>0、归属医助>0
* WHERE: delete_time IS NULL、fulfillment ∈ (NULL 除 4/9/10 外)、create_time 区间、diagnosis_id>0、归属医助>0
* 可选 tagdiagnosis_id IN、归属医助 IN。
*
* @return array<int, float>
@@ -3859,7 +3863,7 @@ class YejiStatsLogic
}
/**
* 全量成交单数:与 sumGlobalPerformanceAmount 同一 WHERE/COUNT非取消订单条数)。
* 全量成交单数:与 sumGlobalPerformanceAmount 同一 WHERE/COUNT剔除 4/9/10)。
*/
private static function countGlobalDealOrders(int $startTs, int $endTs): int
{
@@ -4516,7 +4520,7 @@ class YejiStatsLogic
'end_date' => (string) $c['endDate'],
'channel_code' => (string) $c['channelCode'],
'rows' => $rows,
'note' => '与看板「未归属中心」补差一致:按订单 create_time、剔除履约已取消(4);**订单创建人**人事部门无法映射到任一展示「中心」计入各行;其余(无诊单/创建人为空)汇总在首行。账号数据权限下仅列出可见医助。',
'note' => '与看板「未归属中心」补差一致:按订单 create_time、剔除履约 4/9/10;**订单创建人**人事部门无法映射到任一展示「中心」计入各行;其余(无诊单/创建人为空)汇总在首行。账号数据权限下仅列出可见医助。',
];
}