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