package payment import ( "crypto/rand" "encoding/hex" "encoding/json" "fmt" "gorm.io/datatypes" "hfb_sys/backend/internal/model" "hfb_sys/backend/internal/timeutil" "math" "strings" "time" ) func toDTO(payment model.PaymentOrder) PaymentDTO { return PaymentDTO{ ID: payment.ID, PaymentNo: payment.PaymentNo, OrderID: payment.OrderID, OrderNo: payment.OrderNo, PaymentConfigID: payment.PaymentConfigID, Provider: payment.Provider, ThirdOrderID: payment.ThirdOrderID, ProviderOrderID: payment.ProviderOrderID, PayWay: payment.PayWay, JSPayFlag: payment.JSPayFlag, AmountCent: payment.AmountCent, Status: payment.Status, TDCode: payment.TDCode, JSPayURL: payment.JSPayURL, JSPayInfo: payment.JSPayInfo, Paid: payment.Status == "paid", PaidAt: payment.PaidAt, CreatedAt: payment.CreatedAt, UpdatedAt: payment.UpdatedAt, } } func paymentErrorSummary(status string, raw datatypes.JSON) (string, string) { if status != "failed" { return "", "" } if len(raw) == 0 { return "", "" } var payload map[string]any if err := json.Unmarshal(raw, &payload); err != nil { return "", "" } code := firstStringValue(payload, "code", "resp_code", "result_code", "error_code", "status") message := firstStringValue(payload, "msg", "message", "error", "error_message", "result_msg", "result_desc") return code, message } func moneyCent(value float64) int64 { return int64(math.Round(value * 100)) } func parseCent(value string) int64 { var amount int64 _, _ = fmt.Sscanf(value, "%d", &amount) return amount } func parseChannelTime(value string) *time.Time { if value == "" { return nil } for _, layout := range []string{"2006-01-02 15:04:05", "20060102150405", time.RFC3339} { parsed, err := time.ParseInLocation(layout, value, timeutil.ShanghaiLocation()) if err == nil { return &parsed } } return nil } func jsonMap(value map[string]string) datatypes.JSON { if value == nil { return nil } raw, err := json.Marshal(value) if err != nil { return nil } return datatypes.JSON(raw) } func withRawSource(raw map[string]string, source string) map[string]string { out := map[string]string{} for key, value := range raw { out[key] = value } if source != "" { out["_source"] = source } out["_recorded_at"] = time.Now().Format(time.RFC3339) return out } func jsonString(value map[string]string) string { if len(value) == 0 { return "{}" } raw, err := json.Marshal(value) if err != nil { return "{}" } return string(raw) } func newPaymentNo() (string, error) { buf := make([]byte, 4) if _, err := rand.Read(buf); err != nil { return "", err } return fmt.Sprintf("PAY%d%s", time.Now().UnixNano(), hex.EncodeToString(buf)), nil } func firstNonEmpty(values ...string) string { for _, value := range values { if value != "" { return value } } return "" } // firstNonZero 返回第一个非零 uint64,用于保留历史支付单已有配置 ID。 func firstNonZero(values ...uint64) uint64 { for _, value := range values { if value != 0 { return value } } return 0 } // normalizePayWay 将前端或渠道别名统一为系统内部支付方式编码。 func normalizePayWay(value string) string { switch strings.ToUpper(strings.TrimSpace(value)) { case "", "ZFBZF", "ALIPAY", "ALIPAYPAY": return "ZFBZF" case "WXZF", "WECHAT", "WECHATPAY": return "WXZF" default: return strings.ToUpper(strings.TrimSpace(value)) } }