platform orders: add clear bmpa errors tool and audit

This commit is contained in:
萝卜
2026-03-13 13:13:04 +00:00
parent fb32db6fb6
commit f760d920f3
4 changed files with 213 additions and 4 deletions

View File

@@ -991,10 +991,12 @@ class PlatformOrderController extends Controller
'plan_id' => trim((string) $request->input('plan_id', '')),
'site_subscription_id' => trim((string) $request->input('site_subscription_id', '')),
'fail_only' => (string) $request->input('fail_only', ''),
'bmpa_failed_only' => (string) $request->input('bmpa_failed_only', ''),
'synced_only' => (string) $request->input('synced_only', ''),
'sync_status' => trim((string) $request->input('sync_status', '')),
'keyword' => trim((string) $request->input('keyword', '')),
'sync_error_keyword' => trim((string) $request->input('sync_error_keyword', '')),
'bmpa_error_keyword' => trim((string) $request->input('bmpa_error_keyword', '')),
'syncable_only' => (string) $request->input('syncable_only', ''),
'batch_synced_24h' => (string) $request->input('batch_synced_24h', ''),
// 与列表页筛选保持一致(可治理):用于在批量操作后仍能回到同一口径
@@ -1151,10 +1153,12 @@ class PlatformOrderController extends Controller
'plan_id' => trim((string) $request->input('plan_id', '')),
'site_subscription_id' => trim((string) $request->input('site_subscription_id', '')),
'fail_only' => (string) $request->input('fail_only', ''),
'bmpa_failed_only' => (string) $request->input('bmpa_failed_only', ''),
'synced_only' => (string) $request->input('synced_only', ''),
'sync_status' => trim((string) $request->input('sync_status', '')),
'keyword' => trim((string) $request->input('keyword', '')),
'sync_error_keyword' => trim((string) $request->input('sync_error_keyword', '')),
'bmpa_error_keyword' => trim((string) $request->input('bmpa_error_keyword', '')),
'syncable_only' => (string) $request->input('syncable_only', ''),
'batch_synced_24h' => (string) $request->input('batch_synced_24h', ''),
'batch_mark_activated_24h' => (string) $request->input('batch_mark_activated_24h', ''),
@@ -1348,10 +1352,12 @@ class PlatformOrderController extends Controller
'plan_id' => trim((string) $request->input('plan_id', '')),
'site_subscription_id' => trim((string) $request->input('site_subscription_id', '')),
'fail_only' => (string) $request->input('fail_only', ''),
'bmpa_failed_only' => (string) $request->input('bmpa_failed_only', ''),
'synced_only' => (string) $request->input('synced_only', ''),
'sync_status' => trim((string) $request->input('sync_status', '')),
'keyword' => trim((string) $request->input('keyword', '')),
'sync_error_keyword' => trim((string) $request->input('sync_error_keyword', '')),
'bmpa_error_keyword' => trim((string) $request->input('bmpa_error_keyword', '')),
'syncable_only' => (string) $request->input('syncable_only', ''),
'batch_synced_24h' => (string) $request->input('batch_synced_24h', ''),
// 与列表页筛选保持一致(可治理):用于在批量操作后仍能回到同一口径
@@ -1450,7 +1456,7 @@ class PlatformOrderController extends Controller
}
public function clearSyncErrors(Request $request): RedirectResponse
{
{
$this->ensurePlatformAdmin($request);
// 支持两种模式:
@@ -1470,10 +1476,12 @@ class PlatformOrderController extends Controller
'plan_id' => trim((string) $request->input('plan_id', '')),
'site_subscription_id' => trim((string) $request->input('site_subscription_id', '')),
'fail_only' => (string) $request->input('fail_only', ''),
'bmpa_failed_only' => (string) $request->input('bmpa_failed_only', ''),
'synced_only' => (string) $request->input('synced_only', ''),
'sync_status' => trim((string) $request->input('sync_status', '')),
'keyword' => trim((string) $request->input('keyword', '')),
'sync_error_keyword' => trim((string) $request->input('sync_error_keyword', '')),
'bmpa_error_keyword' => trim((string) $request->input('bmpa_error_keyword', '')),
'syncable_only' => (string) $request->input('syncable_only', ''),
'batch_synced_24h' => (string) $request->input('batch_synced_24h', ''),
// 与列表页筛选保持一致(可治理):用于在批量操作后仍能回到同一口径
@@ -1525,6 +1533,83 @@ class PlatformOrderController extends Controller
return redirect()->back()->with('success', $msg . $cleared . ' 条(命中 ' . $matched . ' 条)');
}
public function clearBmpaErrors(Request $request): RedirectResponse
{
$this->ensurePlatformAdmin($request);
// 支持两种模式:
// - scope=all默认清理所有订单的 BMPA 失败标记(需要 confirm=YES
// - scope=filtered仅清理当前筛选结果命中的订单更安全
$scope = (string) $request->input('scope', 'all');
// 防误操作scope=all 需要二次确认
if ($scope === 'all' && (string) $request->input('confirm', '') !== 'YES') {
return redirect()->back()->with('warning', '为避免误操作,清除全部 BMPA 失败标记前请在确认框输入 YES。');
}
$filters = [
'status' => trim((string) $request->input('status', '')),
'payment_status' => trim((string) $request->input('payment_status', '')),
'merchant_id' => trim((string) $request->input('merchant_id', '')),
'plan_id' => trim((string) $request->input('plan_id', '')),
'site_subscription_id' => trim((string) $request->input('site_subscription_id', '')),
'fail_only' => (string) $request->input('fail_only', ''),
'bmpa_failed_only' => (string) $request->input('bmpa_failed_only', ''),
'synced_only' => (string) $request->input('synced_only', ''),
'sync_status' => trim((string) $request->input('sync_status', '')),
'keyword' => trim((string) $request->input('keyword', '')),
'sync_error_keyword' => trim((string) $request->input('sync_error_keyword', '')),
'bmpa_error_keyword' => trim((string) $request->input('bmpa_error_keyword', '')),
'syncable_only' => (string) $request->input('syncable_only', ''),
'batch_synced_24h' => (string) $request->input('batch_synced_24h', ''),
'batch_mark_activated_24h' => (string) $request->input('batch_mark_activated_24h', ''),
'reconcile_mismatch' => (string) $request->input('reconcile_mismatch', ''),
'receipt_status' => trim((string) $request->input('receipt_status', '')),
'refund_status' => trim((string) $request->input('refund_status', '')),
'refund_inconsistent' => (string) $request->input('refund_inconsistent', ''),
];
$query = PlatformOrder::query()
->whereRaw("JSON_EXTRACT(meta, '$.batch_mark_paid_and_activate_error.message') IS NOT NULL");
if ($scope === 'filtered') {
$query = $this->applyFilters($query, $filters);
}
$orders = $query->get(['id', 'meta']);
$matched = $orders->count();
$cleared = 0;
foreach ($orders as $order) {
$meta = (array) ($order->meta ?? []);
if (! data_get($meta, 'batch_mark_paid_and_activate_error')) {
continue;
}
data_forget($meta, 'batch_mark_paid_and_activate_error');
// 轻量审计:记录清理动作(不做独立表,先落 meta便于排查
$audit = (array) (data_get($meta, 'audit', []) ?? []);
$audit[] = [
'action' => 'clear_bmpa_error',
'scope' => $scope,
'at' => now()->toDateTimeString(),
'admin_id' => $this->platformAdminId($request),
];
data_set($meta, 'audit', $audit);
$order->meta = $meta;
$order->save();
$cleared++;
}
$msg = $scope === 'filtered'
? '已清除当前筛选范围内的 BMPA 失败标记:'
: '已清除全部订单的 BMPA 失败标记:';
return redirect()->back()->with('success', $msg . $cleared . ' 条(命中 ' . $matched . ' 条)');
}
protected function applyFilters(Builder $query, array $filters): Builder
{
return $query