package robuspay import ( "encoding/json" "errors" "fmt" "net/http" "server/modules/pay/base" "server/modules/pay/values" "server/pb" "server/util" "sort" "strings" "time" "github.com/gogo/protobuf/proto" jsoniter "github.com/json-iterator/go" "github.com/liangdas/mqant/log" ) func NewSub(b *base.Base) { sub := &Sub{ Base: b, } b.HttpType = base.HttpTypeJson 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.CallbackReq = new(PayCallbackReq) b.CallbackResp.Msg = "OK" b.HttpType = base.HttpTypeForm } else if b.Opt == base.OPTWithdrawCB { b.CallbackReq = new(WithdrawCallbackReq) b.CallbackResp.Msg = "OK" b.HttpType = base.HttpTypeForm } 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 } else { return } 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() } else if s.Base.Opt == base.OPTQueryWithdraw { return s.PackQueryWithdrawReq() } else if s.Base.Opt == base.OPTQueryPay { return s.PackQueryPayReq() } return nil } func (s *Sub) GetResp() (proto.Message, error) { log.Debug("resp:%v", s.Base.Resp) if s.Base.Opt == base.OPTPay { resp := s.Base.Resp.(*PayResp) if s.Base.Status == 0 && resp.RetCode != "0000" { // 错误 log.Error("robus pay err, %+v", resp) return nil, errors.New("pay fail") } var payurl string if resp.Data.Type == "" || resp.Data.Type == "payurl" { payurl = resp.Data.PayUrl } else { payurl = resp.Data.PayData } if resp.Data.PayUrl == "" { log.Error("robus pay link is nil, %+v", resp) return nil, errors.New("pay fail") } return &pb.InnerRechargeResp{APIOrderID: resp.Data.OrderNo, URL: payurl, Channel: uint32(values.RobusPay)}, nil } else if s.Base.Opt == base.OPTWithdraw { resp := s.Base.Resp.(*WithdrawResp) // notice: 提现的时候,未知错误不能当做错误返回 if s.Base.Status == 0 && resp.RetCode != "0000" { log.Error("robus withdraw err, %+v", resp) return nil, errors.New("withdraw fail") } return &pb.InnerWithdrawResp{APIOrderID: resp.Data.OrderNo, Channel: uint32(values.RobusPay)}, nil } else if s.Base.Opt == base.OPTQueryWithdraw { resp := s.Base.Resp.(*QueryWithdrawResp) ret := &pb.InnerQueryWithdrawResp{} if resp.RetCode != "0000" { // 错误 log.Error("robus query withdraw err, %+v", resp) s.Base.QueryWithdrawResp.Status = base.QueryStatusUnknown return ret, nil } s.Base.QueryWithdrawResp.OrderID = resp.Data.MerchantOrderNo if s.Base.Status != 0 { s.Base.QueryWithdrawResp.Status = base.QueryStatusUnknown } else { if resp.Data.Success == 1 { s.Base.QueryWithdrawResp.Status = base.QueryStatusOrderSuccess } else if resp.Data.Success == -1 { s.Base.QueryWithdrawResp.Status = base.QueryStatusFail } else { s.Base.QueryWithdrawResp.Status = base.QueryStatusUnknown } } return ret, nil } else if s.Base.Opt == base.OPTQueryPay { resp := s.Base.Resp.(*QueryPayResp) ret := &pb.InnerQueryWithdrawResp{} if resp.RetCode != "0000" { // 错误 log.Error("robus query pay err, %+v", resp) s.Base.QueryPayResp.Status = base.QueryStatusUnknown return ret, nil } s.Base.QueryWithdrawResp.OrderID = resp.Data.MerchantOrderNo if s.Base.Status != 0 { s.Base.QueryPayResp.Status = base.QueryStatusUnknown } else { if resp.Data.Success == 1 { s.Base.QueryPayResp.Status = base.QueryStatusOrderSuccess } else if resp.Data.Success == -1 { s.Base.QueryPayResp.Status = base.QueryStatusFail } else { s.Base.QueryPayResp.Status = base.QueryStatusUnknown } } return ret, nil } return nil, errors.New("unknown opt") } func (s *Sub) PackPayReq() interface{} { r := s.Base.PayReq send := &PayReq{ MerchantNo: merchantId, MerchantOrderNo: r.OrderID, Amount: fmt.Sprintf("%d.00", r.Amount), Name: r.Name, Email: r.Email, Mobile: r.Phone, RequestTime: time.Now().Format(time.DateTime), Method: "121001", AsyncCallbackUrl: s.Base.GetPayCallbackURL(), SyncCallbackUrl: s.Base.GetPayCallbackURL(), SignType: "MD5", Country: "IN", } signValue, err := s.GetSign(send) if err != nil { log.Error("get sign err, %s", err.Error()) } send.Sign = signValue return send } func (s *Sub) PackWithdrawReq() interface{} { r := s.Base.WithdrawReq paramBytes, _ := json.Marshal(map[string]string{ "accountName": r.Name, "accountNo": r.CardNo, "bankCode": r.PayCode, }) send := &WithdrawReq{ MerchantNo: merchantId, MerchantOrderNo: r.OrderID, Amount: fmt.Sprintf("%d.00", r.Amount), Name: r.Name, Email: r.Email, Mobile: r.Phone, RequestTime: time.Now().Format(time.DateTime), AsyncCallbackUrl: s.Base.GetWithdrawCallbackURL(), Method: "121002", WithdrawCode: "1002", WithdrawParam: string(paramBytes), SignType: "MD5", Country: "IN", } signValue, err := s.GetSign(send) if err != nil { log.Error("get sign err, %s", err.Error()) } send.Sign = signValue return send } func (s *Sub) GetSignStr(body interface{}) (sign, signStr string) { bodyBytes, err := jsoniter.Marshal(body) if err != nil { log.Error("marshal err, %s", err.Error()) return } var ( paramsMap map[string]interface{} params []string paramsValue []string ) err = jsoniter.Unmarshal(bodyBytes, ¶msMap) if err != nil { log.Error("unmarshal err, %s", err.Error()) return } for k, v := range paramsMap { if k == "sign" { sign = v.(string) continue } params = append(params, k) } sort.Strings(params) for _, v := range params { value := fmt.Sprintf("%+v", paramsMap[v]) switch (paramsMap[v]).(type) { case float32: value = fmt.Sprintf("%d", int(paramsMap[v].(float32))) case float64: value = fmt.Sprintf("%d", int(paramsMap[v].(float64))) } paramsValue = append(paramsValue, fmt.Sprintf("%s=%+v", v, value)) } signStr = strings.Join(paramsValue, "&") return } func (s *Sub) GetSign(body interface{}) (sign string, err error) { bodyBytes, err := jsoniter.Marshal(body) if err != nil { log.Error("marshal err, %s", err.Error()) return } var paramsMap map[string]interface{} err = jsoniter.Unmarshal(bodyBytes, ¶msMap) if err != nil { log.Error("unmarshal err, %s", err.Error()) return } params := make([]string, 0) for k, v := range paramsMap { if k == "sign" || v == nil || v == "" { continue } params = append(params, k) } sort.Strings(params) paramsValue := make([]string, 0) for _, k := range params { paramsValue = append(paramsValue, fmt.Sprintf("%s=%v", k, paramsMap[k])) } paramsValue = append(paramsValue, "key="+key) signStr := strings.Join(paramsValue, "&") sign = strings.ToUpper(util.CalculateMD5(signStr)) return } func (s *Sub) checkSign(body string) (pass bool, err error) { var sign string mySign, err := s.GetSign(s.Base.CallbackReq) if err != nil { log.Error("robus get sign err, %s", err.Error()) return false, err } var ( paramsMap map[string]interface{} ) err = jsoniter.UnmarshalFromString(body, ¶msMap) if err != nil { log.Error("unmarshal err, %s", err.Error()) return } if paramsMap["sign"] == nil { return false, errors.New("sign is nil") } else { sign = paramsMap["sign"].(string) } return sign == mySign, nil } func (s *Sub) CheckSign(str string) bool { log.Debug("callback:%v", s.Base.CallbackReq) data, _ := json.Marshal(s.Base.CallbackReq) pass, err := s.checkSign(string(data)) if err != nil { log.Error("check sign err, %s", err.Error()) return false } if s.Base.Opt == base.OPTPayCB { req := s.Base.CallbackReq.(*PayCallbackReq) s.Base.CallbackResp.OrderID = req.MerchantOrderNo s.Base.CallbackResp.APIOrderID = req.OrderNo s.Base.CallbackResp.Success = req.Success == "1" if req.Success != "1" { s.Base.CallbackResp.FailMessage = fmt.Sprintf("返回结果不为1") } return pass } else if s.Base.Opt == base.OPTWithdrawCB { req := s.Base.CallbackReq.(*WithdrawCallbackReq) s.Base.CallbackResp.OrderID = req.MerchantOrderNo s.Base.CallbackResp.APIOrderID = req.OrderNo s.Base.CallbackResp.Success = req.Success == "1" if req.Success != "1" { s.Base.CallbackResp.FailMessage = fmt.Sprintf("返回结果不为1") } return pass } return false } func (s *Sub) PackQueryWithdrawReq() interface{} { r := s.Base.QueryWithdrawReq send := &QueryWithdrawReq{ MerchantNo: merchantId, MerchantOrderNo: r.OrderID, SignType: "MD5", Sign: "", } signValue, err := s.GetSign(send) if err != nil { log.Error("get sign err, %s", err.Error()) } send.Sign = signValue return send } func (s *Sub) PackQueryPayReq() interface{} { r := s.Base.QueryPayReq send := &QueryPayReq{ MerchantNo: merchantId, MerchantOrderNo: r.OrderID, SignType: "MD5", Sign: "", } signValue, err := s.GetSign(send) if err != nil { log.Error("get sign err, %s", err.Error()) } send.Sign = signValue return send }