fix(payment): structured error responses + disable provider card hint overlay

- Backend: PENDING_ORDERS error uses reason+metadata per CLAUDE.md spec
- Block disabling provider when it has pending orders
- ProviderCard: remove bottom hint area, use opacity + title tooltip instead
This commit is contained in:
erio
2026-04-07 01:49:45 +08:00
parent 757396d1c0
commit d02f8a3e2f
3 changed files with 23 additions and 15 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.108.48
0.1.108.49
@@ -392,12 +392,24 @@ func (s *PaymentConfigService) UpdateProviderInstance(ctx context.Context, id in
return nil, fmt.Errorf("check pending orders: %w", err)
}
if count > 0 {
return nil, infraerrors.Conflict("PENDING_ORDERS",
fmt.Sprintf("this instance has %d in-progress orders; changing credentials may break payment callbacks — wait for orders to complete or disable the instance first", count))
return nil, infraerrors.Conflict("PENDING_ORDERS", "instance has pending orders").
WithMetadata(map[string]string{"count": strconv.Itoa(count)})
}
}
}
// Block disabling a provider that has pending orders
if req.Enabled != nil && !*req.Enabled {
count, err := s.countPendingOrders(ctx, id)
if err != nil {
return nil, fmt.Errorf("check pending orders: %w", err)
}
if count > 0 {
return nil, infraerrors.Conflict("PENDING_ORDERS", "instance has pending orders").
WithMetadata(map[string]string{"count": strconv.Itoa(count)})
}
}
u := s.entClient.PaymentProviderInstance.UpdateOneID(id)
if req.Name != nil {
u.SetName(*req.Name)
@@ -1,11 +1,14 @@
<template>
<div :class="[
'rounded-lg border transition-all',
enabled ? 'border-gray-200 dark:border-dark-600' : 'border-gray-200 bg-gray-50 dark:border-dark-700 dark:bg-dark-800/50',
]">
<div
:class="[
'group relative rounded-lg border transition-all',
enabled ? 'border-gray-200 dark:border-dark-600' : 'border-gray-200 bg-gray-50 opacity-50 dark:border-dark-700 dark:bg-dark-800/50',
]"
:title="!enabled ? t('admin.settings.payment.typeDisabled') + ' — ' + t('admin.settings.payment.enableTypesFirst') : undefined"
>
<div :class="[
'flex items-center justify-between px-4 py-2.5',
!enabled && 'opacity-50 pointer-events-none',
!enabled && 'pointer-events-none',
]">
<!-- Left: icon + name + key badge + type badges -->
<div class="flex items-center gap-3">
@@ -53,13 +56,6 @@
</div>
</div>
</div>
<!-- Disabled hint -->
<div v-if="!enabled" class="border-t border-gray-100 px-4 py-2 dark:border-dark-700">
<span class="text-xs text-amber-500">
{{ t('admin.settings.payment.typeDisabled') }} — {{ t('admin.settings.payment.enableTypesFirst') }}
</span>
</div>
</div>
</template>