|
@@ -15,6 +15,7 @@ import (
|
|
|
wechatV3 "github.com/go-pay/gopay/wechat/v3"
|
|
|
"github.com/shopspring/decimal"
|
|
|
"net/http"
|
|
|
+ "reflect"
|
|
|
"strconv"
|
|
|
"time"
|
|
|
)
|
|
@@ -129,54 +130,205 @@ func UnifiedOrder(c *gin.Context) {
|
|
|
|
|
|
func PayCashOut(c *gin.Context) {
|
|
|
var inData models.PayCashOutRequest
|
|
|
- //var sqlData
|
|
|
+ var merchantAccountSql shanghu.MerchantAccount
|
|
|
+ var clientAccountSql shanghu.MerchantClientAccount
|
|
|
+ var cashOut shanghu.CashOut
|
|
|
+ var trans []models.TransferDetailList
|
|
|
+ var transDetail models.TransferDetailList
|
|
|
|
|
|
- if inData.CashType == "client" {
|
|
|
- //先设置账户状态 为提现中,提现中不允许再操作,提现金额默认全部
|
|
|
+ err := c.ShouldBindJSON(&inData)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if inData.Appid == "" { //appid 不能为空
|
|
|
+ app.Error(c, 400, errors.New("Appid不能为空"), "Appid不能为空")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if inData.Amount.Cmp(decimal.NewFromInt(500)) > 0 {
|
|
|
+ app.Error(c, 400, errors.New("单笔金额不能大于500"), "单笔金额不能大于500")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if inData.Amount.Cmp(decimal.NewFromInt(1)) < 0 {
|
|
|
+ app.Error(c, 400, errors.New("单笔金额不能小于1"), "单笔金额不能大于1")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ cashOut.OpenID = inData.OpenId
|
|
|
+ cashOut.AppID = inData.Appid
|
|
|
+ cashOut.Status = 1 //提现中
|
|
|
+ status := []int{1, 3} //提现中、金额待扣减
|
|
|
|
|
|
- } else if inData.CashType == "merchant" {
|
|
|
+ cashNum := cashOut.GetCashOutByStatusNum(status)
|
|
|
+ if cashNum > 0 {
|
|
|
+ app.Error(c, 400, errors.New("有一笔交易正在提现中"), "有一笔交易正在提现中")
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
+ //校验金额是否够
|
|
|
+ if inData.AccountType == "client" {
|
|
|
+ clientAccountSql.ClientOpenID = inData.OpenId
|
|
|
+ clientAccountInfo, err := clientAccountSql.GetClientAccount()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if inData.Amount.Cmp(clientAccountInfo.Amount) > 0 {
|
|
|
+ app.Error(c, 400, errors.New("账号余额不够"), "账号余额不够")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else if inData.AccountType == "merchant" {
|
|
|
+ merchantAccountSql.MerchantOpenID = inData.OpenId
|
|
|
+ merchantAccountInfo, err := merchantAccountSql.GetMerchantAccount()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if inData.Amount.Cmp(merchantAccountInfo.Amount) > 0 {
|
|
|
+ app.Error(c, 400, errors.New("账号余额不够"), "账号余额不够")
|
|
|
+ return
|
|
|
+ }
|
|
|
} else {
|
|
|
- app.Error(c, 400, errors.New("类型错误"), "类型错误")
|
|
|
+ app.Error(c, 400, errors.New("账户类型错误"), "账户类型错误")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- client := NewWechatService()
|
|
|
+ clientV3, err := NewWechatServiceV3(inData.Appid)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- err := client.AddCertPkcs12FilePath("./apiclient_cert.p12")
|
|
|
+ //clientV3.WxPublicKeyMap()
|
|
|
+ userName, err := clientV3.V3EncryptText(inData.UserName)
|
|
|
if err != nil {
|
|
|
app.Error(c, 400, err, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- bm := make(gopay.BodyMap)
|
|
|
+ transDetail.OutDetailNo = common.GetRandomString(32)
|
|
|
+ transDetail.TransferAmount = inData.Amount.Sub(cashOut.Fee).Mul(decimal.NewFromInt(100)).IntPart()
|
|
|
+ transDetail.UserName = userName
|
|
|
+ transDetail.Openid = inData.OpenId
|
|
|
+ transDetail.TransferRemark = "报销"
|
|
|
|
|
|
- partnerTradeNo := common.GetRandomString(32)
|
|
|
+ trans = append(trans, transDetail)
|
|
|
|
|
|
- bm.Set("nonce_str", common.GetRandomString(32))
|
|
|
- bm.Set("partner_trade_no", partnerTradeNo)
|
|
|
- bm.Set("openid", inData.OpenId)
|
|
|
- bm.Set("check_name", "FORCE_CHECK")
|
|
|
- bm.Set("re_user_name", inData.UserName)
|
|
|
- bm.Set("amount", 30) // 企业付款金额,单位为分
|
|
|
- bm.Set("desc", "测试转账") // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
|
|
|
- bm.Set("spbill_create_ip", "127.0.0.1")
|
|
|
+ //transBody, err := json.Marshal(transDetail)
|
|
|
+ //if err != nil {
|
|
|
+ // app.Error(c, 500, err, err.Error())
|
|
|
+ // return
|
|
|
+ //}
|
|
|
|
|
|
- wxResp, err := client.Transfer(c, bm)
|
|
|
+ partnerTradeNo := common.GetRandomString(32)
|
|
|
+ var cashOutCreate shanghu.CashOut
|
|
|
+ //创建提现记录
|
|
|
+ cashOutCreate.AppID = inData.Appid
|
|
|
+ cashOutCreate.Status = 1 //提现中
|
|
|
+ cashOutCreate.OpenID = inData.OpenId
|
|
|
+ cashOutCreate.Amount = inData.Amount
|
|
|
+ cashOutCreate.CreatedAt = time.Now()
|
|
|
+ cashOutCreate.UpdatedAt = time.Now()
|
|
|
+ cashOutCreate.PartnerTradeNo = partnerTradeNo
|
|
|
+ cashOutCreate.Fee = inData.Amount.Mul(decimal.NewFromFloat32(0.1))
|
|
|
+ cashOutInfo, err := cashOutCreate.Create()
|
|
|
if err != nil {
|
|
|
- app.Error(c, 400, err, "提现失败")
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- if wxResp.ReturnCode != "SUCCESS" {
|
|
|
- app.Error(c, 400, errors.New(wxResp.ReturnMsg), "提现")
|
|
|
+ //client := NewWechatServiceAppid(inData.Appid)
|
|
|
+
|
|
|
+ var bMap []gopay.BodyMap
|
|
|
+ bm := make(gopay.BodyMap)
|
|
|
+
|
|
|
+ bm.Set("appid", inData.Appid)
|
|
|
+ bm.Set("out_batch_no", partnerTradeNo)
|
|
|
+ bm.Set("batch_name", "报销")
|
|
|
+ bm.Set("batch_remark", "报销")
|
|
|
+ bm.Set("total_amount", inData.Amount.Sub(cashOutCreate.Fee).Mul(decimal.NewFromInt(100)).IntPart())
|
|
|
+ bm.Set("total_num", 1)
|
|
|
+ bMap = append(bMap, structToMap(&transDetail))
|
|
|
+
|
|
|
+ bm.Set("transfer_detail_list", bMap)
|
|
|
+ bm.Set("transfer_scene_id", "1001")
|
|
|
+
|
|
|
+ fmt.Println(bm.JsonBody())
|
|
|
+
|
|
|
+ //{
|
|
|
+ // "appid": "wxf636efh567hg4356",
|
|
|
+ // "out_batch_no": "plfk2020042013",
|
|
|
+ // "batch_name": "2019年1月深圳分部报销单",
|
|
|
+ // "batch_remark": "2019年1月深圳分部报销单",
|
|
|
+ // "total_amount": 4000000,
|
|
|
+ // "total_num": 200,
|
|
|
+ // "transfer_detail_list": [
|
|
|
+ //{
|
|
|
+ //"out_detail_no": "x23zy545Bd5436",
|
|
|
+ //"transfer_amount": 200000,
|
|
|
+ //"transfer_remark": "2020年4月报销",
|
|
|
+ //"openid": "o-MYE42l80oelYMDE34nYD456Xoy",
|
|
|
+ //"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45"
|
|
|
+ //}
|
|
|
+ //]
|
|
|
+ //}
|
|
|
+
|
|
|
+ reply, err := clientV3.V3Transfer(c, bm)
|
|
|
+ if err != nil {
|
|
|
+ cashOut.ID = cashOutInfo.ID
|
|
|
+ cashOut.FailRes = err.Error()
|
|
|
+ cashOut.Status = 2 //提现失败
|
|
|
+ cashOut.UpdateMerchantStatus()
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
return
|
|
|
}
|
|
|
- if wxResp.ResultCode != "SUCCESS" {
|
|
|
- app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "提现")
|
|
|
+
|
|
|
+ if reply.Code != 0 {
|
|
|
+ cashOut.ID = cashOutInfo.ID
|
|
|
+ cashOut.FailRes = reply.Error
|
|
|
+ cashOut.Status = 2 //提现失败
|
|
|
+ cashOut.UpdateMerchantStatus()
|
|
|
+ app.Error(c, 500, errors.New(reply.Error), reply.Error)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ cashOut.WxPartnerTradeNo = reply.Response.BatchId
|
|
|
+ cashOut.PartnerTradeNo = reply.Response.OutBatchNo
|
|
|
+ cashOut.UpdateCashOutWxBachNo()
|
|
|
+
|
|
|
+ //wxResp, err := client.Transfer(c, bm)
|
|
|
+ //if err != nil {
|
|
|
+ // cashOut.ID = cashOutInfo.ID
|
|
|
+ // cashOut.FailRes = err.Error()
|
|
|
+ // cashOut.Status = 2 //提现失败
|
|
|
+ // cashOut.UpdateMerchantStatus()
|
|
|
+ //
|
|
|
+ // app.Error(c, 400, err, "提现失败")
|
|
|
+ // return
|
|
|
+ //}
|
|
|
+ //
|
|
|
+ //if wxResp.ReturnCode != "SUCCESS" {
|
|
|
+ // cashOut.ID = cashOutInfo.ID
|
|
|
+ // cashOut.FailRes = wxResp.ReturnMsg
|
|
|
+ // cashOut.Status = 2 //提现失败
|
|
|
+ // cashOut.UpdateMerchantStatus()
|
|
|
+ // app.Error(c, 400, errors.New(wxResp.ReturnMsg), "提现")
|
|
|
+ // return
|
|
|
+ //}
|
|
|
+ //if wxResp.ResultCode != "SUCCESS" {
|
|
|
+ // cashOut.ID = cashOutInfo.ID
|
|
|
+ // cashOut.FailRes = wxResp.ErrCode + "--" + wxResp.ErrCodeDes
|
|
|
+ // cashOut.Status = 2 //提现失败
|
|
|
+ // cashOut.UpdateMerchantStatus()
|
|
|
+ // app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "提现")
|
|
|
+ // return
|
|
|
+ //}
|
|
|
+
|
|
|
+ app.OK(c, nil, app.Success)
|
|
|
+
|
|
|
}
|
|
|
|
|
|
func PayCallBack(c *gin.Context) {
|
|
@@ -266,9 +418,19 @@ func NewWechatService() *wechat.Client {
|
|
|
return client
|
|
|
}
|
|
|
|
|
|
-func NewWechatServiceV3() (*wechatV3.ClientV3, error) {
|
|
|
+func NewWechatServiceAppid(appid string) *wechat.Client {
|
|
|
|
|
|
- key := `MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD/RTrS1Tycrskr
|
|
|
+ client := wechat.NewClient(appid, "1501641641", "1RKRJBVH4vaRrF0XPW9GX2M3ZSImukIz", true)
|
|
|
+ //设置国家
|
|
|
+ client.SetCountry(wechat.China)
|
|
|
+
|
|
|
+ return client
|
|
|
+}
|
|
|
+
|
|
|
+func NewWechatServiceV3(appid string) (*wechatV3.ClientV3, error) {
|
|
|
+
|
|
|
+ key := `-----BEGIN PRIVATE KEY-----
|
|
|
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD/RTrS1Tycrskr
|
|
|
SkuzdLNmOic4UklFtoyKtKDIeklbQFvynJBC1wYaitoOqFkdGWagkcuqRqJOcgEQ
|
|
|
T8DRDD/rnVKTrnntevUSW3vZYwMscomK3dgjRRui5GLY5wYHuKhp02bldLrhPKNy
|
|
|
wT5IYhoDwQLmf5IrURbtT8bKpdC+NyEEfw+d/mHMK56w80YKfzFtSmjoB9SkWDLg
|
|
@@ -293,9 +455,9 @@ egqXhSaSLwgQNFUUCWDbl4pT3ZjRqxVQdcgwpjBkzratkO10dUOV7WoM6vbWuvwz
|
|
|
+vXf3ywE2MNUpsgmciROB3+O1LkhqBsVg9UwZmM+yQKBgQD6yBvxOaHXBSZncz+m
|
|
|
3SpdbcRjK82i3IUJ3sl18J7YEPer0FclsUcQOluqBbHTOAr8letWPrKnjZGuyFfg
|
|
|
gAjwa8uLSyfEEcWb9WcObvud2GNxS/LiI0GnW9ittvT29JvOhmUUtnty5/TiWIsi
|
|
|
-slm2kO53RSw9brymV8PAX2+SXg==`
|
|
|
-
|
|
|
- client, err := wechatV3.NewClientV3("wx25357518f710b8ce", "219B3AF3B5F17D4C2F145EE318188708318DD7BD", "9x9ydkdk0nzsa4mr2ucq75grlvt9n8l3", key)
|
|
|
+slm2kO53RSw9brymV8PAX2+SXg==
|
|
|
+-----END PRIVATE KEY-----`
|
|
|
+ client, err := wechatV3.NewClientV3("1501641641", "219B3AF3B5F17D4C2F145EE318188708318DD7BD", "9x9ydkdk0nzsa4mr2ucq75grlvt9n8l3", key)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -311,3 +473,22 @@ slm2kO53RSw9brymV8PAX2+SXg==`
|
|
|
|
|
|
return client, nil
|
|
|
}
|
|
|
+func structToMap(obj interface{}) gopay.BodyMap {
|
|
|
+ result := make(gopay.BodyMap)
|
|
|
+ value := reflect.ValueOf(obj).Elem() // 获取指针的值
|
|
|
+ typ := value.Type() // 获取类型信息
|
|
|
+
|
|
|
+ for i := 0; i < typ.NumField(); i++ {
|
|
|
+ field := typ.Field(i) // 获取字段信息
|
|
|
+ tag := field.Tag.Get("json") // 获取标签(如果有)
|
|
|
+ if tag != "" && !field.Anonymous { // 只处理非匿名字段且有标签的情况
|
|
|
+ key := field.Name // 默认使用字段名作为Key
|
|
|
+ if tag != "-" { // 若标签不等于-则使用标签作为Key
|
|
|
+ key = tag
|
|
|
+ }
|
|
|
+ result[key] = value.Field(i).Interface() // 存入Map
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result
|
|
|
+}
|