Update mengyastore

This commit is contained in:
2026-05-13 12:11:46 +08:00
parent ad54b1eb7e
commit 37983f3b60
156 changed files with 10064 additions and 5681 deletions

View File

@@ -0,0 +1,143 @@
package payment
import (
"bytes"
"encoding/json"
"fmt"
"math"
"regexp"
"strconv"
"strings"
)
// 依次尝试:微信等常带 ¥支付宝等到账文案多为「收款x.xx元」无货币符号。
var mengyaNoticeAmountPatterns = []*regexp.Regexp{
regexp.MustCompile(`到账[¥¥]\s*([\d]+(?:\.[\d]+)?)`),
regexp.MustCompile(`到账\s*([\d]+(?:\.[\d]+)?)\s*元`),
regexp.MustCompile(`收款[¥¥]\s*([\d]+(?:\.[\d]+)?)(?:\s*元)?`),
regexp.MustCompile(`收款\s*([\d]+(?:\.[\d]+)?)\s*元`),
}
// AmountEpsilonWebhook 到账金额与订单快照金额对比时的容差。
const AmountEpsilon = 0.005
func AmountAlmostEqual(expected, actual float64) bool {
return math.Abs(expected-actual) < AmountEpsilon
}
// ParseWebhookJSON 从转发通知体中解析支付金额:
// 优先 body.notice其次顶层 notice否则在序列化后的 JSON 字符串中扫描。
func ParseWebhookJSON(raw []byte) (float64, bool) {
if len(bytes.TrimSpace(raw)) == 0 {
return 0, false
}
var top map[string]json.RawMessage
if err := json.Unmarshal(raw, &top); err != nil {
return scanAmount(string(raw))
}
if v, ok := top["notice"]; ok {
if s := jsonString(v); s != "" {
return scanAmount(s)
}
}
if inner, ok := top["body"]; ok {
var nested map[string]json.RawMessage
if json.Unmarshal(inner, &nested) == nil {
if v, ok := nested["notice"]; ok {
if s := jsonString(v); s != "" {
return scanAmount(s)
}
}
if amt, ok := scanAmount(jsonString(inner)); ok {
return amt, ok
}
return scanAmount(string(inner))
}
if amt, ok := scanAmount(strings.Trim(strings.Trim(string(inner), "\""), `"`)); ok {
return amt, ok
}
return scanAmount(string(inner))
}
buf, _ := json.Marshal(top)
return scanAmount(string(buf))
}
func jsonString(raw json.RawMessage) string {
var s string
if json.Unmarshal(raw, &s) == nil {
return s
}
return ""
}
func scanAmount(text string) (float64, bool) {
if amt, ok := parseAmountRegex(text); ok {
return amt, true
}
return parseAmountRegex(strings.ReplaceAll(text, `\n`, "\n"))
}
func parseAmountRegex(text string) (float64, bool) {
for _, re := range mengyaNoticeAmountPatterns {
match := re.FindStringSubmatch(text)
if len(match) < 2 {
continue
}
s := strings.ReplaceAll(match[1], ",", "")
yuan, err := strconv.ParseFloat(s, 64)
if err != nil {
continue
}
return yuan, true
}
return 0, false
}
// NoticeFieldsForLog 从常见萌芽/转发 JSON 里抽出 notice 等字段,仅供后台日志排查(如微信/支付宝文案差异)。
func NoticeFieldsForLog(raw []byte) string {
if len(bytes.TrimSpace(raw)) == 0 {
return ""
}
var top map[string]json.RawMessage
if err := json.Unmarshal(raw, &top); err != nil {
return ""
}
var parts []string
add := func(k, v string) {
if v == "" {
return
}
if len(v) > 600 {
v = v[:600] + "…"
}
parts = append(parts, fmt.Sprintf("%s=%s", k, strconv.Quote(v)))
}
if v, ok := top["notice"]; ok {
add("notice", jsonString(v))
}
if inner, ok := top["body"]; ok {
var nested map[string]json.RawMessage
if json.Unmarshal(inner, &nested) == nil {
if v, ok := nested["notice"]; ok {
add("body.notice", jsonString(v))
}
if v, ok := nested["content"]; ok {
add("body.content", jsonString(v))
}
if v, ok := nested["text"]; ok {
add("body.text", jsonString(v))
}
} else if s := jsonString(inner); s != "" {
add("body(string)", s)
}
}
for _, k := range []string{"title", "msg", "message", "desc", "description"} {
if v, ok := top[k]; ok {
add(k, jsonString(v))
}
}
if len(parts) == 0 {
return ""
}
return strings.Join(parts, "; ")
}

View File

@@ -0,0 +1,3 @@
package payment
const MethodMengya = "mengya"