优化结构

This commit is contained in:
Yvan
2026-08-28 10:21:59 +08:00
parent a16d362bb5
commit fec3820464
19 changed files with 138 additions and 136 deletions
@@ -213,6 +213,11 @@ func DefaultIntegrationConfig(kind, provider string) map[string]any {
}
func mergeIntegrationDefaults(defaults, values map[string]any) map[string]any {
return MergeIntegrationDefaults(defaults, values)
}
// MergeIntegrationDefaults returns a new map with stored values overriding defaults.
func MergeIntegrationDefaults(defaults, values map[string]any) map[string]any {
out := make(map[string]any, len(defaults)+len(values))
for key, value := range defaults {
out[key] = value
+36 -36
View File
@@ -158,51 +158,51 @@ type PaymentConfirmation struct {
}
type PaymentResult struct {
Provider string `json:"provider"`
Status string `json:"status"`
TradeNo string `json:"tradeNo"`
ProviderTradeNo string `json:"providerTradeNo"`
Amount int64 `json:"amount"`
PayerPaidAmount int64 `json:"payerPaidAmount,omitempty"`
CashPaidAmount int64 `json:"cashPaidAmount,omitempty"`
PointPaidAmount int64 `json:"pointPaidAmount,omitempty"`
DiscountAmount int64 `json:"discountAmount,omitempty"`
ProviderDiscountAmount int64 `json:"providerDiscountAmount,omitempty"`
MerchantDiscountAmount int64 `json:"merchantDiscountAmount,omitempty"`
SettlementAmount int64 `json:"settlementAmount,omitempty"`
Currency string `json:"currency"`
PayerCurrency string `json:"payerCurrency,omitempty"`
AmountBreakdownKnown bool `json:"amountBreakdownKnown"`
Duplicate bool `json:"duplicate"`
Payload json.RawMessage `json:"payload"`
OrderStatus string `json:"orderStatus,omitempty"`
FulfillmentStatus string `json:"fulfillmentStatus,omitempty"`
RefundStatus string `json:"refundStatus,omitempty"`
EventID string `json:"-"`
QueryID string `json:"-"`
SuccessAck PaymentCallbackAck `json:"-"`
FailureAck PaymentCallbackAck `json:"-"`
Provider string
Status string
TradeNo string
ProviderTradeNo string
Amount int64
PayerPaidAmount int64
CashPaidAmount int64
PointPaidAmount int64
DiscountAmount int64
ProviderDiscountAmount int64
MerchantDiscountAmount int64
SettlementAmount int64
Currency string
PayerCurrency string
AmountBreakdownKnown bool
Duplicate bool
Payload json.RawMessage
OrderStatus string
FulfillmentStatus string
RefundStatus string
EventID string
QueryID string
SuccessAck PaymentCallbackAck
FailureAck PaymentCallbackAck
}
// PaymentTestStage is one step of a provider connectivity test. A skipped
// query/refund is reported explicitly because a prepay flow cannot be marked
// paid without a sandbox payer interaction.
type PaymentTestStage struct {
Name string `json:"name"`
Status string `json:"status"`
Message string `json:"message,omitempty"`
TradeNo string `json:"tradeNo,omitempty"`
Duration int64 `json:"durationMs,omitempty"`
Name string
Status string
Message string
TradeNo string
Duration int64
}
type PaymentTestResult struct {
Provider string `json:"provider"`
TradeNo string `json:"tradeNo"`
Passed bool `json:"passed"`
FullFlow bool `json:"fullFlow"`
Mode string `json:"mode,omitempty"`
Stages []PaymentTestStage `json:"stages"`
Result *PaymentResult `json:"result,omitempty"`
Provider string
TradeNo string
Passed bool
FullFlow bool
Mode string
Stages []PaymentTestStage
Result *PaymentResult
}
type PaymentCallbackAck struct {
-20
View File
@@ -1,20 +0,0 @@
package system
import "context"
type AccessControlUsecase struct {
authorities AuthorityAccessRepo
apis APIRepo
}
func NewAccessControlUsecase(authorities AuthorityAccessRepo, apis APIRepo) *AccessControlUsecase {
return &AccessControlUsecase{authorities: authorities, apis: apis}
}
func (uc *AccessControlUsecase) Authorize(ctx context.Context, authorityID uint, path, method string) (bool, error) {
return uc.apis.Authorize(ctx, authorityID, path, method)
}
func (uc *AccessControlUsecase) ResolveDataScope(ctx context.Context, authorityID, userID uint) (DataScope, error) {
return uc.authorities.ResolveDataScope(ctx, authorityID, userID)
}
+17
View File
@@ -45,6 +45,23 @@ func NewAuthorityUsecase(repo AuthorityAccessRepo) *AuthorityUsecase {
return &AuthorityUsecase{AuthorityAccessRepo: repo}
}
type AccessControlUsecase struct {
authorities AuthorityAccessRepo
apis APIRepo
}
func NewAccessControlUsecase(authorities AuthorityAccessRepo, apis APIRepo) *AccessControlUsecase {
return &AccessControlUsecase{authorities: authorities, apis: apis}
}
func (uc *AccessControlUsecase) Authorize(ctx context.Context, authorityID uint, path, method string) (bool, error) {
return uc.apis.Authorize(ctx, authorityID, path, method)
}
func (uc *AccessControlUsecase) ResolveDataScope(ctx context.Context, authorityID, userID uint) (DataScope, error) {
return uc.authorities.ResolveDataScope(ctx, authorityID, userID)
}
func (uc *AuthorityUsecase) AuthorityTree(ctx context.Context) ([]*Authority, error) {
items, err := uc.ListAuthorities(ctx)
if err != nil {
+19
View File
@@ -21,6 +21,25 @@ type MediaRepo interface {
UploadRepo
}
type StoredFile struct {
Name string
Path string
URL string
Size int64
LastModified time.Time
ContentType string
}
// FileStorage owns the persistence boundary for uploaded files.
type FileStorage interface {
Put(context.Context, string, io.Reader) (*StoredFile, error)
Open(context.Context, string) (io.ReadCloser, error)
Delete(context.Context, string) error
Compose(context.Context, []string, string) (*StoredFile, string, error)
DeletePrefix(context.Context, string) error
List(context.Context, string, string, int) ([]*StoredFile, string, bool, error)
}
type MediaUsecase struct {
MediaRepo
files FileStorage
+11 -6
View File
@@ -6,13 +6,18 @@ import (
)
type SystemParameter struct {
ID uint
CreatedAt time.Time
UpdatedAt time.Time
ID uint
CreatedAt time.Time
UpdatedAt time.Time
Name string
Key string
Value string
Desc string
}
type SystemParameterFilter struct {
Name string
Key string
Value string
Desc string
StartCreatedAt *time.Time
EndCreatedAt *time.Time
}
@@ -23,7 +28,7 @@ type ParameterRepo interface {
DeleteParameters(context.Context, []string) error
FindParameterByID(context.Context, string) (*SystemParameter, error)
FindParameterByKey(context.Context, string) (*SystemParameter, error)
ListParameters(context.Context, int, int, *SystemParameter) ([]*SystemParameter, int64, error)
ListParameters(context.Context, int, int, *SystemParameterFilter) ([]*SystemParameter, int64, error)
}
type ParameterUsecase struct{ ParameterRepo }
-26
View File
@@ -1,26 +0,0 @@
package system
import (
"context"
"io"
"time"
)
type StoredFile struct {
Name string
Path string
URL string
Size int64
LastModified time.Time
ContentType string
}
// FileStorage owns the persistence boundary for uploaded files.
type FileStorage interface {
Put(context.Context, string, io.Reader) (*StoredFile, error)
Open(context.Context, string) (io.ReadCloser, error)
Delete(context.Context, string) error
Compose(context.Context, []string, string) (*StoredFile, string, error)
DeletePrefix(context.Context, string) error
List(context.Context, string, string, int) ([]*StoredFile, string, bool, error)
}
+4 -7
View File
@@ -3,6 +3,7 @@ package integration
import (
"encoding/json"
"errors"
"reflect"
integrationbiz "kra/internal/biz/integration"
"kra/pkg/database/migration"
@@ -66,13 +67,9 @@ func ensurePaymentIntegrationConfigs(db *gorm.DB) error {
return err
}
values := integrationObject(json.RawMessage(row.Config))
changed := false
for key, value := range defaults {
if _, exists := values[key]; !exists {
values[key] = value
changed = true
}
}
merged := integrationbiz.MergeIntegrationDefaults(defaults, values)
changed := !reflect.DeepEqual(values, merged)
values = merged
if changed {
encoded, marshalErr := json.Marshal(values)
if marshalErr != nil {
+1 -1
View File
@@ -57,7 +57,7 @@ func (r *parameterRepo) FindParameterByKey(ctx context.Context, key string) (*sy
}
return parameterFromPO(po), nil
}
func (r *parameterRepo) ListParameters(ctx context.Context, page, size int, q *system.SystemParameter) ([]*system.SystemParameter, int64, error) {
func (r *parameterRepo) ListParameters(ctx context.Context, page, size int, q *system.SystemParameterFilter) ([]*system.SystemParameter, int64, error) {
db := r.data.DB().WithContext(ctx).Model(&parameterPO{})
if q != nil {
if q.StartCreatedAt != nil && q.EndCreatedAt != nil {
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
bizpayment "kra/internal/biz/payment"
"kra/internal/paymentkit"
"net/http"
"net/url"
"strings"
@@ -435,7 +436,7 @@ func alipayCreateMethod(extra, config map[string]any) (string, error) {
if value == "" {
value = firstAny(config, "method", "pay_method", "trade_type", "channel")
}
normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
normalized := paymentkit.NormalizePaymentMethod(value)
switch normalized {
case "", "create", "trade_create", "alipay_trade_create", "jsapi", "miniapp", "mini_program":
return "alipay.trade.create", nil
+2 -1
View File
@@ -12,6 +12,7 @@ import (
"fmt"
"io"
bizpayment "kra/internal/biz/payment"
"kra/internal/paymentkit"
"net/http"
"strings"
"sync"
@@ -207,7 +208,7 @@ func allinpayCreateMethod(extra, config map[string]any) (string, error) {
if value == "" {
value = firstAny(config, "method", "pay_method", "trade_type")
}
normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
normalized := paymentkit.NormalizePaymentMethod(value)
switch normalized {
case "", "pay", "unified", "unified_pay":
return "pay", nil
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
bizpayment "kra/internal/biz/payment"
"kra/internal/paymentkit"
"strings"
"github.com/go-pay/gopay"
@@ -110,7 +111,7 @@ func douyinCreateMethod(extra, config map[string]any) (string, error) {
if value == "" {
value = firstAny(config, "method", "pay_method", "trade_type", "pay_type", "channel")
}
normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
normalized := paymentkit.NormalizePaymentMethod(value)
switch normalized {
case "", "jsapi", "js_api", "mini", "mini_program", "miniprogram", "applet":
return "jsapi", nil
+2 -1
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
bizpayment "kra/internal/biz/payment"
"kra/internal/paymentkit"
"strings"
"github.com/go-pay/gopay"
@@ -71,7 +72,7 @@ func lakalaCreateMethod(extra, config map[string]any) string {
if method == "" {
method = firstAny(config, "method", "pay_method", "trade_type")
}
return strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(method)))
return paymentkit.NormalizePaymentMethod(method)
}
func lakalaCreateResult(tradeNo string, rsp *lakala.PaymentRsp) (*bizpayment.PaymentResult, error) {
+2 -1
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
bizpayment "kra/internal/biz/payment"
"kra/internal/paymentkit"
"strings"
"time"
@@ -89,7 +90,7 @@ func saobeiCreateMethod(extra, config map[string]any) (string, error) {
if value == "" {
value = firstAny(config, "method", "pay_method", "trade_type")
}
normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
normalized := paymentkit.NormalizePaymentMethod(value)
switch normalized {
case "", "mini", "mini_pay", "miniapp", "mini_app", "mini_program", "miniprogram", "jsapi", "js_api":
return "mini", nil
+2 -1
View File
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
bizpayment "kra/internal/biz/payment"
"kra/internal/paymentkit"
"net/http"
"net/url"
"strings"
@@ -180,7 +181,7 @@ func wechatV2CreateMethod(extra, config map[string]any) (string, error) {
if value == "" {
value = firstAny(config, "trade_type", "pay_type", "method", "pay_method", "channel")
}
normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
normalized := paymentkit.NormalizePaymentMethod(value)
switch normalized {
case "", "jsapi", "js_api", "mini", "miniapp", "mini_program", "miniprogram", "applet":
return gopayWechat.TradeType_JsApi, nil
+6
View File
@@ -33,6 +33,12 @@ func NormalizeRefundStatus(value, fallback string) string {
}
}
// NormalizePaymentMethod canonicalizes provider method identifiers while
// leaving provider-specific classification to the integration adapter.
func NormalizePaymentMethod(value string) string {
return strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
}
func ConfiguredInt64(values map[string]any, key string, fallback int64) int64 {
value, ok := values[key]
if !ok {
@@ -84,15 +84,9 @@ func (s *IntegrationConfigService) Delete(ctx context.Context, kind, provider st
}
func mergeConfigJSON(defaults map[string]any, raw json.RawMessage) json.RawMessage {
values := make(map[string]any, len(defaults))
for key, value := range defaults {
values[key] = value
}
stored := map[string]any{}
_ = json.Unmarshal(raw, &stored)
for key, value := range stored {
values[key] = value
}
values := integrationbiz.MergeIntegrationDefaults(defaults, stored)
encoded, _ := json.Marshal(values)
return encoded
}
+2 -2
View File
@@ -24,12 +24,12 @@ func (s *ParameterService) UpdateParameterRequest(ctx context.Context, req *dto.
return s.UpdateParameter(ctx, parameterDomain(req))
}
func (s *ParameterService) ParametersFilter(ctx context.Context, page, size int, name, key string, start, end *time.Time) ([]*dto.SystemParameterResponse, int64, error) {
return s.Parameters(ctx, page, size, &system.SystemParameter{Name: name, Key: key, StartCreatedAt: start, EndCreatedAt: end})
return s.Parameters(ctx, page, size, &system.SystemParameterFilter{Name: name, Key: key, StartCreatedAt: start, EndCreatedAt: end})
}
func parameterDTO(v *system.SystemParameter) *dto.SystemParameterResponse {
return &dto.SystemParameterResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, Key: v.Key, Value: v.Value, Desc: v.Desc}
}
func (s *ParameterService) Parameters(ctx context.Context, page, size int, q *system.SystemParameter) ([]*dto.SystemParameterResponse, int64, error) {
func (s *ParameterService) Parameters(ctx context.Context, page, size int, q *system.SystemParameterFilter) ([]*dto.SystemParameterResponse, int64, error) {
items, total, err := s.uc.ListParameters(ctx, page, size, q)
if err != nil {
return nil, 0, err