156 lines
4.1 KiB
Go
156 lines
4.1 KiB
Go
package payment
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"kra/app/system/internal/biz"
|
|
"kra/pkg/paymentkit"
|
|
)
|
|
|
|
func callbackFields(callback *biz.PaymentCallback) map[string]string {
|
|
fields := map[string]string{}
|
|
if callback == nil {
|
|
return fields
|
|
}
|
|
for key, value := range callback.Query {
|
|
fields[key] = value
|
|
}
|
|
contentType := ""
|
|
for key, value := range callback.Headers {
|
|
if strings.EqualFold(key, "Content-Type") {
|
|
contentType = strings.ToLower(value)
|
|
break
|
|
}
|
|
}
|
|
if strings.Contains(contentType, "application/x-www-form-urlencoded") {
|
|
if values, err := url.ParseQuery(string(callback.Body)); err == nil {
|
|
for key, value := range values {
|
|
if len(value) > 0 {
|
|
fields[key] = value[0]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var object map[string]any
|
|
if json.Unmarshal(callback.Body, &object) == nil {
|
|
for key, value := range object {
|
|
if stringValue, ok := value.(string); ok {
|
|
fields[key] = stringValue
|
|
}
|
|
}
|
|
}
|
|
return fields
|
|
}
|
|
|
|
func first(values map[string]string, keys ...string) string {
|
|
for _, key := range keys {
|
|
if values[key] != "" {
|
|
return values[key]
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func text(values map[string]any, key string) string {
|
|
value, _ := values[key].(string)
|
|
return value
|
|
}
|
|
|
|
func firstAny(values map[string]any, keys ...string) string {
|
|
for _, key := range keys {
|
|
if value, ok := values[key].(string); ok && value != "" {
|
|
return value
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Compatibility shims keep channel adapters focused on protocol and
|
|
// persistence concerns while stateless parsing rules live in paymentutil.
|
|
func normalizePaymentStatus(value, fallback string) string {
|
|
return paymentutil.NormalizeStatus(value, fallback)
|
|
}
|
|
|
|
func parseIntegerAmount(value string) (int64, error) {
|
|
return paymentutil.ParseIntegerAmount(value)
|
|
}
|
|
|
|
func parseDecimalAmount(value string, scale int64) (int64, error) {
|
|
return paymentutil.ParseDecimalAmount(value, scale)
|
|
}
|
|
|
|
func formatDecimalAmount(amount, scale int64) (string, error) {
|
|
return paymentutil.FormatDecimalAmount(amount, scale)
|
|
}
|
|
|
|
func configuredInt64(values map[string]any, key string, fallback int64) int64 {
|
|
return paymentutil.ConfiguredInt64(values, key, fallback)
|
|
}
|
|
|
|
func jsonObject(raw []byte) map[string]any {
|
|
return paymentutil.JSONObject(raw)
|
|
}
|
|
|
|
func nestedString(value any, keys ...string) string {
|
|
return paymentutil.NestedString(value, keys...)
|
|
}
|
|
|
|
func valueAtPath(value any, path string) any {
|
|
return paymentutil.ValueAtPath(value, path)
|
|
}
|
|
|
|
func stringAtPath(value any, path string) string {
|
|
return paymentutil.StringAtPath(value, path)
|
|
}
|
|
|
|
func configuredValues(values map[string]any, key string) []string {
|
|
return paymentutil.ConfiguredValues(values, key)
|
|
}
|
|
|
|
func containsFold(values []string, value string) bool {
|
|
return paymentutil.ContainsFold(values, value)
|
|
}
|
|
|
|
// parseConfiguredAmount reads a provider amount field using an explicit unit
|
|
// conversion. Missing fields are reported separately so callers can avoid
|
|
// manufacturing a complete breakdown from incomplete provider responses.
|
|
func parseConfiguredAmount(object any, config map[string]any, fieldKey, scaleKey string, fallbackScale int64) (int64, bool, error) {
|
|
path := strings.TrimSpace(text(config, fieldKey))
|
|
if path == "" {
|
|
return 0, false, nil
|
|
}
|
|
raw := valueAtPath(object, path)
|
|
if raw == nil || strings.TrimSpace(fmt.Sprint(raw)) == "" || strings.EqualFold(strings.TrimSpace(fmt.Sprint(raw)), "<nil>") {
|
|
return 0, false, nil
|
|
}
|
|
value := strings.TrimSpace(fmt.Sprint(raw))
|
|
scale := configuredInt64(config, scaleKey, fallbackScale)
|
|
if scale <= 0 {
|
|
return 0, false, errors.New("支付金额换算比例无效")
|
|
}
|
|
amount, err := parseIntegerAmount(value)
|
|
if scale != 1 {
|
|
amount, err = parseDecimalAmount(value, scale)
|
|
}
|
|
if err != nil {
|
|
return 0, true, err
|
|
}
|
|
if amount < 0 {
|
|
return 0, true, errors.New("支付金额不能为负数")
|
|
}
|
|
return amount, true, nil
|
|
}
|
|
|
|
func amountFromDecimalField(values map[string]any, key string, fallback int64) (int64, bool, error) {
|
|
value := strings.TrimSpace(fmt.Sprint(values[key]))
|
|
if value == "" || value == "<nil>" {
|
|
return 0, false, nil
|
|
}
|
|
amount, err := parseDecimalAmount(value, fallback)
|
|
return amount, true, err
|
|
}
|