feat(admin): 订阅详情页补回执/退款汇总与对账差额(订阅维度)

This commit is contained in:
萝卜
2026-03-11 00:53:04 +00:00
parent e6626a54b3
commit 10609da93e
3 changed files with 103 additions and 0 deletions

View File

@@ -45,6 +45,62 @@ class SiteSubscriptionController extends Controller
->count(),
];
// 可治理摘要:订阅维度的回执/退款汇总(口径与平台订单列表一致:优先 summary缺省回退 receipts
$metaOrders = (clone $baseOrdersQuery)->get(['id', 'paid_amount', 'meta']);
$totalReceiptAmount = 0.0;
$receiptOrders = 0;
$noReceiptOrders = 0;
$totalRefundedAmount = 0.0;
$refundOrders = 0;
$noRefundOrders = 0;
foreach ($metaOrders as $o) {
$meta = $o->meta ?? [];
$receiptTotal = (float) (data_get($meta, 'payment_summary.total_amount') ?? 0);
if ($receiptTotal <= 0) {
$receipts = (array) (data_get($meta, 'payment_receipts', []) ?? []);
foreach ($receipts as $r) {
$receiptTotal += (float) (data_get($r, 'amount') ?? 0);
}
}
if ($receiptTotal > 0) {
$receiptOrders++;
$totalReceiptAmount += $receiptTotal;
} else {
$noReceiptOrders++;
}
$refundTotal = (float) (data_get($meta, 'refund_summary.total_amount') ?? 0);
if ($refundTotal <= 0) {
$refunds = (array) (data_get($meta, 'refund_receipts', []) ?? []);
foreach ($refunds as $r) {
$refundTotal += (float) (data_get($r, 'amount') ?? 0);
}
}
if ($refundTotal > 0) {
$refundOrders++;
$totalRefundedAmount += $refundTotal;
} else {
$noRefundOrders++;
}
}
$summaryStats = $summaryStats + [
'receipt_orders' => $receiptOrders,
'no_receipt_orders' => $noReceiptOrders,
'total_receipt_amount' => (float) $totalReceiptAmount,
'refund_orders' => $refundOrders,
'no_refund_orders' => $noRefundOrders,
'total_refunded_amount' => (float) $totalRefundedAmount,
// 对账差额:回执总额 - 已付总额(订阅维度)
'reconciliation_delta' => (float) ($totalReceiptAmount - (float) $metaOrders->sum('paid_amount')),
];
// 同步失败原因聚合Top3订阅维度快速判断“常见失败原因”
$failedReasonRows = (clone $baseOrdersQuery)
->whereRaw("JSON_EXTRACT(meta, '$.subscription_activation_error.message') IS NOT NULL")

View File

@@ -131,6 +131,35 @@
<div class="muted muted-xs"> activation 且无 error</div>
</div>
<div class="card">
<h3>有回执订单 / 回执总额</h3>
<div class="num-md">
{{ $summaryStats['receipt_orders'] ?? 0 }}
/ ¥{{ number_format((float) ($summaryStats['total_receipt_amount'] ?? 0), 2) }}
</div>
<div class="muted muted-xs">口径payment_summary.total_amount 存在或 payment_receipts 有记录</div>
</div>
<div class="card">
<h3>有退款订单 / 退款总额</h3>
<div class="num-md">
{{ $summaryStats['refund_orders'] ?? 0 }}
/ ¥{{ number_format((float) ($summaryStats['total_refunded_amount'] ?? 0), 2) }}
</div>
<div class="muted muted-xs">口径refund_summary.total_amount 存在或 refund_receipts 有记录</div>
</div>
<div class="card">
<h3>对账差额(回执-已付)</h3>
@php $delta = (float) ($summaryStats['reconciliation_delta'] ?? 0); @endphp
<div class="num-md">¥{{ number_format($delta, 2) }}</div>
@if(abs($delta) >= 0.01)
<div class="muted muted-xs text-danger">提示:差额非 0,可能存在回执金额与订单已付金额不一致。</div>
@else
<div class="muted muted-xs">差额为 0(当前订阅维度)</div>
@endif
</div>
<div class="card">
<h3>失败原因Top3</h3>
@php $failedReasonStats = $failedReasonStats ?? []; @endphp

View File

@@ -80,6 +80,21 @@ class AdminSiteSubscriptionShowTest extends TestCase
'synced_at' => now()->subDay()->toDateTimeString(),
'admin_id' => 1,
],
// 订阅维度治理摘要:回执/退款汇总口径应可识别 summary
'payment_summary' => [
'count' => 1,
'total_amount' => 88,
'last_at' => now()->subDay()->toDateTimeString(),
'last_amount' => 88,
'last_channel' => 'bank_transfer',
],
'refund_summary' => [
'count' => 1,
'total_amount' => 10,
'last_at' => now()->subHours(12)->toDateTimeString(),
'last_amount' => 10,
'last_channel' => 'bank_transfer',
],
],
]);
@@ -91,6 +106,9 @@ class AdminSiteSubscriptionShowTest extends TestCase
->assertSee('可同步(已支付+已生效+未同步)')
->assertSee('未同步(无记录)')
->assertSee('失败原因Top3')
->assertSee('有回执订单 / 回执总额')
->assertSee('有退款订单 / 退款总额')
->assertSee('对账差额(回执-已付)')
->assertSee('关联平台订单')
->assertSee('PO_SUB_SHOW_0001')
->assertSee('同步时间')