package financial import ( "crypto/hmac" "crypto/md5" "crypto/sha256" "encoding/json" "fmt" "sort" "strings" "time" "git.rosy.net.cn/baseapi/platformapi/tonglianpayapi" "git.rosy.net.cn/baseapi/platformapi/wxpayapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" ) const ( sigKey = "sign" sigTypeMd5 = "MD5" sigTypeSha256 = "HMAC-SHA256" ) var ( payMap = map[string]*wxpayapi.API{ "weixinapp": api.WxpayAPI, "weixinmini": api.WxpayAPI2, } ) func (p *PayHandler) CreatePay() (err error) { switch p.PayType { case model.PayTypeTL: param := &tonglianpayapi.CreateUnitorderOrderParam{ Trxamt: int(p.Order.PayPrice), NotifyUrl: globals.TLPayNotifyURL, Reqsn: p.Order.OrderID, PayType: p.VendorPayType, } if p.VendorPayType == tonglianpayapi.PayTypeWxXcx { if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeWxApp { param.Acct = authInfo.GetAuthID() } } result, err := api.TLpayAPI.CreateUnitorderOrder(param) if err == nil { var result2 tonglianpayapi.PayInfo json.Unmarshal([]byte(result.PayInfo), &result2) p.Order.PrepayID = result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)] p.Order.TransactionID = result.TrxID _, err = dao.UpdateEntity(dao.GetDB(), p.Order, "PrepayID", "TransactionID") } case model.PayTypeWX: param := &wxpayapi.CreateOrderParam{ OutTradeNo: p.Order.OrderID, Body: "冲天猴儿App账户充值", NotifyURL: globals.WxpayNotifyURL, SpbillCreateIP: p.Ctx.GetRealRemoteIP(), TradeType: p.VendorPayType, TotalFee: p.Order.PayPrice, TimeStart: wxpayapi.Time2PayTime(time.Now()), // ProfitSharing: wxpayapi.OptYes, } authBinds, err := dao.GetUserBindAuthInfo(dao.GetDB(), p.Ctx.GetUserID(), model.AuthBindTypeAuth, []string{p.Order.Way}, "", "", "") if err != nil { return err } if len(authBinds) == 0 { return fmt.Errorf("未绑定微信认证方式!") } param.OpenID = authBinds[0].AuthID result, err2 := payMap[p.Order.Way].CreateUnifiedOrder(param) if err2 == nil { param2 := make(map[string]interface{}) param2["prepayid"] = result.PrepayID param2["noncestr"] = utils.GetUUID() param2["timestamp"] = time.Now().Unix() param2["package"] = "Sign=WXPay" param2["partnerid"] = result.MchID param2["appid"] = result.AppID sign := signParam(sigTypeMd5, param2) wxPay := &WxPayParam{ Prepayid: param2["prepayid"].(string), Noncestr: param2["noncestr"].(string), Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(param2["timestamp"])), Package: param2["package"].(string), Partnerid: param2["partnerid"].(string), Appid: param2["appid"].(string), Sign: sign, } p.WxPayParam = wxPay p.Order.PrepayID = result.PrepayID p.Order.Comment = result.CodeURL _, err = dao.UpdateEntity(dao.GetDB(), p.Order, "PrepayID", "Comment") } else { return err2 } default: err = fmt.Errorf("支付方式:%d当前不支持", p.PayType) } return err } func signParam(signType string, params map[string]interface{}) (sig string) { var valueList []string for k, v := range params { if k != sigKey { if str := fmt.Sprint(v); str != "" { valueList = append(valueList, fmt.Sprintf("%s=%s", k, str)) } } } sort.Sort(sort.StringSlice(valueList)) valueList = append(valueList, fmt.Sprintf("key=%s", globals.WxpayAppKey)) sig = strings.Join(valueList, "&") var binSig []byte if signType == sigTypeSha256 { mac := hmac.New(sha256.New, []byte(globals.WxpayAppKey)) mac.Write([]byte(sig)) binSig = mac.Sum(nil) } else { binSig2 := md5.Sum([]byte(sig)) binSig = binSig2[:] } sig = fmt.Sprintf("%X", binSig) // baseapi.SugarLogger.Debug(sig) return sig } func (p *PayHandler) CreateRefund() (err error) { switch p.PayType { case model.PayTypeTL: case model.PayTypeWX: //企业付款(提现) if p.VendorPayType == model.VendorPayTypeCompanyPay { // param := &wxpayapi.TransfersParam{ // PartnerTradeNo: p.Order.OrderID, // CheckName: wxpayapi.CheckName, // Desc: "冲天猴儿app提现到账", // SpbillCreateIP: p.Ctx.GetRealRemoteIP(), // } // //1元以下免费,以上收取对应城市手续费 // place, err := dao.GetPlaceByCode(dao.GetDB(), p.Order.CityCode) // if err != nil || place == nil { // return fmt.Errorf("未找到该城市!code:%v", p.Order.CityCode) // } // if p.Order.PayPrice < 100 { // param.Amount = p.Order.PayPrice // } else { // param.Amount = p.Order.PayPrice * place.DividePercentage / 100 //手续费 // } // if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil { // param.OpenID = authInfo.GetAuthID() // } // globals.SugarLogger.Debugf("CreateRefund wx param: %v", utils.Format4Output(param, false)) // result, err2 := payMap[p.Order.Way].Transfers(param) // if err2 == nil { // p.Order.PayFinishedAt = utils.Str2Time(result.PaymentTime) // p.Order.Comment = result.DeviceInfo // p.Order.OriginalData = utils.Format4Output(result, true) // if result.ReturnMsg == "" { // p.Order.Status = model.OrderStatusFinished // } else { // p.Order.Status = model.OrderStatusCanceled // } // dao.UpdateEntity(dao.GetDB(), p.Order) // if result.ReturnMsg == "" { // err = OnCashFinished(p.Order) // } // } else { // return err2 // } err = OnCashFinished(p.Order) } else if p.VendorPayType == model.VendorPayTypeTransferAccount { p.Order.PayFinishedAt = time.Now() p.Order.Comment = "手动转账" p.Order.Status = model.OrderStatusFinished if _, err := dao.UpdateEntity(dao.GetDB(), p.Order); err == nil { err = OnCashFinished(p.Order) } } } return err } func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) { globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true)) switch call.TrxCode { case tonglianpayapi.MsgTypePay: err = onTLpayFinished(call) case tonglianpayapi.MsgTypeRefund: err = onTLpayRefund(call) } return err } func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) { order := &model.Order{ OrderID: call.CusorderID, } db := dao.GetDB() if err = dao.GetEntity(db, order, "OrderID"); err == nil { if order.Status != model.OrderStatusWait4Pay { globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err) return err } loc, _ := time.LoadLocation("Local") t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc) order.PayFinishedAt = t1 // order.TransactionID = call.ChnlTrxID order.OriginalData = utils.Format4Output(call, true) if call.TrxStatus == tonglianpayapi.TrxStatusSuccess { order.Status = model.OrderStatusFinished } else { order.Status = model.OrderStatusCanceled } dao.UpdateEntity(db, order) if call.TrxStatus == tonglianpayapi.TrxStatusSuccess { err = OnPayFinished(order) } } else { globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err) } return err } func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) { // orderPayRefund := &model.OrderPayRefund{ // RefundID: call.CusorderID, // } // db := dao.GetDB() // if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil { // if call.TrxStatus == tonglianpayapi.TrxStatusSuccess { // orderPayRefund.Status = model.RefundStatusYes // } else { // orderPayRefund.Status = model.RefundStatusFailed // } // orderPayRefund.OriginalData = utils.Format4Output(call, true) // dao.UpdateEntity(db, orderPayRefund) // } else if dao.IsNoRowsError(err) { // globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true)) // } // orderPay := &model.OrderPay{ // VendorOrderID: orderPayRefund.VendorOrderID, // VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID), // PayType: model.PayTypeWX, // Status: model.PayStatusYes, // } // orderPay.DeletedAt = utils.DefaultTimeValue // if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil { // orderPay.Status = model.PayStatusRefund // dao.UpdateEntity(db, orderPay) // } return err } // func RefundOrderByTL(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) { // result, err := api.TLpayAPI.PayRefund(&tonglianpayapi.PayRefundParam{ // Trxamt: refundFee, // Reqsn: utils.GetUUID(), // Remark: refundDesc, // OldTrxID: orderPay.TransactionID, // }) // if err == nil { // orderPayRefund = &model.OrderPayRefund{ // RefundID: refundID, // VendorRefundID: result.TrxID, // VendorOrderID: orderPay.VendorOrderID, // VendorID: orderPay.VendorID, // Status: model.RefundStatusNo, // TransactionID: orderPay.TransactionID, // RefundFee: refundFee, // RefundCreatedAt: time.Now(), // } // dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName()) // db := dao.GetDB() // if result.TrxStatus == tonglianpayapi.TrxStatusSuccess { // orderPayRefund.Status = model.RefundStatusYes // } else { // orderPayRefund.Status = model.RefundStatusFailed // } // orderPayRefund.OriginalData = utils.Format4Output(result, true) // dao.CreateEntity(db, orderPayRefund) // orderPay.Status = model.PayStatusRefund // dao.UpdateEntity(db, orderPay) // } // return orderPayRefund, err // } func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) { globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true)) switch msg.MsgType { case wxpayapi.MsgTypePay: err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg)) case wxpayapi.MsgTypeRefund: // err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg)) } return err } func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) { order := &model.Order{ OrderID: msg.OutTradeNo, } db := dao.GetDB() if err = dao.GetEntity(db, order, "OrderID"); err == nil { order.PayFinishedAt = wxpayapi.PayTime2Time(msg.TimeEnd) order.TransactionID = msg.TransactionID order.OriginalData = utils.Format4Output(msg, true) if msg.ResultCode == wxpayapi.ResponseCodeSuccess { order.Status = model.OrderStatusFinished } else { order.Status = model.OrderStatusCanceled } dao.UpdateEntity(db, order) if msg.ResultCode == wxpayapi.ResponseCodeSuccess { err = OnPayFinished(order) } } else { globals.SugarLogger.Debugf("onWxpayFinished msg:%s, err:%v", utils.Format4Output(msg, true), err) } return err } // func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) { // orderPayRefund := &model.OrderPayRefund{ // RefundID: msg.ReqInfoObj.OutRefundNo, // } // db := dao.GetDB() // if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil { // if msg.ResultCode == wxpayapi.ResponseCodeSuccess { // orderPayRefund.Status = model.RefundStatusYes // } else { // orderPayRefund.Status = model.RefundStatusFailed // } // orderPayRefund.OriginalData = utils.Format4Output(msg, true) // dao.UpdateEntity(db, orderPayRefund) // } else if dao.IsNoRowsError(err) { // globals.SugarLogger.Warnf("收到异常的退款事件, msg:%s", utils.Format4Output(msg, true)) // } // orderPay := &model.OrderPay{ // VendorOrderID: orderPayRefund.VendorOrderID, // VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID), // PayType: model.PayTypeWX, // Status: model.PayStatusYes, // } // orderPay.DeletedAt = utils.DefaultTimeValue // if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil { // orderPay.Status = model.PayStatusRefund // dao.UpdateEntity(db, orderPay) // } // return err // }