kra-new/internal/integration/payment/result.go

137 lines
3.6 KiB
Go

package payment
import (
"encoding/json"
"errors"
"fmt"
bizpayment "kra/internal/biz/payment"
"net/url"
"strings"
"kra/internal/paymentkit"
)
func callbackFields(callback *bizpayment.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 {
return paymentkit.Text(values, key)
}
func firstAny(values map[string]any, keys ...string) string {
return paymentkit.FirstText(values, keys...)
}
// Compatibility shims keep channel adapters focused on protocol and
// persistence concerns while stateless parsing rules live in paymentkit.
func normalizePaymentStatus(value, fallback string) string {
return paymentkit.NormalizeStatus(value, fallback)
}
func parseIntegerAmount(value string) (int64, error) {
return paymentkit.ParseIntegerAmount(value)
}
func parseDecimalAmount(value string, scale int64) (int64, error) {
return paymentkit.ParseDecimalAmount(value, scale)
}
func formatDecimalAmount(amount, scale int64) (string, error) {
return paymentkit.FormatDecimalAmount(amount, scale)
}
func configuredInt64(values map[string]any, key string, fallback int64) int64 {
return paymentkit.ConfiguredInt64(values, key, fallback)
}
func jsonObject(raw []byte) map[string]any {
return paymentkit.JSONObject(raw)
}
func valueAtPath(value any, path string) any {
return paymentkit.ValueAtPath(value, path)
}
func stringAtPath(value any, path string) string {
return paymentkit.StringAtPath(value, path)
}
func configuredValues(values map[string]any, key string) []string {
return paymentkit.ConfiguredValues(values, key)
}
func containsFold(values []string, value string) bool {
return paymentkit.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
}