| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 | package shanghuimport (	"duoduo/apis/common"	"duoduo/apis/shanghu/models"	"duoduo/models/shanghu"	"duoduo/tools"	"duoduo/tools/app"	"encoding/xml"	"errors"	"fmt"	"github.com/gin-gonic/gin"	"github.com/go-pay/gopay"	"github.com/go-pay/gopay/wechat"	wechatV3 "github.com/go-pay/gopay/wechat/v3"	"github.com/shopspring/decimal"	"net/http"	"strconv"	"time")type wechatCallbackResp struct {	XMLName    xml.Name `xml:"xml"`	ReturnCode Cdata    `xml:"return_code"`	ReturnMsg  Cdata    `xml:"return_msg"`}type Cdata struct {	Value string `xml:",cdata"`}var (	successResp = &wechatCallbackResp{ReturnCode: Cdata{Value: "SUCCESS"}, ReturnMsg: Cdata{Value: "OK"}}	failResp    = &wechatCallbackResp{ReturnCode: Cdata{Value: "FAIL"}, ReturnMsg: Cdata{Value: "数据处理异常"}})func UnifiedOrder(c *gin.Context) {	var inData models.UnifiedOrderRequest	var sqlData shanghu.ClientPayTrans	var outData models.UnifiedOrderReply	err := c.ShouldBindJSON(&inData)	if err != nil {		app.Error(c, 400, err, err.Error())		return	}	//校验 防止同一笔记录存在	sqlData.RequestID = inData.RequestId	if sqlData.GetRequestNum() > 0 {		app.Error(c, 400, errors.New("交易已存在"), "交易已存在")		return	}	//校验金额	// 检查微信相关参数	if !inData.Amount.GreaterThan(decimal.NewFromInt(0)) {		app.Error(c, 400, errors.New("amount:金额必须大于0"), "amount:金额必须大于0")		return	}	if inData.Amount.Round(2).String() != inData.Amount.String() {		app.Error(c, 400, errors.New("total_fee:金额最多只能保留两位小数"), "total_fee:金额最多只能保留两位小数")		return	}	//创建支付记录	sqlData.ClientOpenID = inData.ClientOpenId	sqlData.RequestID = inData.RequestId	sqlData.CreatedAt = time.Now()	sqlData.UpdatedAt = time.Now()	sqlData.Amount = inData.Amount	sqlData.OutTradeNo = strconv.FormatInt(inData.MerchantCardId, 10) + strconv.FormatInt(time.Now().UnixNano(), 10)	sqlData.Status = 1 //未支付	sqlData.MerchantCardID = inData.MerchantCardId	sqlData.InvitationCode = inData.InvitationCode	_, err = sqlData.Create()	if err != nil {		app.Error(c, 400, err, "创建支付失败")		return	}	fmt.Println(sqlData.OutTradeNo)	bm := make(gopay.BodyMap)	bm.Set("nonce_str", common.GetRandomString(32))	bm.Set("body", "商户卡")	bm.Set("out_trade_no", sqlData.OutTradeNo)	bm.Set("total_fee", inData.Amount.Mul(decimal.NewFromInt(100)).IntPart())	bm.Set("spbill_create_ip", "127.0.0.1")	bm.Set("notify_url", "https://shisanmiao.com/v1/client/pay/callback")	bm.Set("device_info", "WEB")	bm.Set("trade_type", "JSAPI")	bm.Set("sign_type", wechat.SignType_MD5)	bm.Set("openid", inData.ClientOpenId)	client := NewWechatService()	//请求支付下单,成功后得到结果	wxResp, err := client.UnifiedOrder(c, bm)	if err != nil {		app.Error(c, 400, err, "下单失败")		return	}	if wxResp.ReturnCode != "SUCCESS" {		app.Error(c, 400, errors.New(wxResp.ReturnMsg), "下单失败")		return	}	if wxResp.ResultCode != "SUCCESS" {		app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "下单失败")		return	}	timestamp := strconv.FormatInt(time.Now().Unix(), 10)	pac := "prepay_id=" + wxResp.PrepayId	paySign := wechat.GetMiniPaySign("wx25357518f710b8ce", wxResp.NonceStr, pac, wechat.SignType_MD5, timestamp, "1RKRJBVH4vaRrF0XPW9GX2M3ZSImukIz")	outData.Timestamp = timestamp	outData.NonceStr = wxResp.NonceStr	outData.Package = pac	outData.PaySign = paySign	outData.SignType = wechat.SignType_MD5	//merchant, count, err := sqlData.GetOpenIdList(pageSize, pageIndex)	//if err != nil {	//	app.Error(c, 500, err, err.Error())	//	return	//}	app.OK(c, outData, app.Success)}func PayCashOut(c *gin.Context) {	var inData models.PayCashOutRequest	//var sqlData	if inData.CashType == "client" {		//先设置账户状态 为提现中,提现中不允许再操作,提现金额默认全部	} else if inData.CashType == "merchant" {	} else {		app.Error(c, 400, errors.New("类型错误"), "类型错误")		return	}	client := NewWechatService()	err := client.AddCertPkcs12FilePath("./apiclient_cert.p12")	if err != nil {		app.Error(c, 400, err, err.Error())		return	}	bm := make(gopay.BodyMap)	partnerTradeNo := common.GetRandomString(32)	bm.Set("nonce_str", common.GetRandomString(32))	bm.Set("partner_trade_no", partnerTradeNo)	bm.Set("openid", inData.OpenId)	bm.Set("check_name", "FORCE_CHECK")	bm.Set("re_user_name", inData.UserName)	bm.Set("amount", 30)   // 企业付款金额,单位为分	bm.Set("desc", "测试转账") // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*	bm.Set("spbill_create_ip", "127.0.0.1")	wxResp, err := client.Transfer(c, bm)	if err != nil {		app.Error(c, 400, err, "提现失败")		return	}	if wxResp.ReturnCode != "SUCCESS" {		app.Error(c, 400, errors.New(wxResp.ReturnMsg), "提现")		return	}	if wxResp.ResultCode != "SUCCESS" {		app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "提现")		return	}}func PayCallBack(c *gin.Context) {	var payLog shanghu.PayCallbackLog	var payTrans shanghu.ClientPayTrans	wxNotify, err := wechat.ParseNotifyToBodyMap(c.Request)	if err != nil {		c.XML(http.StatusOK, failResp)		return	}	//通知回调log	payLog.CallBackLog = wxNotify.JsonBody()	payLog.ThirdTradeNo = wxNotify.Get("transaction_id")	payLog.OutTradeNo = wxNotify.Get("out_trade_no")	payLog.CreatedAt = time.Now()	payLog.UpdatedAt = time.Now()	_, err = payLog.Create()	if err != nil {		c.XML(http.StatusOK, failResp)		return	}	if wxNotify.Get("return_code") != "SUCCESS" || wxNotify.Get("result_code") != "SUCCESS" {		payLog.ErrLog = "微信返回错误:" + wxNotify.Get("return_code") + "--" + wxNotify.Get("result_code")		payLog.UpdateMerchant()		c.XML(http.StatusOK, failResp)		return	}	//校验金额	payTrans.OutTradeNo = wxNotify.Get("out_trade_no")	payTransInfo, err := payTrans.GetPayTransByTradeNo()	if err != nil {		payLog.ErrLog = "查询交易信息错误:" + " err=" + err.Error()		payLog.UpdateMerchant()		c.XML(http.StatusOK, failResp)		return	}	// 判断金额与支付流水是否一致	totalFee, err := decimal.NewFromString(wxNotify.Get("total_fee"))	if err != nil {		payLog.ErrLog = "解析总金额报错:" + "err=" + err.Error()		payLog.UpdateMerchant()		c.XML(http.StatusOK, failResp)		return	}	if !totalFee.Equal(payTransInfo.Amount.Mul(decimal.NewFromInt(100))) {		payLog.ErrLog = "验证金额报错:total_fee=" + wxNotify.Get("total_fee") + " amount=" + payTransInfo.Amount.String()		payLog.UpdateMerchant()		c.XML(http.StatusOK, failResp)		return	}	// 解析支付时间	timeEnd, err := time.ParseInLocation("20060102150405", wxNotify.Get("time_end"), tools.TimeLocation)	if err != nil {		payLog.ErrLog = "付款时间解析出错:err=" + err.Error()		payLog.UpdateMerchant()		c.XML(http.StatusOK, failResp)		return	}	payTrans.ThirdTradeNo = wxNotify.Get("transaction_id")	payTrans.Status = 2 //支付成功	payTrans.PayTime = timeEnd	payTrans.AccountStatus = 1 //未分账	err = payTrans.UpdatePayTransByTradeNo()	if err != nil {		payLog.ErrLog = "更新支付状态失败:err=" + err.Error()		payLog.UpdateMerchant()		c.XML(http.StatusOK, failResp)		return	}	c.XML(http.StatusOK, successResp)}func NewWechatService() *wechat.Client {	client := wechat.NewClient("wx25357518f710b8ce", "1501641641", "1RKRJBVH4vaRrF0XPW9GX2M3ZSImukIz", true)	//设置国家	client.SetCountry(wechat.China)	return client}func NewWechatServiceV3() (*wechatV3.ClientV3, error) {	key := `MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD/RTrS1TycrskrSkuzdLNmOic4UklFtoyKtKDIeklbQFvynJBC1wYaitoOqFkdGWagkcuqRqJOcgEQT8DRDD/rnVKTrnntevUSW3vZYwMscomK3dgjRRui5GLY5wYHuKhp02bldLrhPKNywT5IYhoDwQLmf5IrURbtT8bKpdC+NyEEfw+d/mHMK56w80YKfzFtSmjoB9SkWDLgYFBlw91C78E73uqhCKnArN7p2iJe+tsp7EGpDVcdowqcMKjY2YiNPY6ABZaI9YJxnRQs5Sjm6YSsJujMR5rQVZ3HCfLlzxLpPyHfqffbJ+vviend1PJ/ugJeM2hehn1dLrpKuWyHAgMBAAECggEAIbow6nhYGM+TLtATLnPF3ETkt7FPkxFqgk0ZTUOy+4aGX4jGGr60RL+Bzhv6Ijkf8SkyQp4whbLUZyZScIxwyZ2wsmiEHZd4V+OUeoV1fuLnP1zOWOKhoyUP1l630j9YqRrQZpLEuku7wMa9huzHSSWwT2odkvGU2OgIeO/to6P7gIE4Q+3pNmTdaXJweUlVoz6sdqsSWAZ729SxzY34zcRyXI+feBQb9n/C1hr9+Ge4KbBsvrECy0eUNiAT9f5dPwgwjyRpR9gJ8xxaezIYfxdpTTW3EB1Gf+xPX4X7ml2BzObPN2HEwLHhrwbOXLFP8F/62TK4fIGe2yXPIKIe8QKBgQD/t4Xy9pTFrmNhDLMeZMHdj9XMoM/izcquI6rq4pGWLtnyxIcFuXiqvPszbJL+urCc1+HqfPAVScryEg5Wb6AvLENVhC5E3GcZA50ciAr+PUrB1UXH0vbbc7HP/Mofsz61kxEW2SvKaPoKhW8MIavoVWDJkcLHnjM20Gt7tioEXwKBgQD/jZR7FDSB8VCRp687QcH4s0HyAWaRVhmCqId2xVbPFVlbm4BWcQVWPdsUei29sPPtcvzREFStKwTmu2FSUfoDv3uM4Nl2+h/YpbhfuYfHd79UZa0OtT9njJHZcYPwKRmZQIVBVHSJFSZy2HSGLe9AdI7gAsNMx/MmeqZDU79I2QKBgQCBSNoSIpTI9QgNkwwkO7DAQe5IDK3N71mffSz2oCIXGgza7n2NaV4WhIFEWIpg+yY7xfHUSeJgAPT4OiTBkqIb93b7j16NNhlxzh/qwuU78OUQ5rDm/EQOY4nsq9PM/ySfTIGBWb8IENcJ5rhkG8n8Jt5OSsF9hwBBoFIXM9w+ZQKBgQD1rArw43Sy8uTskZKA2e96ggHEgBo1X9s4Y4GO6ZlRjQmRaoVPFGn4BZEGN4qfkGx/egqXhSaSLwgQNFUUCWDbl4pT3ZjRqxVQdcgwpjBkzratkO10dUOV7WoM6vbWuvwz+vXf3ywE2MNUpsgmciROB3+O1LkhqBsVg9UwZmM+yQKBgQD6yBvxOaHXBSZncz+m3SpdbcRjK82i3IUJ3sl18J7YEPer0FclsUcQOluqBbHTOAr8letWPrKnjZGuyFfggAjwa8uLSyfEEcWb9WcObvud2GNxS/LiI0GnW9ittvT29JvOhmUUtnty5/TiWIsislm2kO53RSw9brymV8PAX2+SXg==`	client, err := wechatV3.NewClientV3("wx25357518f710b8ce", "219B3AF3B5F17D4C2F145EE318188708318DD7BD", "9x9ydkdk0nzsa4mr2ucq75grlvt9n8l3", key)	if err != nil {		return nil, err	}	// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)	err = client.AutoVerifySign()	if err != nil {		return nil, err	}	// 打开Debug开关,输出日志,默认是关闭的	//client.DebugSwitch = gopay.DebugOn	return client, nil}
 |