parent
a4b59ae85b
commit
54df366cd8
6 changed files with 361 additions and 20 deletions
@ -0,0 +1,165 @@ |
|||||||
|
package luckyinpay |
||||||
|
|
||||||
|
import ( |
||||||
|
"crypto" |
||||||
|
"encoding/base64" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
"server/common" |
||||||
|
"server/modules/pay/base" |
||||||
|
"server/modules/pay/values" |
||||||
|
"server/pb" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
func NewSub(b *base.Base) { |
||||||
|
sub := &Sub{ |
||||||
|
Base: b, |
||||||
|
} |
||||||
|
b.HttpType = base.HttpTypeJson |
||||||
|
b.ShouldSignUpper = true |
||||||
|
b.Channel = values.LuckyinPay |
||||||
|
if b.Opt == base.OPTPay { |
||||||
|
b.Resp = new(PayWithdrawResponse) |
||||||
|
b.ReqURL = payApi |
||||||
|
} else if b.Opt == base.OPTWithdraw { |
||||||
|
b.Resp = new(PayWithdrawResponse) |
||||||
|
b.ReqURL = withdrawApi |
||||||
|
} else if b.Opt == base.OPTPayCB { |
||||||
|
b.SignPassStr = []string{"sign"} |
||||||
|
b.CallbackResp.Msg = strings.ToLower(statusSuccess) |
||||||
|
b.CallbackReq = new(CallbackReq) |
||||||
|
} else if b.Opt == base.OPTWithdrawCB { |
||||||
|
b.SignPassStr = []string{"sign", "msg"} |
||||||
|
b.CallbackResp.Msg = strings.ToLower(statusSuccess) |
||||||
|
b.CallbackReq = new(CallbackReq) |
||||||
|
} |
||||||
|
b.Sub = sub |
||||||
|
} |
||||||
|
|
||||||
|
type Sub struct { |
||||||
|
Base *base.Base |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sub) PackHeader(_ http.Header) { |
||||||
|
// header.Set("Merchant-Id", config.GetConfig().Pay.IGeek.MID)
|
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sub) PackReq() interface{} { |
||||||
|
if s.Base.Opt == base.OPTPay { |
||||||
|
return s.PackPayReq() |
||||||
|
} |
||||||
|
return s.PackWithdrawReq() |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sub) GetResp() (proto.Message, error) { |
||||||
|
if s.Base.Opt == base.OPTPay { |
||||||
|
resp := s.Base.Resp.(*PayWithdrawResponse) |
||||||
|
if resp.Message != statusSuccess || resp.Data.PayData == "" { |
||||||
|
return nil, errors.New("pay fail") |
||||||
|
} |
||||||
|
return &pb.InnerRechargeResp{APIOrderID: fmt.Sprintf("%v", resp.Data.PayOrderNo), URL: resp.Data.PayData, Channel: uint32(values.LuckyinPay)}, nil |
||||||
|
} |
||||||
|
resp := s.Base.Resp.(*PayWithdrawResponse) |
||||||
|
if s.Base.Status == 0 && resp.Message != statusSuccess { |
||||||
|
return nil, errors.New("withdraw fail") |
||||||
|
} |
||||||
|
return &pb.InnerWithdrawResp{APIOrderID: fmt.Sprintf("%v", resp.Data.PayOrderNo), Channel: uint32(values.LuckyinPay)}, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sub) PackPayReq() interface{} { |
||||||
|
r := s.Base.PayReq |
||||||
|
send := &PayReq{ |
||||||
|
MchNo: mchId, |
||||||
|
MchOrderNo: r.OrderID, |
||||||
|
Currency: "INR", |
||||||
|
PayAmount: fmt.Sprintf("%."+strconv.Itoa(2)+"f", float64(r.Amount)/common.DecimalDigits), |
||||||
|
AccountName: r.Name, |
||||||
|
AccountEmail: r.Email, |
||||||
|
AccountPhone: r.Phone, |
||||||
|
CustomerIp: r.IP, |
||||||
|
NotifyUrl: values.GetPayCallback(values.LuckyinPay), |
||||||
|
SuccessPageUrl: "https://www.tp7k.com", |
||||||
|
Summary: "", |
||||||
|
ReqTime: fmt.Sprintf("%d", time.Now().UnixMilli()), |
||||||
|
} |
||||||
|
signStr := base.GetSignStr(send, s.Base.SignPassStr...) |
||||||
|
sign, err := base.SignRSA(privateKey, crypto.SHA256, []byte(signStr)) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
send.Sign = sign |
||||||
|
return send |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sub) PackWithdrawReq() interface{} { |
||||||
|
r := s.Base.WithdrawReq |
||||||
|
if r.PayType != int64(common.PayTypeBank) { |
||||||
|
return nil |
||||||
|
} |
||||||
|
accountType := "" |
||||||
|
if common.PayType(r.PayType) == common.PayTypeBank { |
||||||
|
accountType = "IFSC" |
||||||
|
} else if common.PayType(r.PayType) == common.PayTypeUPI { |
||||||
|
accountType = "UPI" |
||||||
|
} |
||||||
|
send := &WithdrawReq{ |
||||||
|
MchNo: mchId, |
||||||
|
MchOrderNo: r.OrderID, |
||||||
|
Currency: "INR", |
||||||
|
PayAmount: fmt.Sprintf("%."+strconv.Itoa(2)+"f", float64(r.Amount)/common.DecimalDigits), |
||||||
|
AccountType: accountType, |
||||||
|
AccountCode: r.PayCode, |
||||||
|
AccountNo: r.CardNo, |
||||||
|
AccountName: r.Name, |
||||||
|
AccountEmail: r.Email, |
||||||
|
AccountPhone: r.Phone, |
||||||
|
CustomerIp: r.IP, |
||||||
|
NotifyUrl: values.GetWithdrawCallback(values.LuckyinPay), |
||||||
|
ReqTime: fmt.Sprintf("%d", time.Now().UnixMilli()), |
||||||
|
} |
||||||
|
signStr := base.GetSignStr(send, s.Base.SignPassStr...) |
||||||
|
sign, err := base.SignRSA(privateKey, crypto.SHA256, []byte(signStr)) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
send.Sign = sign |
||||||
|
return send |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sub) CheckSign(_ string) bool { |
||||||
|
if s.Base.Opt == base.OPTPayCB { |
||||||
|
req := s.Base.CallbackReq.(*CallbackReq) |
||||||
|
log.Debug("checkSign pay:%+v", *req) |
||||||
|
s.Base.CallbackResp.OrderID = req.MchOrderNo |
||||||
|
s.Base.CallbackResp.Success = req.PayState == 2 |
||||||
|
signStr := base.GetSignStr(req, s.Base.SignPassStr...) |
||||||
|
sign, _ := base64.StdEncoding.DecodeString(req.Sign) |
||||||
|
err := base.RsaVerify(publicKey, crypto.SHA256, []byte(signStr), sign) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
return err == nil |
||||||
|
} else if s.Base.Opt == base.OPTWithdrawCB { |
||||||
|
req := s.Base.CallbackReq.(*CallbackReq) |
||||||
|
log.Debug("checkSign withdraw:%+v", *req) |
||||||
|
s.Base.CallbackResp.OrderID = req.MchOrderNo |
||||||
|
s.Base.CallbackResp.Success = req.PayState == 2 |
||||||
|
s.Base.CallbackResp.APIOrderID = req.PayOrderNo |
||||||
|
s.Base.CallbackResp.FailMessage = req.ErrMsg |
||||||
|
signStr := base.GetSignStr(req, s.Base.SignPassStr...) |
||||||
|
sign, _ := base64.StdEncoding.DecodeString(req.Sign) |
||||||
|
err := base.RsaVerify(publicKey, crypto.SHA256, []byte(signStr), sign) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
return err == nil |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
@ -0,0 +1,90 @@ |
|||||||
|
package luckyinpay |
||||||
|
|
||||||
|
// 常量定义
|
||||||
|
const ( |
||||||
|
statusSuccess = "SUCCESS" |
||||||
|
statusFail = "FAIL" |
||||||
|
payApi = "https://api.luckyinpay.xyz/api/pay/createPayinOrder" |
||||||
|
withdrawApi = "https://api.luckyinpay.xyz/api/pay/createPayoutOrder" |
||||||
|
mchId = "M1723690026" |
||||||
|
) |
||||||
|
|
||||||
|
var privateKey = []byte(`-----BEGIN PRIVATE KEY----- |
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCaOiesI2CY1qG6WxCnYbzI4WRmJrOTWnagPBm4YGjP5HaKlYNGeoRQKwrd6nm7KdyUCAg4LW2p/5NINXquLAGLkDcPUzTEaK36JiJd46lyTw2a+LQAtXMXq6PLM8MVU5yrR7Ndqj8/6SYjIaH6xE7yZq7YioAZoqENfn2Nzz7i5JY5rAi9DOjJ2Ti2lIkV/I6eaCpJecp9DgDMfGsTK4Dbh26uHgFaQ9ruwLP437V+h1x7QkEF1mzpqTgtXV7+opLgGX0fpdT8GabBoAEqQL41rxWQo3oVnV3A69eW2t16/LFMZLFVp7tzFzv4iRDehZuAVHFw7bykbaZ9omEy00cfAgMBAAECggEAK+S5PcijyVvsk3kveDPc4t8jD9+b5Cgu8tOoDk2CBwjio/aBciGUXqyhXx9InfgACzFuBW8IcwWGCVsPG1ry5aGZygbIUc3pFfSce1Q7+Yh+Osjlkf4ST35OE5sbvooZYLX7WoEFl07nx7/etdwBDAQlZwOkCae7ZnfFjAKbxz8OTz0ZLH68LKYBB51KvSrto+ZJDzSmqMV/21P9JwpZklvG+oNmA1D6fYOdz0QcKpewcJbmZ4JsPdVOy9zyUVCFhra+5P5IlI07x5tWAFZmktiXGKC+a+gLrqR96FJ+l/SjeMWkhFEiGuFBDTNvfpVHxNY30i5YQ6b1zNDmZZ/AgQKBgQDLlgEeImy6/iVin3jecZuzsgbQiB9SuyrIjziBzlxMTMRgNuGmwCX5ScmObxpwzCKwN/r24wX9HB92+vPXG3CuWRvLCy53iTfg4K08CIhR5qZKjK7XknMN+c16JA9jD358MIol3PhY5qdfV2WEoDRioEGPooNrP4Ka6SoSc/GlLwKBgQDB7v+7UCCU2hyCEhSNWLPvhuzy6BbqNHZYA+WH8aRt+T/9vqDefXj9uBjBQC2IIdfB1bTiZXOonwQsdLw8UEw0sTSg9GNqJY60TJCkJCFoSK1pjP0oS6CSjfcMg6TJ07RKxmnfKt5muIfarJs4jDXLbhLRcMfVnx+CjUu9R7fhEQKBgCxVvmiRlpwiPIH9uJS4qO+5FULUYf3iRK7ogaXDCtaS4TESwpFNxvdC2mHqUBfAXM2DY2PgjK1SMof2nqN5llBhl2vgQ35Eo6aVRySLtyQe1pfliy3m9qdUfyraL3+jIChraapVNMAnesuIfNMlEENqItzkxznT2t1haYgbN8SBAoGAKUAg/ULJ61+JeNFHtdkMTQKyG+jqFt8Z3RbXF9d6VjoSNnL53NlrhuxFt7Vi+fXY4s4GL7HMrC1Gwf4CnAGoc/zNaP8Stl1OwWMX0RIuWPQ8jpsCrjOH8CRqTCskPhnd25ngoyuHKupNW2Ijkh+gwaikMBCBMRsrpKVRWu2KW0ECgYEAw3ddkjrPmvqXAL1l8M/vymxsYFO6HpRunf7zknwOZDETfqm/0uJhuH8YJqQRnsgUxTgealid9M2hgO0L/IcqyA7/AoCP5FHFB82kmcBV5Nz0+jB0gGKw222foCLTuyjv0GxL3DgoYjASFgJUHICsc1scCc5rVd45uJgUbtR/g6k= |
||||||
|
-----END PRIVATE KEY----- |
||||||
|
`) |
||||||
|
var publicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjOrF8H78wLlVUd0Xe3qe+mBvkzchxccuBqtPZGbK9ebhXbqOaIgRQByjWSuC1/qJcT6eBumSX/iHUVaTdf3v2XO1QCbUZZm74vcSsO5f64bmzTtk/cLa1S4068Rfde0YoX/avNfiX2nRz1SBzy3zaiwA8pmhkbpU+L3k+a8qd3WH3Hq2MpX/dD1haqzTHYiA8+xJANixvNtKWq5AMyrs9rSkwGTEHV33ETLUZgpHjtgI+L/PAqzIaW89dgh4EIga4sNGr/3iUkZU1vYKj2PHY6/pfgs5wCS0BhxHF35LYCHgyZV7UH4oxu0kOtGGmdOAeIylCWRXdPkaXGGnOlmYmQIDAQAB |
||||||
|
-----END PUBLIC KEY-----`) |
||||||
|
|
||||||
|
// PayReq 代收下单请求结构体
|
||||||
|
type PayReq struct { |
||||||
|
MchNo string `json:"mchNo"` // 商户号
|
||||||
|
MchOrderNo string `json:"mchOrderNo"` // 商户订单号
|
||||||
|
Currency string `json:"currency"` // 币种
|
||||||
|
PayAmount string `json:"payAmount"` // 支付金额
|
||||||
|
AccountName string `json:"accountName"` // 客户姓名
|
||||||
|
AccountEmail string `json:"accountEmail"` // 客户邮箱
|
||||||
|
AccountPhone string `json:"accountPhone"` // 客户手机号
|
||||||
|
CustomerIp string `json:"customerIp"` // 客户IP
|
||||||
|
NotifyUrl string `json:"notifyUrl"` // 回调地址
|
||||||
|
SuccessPageUrl string `json:"successPageUrl"` // 成功跳转页面
|
||||||
|
Summary string `json:"summary,omitempty"` // 备注
|
||||||
|
ReqTime string `json:"reqTime"` // 请求接口时间,13位时间戳
|
||||||
|
Sign string `json:"sign"` // 签名
|
||||||
|
} |
||||||
|
|
||||||
|
// WithdrawReq 代付下单请求结构体
|
||||||
|
type WithdrawReq struct { |
||||||
|
MchNo string `json:"mchNo"` // 商户号
|
||||||
|
MchOrderNo string `json:"mchOrderNo"` // 商户订单号
|
||||||
|
Currency string `json:"currency"` // 币种
|
||||||
|
PayAmount string `json:"payAmount"` // 支付金额
|
||||||
|
Sign string `json:"sign"` // 签名
|
||||||
|
AccountType string `json:"accountType"` // 收款账户类型
|
||||||
|
AccountCode string `json:"accountCode"` // 收款账户编码
|
||||||
|
AccountNo string `json:"accountNo"` // 收款账户号码
|
||||||
|
AccountName string `json:"accountName"` // 客户姓名
|
||||||
|
AccountEmail string `json:"accountEmail"` // 客户邮箱
|
||||||
|
AccountPhone string `json:"accountPhone"` // 客户手机号
|
||||||
|
CustomerIp string `json:"customerIp"` // 客户IP
|
||||||
|
NotifyUrl string `json:"notifyUrl"` // 回调地址
|
||||||
|
Summary string `json:"summary,omitempty"` // 备注
|
||||||
|
ReqTime string `json:"reqTime"` // 请求时间,13位时间戳
|
||||||
|
} |
||||||
|
|
||||||
|
// PayWithdrawResponse 代收和代付响应数据体
|
||||||
|
type PayWithdrawResponse struct { |
||||||
|
Code string `json:"code"` // 响应状态码
|
||||||
|
Message string `json:"message"` // 响应消息
|
||||||
|
Data OrderData `json:"data,omitempty"` // 响应数据体
|
||||||
|
Sign string `json:"sign,omitempty"` // 签名
|
||||||
|
Timestamp string `json:"timestamp"` // 响应时间戳
|
||||||
|
} |
||||||
|
|
||||||
|
// OrderData 订单数据体
|
||||||
|
type OrderData struct { |
||||||
|
PayOrderNo string `json:"payOrderNo"` // 平台订单号
|
||||||
|
MchOrderNo string `json:"mchOrderNo"` // 商户订单号
|
||||||
|
MchNo string `json:"mchNo"` // 商户号
|
||||||
|
Currency string `json:"currency"` // 币种
|
||||||
|
PayAmount string `json:"payAmount"` // 金额
|
||||||
|
PayInitiateTime string `json:"payInitiateTime"` // 下单时间
|
||||||
|
PayData string `json:"payData"` // 支付链接
|
||||||
|
PayReference string `json:"payReference"` // 支付二维码
|
||||||
|
PayState int `json:"payState"` // 支付状态
|
||||||
|
} |
||||||
|
|
||||||
|
// CallbackReq 代收和代付回调请求结构体
|
||||||
|
type CallbackReq struct { |
||||||
|
PayOrderNo string `json:"payOrderNo"` // 平台订单号
|
||||||
|
MchOrderNo string `json:"mchOrderNo"` // 商户订单号
|
||||||
|
MchNo string `json:"mchNo"` // 商户号
|
||||||
|
Currency string `json:"currency"` // 币种
|
||||||
|
PayAmount string `json:"payAmount"` // 金额
|
||||||
|
PayState int `json:"payState"` // 支付状态
|
||||||
|
PayInitiateTime string `json:"payInitiateTime"` // 下单时间
|
||||||
|
PayFinishTime string `json:"payFinishTime"` // 完成时间
|
||||||
|
ErrMsg string `json:"errMsg,omitempty"` // 错误信息
|
||||||
|
Sign string `json:"sign"` // 签名
|
||||||
|
} |
||||||
Loading…
Reference in new issue