修复跨月差额筛选重复计算导致页面缓慢 #508
@ -160,6 +160,8 @@ class Pages extends Controller
|
||||
'订单实付按应付/已付核对',
|
||||
];
|
||||
|
||||
private const RECEIPT_CROSS_MONTH_REMARK = '差额=跨月收款(合并已对平)';
|
||||
|
||||
/** 业绩明细「异常标注」筛选项,取值与同步命令写入的标注一致。 */
|
||||
private const RECEIPT_REMARK_OPTIONS = [
|
||||
'账单无单号',
|
||||
@ -341,7 +343,7 @@ class Pages extends Controller
|
||||
$effective = 'COALESCE(difference, ' . self::receiptNetSql() . ')';
|
||||
// 同一交易单号在相邻月份的收入/优惠/冲减合并后与订单实付对平时,
|
||||
// 这是最能解释单月差额的原因,必须排在其它逐月规则之前。
|
||||
$rules['差额=跨月收款(合并已对平)'] = 'cross_month_balanced = 1';
|
||||
$rules[self::RECEIPT_CROSS_MONTH_REMARK] = 'cross_month_balanced = 1';
|
||||
$rules[$label . '未匹配'] = "match_status = '未匹配'";
|
||||
$rules[$label . '取数为0(种菜)'] = "match_status = '已匹配' AND planting_amount IS NOT NULL AND ABS(COALESCE($column, 0)) < 0.005";
|
||||
$rules[$label . '取数为0'] = "match_status = '已匹配' AND planting_amount IS NULL AND ABS(COALESCE($column, 0)) < 0.005";
|
||||
@ -658,7 +660,7 @@ class Pages extends Controller
|
||||
}
|
||||
|
||||
if ((int) ($row->cross_month_balanced ?? 0) === 1) {
|
||||
return '差额=跨月收款(合并已对平)';
|
||||
return self::RECEIPT_CROSS_MONTH_REMARK;
|
||||
}
|
||||
|
||||
if (($row->match_status ?? '') === '未匹配') {
|
||||
@ -1422,11 +1424,12 @@ class Pages extends Controller
|
||||
$platformFilter = $this->receiptOrderMatchFilterValues(request('platform'));
|
||||
$storeFilter = $this->receiptOrderMatchFilterValues(request('store_name'));
|
||||
[$statusFilter, $remarkFilter] = $this->receiptOrderMatchStatusFilters(request('match_status'), request('remark'));
|
||||
$crossMonthOnly = self::isReceiptCrossMonthOnlyFilter($remarkFilter);
|
||||
$unmatchedReasonFilter = $this->receiptOrderMatchFilterValues(request('unmatched_reason'));
|
||||
$differenceState = $this->receiptOrderMatchFilterValues(request('difference_state'));
|
||||
$orderNo = trim((string) request('online_order_no', ''));
|
||||
// 闭包里要用 $this->applyReceiptRemarkFilter()(差异原因备注按公式判定),所以不能声明为 static
|
||||
$applyFilters = function ($query) use ($platformFilter, $storeFilter, $orderNo, $statusFilter, $remarkFilter, $unmatchedReasonFilter, $differenceState): void {
|
||||
$applyFilters = function ($query) use ($platformFilter, $storeFilter, $orderNo, $statusFilter, $remarkFilter, $crossMonthOnly, $unmatchedReasonFilter, $differenceState): void {
|
||||
if ($platformFilter !== []) {
|
||||
$query->whereIn('platform', $platformFilter);
|
||||
}
|
||||
@ -1447,7 +1450,7 @@ class Pages extends Controller
|
||||
$this->applyReceiptUnmatchedReasonFilter($query, $unmatchedReasonFilter);
|
||||
}
|
||||
if ($differenceState !== []) {
|
||||
$this->applyReceiptDifferenceStateFilter($query, $differenceState);
|
||||
$this->applyReceiptDifferenceStateFilter($query, $differenceState, $crossMonthOnly);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1482,7 +1485,7 @@ class Pages extends Controller
|
||||
")->first();
|
||||
$total = (int) ($agg->total ?? 0);
|
||||
$differenceTotal = (float) ($agg->difference_base ?? 0);
|
||||
if ((int) ($agg->basis_fallback_rows ?? 0) > 0) {
|
||||
if (! $crossMonthOnly && (int) ($agg->basis_fallback_rows ?? 0) > 0) {
|
||||
$adjustmentQuery = $base();
|
||||
$applyFilters($adjustmentQuery);
|
||||
$adjustment = $adjustmentQuery
|
||||
@ -1638,7 +1641,9 @@ class Pages extends Controller
|
||||
}
|
||||
|
||||
$query = $this->receiptOrderMatchFilteredQuery($month);
|
||||
$total = $this->receiptOrderMatchMetricTotal($query, $metric);
|
||||
[, $remarkFilter] = $this->receiptOrderMatchStatusFilters(null, request('remark'));
|
||||
$crossMonthOnly = self::isReceiptCrossMonthOnlyFilter($remarkFilter);
|
||||
$total = $this->receiptOrderMatchMetricTotal($query, $metric, $crossMonthOnly);
|
||||
$connection = (string) config('upstream_mirrors.connection', 'business_mirror');
|
||||
$detailMetric = $definition['metric'];
|
||||
|
||||
@ -1781,6 +1786,7 @@ class Pages extends Controller
|
||||
request('match_status'),
|
||||
request('remark'),
|
||||
);
|
||||
$crossMonthOnly = self::isReceiptCrossMonthOnlyFilter($remarkFilter);
|
||||
$unmatchedReasonFilter = $this->receiptOrderMatchFilterValues(request('unmatched_reason'));
|
||||
$differenceState = $this->receiptOrderMatchFilterValues(request('difference_state'));
|
||||
$orderNo = trim((string) request('online_order_no', ''));
|
||||
@ -1809,13 +1815,13 @@ class Pages extends Controller
|
||||
$this->applyReceiptUnmatchedReasonFilter($query, $unmatchedReasonFilter);
|
||||
}
|
||||
if ($differenceState !== []) {
|
||||
$this->applyReceiptDifferenceStateFilter($query, $differenceState);
|
||||
$this->applyReceiptDifferenceStateFilter($query, $differenceState, $crossMonthOnly);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
private function receiptOrderMatchMetricTotal($query, string $metric): float
|
||||
private function receiptOrderMatchMetricTotal($query, string $metric, bool $crossMonthOnly = false): float
|
||||
{
|
||||
if ($metric !== 'difference') {
|
||||
return round((float) (clone $query)->sum($metric), 2);
|
||||
@ -1827,7 +1833,7 @@ class Pages extends Controller
|
||||
. "SUM(CASE WHEN remark IN ({$fallbackSql}) THEN 1 ELSE 0 END) as basis_fallback_rows"
|
||||
)->first();
|
||||
$total = (float) ($row->difference_base ?? 0);
|
||||
if ((int) ($row->basis_fallback_rows ?? 0) > 0) {
|
||||
if (! $crossMonthOnly && (int) ($row->basis_fallback_rows ?? 0) > 0) {
|
||||
$adjustment = (clone $query)
|
||||
->whereIn('remark', self::RECEIPT_BASIS_FALLBACK_REMARKS)
|
||||
->selectRaw('SUM(' . self::receiptFallbackDifferenceAdjustmentSql() . ') as adjustment')
|
||||
@ -1851,20 +1857,44 @@ class Pages extends Controller
|
||||
}
|
||||
|
||||
$labels = self::receiptDifferenceRemarkLabels();
|
||||
$crossMonthSelected = in_array(self::RECEIPT_CROSS_MONTH_REMARK, $remarkFilter, true);
|
||||
$indexes = [];
|
||||
foreach ($remarkFilter as $label) {
|
||||
if ($label === self::RECEIPT_CROSS_MONTH_REMARK) {
|
||||
continue;
|
||||
}
|
||||
$index = array_search($label, $labels, true);
|
||||
if ($index !== false) {
|
||||
$indexes[] = (int) $index + 1;
|
||||
}
|
||||
}
|
||||
if ($indexes === []) {
|
||||
if (! $crossMonthSelected && $indexes === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query->whereRaw(
|
||||
self::receiptDifferenceRemarkIndexSql() . ' IN (' . implode(', ', array_unique($indexes)) . ')'
|
||||
);
|
||||
if ($crossMonthSelected && $indexes === []) {
|
||||
$query->where('cross_month_balanced', 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$query->where(function ($group) use ($crossMonthSelected, $indexes): void {
|
||||
if ($crossMonthSelected) {
|
||||
$group->where('cross_month_balanced', 1);
|
||||
}
|
||||
if ($indexes !== []) {
|
||||
$condition = self::receiptDifferenceRemarkIndexSql()
|
||||
. ' IN (' . implode(', ', array_unique($indexes)) . ')';
|
||||
$crossMonthSelected ? $group->orWhereRaw($condition) : $group->whereRaw($condition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** @param list<string> $remarkFilter */
|
||||
private static function isReceiptCrossMonthOnlyFilter(array $remarkFilter): bool
|
||||
{
|
||||
return count($remarkFilter) === 1
|
||||
&& $remarkFilter[0] === self::RECEIPT_CROSS_MONTH_REMARK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1900,7 +1930,7 @@ class Pages extends Controller
|
||||
* @param \Illuminate\Database\Query\Builder $query
|
||||
* @param string|list<string> $state
|
||||
*/
|
||||
private function applyReceiptDifferenceStateFilter($query, $state): void
|
||||
private function applyReceiptDifferenceStateFilter($query, $state, bool $crossMonthOnly = false): void
|
||||
{
|
||||
$states = is_array($state) ? $state : [$state];
|
||||
$has = in_array('有差额', $states, true);
|
||||
@ -1908,7 +1938,11 @@ class Pages extends Controller
|
||||
if ($has === $none) {
|
||||
return;
|
||||
}
|
||||
$effective = self::receiptEffectiveDifferenceSql();
|
||||
// 已限定跨月第一优先级时,跨月行不会再落入口径兜底归零,
|
||||
// “有/无差额”可直接使用默认差额,避免整串原因 CASE 重复执行。
|
||||
$effective = $crossMonthOnly
|
||||
? self::receiptDefaultDifferenceSql()
|
||||
: self::receiptEffectiveDifferenceSql();
|
||||
$query->whereRaw($has ? 'ABS(' . $effective . ') > 0.005' : 'ABS(' . $effective . ') <= 0.005');
|
||||
}
|
||||
|
||||
@ -1921,6 +1955,9 @@ class Pages extends Controller
|
||||
*/
|
||||
private function receiptDifferenceStateFacet(string $month, array $filters, string $orderNo): array
|
||||
{
|
||||
$crossMonthOnly = self::isReceiptCrossMonthOnlyFilter(
|
||||
array_values((array) ($filters['remark'] ?? []))
|
||||
);
|
||||
$query = DB::connection((string) config('upstream_mirrors.connection', 'business_mirror'))
|
||||
->table('store_receipt_order_match_rows')
|
||||
->where('report_month', $month)
|
||||
@ -1944,7 +1981,9 @@ class Pages extends Controller
|
||||
$query->where('online_order_no', 'like', '%' . addcslashes($orderNo, '%_\\') . '%');
|
||||
}
|
||||
|
||||
$effective = self::receiptEffectiveDifferenceSql();
|
||||
$effective = $crossMonthOnly
|
||||
? self::receiptDefaultDifferenceSql()
|
||||
: self::receiptEffectiveDifferenceSql();
|
||||
$row = $query->selectRaw('SUM(CASE WHEN ABS(' . $effective . ') > 0.005 THEN 1 ELSE 0 END) as has_diff, '
|
||||
. 'SUM(CASE WHEN ABS(' . $effective . ') <= 0.005 THEN 1 ELSE 0 END) as none_diff')->first();
|
||||
|
||||
@ -2253,6 +2292,9 @@ class Pages extends Controller
|
||||
*/
|
||||
private function receiptOrderMatchFacet(string $month, string $column, array $filters, string $orderNo, array $order = []): array
|
||||
{
|
||||
$crossMonthOnly = self::isReceiptCrossMonthOnlyFilter(
|
||||
array_values((array) ($filters['remark'] ?? []))
|
||||
);
|
||||
$query = DB::connection((string) config('upstream_mirrors.connection', 'business_mirror'))
|
||||
->table('store_receipt_order_match_rows')
|
||||
->where('report_month', $month);
|
||||
@ -2273,7 +2315,7 @@ class Pages extends Controller
|
||||
}
|
||||
// 差额(有/无):按页面差额口径过滤
|
||||
if ($key === 'difference_state') {
|
||||
$this->applyReceiptDifferenceStateFilter($query, (array) $values);
|
||||
$this->applyReceiptDifferenceStateFilter($query, (array) $values, $crossMonthOnly);
|
||||
continue;
|
||||
}
|
||||
$query->whereIn($key, $values);
|
||||
@ -2437,6 +2479,7 @@ class Pages extends Controller
|
||||
}
|
||||
$statusFilter = $this->receiptOrderMatchFilterValues($request->query('match_status'));
|
||||
[$statusValues, $remarkValues] = $this->receiptOrderMatchStatusFilters($statusFilter, $request->query('remark'));
|
||||
$crossMonthOnly = self::isReceiptCrossMonthOnlyFilter($remarkValues);
|
||||
if ($statusValues !== []) {
|
||||
$query->whereIn('match_status', $statusValues);
|
||||
}
|
||||
@ -2449,7 +2492,7 @@ class Pages extends Controller
|
||||
}
|
||||
$differenceState = $this->receiptOrderMatchFilterValues($request->query('difference_state'));
|
||||
if ($differenceState !== []) {
|
||||
$this->applyReceiptDifferenceStateFilter($query, $differenceState);
|
||||
$this->applyReceiptDifferenceStateFilter($query, $differenceState, $crossMonthOnly);
|
||||
}
|
||||
|
||||
// 「订单实付含已退款部分」「订单实付未减联合营销费」判定所需证据列(与页面同一口径;仅对应平台负差额行会真正计算子查询)。
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace Tests\Unit\EcommerceFinance;
|
||||
|
||||
use App\Http\Controllers\Business\Pages;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use ReflectionMethod;
|
||||
use Tests\TestCase;
|
||||
|
||||
@ -74,6 +75,25 @@ class PerformanceDifferenceRemarkTest extends TestCase
|
||||
]));
|
||||
}
|
||||
|
||||
public function test_cross_month_filters_use_direct_columns_without_recomputing_reason_case(): void
|
||||
{
|
||||
$controller = app(Pages::class);
|
||||
$query = DB::connection('business_mirror')->table('store_receipt_order_match_rows');
|
||||
|
||||
$remarkFilter = new ReflectionMethod(Pages::class, 'applyReceiptRemarkFilter');
|
||||
$remarkFilter->setAccessible(true);
|
||||
$remarkFilter->invoke($controller, $query, ['差额=跨月收款(合并已对平)']);
|
||||
|
||||
$this->assertStringContainsString('cross_month_balanced', $query->toSql());
|
||||
$this->assertStringNotContainsString('CASE WHEN', $query->toSql());
|
||||
|
||||
$differenceFilter = new ReflectionMethod(Pages::class, 'applyReceiptDifferenceStateFilter');
|
||||
$differenceFilter->setAccessible(true);
|
||||
$differenceFilter->invoke($controller, $query, ['有差额'], true);
|
||||
|
||||
$this->assertStringNotContainsString('CASE WHEN', $query->toSql());
|
||||
}
|
||||
|
||||
public function test_pinduoduo_partial_refund_marks_platform_payment_discount(): void
|
||||
{
|
||||
$this->assertSame('差额=平台支付立减', $this->remark([
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user