diff --git a/backend/cmd/server/VERSION b/backend/cmd/server/VERSION
index 20f0101a2d..e794306a69 100644
--- a/backend/cmd/server/VERSION
+++ b/backend/cmd/server/VERSION
@@ -1 +1 @@
-0.1.108.42
+0.1.108.43
diff --git a/backend/internal/service/payment_config_service.go b/backend/internal/service/payment_config_service.go
index f33505895e..5a5de735d0 100644
--- a/backend/internal/service/payment_config_service.go
+++ b/backend/internal/service/payment_config_service.go
@@ -207,52 +207,56 @@ func (s *PaymentConfigService) parsePaymentConfig(vals map[string]string) *Payme
// nil-check before serialisation — this is inherent to patch-style update patterns
// and cannot be meaningfully decomposed without introducing unnecessary abstraction.
func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req UpdatePaymentConfigRequest) error {
- m := make(map[string]string)
- if req.Enabled != nil {
- m[SettingPaymentEnabled] = strconv.FormatBool(*req.Enabled)
- }
- if req.MinAmount != nil {
- m[SettingMinRechargeAmount] = strconv.FormatFloat(*req.MinAmount, 'f', 2, 64)
- }
- if req.MaxAmount != nil {
- m[SettingMaxRechargeAmount] = strconv.FormatFloat(*req.MaxAmount, 'f', 2, 64)
- }
- if req.DailyLimit != nil {
- m[SettingDailyRechargeLimit] = strconv.FormatFloat(*req.DailyLimit, 'f', 2, 64)
- }
- if req.OrderTimeoutMin != nil {
- m[SettingOrderTimeoutMinutes] = strconv.Itoa(*req.OrderTimeoutMin)
- }
- if req.MaxPendingOrders != nil {
- m[SettingMaxPendingOrders] = strconv.Itoa(*req.MaxPendingOrders)
+ m := map[string]string{
+ SettingPaymentEnabled: formatBoolOrEmpty(req.Enabled),
+ SettingMinRechargeAmount: formatPositiveFloat(req.MinAmount),
+ SettingMaxRechargeAmount: formatPositiveFloat(req.MaxAmount),
+ SettingDailyRechargeLimit: formatPositiveFloat(req.DailyLimit),
+ SettingOrderTimeoutMinutes: formatPositiveInt(req.OrderTimeoutMin),
+ SettingMaxPendingOrders: formatPositiveInt(req.MaxPendingOrders),
+ SettingBalancePayDisabled: formatBoolOrEmpty(req.BalanceDisabled),
+ SettingLoadBalanceStrategy: derefStr(req.LoadBalanceStrategy),
+ SettingProductNamePrefix: derefStr(req.ProductNamePrefix),
+ SettingProductNameSuffix: derefStr(req.ProductNameSuffix),
+ SettingHelpImageURL: derefStr(req.HelpImageURL),
+ SettingHelpText: derefStr(req.HelpText),
}
if req.EnabledTypes != nil {
m[SettingEnabledPaymentTypes] = strings.Join(req.EnabledTypes, ",")
- }
- if req.BalanceDisabled != nil {
- m[SettingBalancePayDisabled] = strconv.FormatBool(*req.BalanceDisabled)
- }
- if req.LoadBalanceStrategy != nil {
- m[SettingLoadBalanceStrategy] = *req.LoadBalanceStrategy
- }
- if req.ProductNamePrefix != nil {
- m[SettingProductNamePrefix] = *req.ProductNamePrefix
- }
- if req.ProductNameSuffix != nil {
- m[SettingProductNameSuffix] = *req.ProductNameSuffix
- }
- if req.HelpImageURL != nil {
- m[SettingHelpImageURL] = *req.HelpImageURL
- }
- if req.HelpText != nil {
- m[SettingHelpText] = *req.HelpText
- }
- if len(m) == 0 {
- return nil
+ } else {
+ m[SettingEnabledPaymentTypes] = ""
}
return s.settingRepo.SetMultiple(ctx, m)
}
+func formatBoolOrEmpty(v *bool) string {
+ if v == nil {
+ return ""
+ }
+ return strconv.FormatBool(*v)
+}
+
+func formatPositiveFloat(v *float64) string {
+ if v == nil || *v <= 0 {
+ return "" // empty → parsePaymentConfig uses default
+ }
+ return strconv.FormatFloat(*v, 'f', 2, 64)
+}
+
+func formatPositiveInt(v *int) string {
+ if v == nil || *v <= 0 {
+ return ""
+ }
+ return strconv.Itoa(*v)
+}
+
+func derefStr(v *string) string {
+ if v == nil {
+ return ""
+ }
+ return *v
+}
+
// --- Provider Instance CRUD ---
func (s *PaymentConfigService) ListProviderInstances(ctx context.Context) ([]*dbent.PaymentProviderInstance, error) {
diff --git a/frontend/src/views/user/PaymentView.vue b/frontend/src/views/user/PaymentView.vue
index 59ade1063a..35d502b8a5 100644
--- a/frontend/src/views/user/PaymentView.vue
+++ b/frontend/src/views/user/PaymentView.vue
@@ -25,7 +25,7 @@
{{ amountError }}
@@ -151,9 +151,15 @@ const tabs = computed(() => { }) const enabledMethods = computed(() => config.value?.enabled_payment_types ?? []) +const minAmount = computed(() => { + const limit = methodLimits.value[selectedMethod.value] + if (limit?.single_min && limit.single_min > 0) return limit.single_min + return config.value?.min_amount && config.value.min_amount > 0 ? config.value.min_amount : 1 +}) const maxAmount = computed(() => { const limit = methodLimits.value[selectedMethod.value] - return limit?.single_max && limit.single_max > 0 ? limit.single_max : (config.value?.max_amount ?? 10000) + if (limit?.single_max && limit.single_max > 0) return limit.single_max + return config.value?.max_amount && config.value.max_amount > 0 ? config.value.max_amount : 99999999 }) const methodOptions = computed