From 76db6eae6f866e7cdb41a25f33f5448c517e14c0 Mon Sep 17 00:00:00 2001 From: mofangmin Date: Fri, 23 Aug 2024 17:32:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Eagropay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/backend/handler/examine/examine.go | 1 + modules/pay/agropay/base.go | 170 ++++++++++++++++++++ modules/pay/agropay/values.go | 176 +++++++++++++++++++++ modules/pay/allpay/all.go | 3 + modules/pay/values/values.go | 1 + 5 files changed, 351 insertions(+) create mode 100644 modules/pay/agropay/base.go create mode 100644 modules/pay/agropay/values.go diff --git a/modules/backend/handler/examine/examine.go b/modules/backend/handler/examine/examine.go index 62df62a..bd41b3f 100644 --- a/modules/backend/handler/examine/examine.go +++ b/modules/backend/handler/examine/examine.go @@ -114,6 +114,7 @@ func WithdrawList(c *gin.Context) { 43: "PayPlus", 44: "LuckinPay", 45: "EaniPay", + 46: "AgroPay", } a.Data = values.WithdrawListResp{List: WithdrawOrderArr, Count: count, PayList: payList} } diff --git a/modules/pay/agropay/base.go b/modules/pay/agropay/base.go new file mode 100644 index 0000000..97021fc --- /dev/null +++ b/modules/pay/agropay/base.go @@ -0,0 +1,170 @@ +package agropay + +import ( + "errors" + "fmt" + "net/http" + "server/common" + "server/modules/pay/base" + "server/modules/pay/values" + "server/pb" + "server/util" + + "github.com/gogo/protobuf/proto" + "github.com/liangdas/mqant/log" +) + +func NewSub(b *base.Base) { + sub := &Sub{ + Base: b, + } + b.SignKey = key + b.HttpType = base.HttpTypeJson + b.ShouldSignUpper = true + if b.Opt == base.OPTPay { + b.Resp = new(PayResp) + b.ReqURL = baseURL + payURL + } else if b.Opt == base.OPTWithdraw { + b.Resp = new(WithdrawResp) + b.ReqURL = baseURL + withdrawURL + } else if b.Opt == base.OPTPayCB { + b.SignPassStr = []string{"sign"} + b.CallbackResp.Msg = "SUCCESS" + b.CallbackReq = new(PayCallbackReq) + } else if b.Opt == base.OPTWithdrawCB { + b.SignPassStr = []string{"sign", "msg"} + b.CallbackResp.Msg = "SUCCESS" + b.CallbackReq = new(WithdrawCallbackReq) + } else if b.Opt == base.OPTQueryWithdraw { + b.Resp = new(QueryWithdrawResp) + b.ReqURL = baseURL + queryWithdrawURL + } else if b.Opt == base.OPTQueryPay { + b.Resp = new(QueryPayResp) + b.ReqURL = baseURL + queryPayURL + } + b.Sub = sub +} + +type Sub struct { + Base *base.Base +} + +func (s *Sub) PackHeader(header http.Header) { +} + +func (s *Sub) PackReq() interface{} { + if s.Base.Opt == base.OPTPay { + return s.PackPayReq() + } else if s.Base.Opt == base.OPTWithdraw { + return s.PackWithdrawReq() + } + return nil +} + +func (s *Sub) GetResp() (proto.Message, error) { + if s.Base.Opt == 1 { + resp := s.Base.Resp.(*PayResp) + if resp.Code != 2000 || resp.Data.PayData == "" { + return nil, errors.New("pay fail") + } + return &pb.InnerRechargeResp{APIOrderID: resp.Data.PayOrderId, URL: resp.Data.PayData, Channel: uint32(values.AgroPay)}, nil + } else if s.Base.Opt == base.OPTWithdraw { + resp := s.Base.Resp.(*WithdrawResp) + if s.Base.Status == 0 && resp.Code != 2000 { + return nil, errors.New("withdraw fail") + } + return &pb.InnerWithdrawResp{APIOrderID: fmt.Sprintf("%v", resp.Data.TransferId), Channel: uint32(values.AgroPay)}, nil + } + return nil, fmt.Errorf("unknow opt") +} + +func (s *Sub) PackPayReq() interface{} { + r := s.Base.PayReq + send := &PayReq{ + MchNo: mid, + AppId: appID, + MchOrderNo: r.OrderID, + // Amount: fmt.Sprintf("%d", r.Amount), + Amount: float64(r.Amount), + Currency: "INR", + UserName: r.Name, + Phone: r.Phone, + Email: r.Email, + Subject: "shop", + Body: "shop buy", + NotifyUrl: values.GetPayCallback(values.AgroPay), + ReturnUrl: values.GetFrontCallback(), + RiskControlExtParam: fmt.Sprintf(`{"userId":%d}`, r.UID), + EncryptPhone: util.CalculateMD5(r.Phone), + EncryptEmail: util.CalculateMD5(r.Email), + } + + send.Sign = s.Base.SignMD5(send) + return send +} + +func (s *Sub) PackWithdrawReq() interface{} { + r := s.Base.WithdrawReq + send := &WithdrawReq{ + MchNo: mid, + AppId: appID, + MchOrderNo: r.OrderID, + Amount: fmt.Sprintf("%d", r.Amount), + Currency: "INR", + // EntryType: , + // AccountNo: , + // IfscCode: , + AccountName: r.Name, + Phone: r.Phone, + Email: r.Email, + Address: r.Address, + // BankName: , + ClientIp: r.IP, + TransferDesc: "shop withdraw", + NotifyUrl: values.GetWithdrawCallback(values.AgroPay), + // ChannelExtra + // ExtParam: , + EncryptPhone: util.CalculateMD5(r.Phone), + EncryptEmail: util.CalculateMD5(r.Email), + DeviceId: r.DeviceID, + } + if r.PayType == common.WithdrawTypeBank { + send.EntryType = "banks" + send.AccountNo = r.CardNo + send.IfscCode = r.PayCode + send.BankName = r.BankName + } else if r.PayType == common.WithdrawTypeUPI { + send.EntryType = "upi" + send.AccountNo = r.PayCode + } else { + return nil + } + + send.Sign = s.Base.SignMD5(send) + return send +} + +func (s *Sub) CheckSign(str string) bool { + // str += "&key=" + key + checkSign := "" + s.Base.CallbackResp.Msg = "success" + mySign := "" + if s.Base.Opt == base.OPTPayCB { + req := s.Base.CallbackReq.(*PayCallbackReq) + log.Debug("checkSign pay:%+v", *req) + checkSign = req.Sign + s.Base.CallbackResp.OrderID = req.MchOrderNo + s.Base.CallbackResp.Success = req.State == 2 + mySign = s.Base.SignMD5(req) + } else if s.Base.Opt == base.OPTWithdrawCB { + req := s.Base.CallbackReq.(*WithdrawCallbackReq) + log.Debug("checkSign withdraw:%+v", *req) + checkSign = req.Sign + s.Base.CallbackResp.OrderID = req.MchOrderNo + s.Base.CallbackResp.Success = req.State == 2 + s.Base.CallbackResp.APIOrderID = req.TransferId + s.Base.CallbackResp.FailMessage = req.ErrMsg + mySign = s.Base.SignMD5(req) + } + return mySign == checkSign +} diff --git a/modules/pay/agropay/values.go b/modules/pay/agropay/values.go new file mode 100644 index 0000000..08ac5e3 --- /dev/null +++ b/modules/pay/agropay/values.go @@ -0,0 +1,176 @@ +package agropay + +const ( + baseURL = "https://api.agropay.in" + payURL = "/api/pay/unifiedOrder" + queryPayURL = "/api/pay/query" + withdrawURL = "/api/transferOrder" + queryWithdrawURL = "/api/transfer/query" + mid = "M1724385307" + appID = "66c8081ce4b08979898ba25d" + key = "W6zCKP5RcJ6fAimnYgPxE4I8cd0yxzLJ5Vb3N6OLfMNstea7WzxVtgYo1wOJq45nD8xa1dAoNm23PSqfiaIaxkWxjy4XaXSGC3jv49mRCIkqnLOh2uaQRu9zysbon1DO" +) + +type PayReq struct { + MchNo string `json:"mchNo"` + AppId string `json:"appId"` + MchOrderNo string `json:"mchOrderNo"` + Amount float64 `json:"amount"` + Currency string `json:"currency"` + UserName string `json:"userName"` + Phone string `json:"phone"` + Email string `json:"email"` + Subject string `json:"subject"` + Body string `json:"body"` + NotifyUrl string `json:"notifyUrl"` + ReturnUrl string `json:"returnUrl"` + ExtParam string `json:"extParam"` + RiskControlExtParam string `json:"riskControlExtParam"` + EncryptPhone string `json:"encryptPhone"` + EncryptEmail string `json:"encryptEmail"` + DeviceId string `json:"deviceId"` + Sign string `json:"sign"` +} + +type PayResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + PayOrderId string `json:"payOrderId"` + MchOrderNo string `json:"mchOrderNo"` + State int `json:"state"` + PayDataType string `json:"payDataType"` + PayData string `json:"payData"` + ErrCode string `json:"errCode"` + ErrMsg string `json:"errMsg"` + } `json:"data"` + Sign string `json:"sign"` +} + +type PayCallbackReq struct { + PayOrderId string `json:"payOrderId"` // 支付平台订单号 + MchOrderNo string `json:"mchOrderNo"` // 商户订单号 + MchNo string `json:"mchNo"` // 商户号 + AppId string `json:"appId"` // 商户应用ID + Amount string `json:"amount"` // 订单金额 保留两位小数 + RealAmount string `json:"realAmount"` // 实际支付金额 state=2 时,必须以这个金额为准,其它状态时,值为 0 + State int `json:"state"` // 订单状态 1 - 支付中 2 - 支付成功 3 - 支付失败 5 - 已退款 + ErrCode string `json:"errCode"` // 错误码 + ErrMsg string `json:"errMsg"` // 错误描述 + ExtParam string `json:"extParam"` // 商户扩展参数 + SuccessTime int64 `json:"successTime"` // 订单支付成功时间 + CreatedAt int64 `json:"createdAt"` // 订单创建时间 + Sign string `json:"sign"` // 参数签名 +} + +type WithdrawReq struct { + MchNo string `json:"mchNo"` // 商户号 String 是 平台分配的商户号 + AppId string `json:"appId"` // 商户应用ID String 是 商户应用ID + MchOrderNo string `json:"mchOrderNo"` // 商户生成的唯一订单号 String 是 商户保证唯一性 + Amount string `json:"amount"` // 代付订单金额 BigDecimal 是 单位:卢比,最多保留两位小数 + Currency string `json:"currency"` // 货币代码 String 是 货币代码:INR + EntryType string `json:"entryType"` // 入账方式 String 否 banks,upi,paytm,不传默认 banks(paytm 暂不支持) + AccountNo string `json:"accountNo"` // 收款账号 String 是 收款账号, banks: 银行卡号,upi: UPI 账号,paytm:paytm 账号 + IfscCode string `json:"ifscCode"` // ifscCode String 否 如果入账方式为 banks,这个参数必传 + AccountName string `json:"accountName"` // 收款人姓名 String 是 收款人姓名,5 - 255 个字符,前后不允许有空格,不支持空格以外的其它特殊字符 + Phone string `json:"phone"` // 收款人电话 String 是 收款人电话。十位数字,不用加印度的国际电话区号 91。 + Email string `json:"email"` // 邮箱 String 是 收款人邮箱 + Address string `json:"address"` // 收款人地址 String 是 收款人地址 + BankName string `json:"bankName"` // 开户行名称 String 否 开户行名称 + ClientIp string `json:"clientIp"` // 客户端 IP String 否 客户端 IP + TransferDesc string `json:"transferDesc"` // 转账备注 String 是 转账备注 + NotifyUrl string `json:"notifyUrl"` // 异步通知地址 String 是 异步通知地址,只支持 https + ChannelExtra string `json:"channelExtra"` // 特定渠道发起额外参数 String 否 + ExtParam string `json:"extParam"` // 商户扩展参数 String 否 + EncryptPhone string `json:"encryptPhone"` // MD5 加密后的真实手机号 String 是 加密方法请参考签名文档中的 MD5 加密方法,用于黑名单校验 + EncryptEmail string `json:"encryptEmail"` // MD5 加密后的真实邮件地址 String 是 加密方法请参考签名文档中的 MD5 加密方法,用于黑名单校验 + DeviceId string `json:"deviceId"` // 用户设备 ID String 是 设备 ID:用来标识用户当前使用的设备,要求最好是唯一、并且与用户账号无关的。 + Sign string `json:"sign"` // 签名 String 是 详见签名算法 +} + +type WithdrawResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + TransferId string `json:"transferId"` + MchOrderNo string `json:"mchOrderNo"` + State int `json:"state"` + ErrCode string `json:"errCode"` + ErrMsg string `json:"errMsg"` + } `json:"data"` + Sign string `json:"sign"` +} + +type WithdrawCallbackReq struct { + TransferId string `json:"transferId"` + MchOrderNo string `json:"mchOrderNo"` + MchNo string `json:"mchNo"` + AppId string `json:"appId"` + Amount string `json:"amount"` + Utr string `json:"utr"` + State byte `json:"state"` + ErrCode string `json:"errCode"` + ErrMsg string `json:"errMsg"` + ExtParam string `json:"extParam"` + SuccessTime int64 `json:"successTime"` + CreatedAt int64 `json:"createdAt"` + Sign string `json:"sign"` +} + +type QueryWithdrawReq struct { + MchNo string `json:"mchNo"` // 商户号 String 是 平台分配的商户号 + AppId string `json:"appId"` // 商户应用ID String 是 商户应用ID + MchOrderNo string `json:"mchOrderNo"` // 商户生成的唯一订单号 String 否 商户订单号与平台代付订单号必须传一个 + TransferId string `json:"transferId"` // 平台代付订单号 String 否 商户订单号与平台代付订单号必须传一个 + Sign string `json:"sign"` // 签名 String 是 详见签名算法 +} + +type QueryWithdrawResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + TransferId string `json:"transferId"` + MchOrderNo string `json:"mchOrderNo"` + MchNo string `json:"mchNo"` + AppId string `json:"appId"` + Amount string `json:"amount"` + Utr string `json:"utr"` + State int `json:"state"` + ErrCode string `json:"errCode"` + ErrMsg string `json:"errMsg"` + ExtParam string `json:"extParam"` + SuccessTime int64 `json:"successTime"` + CreatedAt int64 `json:"createdAt"` + Sign string `json:"sign"` + } `json:"data"` + Sign string `json:"sign"` +} + +type QueryPayReq struct { + MchNo string `json:"mchNo"` // 商户号 String 是 平台分配的商户号 + AppId string `json:"appId"` // 商户应用ID String 是 商户应用ID + MchOrderNo string `json:"mchOrderNo"` // 商户生成的唯一订单号 String 否 商户订单号与平台订单号必须传一个 + PayOrderId string `json:"payOrderId"` // 平台订单号 String 否 商户订单号与平台订单号必须传一个 + Sign string `json:"sign"` // 签名 String 是 详见签名算法 +} + +type QueryPayResp struct { + Code int // 返回码 2000:成功(仅代表请求成功,不代表业务成功);2010:系统异常;2011:参数有误;2012:数据库服务异常;9999:自定义业务异常 + Msg string // 业务响应信息 成功:success + Data struct { + PayOrderId string // 支付平台订单号 + MchOrderNo string // 商户订单号 + MchNo string // 商户号 + AppId string // 商户应用ID + Amount string // 支付金额 保留两位小数 + RealAmount string // 实际支付金额 state=2 时,必须以这个金额为准,其它状态时,值为 0 + State int // 订单状态 1 - 支付中 2 - 支付成功 3 - 支付失败 5 - 已退款 + ErrCode string // 错误码 + ErrMsg string // 错误描述 + ExtParam string // 商户扩展参数 + SuccessTime int64 // 订单支付成功时间 + CreatedAt int64 // 订单创建时间 + Sign string // 参数签名 + } // 数据对象 成功时返回 + Sign string // 签名 详见签名算法(data 中的数据参与签名) +} diff --git a/modules/pay/allpay/all.go b/modules/pay/allpay/all.go index 36993e8..22c0bbf 100644 --- a/modules/pay/allpay/all.go +++ b/modules/pay/allpay/all.go @@ -2,6 +2,7 @@ package allpay import ( "reflect" + "server/modules/pay/agropay" "server/modules/pay/base" "server/modules/pay/eanipay" "server/modules/pay/gopay" @@ -61,6 +62,7 @@ type AllPay struct { PayPlus func(b *base.Base) LuckyinPay func(b *base.Base) Eanipay func(b *base.Base) + AgroPay func(b *base.Base) } var All = &AllPay{} @@ -73,6 +75,7 @@ func init() { All.PayPlus = payplus.NewSub All.LuckyinPay = luckyinpay.NewSub All.Eanipay = eanipay.NewSub + All.AgroPay = agropay.NewSub } func NewSub(b *base.Base, index int) { diff --git a/modules/pay/values/values.go b/modules/pay/values/values.go index 7fa6a5f..9a7b9b9 100644 --- a/modules/pay/values/values.go +++ b/modules/pay/values/values.go @@ -70,6 +70,7 @@ const ( PayPlus LuckyinPay EaniPay + AgroPay PayAll )