平台订单对账明细导出:支持 include_order_snapshot 并加入口

This commit is contained in:
萝卜
2026-03-13 20:51:29 +00:00
parent c6a8792763
commit a15cc917e1
3 changed files with 42 additions and 3 deletions

View File

@@ -426,17 +426,39 @@ class PlatformOrderController extends Controller
$paymentReceipts = (array) (data_get($order->meta, 'payment_receipts', []) ?? []); $paymentReceipts = (array) (data_get($order->meta, 'payment_receipts', []) ?? []);
$refundReceipts = (array) (data_get($order->meta, 'refund_receipts', []) ?? []); $refundReceipts = (array) (data_get($order->meta, 'refund_receipts', []) ?? []);
$includeOrderSnapshot = (string) $request->query('include_order_snapshot', '') === '1';
$filename = 'platform_order_' . $order->id . '_ledger_' . now()->format('Ymd_His') . '.csv'; $filename = 'platform_order_' . $order->id . '_ledger_' . now()->format('Ymd_His') . '.csv';
return response()->streamDownload(function () use ($order, $paymentReceipts, $refundReceipts) { return response()->streamDownload(function () use ($order, $paymentReceipts, $refundReceipts, $includeOrderSnapshot) {
$out = fopen('php://output', 'w'); $out = fopen('php://output', 'w');
// UTF-8 BOM避免 Excel 打开中文乱码 // UTF-8 BOM避免 Excel 打开中文乱码
fwrite($out, "\xEF\xBB\xBF"); fwrite($out, "\xEF\xBB\xBF");
// 订单摘要(两行) // 订单摘要(基础两行)
fputcsv($out, ['order_id', (string) $order->id]); fputcsv($out, ['order_id', (string) $order->id]);
fputcsv($out, ['order_no', (string) $order->order_no]); fputcsv($out, ['order_no', (string) $order->order_no]);
// 可选:导出更多订单快照字段(便于财务/对账留档,不必另截图)
if ($includeOrderSnapshot) {
fputcsv($out, ['merchant_id', (string) ($order->merchant_id ?? '')]);
fputcsv($out, ['merchant_name', (string) ($order->merchant?->name ?? '')]);
fputcsv($out, ['plan_id', (string) ($order->plan_id ?? '')]);
fputcsv($out, ['plan_name', (string) ($order->plan_name ?? ($order->plan?->name ?? ''))]);
fputcsv($out, ['order_type', (string) ($order->order_type ?? '')]);
fputcsv($out, ['status', (string) ($order->status ?? '')]);
fputcsv($out, ['payment_status', (string) ($order->payment_status ?? '')]);
fputcsv($out, ['payable_amount', (string) ($order->payable_amount ?? '')]);
fputcsv($out, ['paid_amount', (string) ($order->paid_amount ?? '')]);
fputcsv($out, ['placed_at', (string) (optional($order->placed_at)->format('Y-m-d H:i:s') ?? '')]);
fputcsv($out, ['paid_at', (string) (optional($order->paid_at)->format('Y-m-d H:i:s') ?? '')]);
fputcsv($out, ['activated_at', (string) (optional($order->activated_at)->format('Y-m-d H:i:s') ?? '')]);
fputcsv($out, ['refunded_at', (string) (optional($order->refunded_at)->format('Y-m-d H:i:s') ?? '')]);
fputcsv($out, ['site_subscription_id', (string) ($order->site_subscription_id ?? '')]);
fputcsv($out, ['subscription_no', (string) ($order->siteSubscription?->subscription_no ?? '')]);
}
fputcsv($out, []); fputcsv($out, []);
// 明细表头 // 明细表头

View File

@@ -326,7 +326,10 @@
<div class="card mb-20" id="payment-receipts"> <div class="card mb-20" id="payment-receipts">
<div class="flex-between" style="align-items:center;"> <div class="flex-between" style="align-items:center;">
<h3 style="margin:0;">支付回执(对账留痕)</h3> <h3 style="margin:0;">支付回执(对账留痕)</h3>
<a class="muted" href="/admin/platform-orders/{{ $order->id }}/export-ledger">导出对账明细CSV</a> <div class="muted" style="display:flex; gap:10px;">
<a class="muted" href="/admin/platform-orders/{{ $order->id }}/export-ledger">导出对账明细CSV</a>
<a class="muted" href="/admin/platform-orders/{{ $order->id }}/export-ledger?include_order_snapshot=1">导出含订单摘要CSV</a>
</div>
</div> </div>
<p class="muted muted-tight">用于“线下收款/转账/人工核对”的留痕记录(当前阶段先落 meta不引入独立表</p> <p class="muted muted-tight">用于“线下收款/转账/人工核对”的留痕记录(当前阶段先落 meta不引入独立表</p>

View File

@@ -83,15 +83,27 @@ class AdminPlatformOrderExportLedgerTest extends TestCase
$content = $res->streamedContent(); $content = $res->streamedContent();
$res2 = $this->get('/admin/platform-orders/' . $order->id . '/export-ledger?include_order_snapshot=1');
$res2->assertOk();
$content2 = $res2->streamedContent();
// UTF-8 BOM // UTF-8 BOM
$this->assertStringStartsWith("\xEF\xBB\xBF", $content); $this->assertStringStartsWith("\xEF\xBB\xBF", $content);
$this->assertStringStartsWith("\xEF\xBB\xBF", $content2);
// 核心表头 // 核心表头
$this->assertStringContainsString('record_type,receipt_type,channel,amount,biz_time,created_at,admin_id,note', $content); $this->assertStringContainsString('record_type,receipt_type,channel,amount,biz_time,created_at,admin_id,note', $content);
$this->assertStringContainsString('record_type,receipt_type,channel,amount,biz_time,created_at,admin_id,note', $content2);
// 至少包含一条 payment 与一条 refund 行(包含 type 字段) // 至少包含一条 payment 与一条 refund 行(包含 type 字段)
$this->assertStringContainsString('payment,bank_transfer,offline,10', $content); $this->assertStringContainsString('payment,bank_transfer,offline,10', $content);
$this->assertStringContainsString('refund,refund,offline,1', $content); $this->assertStringContainsString('refund,refund,offline,1', $content);
// include_order_snapshot=1 时应包含更多摘要字段
$this->assertStringContainsString("merchant_id,{$merchant->id}", $content2);
$this->assertStringContainsString('payment_status,unpaid', $content2);
$this->assertStringContainsString('site_subscription_id,', $content2);
} }
public function test_show_page_should_render_export_ledger_link(): void public function test_show_page_should_render_export_ledger_link(): void
@@ -131,6 +143,8 @@ class AdminPlatformOrderExportLedgerTest extends TestCase
$res->assertOk(); $res->assertOk();
$res->assertSee('/admin/platform-orders/' . $order->id . '/export-ledger', false); $res->assertSee('/admin/platform-orders/' . $order->id . '/export-ledger', false);
$res->assertSee('/admin/platform-orders/' . $order->id . '/export-ledger?include_order_snapshot=1', false);
$res->assertSee('导出对账明细CSV', false); $res->assertSee('导出对账明细CSV', false);
$res->assertSee('导出含订单摘要CSV', false);
} }
} }