kra-new/internal/paymentkit/status.go

142 lines
3.8 KiB
Go

package paymentkit
import (
"encoding/json"
"fmt"
"net/url"
"strings"
)
func NormalizeStatus(value, fallback string) string {
switch strings.ToUpper(strings.TrimSpace(value)) {
case "SUCCESS", "OK", "PAID", "FULFILLED", "TRADE_SUCCESS", "TRADE_FINISHED", "COMPLETED", "PAY_SUCCESS", "REFUND_SUCCESS", "REFUNDED":
return "success"
case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "CLIENT_PENDING", "ACCEPT", "ACCEPTED", "PAYING":
return "pending"
case "CLOSED", "TRADE_CLOSED", "CANCELLED", "CANCELED", "REVOKED", "FAILED", "FAIL", "REJECTED", "DENIED", "DECLINED", "ERROR", "PAYERROR":
return "failed"
default:
return fallback
}
}
func NormalizeRefundStatus(value, fallback string) string {
switch strings.ToUpper(strings.TrimSpace(value)) {
case "SUCCESS", "OK", "PAID", "REFUND_SUCCESS", "REFUNDED", "COMPLETED", "FINISHED", "TRADE_SUCCESS":
return "success"
case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "ACCEPT", "ACCEPTED", "PAYING":
return "pending"
case "CLOSED", "TRADE_CLOSED", "CANCELLED", "CANCELED", "REVOKED", "REFUND", "FAILED", "FAIL", "REJECTED", "DENIED", "DECLINED", "ERROR", "PAYERROR":
return "failed"
default:
return fallback
}
}
// 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 {
return fallback
}
parsed, err := ParseIntegerAmount(strings.TrimSpace(toString(value)))
if err != nil || parsed <= 0 {
return fallback
}
return parsed
}
func ConfiguredValues(values map[string]any, key string) []string {
result := []string{}
for _, item := range strings.Split(toString(values[key]), ",") {
item = strings.ToUpper(strings.TrimSpace(item))
if item != "" {
result = append(result, item)
}
}
return result
}
func ContainsFold(values []string, value string) bool {
value = strings.ToUpper(strings.TrimSpace(value))
for _, item := range values {
if item == value {
return true
}
}
return false
}
func Text(values map[string]any, key string) string {
value, _ := values[key].(string)
return value
}
func FirstText(values map[string]any, keys ...string) string {
for _, key := range keys {
if value := Text(values, key); value != "" {
return value
}
}
return ""
}
func FirstString(values map[string]string, keys ...string) string {
for _, key := range keys {
if values[key] != "" {
return values[key]
}
}
return ""
}
// CallbackFields merges query parameters, form data, and top-level JSON
// strings using the same precedence for every payment boundary.
func CallbackFields(query, headers map[string]string, body []byte) map[string]string {
fields := make(map[string]string, len(query))
for key, value := range query {
fields[key] = value
}
contentType := ""
for key, value := range 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(body)); err == nil {
for key, value := range values {
if len(value) > 0 {
fields[key] = value[0]
}
}
}
}
var object map[string]any
if json.Unmarshal(body, &object) == nil {
for key, value := range object {
if text, ok := value.(string); ok {
fields[key] = text
}
}
}
return fields
}
func toString(value any) string {
if value == nil {
return ""
}
return strings.TrimSpace(strings.ReplaceAll(strings.TrimSpace(stringify(value)), "<nil>", ""))
}
func stringify(value any) string {
return fmt.Sprint(value)
}