feat(payment): add complete payment system with multi-provider support
Add a full payment and subscription system supporting EasyPay (Alipay/WeChat), Stripe, and direct Alipay/WeChat Pay providers with multi-instance load balancing.
This commit is contained in:
323
backend/internal/handler/admin/payment_handler.go
Normal file
323
backend/internal/handler/admin/payment_handler.go
Normal file
@@ -0,0 +1,323 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// PaymentHandler handles admin payment management.
|
||||
type PaymentHandler struct {
|
||||
paymentService *service.PaymentService
|
||||
configService *service.PaymentConfigService
|
||||
}
|
||||
|
||||
// NewPaymentHandler creates a new admin PaymentHandler.
|
||||
func NewPaymentHandler(paymentService *service.PaymentService, configService *service.PaymentConfigService) *PaymentHandler {
|
||||
return &PaymentHandler{
|
||||
paymentService: paymentService,
|
||||
configService: configService,
|
||||
}
|
||||
}
|
||||
|
||||
// --- Dashboard ---
|
||||
|
||||
// GetDashboard returns payment dashboard statistics.
|
||||
// GET /api/v1/admin/payment/dashboard
|
||||
func (h *PaymentHandler) GetDashboard(c *gin.Context) {
|
||||
days := 30
|
||||
if d := c.Query("days"); d != "" {
|
||||
if v, err := strconv.Atoi(d); err == nil && v > 0 {
|
||||
days = v
|
||||
}
|
||||
}
|
||||
stats, err := h.paymentService.GetDashboardStats(c.Request.Context(), days)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, stats)
|
||||
}
|
||||
|
||||
// --- Orders ---
|
||||
|
||||
// ListOrders returns a paginated list of all payment orders.
|
||||
// GET /api/v1/admin/payment/orders
|
||||
func (h *PaymentHandler) ListOrders(c *gin.Context) {
|
||||
page, pageSize := response.ParsePagination(c)
|
||||
var userID int64
|
||||
if uid := c.Query("user_id"); uid != "" {
|
||||
if v, err := strconv.ParseInt(uid, 10, 64); err == nil {
|
||||
userID = v
|
||||
}
|
||||
}
|
||||
orders, total, err := h.paymentService.AdminListOrders(c.Request.Context(), userID, service.OrderListParams{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Status: c.Query("status"),
|
||||
OrderType: c.Query("order_type"),
|
||||
PaymentType: c.Query("payment_type"),
|
||||
Keyword: c.Query("keyword"),
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Paginated(c, orders, int64(total), page, pageSize)
|
||||
}
|
||||
|
||||
// GetOrderDetail returns detailed information about a single order.
|
||||
// GET /api/v1/admin/payment/orders/:id
|
||||
func (h *PaymentHandler) GetOrderDetail(c *gin.Context) {
|
||||
orderID, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
order, err := h.paymentService.GetOrderByID(c.Request.Context(), orderID)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
auditLogs, _ := h.paymentService.GetOrderAuditLogs(c.Request.Context(), orderID)
|
||||
response.Success(c, gin.H{"order": order, "auditLogs": auditLogs})
|
||||
}
|
||||
|
||||
// CancelOrder cancels a pending order (admin).
|
||||
// POST /api/v1/admin/payment/orders/:id/cancel
|
||||
func (h *PaymentHandler) CancelOrder(c *gin.Context) {
|
||||
orderID, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
msg, err := h.paymentService.AdminCancelOrder(c.Request.Context(), orderID)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": msg})
|
||||
}
|
||||
|
||||
// RetryFulfillment retries fulfillment for a paid order.
|
||||
// POST /api/v1/admin/payment/orders/:id/retry
|
||||
func (h *PaymentHandler) RetryFulfillment(c *gin.Context) {
|
||||
orderID, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if err := h.paymentService.RetryFulfillment(c.Request.Context(), orderID); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "fulfillment retried"})
|
||||
}
|
||||
|
||||
// AdminProcessRefundRequest is the request body for admin refund processing.
|
||||
type AdminProcessRefundRequest struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Reason string `json:"reason"`
|
||||
Force bool `json:"force"`
|
||||
DeductBalance bool `json:"deduct_balance"`
|
||||
}
|
||||
|
||||
// ProcessRefund processes a refund for an order (admin).
|
||||
// POST /api/v1/admin/payment/orders/:id/refund
|
||||
func (h *PaymentHandler) ProcessRefund(c *gin.Context) {
|
||||
orderID, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req AdminProcessRefundRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
plan, earlyResult, err := h.paymentService.PrepareRefund(c.Request.Context(), orderID, req.Amount, req.Reason, req.Force, req.DeductBalance)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
if earlyResult != nil {
|
||||
response.Success(c, earlyResult)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.paymentService.ExecuteRefund(c.Request.Context(), plan)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
// --- Subscription Plans ---
|
||||
|
||||
// ListPlans returns all subscription plans.
|
||||
// GET /api/v1/admin/payment/plans
|
||||
func (h *PaymentHandler) ListPlans(c *gin.Context) {
|
||||
plans, err := h.configService.ListPlans(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, plans)
|
||||
}
|
||||
|
||||
// CreatePlan creates a new subscription plan.
|
||||
// POST /api/v1/admin/payment/plans
|
||||
func (h *PaymentHandler) CreatePlan(c *gin.Context) {
|
||||
var req service.CreatePlanRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
plan, err := h.configService.CreatePlan(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Created(c, plan)
|
||||
}
|
||||
|
||||
// UpdatePlan updates an existing subscription plan.
|
||||
// PUT /api/v1/admin/payment/plans/:id
|
||||
func (h *PaymentHandler) UpdatePlan(c *gin.Context) {
|
||||
id, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var req service.UpdatePlanRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
plan, err := h.configService.UpdatePlan(c.Request.Context(), id, req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, plan)
|
||||
}
|
||||
|
||||
// DeletePlan deletes a subscription plan.
|
||||
// DELETE /api/v1/admin/payment/plans/:id
|
||||
func (h *PaymentHandler) DeletePlan(c *gin.Context) {
|
||||
id, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if err := h.configService.DeletePlan(c.Request.Context(), id); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "deleted"})
|
||||
}
|
||||
|
||||
// --- Provider Instances ---
|
||||
|
||||
// ListProviders returns all payment provider instances.
|
||||
// GET /api/v1/admin/payment/providers
|
||||
func (h *PaymentHandler) ListProviders(c *gin.Context) {
|
||||
providers, err := h.configService.ListProviderInstancesWithConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, providers)
|
||||
}
|
||||
|
||||
// CreateProvider creates a new payment provider instance.
|
||||
// POST /api/v1/admin/payment/providers
|
||||
func (h *PaymentHandler) CreateProvider(c *gin.Context) {
|
||||
var req service.CreateProviderInstanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
inst, err := h.configService.CreateProviderInstance(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
h.paymentService.RefreshProviders(c.Request.Context())
|
||||
response.Created(c, inst)
|
||||
}
|
||||
|
||||
// UpdateProvider updates an existing payment provider instance.
|
||||
// PUT /api/v1/admin/payment/providers/:id
|
||||
func (h *PaymentHandler) UpdateProvider(c *gin.Context) {
|
||||
id, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var req service.UpdateProviderInstanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
inst, err := h.configService.UpdateProviderInstance(c.Request.Context(), id, req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
h.paymentService.RefreshProviders(c.Request.Context())
|
||||
response.Success(c, inst)
|
||||
}
|
||||
|
||||
// DeleteProvider deletes a payment provider instance.
|
||||
// DELETE /api/v1/admin/payment/providers/:id
|
||||
func (h *PaymentHandler) DeleteProvider(c *gin.Context) {
|
||||
id, ok := parseIDParam(c, "id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if err := h.configService.DeleteProviderInstance(c.Request.Context(), id); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
h.paymentService.RefreshProviders(c.Request.Context())
|
||||
response.Success(c, gin.H{"message": "deleted"})
|
||||
}
|
||||
|
||||
// parseIDParam parses an int64 path parameter.
|
||||
// Returns the parsed ID and true on success; on failure it writes a BadRequest response and returns false.
|
||||
func parseIDParam(c *gin.Context, paramName string) (int64, bool) {
|
||||
id, err := strconv.ParseInt(c.Param(paramName), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid "+paramName)
|
||||
return 0, false
|
||||
}
|
||||
return id, true
|
||||
}
|
||||
|
||||
// --- Config ---
|
||||
|
||||
// GetConfig returns the payment configuration (admin view).
|
||||
// GET /api/v1/admin/payment/config
|
||||
func (h *PaymentHandler) GetConfig(c *gin.Context) {
|
||||
cfg, err := h.configService.GetPaymentConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, cfg)
|
||||
}
|
||||
|
||||
// UpdateConfig updates the payment configuration.
|
||||
// PUT /api/v1/admin/payment/config
|
||||
func (h *PaymentHandler) UpdateConfig(c *gin.Context) {
|
||||
var req service.UpdatePaymentConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.configService.UpdatePaymentConfig(c.Request.Context(), req); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "updated"})
|
||||
}
|
||||
@@ -46,19 +46,23 @@ func scopesContainOpenID(scopes string) bool {
|
||||
|
||||
// SettingHandler 系统设置处理器
|
||||
type SettingHandler struct {
|
||||
settingService *service.SettingService
|
||||
emailService *service.EmailService
|
||||
turnstileService *service.TurnstileService
|
||||
opsService *service.OpsService
|
||||
settingService *service.SettingService
|
||||
emailService *service.EmailService
|
||||
turnstileService *service.TurnstileService
|
||||
opsService *service.OpsService
|
||||
paymentConfigService *service.PaymentConfigService
|
||||
paymentService *service.PaymentService
|
||||
}
|
||||
|
||||
// NewSettingHandler 创建系统设置处理器
|
||||
func NewSettingHandler(settingService *service.SettingService, emailService *service.EmailService, turnstileService *service.TurnstileService, opsService *service.OpsService) *SettingHandler {
|
||||
func NewSettingHandler(settingService *service.SettingService, emailService *service.EmailService, turnstileService *service.TurnstileService, opsService *service.OpsService, paymentConfigService *service.PaymentConfigService, paymentService *service.PaymentService) *SettingHandler {
|
||||
return &SettingHandler{
|
||||
settingService: settingService,
|
||||
emailService: emailService,
|
||||
turnstileService: turnstileService,
|
||||
opsService: opsService,
|
||||
settingService: settingService,
|
||||
emailService: emailService,
|
||||
turnstileService: turnstileService,
|
||||
opsService: opsService,
|
||||
paymentConfigService: paymentConfigService,
|
||||
paymentService: paymentService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +85,15 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// Load payment config
|
||||
var paymentCfg *service.PaymentConfig
|
||||
if h.paymentConfigService != nil {
|
||||
paymentCfg, _ = h.paymentConfigService.GetPaymentConfig(c.Request.Context())
|
||||
}
|
||||
if paymentCfg == nil {
|
||||
paymentCfg = &service.PaymentConfig{}
|
||||
}
|
||||
|
||||
response.Success(c, dto.SystemSettings{
|
||||
RegistrationEnabled: settings.RegistrationEnabled,
|
||||
EmailVerifyEnabled: settings.EmailVerifyEnabled,
|
||||
@@ -160,6 +173,24 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
||||
EnableFingerprintUnification: settings.EnableFingerprintUnification,
|
||||
EnableMetadataPassthrough: settings.EnableMetadataPassthrough,
|
||||
EnableCCHSigning: settings.EnableCCHSigning,
|
||||
PaymentEnabled: paymentCfg.Enabled,
|
||||
PaymentMinAmount: paymentCfg.MinAmount,
|
||||
PaymentMaxAmount: paymentCfg.MaxAmount,
|
||||
PaymentDailyLimit: paymentCfg.DailyLimit,
|
||||
PaymentOrderTimeoutMin: paymentCfg.OrderTimeoutMin,
|
||||
PaymentMaxPendingOrders: paymentCfg.MaxPendingOrders,
|
||||
PaymentEnabledTypes: paymentCfg.EnabledTypes,
|
||||
PaymentBalanceDisabled: paymentCfg.BalanceDisabled,
|
||||
PaymentLoadBalanceStrat: paymentCfg.LoadBalanceStrategy,
|
||||
PaymentProductNamePrefix: paymentCfg.ProductNamePrefix,
|
||||
PaymentProductNameSuffix: paymentCfg.ProductNameSuffix,
|
||||
PaymentHelpImageURL: paymentCfg.HelpImageURL,
|
||||
PaymentHelpText: paymentCfg.HelpText,
|
||||
PaymentCancelRateLimitEnabled: paymentCfg.CancelRateLimitEnabled,
|
||||
PaymentCancelRateLimitMax: paymentCfg.CancelRateLimitMax,
|
||||
PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow,
|
||||
PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit,
|
||||
PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -268,6 +299,28 @@ type UpdateSettingsRequest struct {
|
||||
EnableFingerprintUnification *bool `json:"enable_fingerprint_unification"`
|
||||
EnableMetadataPassthrough *bool `json:"enable_metadata_passthrough"`
|
||||
EnableCCHSigning *bool `json:"enable_cch_signing"`
|
||||
|
||||
// Payment configuration (integrated into settings, full replace)
|
||||
PaymentEnabled *bool `json:"payment_enabled"`
|
||||
PaymentMinAmount *float64 `json:"payment_min_amount"`
|
||||
PaymentMaxAmount *float64 `json:"payment_max_amount"`
|
||||
PaymentDailyLimit *float64 `json:"payment_daily_limit"`
|
||||
PaymentOrderTimeoutMin *int `json:"payment_order_timeout_minutes"`
|
||||
PaymentMaxPendingOrders *int `json:"payment_max_pending_orders"`
|
||||
PaymentEnabledTypes []string `json:"payment_enabled_types"`
|
||||
PaymentBalanceDisabled *bool `json:"payment_balance_disabled"`
|
||||
PaymentLoadBalanceStrat *string `json:"payment_load_balance_strategy"`
|
||||
PaymentProductNamePrefix *string `json:"payment_product_name_prefix"`
|
||||
PaymentProductNameSuffix *string `json:"payment_product_name_suffix"`
|
||||
PaymentHelpImageURL *string `json:"payment_help_image_url"`
|
||||
PaymentHelpText *string `json:"payment_help_text"`
|
||||
|
||||
// Cancel rate limit
|
||||
PaymentCancelRateLimitEnabled *bool `json:"payment_cancel_rate_limit_enabled"`
|
||||
PaymentCancelRateLimitMax *int `json:"payment_cancel_rate_limit_max"`
|
||||
PaymentCancelRateLimitWindow *int `json:"payment_cancel_rate_limit_window"`
|
||||
PaymentCancelRateLimitUnit *string `json:"payment_cancel_rate_limit_unit"`
|
||||
PaymentCancelRateLimitMode *string `json:"payment_cancel_rate_limit_window_mode"`
|
||||
}
|
||||
|
||||
// UpdateSettings 更新系统设置
|
||||
@@ -822,6 +875,39 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Update payment configuration (integrated into system settings).
|
||||
// Skip if no payment fields were provided (prevents accidental wipe).
|
||||
if h.paymentConfigService != nil && hasPaymentFields(req) {
|
||||
paymentReq := service.UpdatePaymentConfigRequest{
|
||||
Enabled: req.PaymentEnabled,
|
||||
MinAmount: req.PaymentMinAmount,
|
||||
MaxAmount: req.PaymentMaxAmount,
|
||||
DailyLimit: req.PaymentDailyLimit,
|
||||
OrderTimeoutMin: req.PaymentOrderTimeoutMin,
|
||||
MaxPendingOrders: req.PaymentMaxPendingOrders,
|
||||
EnabledTypes: req.PaymentEnabledTypes,
|
||||
BalanceDisabled: req.PaymentBalanceDisabled,
|
||||
LoadBalanceStrategy: req.PaymentLoadBalanceStrat,
|
||||
ProductNamePrefix: req.PaymentProductNamePrefix,
|
||||
ProductNameSuffix: req.PaymentProductNameSuffix,
|
||||
HelpImageURL: req.PaymentHelpImageURL,
|
||||
HelpText: req.PaymentHelpText,
|
||||
CancelRateLimitEnabled: req.PaymentCancelRateLimitEnabled,
|
||||
CancelRateLimitMax: req.PaymentCancelRateLimitMax,
|
||||
CancelRateLimitWindow: req.PaymentCancelRateLimitWindow,
|
||||
CancelRateLimitUnit: req.PaymentCancelRateLimitUnit,
|
||||
CancelRateLimitMode: req.PaymentCancelRateLimitMode,
|
||||
}
|
||||
if err := h.paymentConfigService.UpdatePaymentConfig(c.Request.Context(), paymentReq); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
// Refresh in-memory provider registry so config changes take effect immediately
|
||||
if h.paymentService != nil {
|
||||
h.paymentService.RefreshProviders(c.Request.Context())
|
||||
}
|
||||
}
|
||||
|
||||
h.auditSettingsUpdate(c, previousSettings, settings, req)
|
||||
|
||||
// 重新获取设置返回
|
||||
@@ -838,6 +924,15 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// Reload payment config for response
|
||||
var updatedPaymentCfg *service.PaymentConfig
|
||||
if h.paymentConfigService != nil {
|
||||
updatedPaymentCfg, _ = h.paymentConfigService.GetPaymentConfig(c.Request.Context())
|
||||
}
|
||||
if updatedPaymentCfg == nil {
|
||||
updatedPaymentCfg = &service.PaymentConfig{}
|
||||
}
|
||||
|
||||
response.Success(c, dto.SystemSettings{
|
||||
RegistrationEnabled: updatedSettings.RegistrationEnabled,
|
||||
EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled,
|
||||
@@ -917,9 +1012,40 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
EnableFingerprintUnification: updatedSettings.EnableFingerprintUnification,
|
||||
EnableMetadataPassthrough: updatedSettings.EnableMetadataPassthrough,
|
||||
EnableCCHSigning: updatedSettings.EnableCCHSigning,
|
||||
PaymentEnabled: updatedPaymentCfg.Enabled,
|
||||
PaymentMinAmount: updatedPaymentCfg.MinAmount,
|
||||
PaymentMaxAmount: updatedPaymentCfg.MaxAmount,
|
||||
PaymentDailyLimit: updatedPaymentCfg.DailyLimit,
|
||||
PaymentOrderTimeoutMin: updatedPaymentCfg.OrderTimeoutMin,
|
||||
PaymentMaxPendingOrders: updatedPaymentCfg.MaxPendingOrders,
|
||||
PaymentEnabledTypes: updatedPaymentCfg.EnabledTypes,
|
||||
PaymentBalanceDisabled: updatedPaymentCfg.BalanceDisabled,
|
||||
PaymentLoadBalanceStrat: updatedPaymentCfg.LoadBalanceStrategy,
|
||||
PaymentProductNamePrefix: updatedPaymentCfg.ProductNamePrefix,
|
||||
PaymentProductNameSuffix: updatedPaymentCfg.ProductNameSuffix,
|
||||
PaymentHelpImageURL: updatedPaymentCfg.HelpImageURL,
|
||||
PaymentHelpText: updatedPaymentCfg.HelpText,
|
||||
PaymentCancelRateLimitEnabled: updatedPaymentCfg.CancelRateLimitEnabled,
|
||||
PaymentCancelRateLimitMax: updatedPaymentCfg.CancelRateLimitMax,
|
||||
PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow,
|
||||
PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit,
|
||||
PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode,
|
||||
})
|
||||
}
|
||||
|
||||
// hasPaymentFields returns true if any payment-related field was explicitly provided.
|
||||
func hasPaymentFields(req UpdateSettingsRequest) bool {
|
||||
return req.PaymentEnabled != nil || req.PaymentMinAmount != nil ||
|
||||
req.PaymentMaxAmount != nil || req.PaymentDailyLimit != nil ||
|
||||
req.PaymentOrderTimeoutMin != nil || req.PaymentMaxPendingOrders != nil ||
|
||||
req.PaymentEnabledTypes != nil || req.PaymentBalanceDisabled != nil ||
|
||||
req.PaymentLoadBalanceStrat != nil || req.PaymentProductNamePrefix != nil ||
|
||||
req.PaymentProductNameSuffix != nil || req.PaymentHelpImageURL != nil ||
|
||||
req.PaymentHelpText != nil || req.PaymentCancelRateLimitEnabled != nil ||
|
||||
req.PaymentCancelRateLimitMax != nil || req.PaymentCancelRateLimitWindow != nil ||
|
||||
req.PaymentCancelRateLimitUnit != nil || req.PaymentCancelRateLimitMode != nil
|
||||
}
|
||||
|
||||
func (h *SettingHandler) auditSettingsUpdate(c *gin.Context, before *service.SystemSettings, after *service.SystemSettings, req UpdateSettingsRequest) {
|
||||
if before == nil || after == nil {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user