package wechat import ( "context" "encoding/json" "os" "time" "bsm/full/module/finance/wallet/internal/config" "bsm/full/module/finance/wallet/internal/excode" "github.com/go-pay/gopay" "github.com/go-pay/gopay/wechat/v3" ) type WeChatPay struct { ctx context.Context Client *wechat.ClientV3 Body *gopay.BodyMap } var ( mchID string SerialNumber string mchAPIv3Key string ApiClientKey string AppId string Currency string NotifyUrl string ) func new() { mchID = config.Spec.WeChat.MchID // 商户号 SerialNumber = config.Spec.WeChat.SerialNo // 商户证书序列号 mchAPIv3Key = config.Spec.WeChat.APIV3Key // 商户APIv3密钥 ApiClientKey = config.Spec.WeChat.PrivateKey // 私钥 AppId = config.Spec.WeChat.AppID // Appid Currency = config.Spec.WeChat.Currency // 货币类型 CNY:人民币,境内商户号仅支持人民币。 NotifyUrl = config.Spec.WeChat.NotifyURL // 通知URL必须为直接可访问的URL,不允许携带查询串,要求必须为https地址。 } func NewWechat() (*WeChatPay, error) { new() // NewClientV3 初始化微信客户端 v3 // mchid:商户ID 或者服务商模式的 sp_mchid // serialNo:商户证书的证书序列号 // apiV3Key:apiV3Key,商户平台获取 // privateKey:私钥 apiclient_key.pem 读取后的内容 privateKey, err := os.ReadFile(ApiClientKey) if err != nil { return nil, err } client, err := wechat.NewClientV3(mchID, SerialNumber, mchAPIv3Key, string(privateKey)) if err != nil { return nil, err } // 设置微信平台API证书和序列号(如开启自动验签,请忽略此步骤) //client.SetPlatformCert([]byte(""), "") // 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号) err = client.AutoVerifySign() if err != nil { return nil, err } // 打开Debug开关,输出日志,默认是关闭的 client.DebugSwitch = gopay.DebugOn return &WeChatPay{ ctx: context.Background(), Client: client, }, nil } // GetResponse tradeNo:finance_payment表的identity func (srv *WeChatPay) GetResponse(Attach, OrderNo, desc, openid string, amount int64) (*wechat.Prepay, error) { expire := time.Now().Add(60 * time.Minute).Format(time.RFC3339) // 初始化 BodyMap bm := make(gopay.BodyMap) bm.Set("appid", AppId). Set("mchid", mchID). Set("description", desc). Set("attach", Attach). //finance_payment表的identity 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段 Set("out_trade_no", OrderNo). Set("time_expire", expire). Set("notify_url", NotifyUrl). SetBodyMap("amount", func(bm gopay.BodyMap) { bm.Set("total", amount). Set("currency", Currency) }). SetBodyMap("payer", func(bm gopay.BodyMap) { bm.Set("openid", openid) }) wxRsp, err := srv.Client.V3TransactionJsapi(srv.ctx, bm) if err != nil { return nil, err } return wxRsp.Response, nil } func (srv *WeChatPay) MiniPaySign(prepayid string) (map[string]string, error) { applet, err := srv.Client.PaySignOfApplet(AppId, prepayid) if err != nil { return nil, err } reply, err := struct2map(applet) if err != nil { return nil, err } return reply, nil } func (srv *WeChatPay) AppPaySign(prepayid string) (map[string]string, error) { app, err := srv.Client.PaySignOfApp(AppId, prepayid) if err != nil { return nil, err } reply, err := struct2map(app) if err != nil { return nil, err } return reply, nil } func (srv *WeChatPay) JsapiPaySign(prepayid string) (map[string]string, error) { jsapi, err := srv.Client.PaySignOfJSAPI(AppId, prepayid) if err != nil { return nil, err } reply, err := struct2map(jsapi) if err != nil { return nil, err } return reply, nil } func (srv *WeChatPay) NativePaySign(Attach, OrderNo, description, expire, openid string, amount int64) (map[string]string, error) { // 初始化 BodyMap body := make(gopay.BodyMap) body.Set("appid", AppId). Set("mchid", mchID). Set("description", description). Set("attach", Attach). //finance_payment表的identity 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段 Set("out_trade_no", OrderNo). Set("time_expire", expire). Set("notify_url", NotifyUrl). SetBodyMap("amount", func(bm gopay.BodyMap) { bm.Set("total", amount). Set("currency", Currency) }). SetBodyMap("payer", func(bm gopay.BodyMap) { bm.Set("openid", openid) }) native, err := srv.Client.V3TransactionNative(srv.ctx, body) if err != nil { return nil, err } reply, err := struct2map(native) if err != nil { return nil, err } return reply, nil } func struct2map(in any) (map[string]string, error) { b, err := json.Marshal(in) var m map[string]string err = json.Unmarshal(b, &m) return m, err } func CheckParam(amount int64, auth_code string, identity string, order_no string) (err error) { if amount == 0 { return excode.ErrAmount } if auth_code == "" { return excode.ErrAuthCode } if identity == "" { return excode.ErrPassportId } if order_no == "" { return excode.ErrOrderNo } return nil }