修正业绩明细订单核对金额展示 #520
@ -115,7 +115,7 @@ class Pages extends Controller
|
||||
/** 业绩明细可点击指标 → 主表金额列、账单项目明细桶、页面名称。 */
|
||||
private const RECEIPT_METRIC_MAP = [
|
||||
'income_amount' => ['label' => '账单收入', 'metric' => 'income'],
|
||||
'paid_amount' => ['label' => '订单实付', 'metric' => null],
|
||||
'paid_amount' => ['label' => '订单核对金额', 'metric' => null],
|
||||
'discount_amount' => ['label' => '优惠收入', 'metric' => 'discount'],
|
||||
'offset_amount' => ['label' => '冲减收入', 'metric' => 'offset'],
|
||||
'default_compensation_amount' => ['label' => '违约赔付', 'metric' => 'default_compensation'],
|
||||
@ -324,6 +324,35 @@ class Pages extends Controller
|
||||
return "COALESCE(remark, '') NOT IN ('订单实付按卖家实收核对', '订单实付按应付/已付核对')";
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面展示的订单核对金额。
|
||||
*
|
||||
* 命中卖家实收/应付口径时,原 buyer_paid_amount 可能远大于本次账单核对值;
|
||||
* 页面改为展示实际参与比对的金额,避免“收入 10、订单实付 13,079.80、差额 0”的视觉冲突。
|
||||
*/
|
||||
private static function receiptComparablePaidSql(): string
|
||||
{
|
||||
return "CASE WHEN COALESCE(remark, '') IN (" . self::receiptBasisFallbackSqlList() . ')'
|
||||
. ' THEN (' . self::receiptNetSql() . ')'
|
||||
. ' ELSE COALESCE(paid_amount, 0) END';
|
||||
}
|
||||
|
||||
private static function receiptComparablePaidAmount(object $row): float
|
||||
{
|
||||
$remark = trim((string) ($row->remark ?? ''));
|
||||
if (! in_array($remark, self::RECEIPT_BASIS_FALLBACK_REMARKS, true)) {
|
||||
return round((float) ($row->paid_amount ?? 0), 2);
|
||||
}
|
||||
|
||||
return round(
|
||||
(float) ($row->income_amount ?? 0)
|
||||
+ (float) ($row->discount_amount ?? 0)
|
||||
+ (float) ($row->offset_amount ?? 0)
|
||||
+ (float) ($row->default_compensation_amount ?? 0),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 「差额异常备注」基础原因(不落库),按页面优先级排列。
|
||||
*
|
||||
@ -1510,7 +1539,7 @@ class Pages extends Controller
|
||||
SUM(default_compensation_amount) as default_compensation_total,
|
||||
SUM(refund_amount) as refund_total,
|
||||
SUM(planting_amount) as planting_total,
|
||||
SUM(paid_amount) as paid_total,
|
||||
SUM(" . self::receiptComparablePaidSql() . ") as paid_total,
|
||||
SUM({$differenceBaseExpr}) as difference_base,
|
||||
SUM(CASE WHEN remark IN ({$fallbackSql}) THEN 1 ELSE 0 END) as basis_fallback_rows,
|
||||
SUM(CASE WHEN payment_count > 1 THEN 1 ELSE 0 END) as multi_pay,
|
||||
@ -1615,6 +1644,7 @@ class Pages extends Controller
|
||||
// 未匹配行(差额为空)按比对基准金额=0 计入差额。
|
||||
$items = $items->map(static function (object $row): object {
|
||||
$rawRemark = trim((string) ($row->remark ?? ''));
|
||||
$comparablePaid = self::receiptComparablePaidAmount($row);
|
||||
// 未匹配原因列:未匹配行照旧;「订单实付按卖家实收核对」这类口径标识在已匹配行同样展示。
|
||||
$row->unmatched_reason = $rawRemark === ''
|
||||
? null
|
||||
@ -1637,6 +1667,7 @@ class Pages extends Controller
|
||||
&& in_array($rawRemark, ['订单实付按卖家实收核对', '订单实付按应付/已付核对'], true)) {
|
||||
$row->difference = 0.0;
|
||||
}
|
||||
$row->paid_amount = $comparablePaid;
|
||||
|
||||
return $row;
|
||||
});
|
||||
@ -1767,7 +1798,9 @@ class Pages extends Controller
|
||||
})
|
||||
->values();
|
||||
} else {
|
||||
$amountSql = 'COALESCE(' . $metric . ', 0)';
|
||||
$amountSql = $metric === 'paid_amount'
|
||||
? self::receiptComparablePaidSql()
|
||||
: 'COALESCE(' . $metric . ', 0)';
|
||||
$rows = (clone $query)
|
||||
->select(['platform', 'store_name'])
|
||||
->selectRaw('SUM(' . $amountSql . ') as amount')
|
||||
@ -1859,6 +1892,14 @@ class Pages extends Controller
|
||||
private function receiptOrderMatchMetricTotal($query, string $metric, bool $crossMonthOnly = false): float
|
||||
{
|
||||
if ($metric !== 'difference') {
|
||||
if ($metric === 'paid_amount') {
|
||||
$total = (clone $query)
|
||||
->selectRaw('SUM(' . self::receiptComparablePaidSql() . ') as aggregate')
|
||||
->value('aggregate');
|
||||
|
||||
return round((float) $total, 2);
|
||||
}
|
||||
|
||||
return round((float) (clone $query)->sum($metric), 2);
|
||||
}
|
||||
|
||||
@ -2488,7 +2529,7 @@ class Pages extends Controller
|
||||
'default_compensation_amount' => ['default_compensation_amount', '违约赔付(冲减收入)', 'money'],
|
||||
'refund_amount' => ['refund_amount', '退款金额', 'money'],
|
||||
'planting_amount' => ['planting_amount', '种菜金额', 'money'],
|
||||
'paid_amount' => ['paid_amount', '订单实付金额', 'money'],
|
||||
'paid_amount' => ['paid_amount', '订单核对金额', 'money'],
|
||||
'difference' => ['difference', '差额', 'money'],
|
||||
'match_status' => ['match_status', '匹配状态', 'text'],
|
||||
'remark' => ['remark', '差额异常备注', 'text'],
|
||||
@ -2577,6 +2618,9 @@ class Pages extends Controller
|
||||
foreach ($selected as $key) {
|
||||
$format = $map[$key][2];
|
||||
$value = $row->{$map[$key][0]} ?? '';
|
||||
if ($key === 'paid_amount') {
|
||||
$value = self::receiptComparablePaidAmount($row);
|
||||
}
|
||||
// 「差额异常备注」列与页面一致:只写差额产生的原因
|
||||
if ($key === 'remark') {
|
||||
$value = self::receiptDifferenceRemark($row) ?? '';
|
||||
@ -2592,6 +2636,11 @@ class Pages extends Controller
|
||||
2
|
||||
);
|
||||
}
|
||||
$rawRemark = trim((string) ($row->remark ?? ''));
|
||||
if ($key === 'difference'
|
||||
&& in_array($rawRemark, self::RECEIPT_BASIS_FALLBACK_REMARKS, true)) {
|
||||
$value = 0;
|
||||
}
|
||||
if ($format === 'money') {
|
||||
// 金额列空值导出成 0.00:Excel 里直接求和、做差额核对不用再补空。
|
||||
$line[] = number_format((float) ($value === null || $value === '' ? 0 : $value), 2, '.', '');
|
||||
|
||||
@ -835,7 +835,7 @@ $navigation = [
|
||||
['name' => 'default_compensation_amount', 'label' => '违约赔付(冲减收入)', 'kind' => 'number'],
|
||||
['name' => 'refund_amount', 'label' => '退款金额', 'kind' => 'number'],
|
||||
['name' => 'planting_amount', 'label' => '种菜金额', 'kind' => 'number'],
|
||||
['name' => 'paid_amount', 'label' => '订单实付/实收金额', 'kind' => 'number'],
|
||||
['name' => 'paid_amount', 'label' => '订单核对金额', 'kind' => 'number'],
|
||||
['name' => 'difference', 'label' => '差额', 'kind' => 'number'],
|
||||
['name' => 'remark', 'label' => '差额异常备注'],
|
||||
['name' => 'match_status', 'label' => '匹配状态'],
|
||||
|
||||
@ -1454,7 +1454,7 @@
|
||||
@php
|
||||
$receiptMetricCards = [
|
||||
['metric' => 'income_amount', 'label' => '账单收入', 'value' => $receiptStats['income_total']],
|
||||
['metric' => 'paid_amount', 'label' => '订单实付', 'value' => $receiptStats['paid_total'] ?? 0],
|
||||
['metric' => 'paid_amount', 'label' => '订单核对金额', 'value' => $receiptStats['paid_total'] ?? 0],
|
||||
['metric' => 'discount_amount', 'label' => '优惠收入', 'value' => $receiptStats['discount_total'] ?? 0],
|
||||
['metric' => 'offset_amount', 'label' => '冲减收入', 'value' => $receiptStats['offset_total'] ?? 0],
|
||||
['metric' => 'default_compensation_amount', 'label' => '违约赔付', 'value' => $receiptStats['default_compensation_total'] ?? 0],
|
||||
@ -1607,6 +1607,7 @@
|
||||
<h3>金额关系</h3>
|
||||
<ul>
|
||||
<li>差额 = 收入 + 优惠收入 + 冲减收入 + 违约赔付 − 订单实付。</li>
|
||||
<li>命中“订单实付按卖家实收核对”或“订单实付按应付/已付核对”时,订单核对金额展示实际参与比对的金额。</li>
|
||||
<li>退款金额、种菜金额单独展示,不参与差额计算。</li>
|
||||
<li>点击指标卡后,账单类指标按平台、店铺、账单名称汇总;明细合计应与指标总额一致。</li>
|
||||
</ul>
|
||||
|
||||
@ -117,6 +117,54 @@ class PerformanceDetailsMetricDetailsTest extends FeatureTestCase
|
||||
], $response->json('rows'));
|
||||
}
|
||||
|
||||
public function test_paid_metric_uses_the_amount_used_by_the_matching_basis(): void
|
||||
{
|
||||
$mirror = DB::connection('business_mirror');
|
||||
$mirror->table('store_receipt_order_match_rows')->insert([
|
||||
array_merge($this->row('row-basis', '店铺A', 0), [
|
||||
'income_amount' => 10.00,
|
||||
'paid_amount' => 13079.80,
|
||||
'difference' => -13069.80,
|
||||
'remark' => '订单实付按应付/已付核对',
|
||||
]),
|
||||
array_merge($this->row('row-normal', '店铺B', 0), [
|
||||
'income_amount' => 80.00,
|
||||
'paid_amount' => 100.00,
|
||||
'difference' => -20.00,
|
||||
]),
|
||||
]);
|
||||
|
||||
$response = $this->loginAs()->getJson(route(
|
||||
'business.financial-operations.performance-details.metric-details',
|
||||
[
|
||||
'metric' => 'paid_amount',
|
||||
'month' => '2026-09',
|
||||
],
|
||||
));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertJsonPath('label', '订单核对金额')
|
||||
->assertJsonPath('total', 110)
|
||||
->assertJsonPath('detail_total', 110)
|
||||
->assertJsonPath('balanced', true);
|
||||
|
||||
$this->assertContains([
|
||||
'platform' => '京东账单',
|
||||
'store_name' => '店铺A',
|
||||
'bill_item' => '订单核对金额',
|
||||
'amount' => 10,
|
||||
'line_count' => 1,
|
||||
], $response->json('rows'));
|
||||
$this->assertContains([
|
||||
'platform' => '京东账单',
|
||||
'store_name' => '店铺B',
|
||||
'bill_item' => '订单核对金额',
|
||||
'amount' => 100,
|
||||
'line_count' => 1,
|
||||
], $response->json('rows'));
|
||||
}
|
||||
|
||||
private function row(string $rowKey, string $storeName, float $offset, string $platform = '京东账单'): array
|
||||
{
|
||||
return [
|
||||
|
||||
@ -40,6 +40,20 @@ class PerformanceDifferenceRemarkTest extends TestCase
|
||||
return (new ReflectionMethod(Pages::class, 'receiptDifferenceRemark'))->invoke(null, $row);
|
||||
}
|
||||
|
||||
private function comparablePaid(array $attributes): float
|
||||
{
|
||||
$row = (object) array_merge([
|
||||
'income_amount' => 0,
|
||||
'discount_amount' => 0,
|
||||
'offset_amount' => 0,
|
||||
'default_compensation_amount' => 0,
|
||||
'paid_amount' => 0,
|
||||
'remark' => null,
|
||||
], $attributes);
|
||||
|
||||
return (new ReflectionMethod(Pages::class, 'receiptComparablePaidAmount'))->invoke(null, $row);
|
||||
}
|
||||
|
||||
public function test_pinduoduo_full_refund_wins_before_other_difference_rules(): void
|
||||
{
|
||||
$this->assertSame('订单实付含已退款部分', $this->remark([
|
||||
@ -158,6 +172,26 @@ class PerformanceDifferenceRemarkTest extends TestCase
|
||||
]));
|
||||
}
|
||||
|
||||
public function test_basis_matched_rows_display_the_amount_used_for_comparison(): void
|
||||
{
|
||||
$this->assertSame(10.0, $this->comparablePaid([
|
||||
'income_amount' => 10.00,
|
||||
'paid_amount' => 13079.80,
|
||||
'remark' => '订单实付按应付/已付核对',
|
||||
]));
|
||||
$this->assertSame(90.0, $this->comparablePaid([
|
||||
'income_amount' => 100.00,
|
||||
'discount_amount' => -10.00,
|
||||
'paid_amount' => 150.00,
|
||||
'remark' => '订单实付按卖家实收核对',
|
||||
]));
|
||||
$this->assertSame(123.45, $this->comparablePaid([
|
||||
'income_amount' => 100.00,
|
||||
'paid_amount' => 123.45,
|
||||
'remark' => null,
|
||||
]));
|
||||
}
|
||||
|
||||
public function test_refund_difference_requires_the_refund_amount_to_reconcile(): void
|
||||
{
|
||||
$this->assertSame('订单实付含已退款部分', $this->remark([
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user