feat(platform-orders): 支持支付回执留痕(meta.payment_receipts)
This commit is contained in:
@@ -302,6 +302,24 @@ class PlatformOrderController extends Controller
|
||||
$order->paid_at = $order->paid_at ?: $now;
|
||||
$order->activated_at = $order->activated_at ?: $now;
|
||||
$order->paid_amount = $order->paid_amount > 0 ? $order->paid_amount : $order->payable_amount;
|
||||
|
||||
// 兼容:若尚未写入“支付回执”,则自动补一条(可治理)
|
||||
$meta = (array) ($order->meta ?? []);
|
||||
$receipts = (array) (data_get($meta, 'payment_receipts', []) ?? []);
|
||||
if (count($receipts) === 0) {
|
||||
$receipts[] = [
|
||||
'type' => 'manual_mark_paid',
|
||||
'channel' => (string) ($order->payment_channel ?? ''),
|
||||
'amount' => (float) $order->paid_amount,
|
||||
'paid_at' => $order->paid_at ? $order->paid_at->format('Y-m-d H:i:s') : $now->toDateTimeString(),
|
||||
'note' => '由【标记支付并生效】自动补记(可治理)',
|
||||
'created_at' => $now->toDateTimeString(),
|
||||
'admin_id' => $admin->id,
|
||||
];
|
||||
data_set($meta, 'payment_receipts', $receipts);
|
||||
$order->meta = $meta;
|
||||
}
|
||||
|
||||
$order->save();
|
||||
|
||||
// 立刻同步订阅
|
||||
@@ -328,6 +346,40 @@ class PlatformOrderController extends Controller
|
||||
return redirect()->back()->with('success', '订单已标记支付并生效,订阅已同步:' . $subscription->subscription_no);
|
||||
}
|
||||
|
||||
public function addPaymentReceipt(Request $request, PlatformOrder $order): RedirectResponse
|
||||
{
|
||||
$admin = $this->ensurePlatformAdmin($request);
|
||||
|
||||
$data = $request->validate([
|
||||
'type' => ['required', 'string', 'max:30'],
|
||||
'channel' => ['nullable', 'string', 'max:30'],
|
||||
'amount' => ['required', 'numeric', 'min:0'],
|
||||
'paid_at' => ['nullable', 'date'],
|
||||
'note' => ['nullable', 'string', 'max:2000'],
|
||||
]);
|
||||
|
||||
$now = now();
|
||||
|
||||
$meta = (array) ($order->meta ?? []);
|
||||
$receipts = (array) (data_get($meta, 'payment_receipts', []) ?? []);
|
||||
|
||||
$receipts[] = [
|
||||
'type' => (string) $data['type'],
|
||||
'channel' => (string) ($data['channel'] ?? ''),
|
||||
'amount' => (float) $data['amount'],
|
||||
'paid_at' => $data['paid_at'] ? (string) $data['paid_at'] : null,
|
||||
'note' => (string) ($data['note'] ?? ''),
|
||||
'created_at' => $now->toDateTimeString(),
|
||||
'admin_id' => $admin->id,
|
||||
];
|
||||
|
||||
data_set($meta, 'payment_receipts', $receipts);
|
||||
$order->meta = $meta;
|
||||
$order->save();
|
||||
|
||||
return redirect()->back()->with('success', '已追加支付回执记录(仅用于对账留痕,不自动改状态)。');
|
||||
}
|
||||
|
||||
public function markActivated(Request $request, PlatformOrder $order): RedirectResponse
|
||||
{
|
||||
$admin = $this->ensurePlatformAdmin($request);
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
$activation = data_get($order->meta, 'subscription_activation');
|
||||
$activationError = data_get($order->meta, 'subscription_activation_error');
|
||||
$audit = (array) (data_get($order->meta, 'audit', []) ?? []);
|
||||
$paymentReceipts = (array) (data_get($order->meta, 'payment_receipts', []) ?? []);
|
||||
@endphp
|
||||
|
||||
@php
|
||||
@@ -107,6 +108,64 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="card mb-20">
|
||||
<h3>支付回执(对账留痕)</h3>
|
||||
<p class="muted muted-tight">用于“线下收款/转账/人工核对”的留痕记录(当前阶段先落 meta,不引入独立表)。</p>
|
||||
|
||||
@if(count($paymentReceipts) > 0)
|
||||
@php $items = array_slice(array_reverse($paymentReceipts), 0, 20); @endphp
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:140px;">类型</th>
|
||||
<th style="width:120px;">渠道</th>
|
||||
<th style="width:120px;">金额</th>
|
||||
<th style="width:200px;">支付时间</th>
|
||||
<th style="width:160px;">记录时间</th>
|
||||
<th style="width:100px;">管理员</th>
|
||||
<th>备注</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($items as $r)
|
||||
<tr>
|
||||
<td>{{ data_get($r, 'type') ?: '-' }}</td>
|
||||
<td>{{ data_get($r, 'channel') ?: '-' }}</td>
|
||||
<td>¥{{ number_format((float) (data_get($r, 'amount') ?? 0), 2) }}</td>
|
||||
<td>{{ data_get($r, 'paid_at') ?: '-' }}</td>
|
||||
<td>{{ data_get($r, 'created_at') ?: '-' }}</td>
|
||||
<td>{{ data_get($r, 'admin_id') ?: '-' }}</td>
|
||||
<td class="muted">{{ data_get($r, 'note') ?: '' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@else
|
||||
<p class="muted">暂无支付回执记录。</p>
|
||||
@endif
|
||||
|
||||
<details style="margin-top:12px;">
|
||||
<summary class="muted">追加一条支付回执(不自动改状态)</summary>
|
||||
<form method="post" action="/admin/platform-orders/{{ $order->id }}/add-payment-receipt" style="margin-top:10px;">
|
||||
@csrf
|
||||
<div class="grid-3">
|
||||
<input type="text" name="type" placeholder="类型:bank_transfer/现金/支付宝等" value="bank_transfer">
|
||||
<input type="text" name="channel" placeholder="渠道(可选)" value="{{ (string) ($order->payment_channel ?? '') }}">
|
||||
<input type="number" step="0.01" name="amount" placeholder="金额" value="{{ number_format((float) ($order->paid_amount > 0 ? $order->paid_amount : $order->payable_amount), 2, '.', '') }}">
|
||||
</div>
|
||||
<div style="margin-top:10px;">
|
||||
<input type="text" name="paid_at" placeholder="支付时间:YYYY-mm-dd HH:ii:ss(可选)" value="{{ optional($order->paid_at)->format('Y-m-d H:i:s') }}">
|
||||
</div>
|
||||
<div style="margin-top:10px;">
|
||||
<textarea name="note" placeholder="备注(可选,用于对账说明)" rows="3" style="width:100%;"></textarea>
|
||||
</div>
|
||||
<div style="margin-top:10px;">
|
||||
<button type="submit">追加回执记录</button>
|
||||
</div>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div class="card mb-20">
|
||||
<h3>订阅同步记录</h3>
|
||||
@if($activation)
|
||||
@@ -145,6 +204,8 @@
|
||||
$auditActionLabels = [
|
||||
'clear_sync_error' => '清除同步失败标记',
|
||||
'batch_activate_subscription' => '批量同步订阅',
|
||||
'mark_activated' => '仅标记为已生效',
|
||||
'batch_mark_activated' => '批量仅标记为已生效',
|
||||
];
|
||||
@endphp
|
||||
<table>
|
||||
|
||||
@@ -109,6 +109,7 @@ Route::prefix('admin')->group(function () {
|
||||
Route::get('/platform-orders/{order}', [PlatformOrderController::class, 'show']);
|
||||
Route::post('/platform-orders/{order}/activate-subscription', [PlatformOrderController::class, 'activateSubscription']);
|
||||
Route::post('/platform-orders/{order}/mark-paid-and-activate', [PlatformOrderController::class, 'markPaidAndActivate']);
|
||||
Route::post('/platform-orders/{order}/add-payment-receipt', [PlatformOrderController::class, 'addPaymentReceipt']);
|
||||
Route::post('/platform-orders/{order}/mark-activated', [PlatformOrderController::class, 'markActivated']);
|
||||
|
||||
Route::get('/site-subscriptions', [SiteSubscriptionController::class, 'index']);
|
||||
|
||||
Reference in New Issue
Block a user