82 lines
1.9 KiB
Go
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") }
|