package talent_service import ( "context" "fmt" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" "github.com/gogf/gf/os/glog" "github.com/gogf/gf/os/gtime" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/core/option" "github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi" wxUtils "github.com/wechatpay-apiv3/wechatpay-go/utils" "math/rand" "strconv" "time" "youngmini_server/app/dao" "youngmini_server/app/model" "youngmini_server/app/model/talent_model" "youngmini_server/app/utils" ) var ( mchID string = "1615933939" // 商户号 mchCertificateSerialNumber string = "636DC3B258E436FAD123DAC6453E485CCDBF8770" // 商户证书序列号 mchAPIv3Key string = "zwbx8iae5llhpwj48guterlpodt3xngo" // 商户APIv3密钥 keyFilePath string = "./config/secret/apiclient_key.pem" // 密钥文件路径 ) func generatePayOrderNumber(talentId int) string { orderNo := gtime.Now().Format("YmdHis") rand.Seed(time.Now().UnixNano()) r := rand.Intn(899) orderNo += strconv.Itoa(r + 100) orderNo += fmt.Sprintf("%04d", talentId) return orderNo } func WxPayOnTalentRequestPay(r *ghttp.Request) *TalentHttpResult { tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) if err != nil { return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} } // 获取上传参数 var payInfo *talent_model.WxPrepayRequestData err = r.ParseForm(&payInfo) if err != nil { return &TalentHttpResult{Code: -2, Msg: "param error"} } // 获取达人信息 var talentInfo *model.TalentInfo err = g.DB().Model(dao.TalentInfo.Table).Scan(&talentInfo, dao.TalentInfo.Columns.Id, tid) if err != nil { return &TalentHttpResult{Code: -3, Msg: "query talent info failed"} } if talentInfo.InBlacklist >= 1 { return &TalentHttpResult{Code: -4, Msg: "talent in blacklist"} } // 获取任务信息 var taskInfo *talent_model.TaskDetail err = g.DB().Model(dao.TaskBaseInfo.Table).WithAll().Where(dao.TaskBaseInfo.Columns.TaskId, payInfo.TaskId).Scan(&taskInfo) if err != nil || taskInfo == nil { return &TalentHttpResult{Code: -5, Msg: "query task info failed"} } // 任务当前不是执行状态,返回 if taskInfo.TaskStatus != 2 { return &TalentHttpResult{Code: -6, Msg: "task can not sign up"} } // 任务已截止报名 if taskInfo.DeadlineTime.Before(gtime.Now()) { return &TalentHttpResult{Code: -7, Msg: "task sign up has finished"} } // 如果任务不需要拍单,或拍单方式为不拍单则返回 if taskInfo.IsBuySamples == nil || taskInfo.IsBuySamples.BuySamplesType != 1 { return &TalentHttpResult{Code: -8, Msg: "task do not need buy samples"} } // 任务拍单费用和上传的拍单费用不符,返回 if taskInfo.IsBuySamples.BuySamplesCost != payInfo.BuySamplesCost { return &TalentHttpResult{Code: -9, Msg: "task buy samples cost != input cost"} } mchPrivateKey, err := wxUtils.LoadPrivateKeyWithPath(keyFilePath) if err != nil { glog.Error("load merchant private key error") return &TalentHttpResult{Code: -10, Msg: "load client key failed"} } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { glog.Error("new wechat pay client err:", err) return &TalentHttpResult{Code: -11, Msg: "create client failed"} } orderNumber := generatePayOrderNumber(talentInfo.Id) svc := jsapi.JsapiApiService{Client: client} // 得到prepay_id,以及调起支付所需的参数和签名 resp, result, err := svc.PrepayWithRequestPayment(ctx, jsapi.PrepayRequest{ Appid: core.String(g.Config().GetString("miniapp.appid")), Mchid: core.String(mchID), Description: core.String("拍单费用_" + strconv.Itoa(taskInfo.TaskId) + "_" +taskInfo.TaskName + "_" + payInfo.PlatformNickname), OutTradeNo: core.String(orderNumber), Attach: core.String("报名任务拍单费用"), NotifyUrl: core.String("https://www.weixin.qq.com/wxpay/pay.php"), Amount: &jsapi.Amount{ Total: core.Int64(payInfo.BuySamplesCost), }, Payer: &jsapi.Payer{ Openid: core.String(talentInfo.TalentWxOpenid), }, }, ) if err != nil { // 处理错误 glog.Error("call Prepay err:%s", err) return &TalentHttpResult{Code: -12, Msg: "request prepay info failed"} } // 处理返回结果 glog.Println("status=%d resp=%s", result.Response.StatusCode, resp) if result.Response.StatusCode != 200 { glog.Println(result.Response) } // 将支付记录写入数据库 _, err = g.DB().Model(dao.WxPayOrder.Table).Insert(model.WxPayOrder{ OutTradeNo: orderNumber, WxOrderNo: "", PayAmount: payInfo.BuySamplesCost, TaskName: taskInfo.TaskName, PayReason: 1, TalentId: talentInfo.Id, TalentWxNickname: talentInfo.TalentWxNickname, TalentPlatformAccountName: payInfo.PlatformNickname, TaskId: taskInfo.TaskId, TaskPlatform: taskInfo.TaskPlatform, Success: 0, CreateAt: gtime.Now(), Desc: "", }) if err != nil { return &TalentHttpResult{Code: -13, Msg: "insert wx pay order failed"} } return &TalentHttpResult{Code: 0, Msg: "success", Data: talent_model.WxPrepayResponseData{ OutTradeNo: orderNumber, WxResp: resp, }} } func WxPayQueryOrderById(r *ghttp.Request) *TalentHttpResult { transactionId := r.GetRequestString("transaction_id", "nil") if transactionId == "nil" { glog.Error("not input transaction_id param") return &TalentHttpResult{Code: -2, Msg: "input transaction_id param"} } // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := wxUtils.LoadPrivateKeyWithPath(keyFilePath) if err != nil { glog.Error("load merchant private key error") return &TalentHttpResult{Code: -3, Msg: "load merchant private key error"} } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { glog.Error("new wechat pay client err:%s", err) return &TalentHttpResult{Code: -4, Msg: "load merchant private key error"} } svc := jsapi.JsapiApiService{Client: client} resp, _, err := svc.QueryOrderById(ctx, jsapi.QueryOrderByIdRequest{ TransactionId: core.String(transactionId), Mchid: core.String(mchID), }, ) if err != nil { // 处理错误 glog.Error("call WxPayQueryOrderById err:%s", err) return &TalentHttpResult{Code: -5, Msg: "call WxPayQueryOrderById failed"} } // TODO:支付结果写入数据库 _, err = g.DB().Model(dao.WxPayOrder.Table).Update(g.Map{ dao.WxPayOrder.Columns.WxOrderNo: resp.TransactionId, dao.WxPayOrder.Columns.Success: 1, dao.WxPayOrder.Columns.Desc: resp.TradeStateDesc, }, dao.WxPayOrder.Columns.OutTradeNo, resp.OutTradeNo) if err != nil { glog.Error("wxpay_handler.WxPayQueryOrderById Update database failed, order number = ", resp.OutTradeNo) return &TalentHttpResult{Code: -6, Msg: "Update database failed"} } return &TalentHttpResult{Code: 0, Msg: "success"} } func QueryOrderByOutTradeNo(r *ghttp.Request) *TalentHttpResult { outTradeNo := r.GetRequestString("out_trade_no", "nil") if outTradeNo == "nil" { glog.Error("not input out_trade_no param") return &TalentHttpResult{Code: -2, Msg: "input transaction_id param"} } g.DB().Model() // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := wxUtils.LoadPrivateKeyWithPath(keyFilePath) if err != nil { glog.Error("load merchant private key error") return &TalentHttpResult{Code: -3, Msg: "load merchant private key error"} } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { glog.Error("new wechat pay client err:%s", err) return &TalentHttpResult{Code: -4, Msg: "load merchant private key error"} } svc := jsapi.JsapiApiService{Client: client} resp, _, err := svc.QueryOrderByOutTradeNo(ctx, jsapi.QueryOrderByOutTradeNoRequest{ OutTradeNo: core.String(outTradeNo), Mchid: core.String(mchID), }, ) if err != nil { // 处理错误 glog.Error("call QueryOrderByOutTradeNo err:%s", err) return &TalentHttpResult{Code: -5, Msg: "call QueryOrderByOutTradeNo failed"} } // TODO:支付结果写入数据库 _, err = g.DB().Model(dao.WxPayOrder.Table).Update(g.Map{ dao.WxPayOrder.Columns.WxOrderNo: resp.TransactionId, dao.WxPayOrder.Columns.Success: 1, dao.WxPayOrder.Columns.Desc: resp.TradeStateDesc, }, dao.WxPayOrder.Columns.OutTradeNo, resp.OutTradeNo) if err != nil { glog.Error("wxpay_handler.WxPayQueryOrderById Update database failed, order number = ", resp.OutTradeNo) return &TalentHttpResult{Code: -6, Msg: "Update database failed"} } return &TalentHttpResult{Code: 0, Msg: "success"} } func OnWxPayNotify(r *ghttp.Request) { wxSignature := r.GetHeader("Wechatpay-Signature") if wxSignature == "" { glog.Error("OnWxPayNotify header not contain Wechatpay-Signature property") r.Response.WriteJsonExit(g.Map{ "code": "FAILED", "message": "header中不包括Wechatpay-Signature", }) } }