Files
2026-09-15 12:46:29 +08:00

82 lines
1.9 KiB
Go

package payment
import (
"crypto/rand"
"fmt"
"math/big"
"strconv"
"strings"
"sync"
"time"
)
/* ---------------- 金额工具 ---------------- */
// FenToYuan 分 -> 元(两位小数字符串),供渠道下单参数使用
func FenToYuan(fen int64) string {
if fen < 0 {
fen = 0
}
return strconv.FormatInt(fen/100, 10) + "." + fmt.Sprintf("%02d", fen%100)
}
// YuanToFen 元(字符串)-> 分
func YuanToFen(yuan string) (int64, error) {
yuan = strings.TrimSpace(yuan)
if yuan == "" {
return 0, nil
}
f, err := strconv.ParseFloat(yuan, 64)
if err != nil {
return 0, fmt.Errorf("金额格式不正确: %s", yuan)
}
if f < 0 {
return 0, fmt.Errorf("金额不能为负数: %s", yuan)
}
return int64(f*100 + 0.5), nil
}
/* ---------------- 单号生成 ----------------
规则:前缀 + yyyyMMddHHmmss + 4 位随机数字(进程内串行生成,避免同秒碰撞;
落库仍有唯一键兜底,撞号时由调用方重试一次)。
支付单 P202609151024310001
退回单 R202609151024310001
佣金单 CM202609151024310001
对账批次 RC202609151024310001
---------------------------------------- */
var (
noMu sync.Mutex
lastNoTime int64
lastNoSeq int64
)
func nextSerial(prefix string) string {
noMu.Lock()
defer noMu.Unlock()
now := time.Now().Unix()
seq := int64(0)
if now == lastNoTime {
seq = lastNoSeq + 1
}
lastNoTime = now
lastNoSeq = seq
n, _ := rand.Int(rand.Reader, big.NewInt(10000))
return fmt.Sprintf("%s%s%04d%04d", prefix, time.Now().Format("20060102150405"), seq, n.Int64())
}
// NextPayNo 生成支付单号
func NextPayNo() string { return nextSerial("P") }
// NextRefundNo 生成退回单号
func NextRefundNo() string { return nextSerial("R") }
// NextCommissionNo 生成佣金单号
func NextCommissionNo() string { return nextSerial("CM") }
// NextBatchNo 生成对账批次号
func NextBatchNo() string { return nextSerial("RC") }