diff --git a/app/flexible_employment/db/db_new_flexible_employment_pupiao_basic.go b/app/flexible_employment/db/db_new_flexible_employment_pupiao_basic.go new file mode 100644 index 0000000..1cf47e1 --- /dev/null +++ b/app/flexible_employment/db/db_new_flexible_employment_pupiao_basic.go @@ -0,0 +1,40 @@ +package db + +import ( + "applet/app/db" + "applet/app/flexible_employment/db/model" + "applet/app/utils/logx" + "xorm.io/xorm" +) + +type NewFlexibleEmploymentPuiaoBasicDb struct { + Db *xorm.Engine `json:"model"` +} + +func (flexibleEmploymentPupiaoBasicDb *NewFlexibleEmploymentPuiaoBasicDb) Set() { // set方法 + flexibleEmploymentPupiaoBasicDb.Db = db.Db +} + +func (flexibleEmploymentPupiaoBasicDb *NewFlexibleEmploymentPuiaoBasicDb) GetBasic(masterId string) (m *model.NewFlexibleEmploymentPupiaoBasic, err error) { + m = new(model.NewFlexibleEmploymentPupiaoBasic) + has, err := flexibleEmploymentPupiaoBasicDb.Db.Where("master_id = ?", masterId).Get(m) + if err != nil { + return nil, logx.Error(err) + } + if has == false { + return nil, nil + } + return m, nil +} + +func (flexibleEmploymentPupiaoBasicDb *NewFlexibleEmploymentPuiaoBasicDb) GetBasicByAppId(appKey string) (m *model.NewFlexibleEmploymentPupiaoBasic, err error) { + m = new(model.NewFlexibleEmploymentPupiaoBasic) + has, err := flexibleEmploymentPupiaoBasicDb.Db.Where("app_key = ?", appKey).Get(m) + if err != nil { + return nil, logx.Error(err) + } + if has == false { + return nil, nil + } + return m, nil +} diff --git a/app/flexible_employment/db/db_new_flexible_employment_pupiao_ord.go b/app/flexible_employment/db/db_new_flexible_employment_pupiao_ord.go new file mode 100644 index 0000000..676ead8 --- /dev/null +++ b/app/flexible_employment/db/db_new_flexible_employment_pupiao_ord.go @@ -0,0 +1,44 @@ +package db + +import ( + commDb "applet/app/db" + "applet/app/flexible_employment/db/model" + "applet/app/utils/logx" + "xorm.io/xorm" +) + +type NewFlexibleEmploymentPupiaoOrdDb struct { + Db *xorm.Engine `json:"model"` +} + +func (NewFlexibleEmploymentPupiaoOrdDb *NewFlexibleEmploymentPupiaoOrdDb) Set(masterId string) { // set方法 + NewFlexibleEmploymentPupiaoOrdDb.Db = commDb.DBs[masterId] +} + +func (NewFlexibleEmploymentPupiaoOrdDb *NewFlexibleEmploymentPupiaoOrdDb) Get(outBatchNo string) (m *model.NewFlexibleEmploymentPupiaoOrd, err error) { + m = new(model.NewFlexibleEmploymentPupiaoOrd) + has, err := NewFlexibleEmploymentPupiaoOrdDb.Db.Where("out_batch_no = ?", outBatchNo).Get(m) + if err != nil { + return nil, logx.Error(err) + } + if has == false { + return nil, nil + } + return m, nil +} + +func (NewFlexibleEmploymentPupiaoOrdDb *NewFlexibleEmploymentPupiaoOrdDb) Update(id interface{}, m *model.NewFlexibleEmploymentPupiaoOrd, forceColums ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceColums != nil { + affected, err = NewFlexibleEmploymentPupiaoOrdDb.Db.Where("id=?", id).Cols(forceColums...).Update(m) + } else { + affected, err = NewFlexibleEmploymentPupiaoOrdDb.Db.Where("id=?", id).Update(m) + } + if err != nil { + return 0, err + } + return affected, nil +} diff --git a/app/flexible_employment/db/model/new_flexible_employment_pupiao_basic.go b/app/flexible_employment/db/model/new_flexible_employment_pupiao_basic.go new file mode 100644 index 0000000..5b1b66a --- /dev/null +++ b/app/flexible_employment/db/model/new_flexible_employment_pupiao_basic.go @@ -0,0 +1,13 @@ +package model + +type NewFlexibleEmploymentPupiaoBasic struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + MasterId int `json:"master_id" xorm:"not null default 0 comment('站长ID') INT(11)"` + AppKey string `json:"app_key" xorm:"not null default '' comment('Appkey') VARCHAR(255)"` + SecretKey string `json:"secret_key" xorm:"not null default '' comment('Serctkey') VARCHAR(255)"` + MerchantId string `json:"merchant_id" xorm:"not null default '' comment('商户id') VARCHAR(255)"` + AgreementId string `json:"agreement_id" xorm:"not null default '' comment('协议id') VARCHAR(255)"` + CallbackUrl string `json:"callback_url" xorm:"not null default '' comment('回调地址') VARCHAR(255)"` + CreateAt string `json:"create_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"` + UpdateAt string `json:"update_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') DATETIME"` +} diff --git a/app/flexible_employment/db/model/new_flexible_employment_pupiao_ord.go b/app/flexible_employment/db/model/new_flexible_employment_pupiao_ord.go new file mode 100644 index 0000000..f2a716f --- /dev/null +++ b/app/flexible_employment/db/model/new_flexible_employment_pupiao_ord.go @@ -0,0 +1,19 @@ +package model + +type NewFlexibleEmploymentPupiaoOrd struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Uid int `json:"uid" xorm:"not null default 0 comment('用户id') INT(11)"` + WithdrawApplyId int64 `json:"withdraw_apply_id" xorm:"not null default 0 comment('提现记录ID') BIGINT(20)"` + OutBatchNo string `json:"out_batch_no" xorm:"not null default '' comment('外部商户批次订单号') VARCHAR(255)"` + PlatformBatchNo string `json:"platform_batch_no" xorm:"not null default '' comment('平台批次订单号') VARCHAR(255)"` + TotalAmount string `json:"total_amount" xorm:"not null default 0.00 comment('总金额') DECIMAL(8,2)"` + BatchStatus int `json:"batch_status" xorm:"not null default 0 comment('发放状态(0:待发放 1:发放成功 2:发放取消)') TINYINT(1)"` + SettleType string `json:"settle_type" xorm:"not null default '' comment('结算方式(CARD:银行卡,ALIPAY:支付宝)') CHAR(50)"` + PayeeNo string `json:"payee_no" xorm:"not null default '' comment('收款人账户') CHAR(50)"` + PayeePhone string `json:"payee_phone" xorm:"not null default '' comment('收款人手机号') CHAR(50)"` + PayeeName string `json:"payee_name" xorm:"not null default '' comment('收款人姓名') CHAR(50)"` + PayeeIdCard string `json:"payee_id_card" xorm:"not null default '' comment('收款人身份证号') CHAR(50)"` + CallbackData string `json:"callback_data" xorm:"not null comment('回调通知') TEXT"` + CreateAt string `json:"create_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"` + UpdateAt string `json:"update_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') DATETIME"` +} diff --git a/app/flexible_employment/db/model/new_flexible_employment_pupiao_user_info.go b/app/flexible_employment/db/model/new_flexible_employment_pupiao_user_info.go new file mode 100644 index 0000000..7446c20 --- /dev/null +++ b/app/flexible_employment/db/model/new_flexible_employment_pupiao_user_info.go @@ -0,0 +1,13 @@ +package model + +type NewFlexibleEmploymentPupiaoUserInfo struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Uid int `json:"uid" xorm:"not null default 0 INT(11)"` + Name string `json:"name" xorm:"not null default '' comment('姓名') VARCHAR(255)"` + Mobile string `json:"mobile" xorm:"not null default '' comment('手机号') VARCHAR(255)"` + Identity string `json:"identity" xorm:"not null default '' comment('证件号码') VARCHAR(255)"` + BankAccountNo string `json:"bank_account_no" xorm:"not null default '' comment('默认银行账号') VARCHAR(255)"` + AlipayAccountNo string `json:"alipay_account_no" xorm:"not null default '' comment('默认支付宝账号') VARCHAR(255)"` + CreateAt string `json:"create_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"` + UpdateAt string `json:"update_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') DATETIME"` +} diff --git a/app/flexible_employment/enum/enum_new_pupiao_api.go b/app/flexible_employment/enum/enum_new_pupiao_api.go new file mode 100644 index 0000000..e85e899 --- /dev/null +++ b/app/flexible_employment/enum/enum_new_pupiao_api.go @@ -0,0 +1,16 @@ +package enum + +type NewPuPiaoMethodName string + +const ( + MerchantExportApiPayPayApi = "/merchant/exportApi/pay/payApi" +) + +func (gt NewPuPiaoMethodName) String() string { + switch gt { + case MerchantExportApiPayPayApi: + return "委托代征佣金发放API" + default: + return "未知" + } +} diff --git a/app/lib/flexible_employment/new_pupiao.go b/app/lib/flexible_employment/new_pupiao.go new file mode 100644 index 0000000..1023487 --- /dev/null +++ b/app/lib/flexible_employment/new_pupiao.go @@ -0,0 +1,178 @@ +package flexible_employment + +import ( + "applet/app/cfg" + "applet/app/utils" + "crypto/md5" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strings" + "time" +) + +type PuPiaoService struct { + BaseURL string + MerchantNo string + AgreementId string + AppKey string + SecretKey string +} + +const NewUrlForPrd = "https://admin.linglong.net.cn" +const NewUrlForDev = "http://saas-merchant-test.youjiayun.com" + +func NewNewPuPiao(appKey, secretKey, merchantNo, agreementId string) *PuPiaoService { + var baseURL string + if cfg.Prd { + baseURL = NewUrlForPrd + } else { + baseURL = NewUrlForDev + } + return &PuPiaoService{ + BaseURL: baseURL, + MerchantNo: merchantNo, + AgreementId: agreementId, + AppKey: appKey, + SecretKey: secretKey, + } +} + +func (as *PuPiaoService) Encrypt(data map[string]interface{}) string { + utils.FilePutContents("new_pupiao_encrypt", utils.SerializeStr(data)) + // 排序键 + keys := make([]string, 0, len(data)) + for k := range data { + keys = append(keys, k) + } + sort.Strings(keys) + + var str = as.SecretKey + for _, k := range keys { + v := data[k] + if k == "payDetailList" { + strByte, _ := json.Marshal(v) + var tmpMap []map[string]string + json.Unmarshal(strByte, &tmpMap) + str += fmt.Sprintf("[{\"detailOrderNo\":\"%s\",\"amount\":\"%s\",\"phone\":\"%s\",\"idCard\":\"%s\",\"accountNo\":\"%s\",\"userName\":\"%s\"}]", + tmpMap[0]["detailOrderNo"], + tmpMap[0]["amount"], + tmpMap[0]["phone"], + tmpMap[0]["idCard"], + tmpMap[0]["accountNo"], + tmpMap[0]["userName"], + ) + } else { + toString, _ := utils.InterfaceToString(v) + str += toString + } + } + + return utils.MD5ToLower32(str) +} + +func (as *PuPiaoService) CurlPost(url string, data map[string]interface{}) (map[string]interface{}, error) { + sign := as.Encrypt(data) + + jsonData, err := json.Marshal(data) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", url, strings.NewReader(string(jsonData))) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("orderId", fmt.Sprintf("%d%d", time.Now().Unix(), time.Now().Nanosecond())) + req.Header.Set("merchantNo", as.MerchantNo) + req.Header.Set("agreementId", as.AgreementId) + req.Header.Set("sign", sign) + req.Header.Set("appKey", as.AppKey) + req.Header.Set("requireTime", time.Now().Format("2006-01-02 15:04:05")) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var result map[string]interface{} + err = json.Unmarshal(body, &result) + if err != nil { + return nil, err + } + + return result, nil +} + +func (as *PuPiaoService) EncryptGet(data url.Values) string { + // 将 data 转换为 sorted keys 字符串 + var keys []string + for k := range data { + keys = append(keys, k) + } + sort.Strings(keys) + var str strings.Builder + str.WriteString(as.SecretKey) + for _, k := range keys { + values := data[k] + // 如果 key 有多个值,这里简单处理为只取第一个值 + if len(values) > 0 { + str.WriteString(values[0]) + } + } + hasher := md5.New() + hasher.Write([]byte(str.String())) + return hex.EncodeToString(hasher.Sum(nil)) + +} + +func (as *PuPiaoService) CurlGet(uri string, data url.Values) (map[string]interface{}, error) { + sign := as.EncryptGet(data) + // 附加查询参数到 URL + query := url.Values{} + for k, v := range data { + query.Add(k, v[0]) // 假设每个 key 只有一个值 + } + query.Add("sign", sign) + fullURL := uri + "?" + query.Encode() + req, err := http.NewRequest("GET", fullURL, nil) + if err != nil { + return nil, err + } + + req.Header.Set("orderId", fmt.Sprintf("%d", time.Now().Unix())) + req.Header.Set("merchantNo", as.MerchantNo) + req.Header.Set("agreementId", as.AgreementId) + req.Header.Set("appKey", as.AppKey) + req.Header.Set("requireTime", time.Now().Format("2006-01-02 15:04:05")) + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var result map[string]interface{} + err = json.Unmarshal(body, &result) + if err != nil { + return nil, err + } + return result, nil +} diff --git a/consume/init.go b/consume/init.go index bbcecbb..e50901a 100644 --- a/consume/init.go +++ b/consume/init.go @@ -100,6 +100,7 @@ func initConsumes() { jobs[consumeMd.WithdrawConsumeFunName] = WithdrawConsume jobs[consumeMd.FlexibleEmploymentWithdrawForGongMaoConsumeFunName] = FlexibleEmploymentWithdrawForGongMaoConsume jobs[consumeMd.FlexibleEmploymentWithdrawForPupiaoConsumeFunName] = FlexibleEmploymentWithdrawForPupiaoConsume + jobs[consumeMd.NewFlexibleEmploymentWithdrawForPupiaoConsumeFunName] = NewFlexibleEmploymentWithdrawForPupiaoConsume jobs[consumeMd.ServiceAwardDividendRelationConsumeFunName] = ServiceAwardDividendRelationConsume //jobs[consumeMd.ZhiosMallGreenCoinConsumeFunName] = ZhiosMallGreenCoinConsume //绿色双链积分 diff --git a/consume/md/consume_key.go b/consume/md/consume_key.go index a4b47c9..97c5b20 100644 --- a/consume/md/consume_key.go +++ b/consume/md/consume_key.go @@ -596,6 +596,15 @@ var RabbitMqQueueKeyList = []*MqQueue{ BindKey: "", ConsumeFunName: "FlexibleEmploymentWithdrawForPupiaoConsume", }, + { + ExchangeName: "zhios.app.user.withdraw.apply.flexible.employment.exchange", + Name: "zhios_app_user_withdraw_apply_new_pupiao_queue", + Type: DirectQueueType, + IsPersistent: false, + RoutKey: "new_pupiao", + BindKey: "", + ConsumeFunName: "NewFlexibleEmploymentWithdrawForPupiaoConsume", + }, { ExchangeName: "installment.payment", Name: "zhios_installment_payment_auto_repaid", @@ -679,6 +688,7 @@ const ( WithdrawConsumeFunName = "WithdrawConsume" FlexibleEmploymentWithdrawForGongMaoConsumeFunName = "FlexibleEmploymentWithdrawForGongMaoConsume" FlexibleEmploymentWithdrawForPupiaoConsumeFunName = "FlexibleEmploymentWithdrawForPupiaoConsume" + NewFlexibleEmploymentWithdrawForPupiaoConsumeFunName = "NewFlexibleEmploymentWithdrawForPupiaoConsume" ZhiosTaskTotal = "zhiosTaskTotal" ZhiosUserProfileInviteCode = "ZhiosUserProfileInviteCode" ZhiosAutoUnFreeze = "ZhiosAutoUnFreeze" diff --git a/consume/withdraw_consume_new_pupiao.go b/consume/withdraw_consume_new_pupiao.go new file mode 100644 index 0000000..7f3ebad --- /dev/null +++ b/consume/withdraw_consume_new_pupiao.go @@ -0,0 +1,184 @@ +package consume + +import ( + "applet/app/cfg" + "applet/app/db" + db2 "applet/app/flexible_employment/db" + "applet/app/flexible_employment/enum" + "applet/app/flexible_employment/svc" + "applet/app/lib/flexible_employment" + "applet/app/utils" + "applet/app/utils/logx" + "applet/consume/md" + "code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit" + "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/rule/one_circles" + "encoding/json" + "errors" + "fmt" + "github.com/streadway/amqp" + "time" +) + +func NewFlexibleEmploymentWithdrawForPupiaoConsume(queue md.MqQueue) { + fmt.Println(">>>>>>>>>>>>NewFlexibleEmploymentWithdrawForPupiaoConsume>>>>>>>>>>>>") + ch, err := rabbit.Cfg.Pool.GetChannel() + if err != nil { + logx.Error(err) + return + } + defer ch.Release() + //1、将自己绑定到交换机上 + ch.Bind(queue.Name, queue.ExchangeName, queue.RoutKey) + //2、取出数据进行消费 + ch.Qos(1) + delivery := ch.Consume(queue.Name, false) + + one_circles.Init(cfg.RedisAddr) + + var res amqp.Delivery + var ok bool + for { + res, ok = <-delivery + if ok == true { + err = handleNewFlexibleEmploymentWithdrawForPupiaoConsume(res.Body) + fmt.Println("err ::: ", err) + if err != nil { + fmt.Println("NewFlexibleEmploymentWithdrawForPupiaoConsume_ERR:::::", err.Error()) + //_ = res.Reject(true) + _ = res.Reject(false) + var msg interface{} + json.Unmarshal(res.Body, &msg) + if err.Error() == "Connection timed out" { + //TODO::重新推回队列末尾,避免造成队列堵塞 + ch.Publish(queue.ExchangeName, msg, queue.RoutKey) + } else { + //TODO::推入新的队列中备份 + utils.FilePutContents("NewFlexibleEmploymentWithdrawForPupiaoConsume_ERR", utils.SerializeStr(err.Error())) + ch.Publish("zhios.app.user.withdraw.apply.exception.exchange", msg, "new_pupiao") + } + } else { + err = res.Ack(true) + } + } else { + panic(errors.New("error getting message")) + } + } + fmt.Println("get msg done") +} + +func handleNewFlexibleEmploymentWithdrawForPupiaoConsume(msgData []byte) error { + var ms string + err := json.Unmarshal(msgData, &ms) + if err != nil { + return err + } + time.Sleep(time.Microsecond * 200) // 等待200毫秒 + //1、解析mq中queue的数据结构体 + var msg struct { + Uid string `json:"uid"` + Nickname string `json:"nickname"` + MasterId string `json:"master_id"` + AppName string `json:"app_name"` + ApplyOrder string `json:"apply_order"` + ActualAmount string `json:"actual_amount"` + Oid string `json:"oid"` + MobCfg interface{} `json:"mob_cfg"` + } + err = json.Unmarshal([]byte(ms), &msg) + if err != nil { + return err + } + fmt.Println("pupiao_message:::::::::::>>>>>>>>>") + fmt.Println(msg) + if db.DBs[msg.MasterId] == nil { + return nil + } + engine := db.DBs[msg.MasterId] + + //1、查找对应记录 + flexibleEmploymentPupiaoOrdDb := db2.NewFlexibleEmploymentPupiaoOrdDb{} + flexibleEmploymentPupiaoOrdDb.Set(msg.MasterId) + flexibleEmploymentPupiaoOrd, err := flexibleEmploymentPupiaoOrdDb.Get(msg.Oid) + if err != nil { + return err + } + if flexibleEmploymentPupiaoOrd == nil { + return errors.New("未查询到对应订单记录") + } + + flexibleEmploymentPuiaoBasicDb := db2.NewFlexibleEmploymentPuiaoBasicDb{} + flexibleEmploymentPuiaoBasicDb.Set() + basic, err := flexibleEmploymentPuiaoBasicDb.GetBasic(msg.MasterId) + if err != nil { + return err + } + + //2、发起制单 + puPiao := flexible_employment.NewNewPuPiao(basic.AppKey, basic.SecretKey, basic.MerchantId, basic.AgreementId) + var userAESData = []map[string]string{ + { + "detailOrderNo": "o_" + utils.Int64ToStr(flexibleEmploymentPupiaoOrd.WithdrawApplyId), + "amount": flexibleEmploymentPupiaoOrd.TotalAmount, + "phone": flexibleEmploymentPupiaoOrd.PayeePhone, + "idCard": flexibleEmploymentPupiaoOrd.PayeeIdCard, + "accountNo": flexibleEmploymentPupiaoOrd.PayeeNo, + "userName": flexibleEmploymentPupiaoOrd.PayeeName, + }, + } + + var bankType = "1" //银行卡 + var payMethod = "1" //银行卡 + if flexibleEmploymentPupiaoOrd.SettleType == "ALIPAY" { + bankType = "3" + payMethod = "2" + } + result, err := puPiao.CurlPost(enum.OpenApiPaymentReceiveOrder, map[string]interface{}{ + "bizOrderNo": flexibleEmploymentPupiaoOrd.OutBatchNo, + "totalCount": "1", + "totalAmount": flexibleEmploymentPupiaoOrd.TotalAmount, + "bankType": bankType, //打款通道 1银行卡 3支付宝&安全发 6微信或微工卡 + "payMethod": payMethod, //收款方式 1银行卡 2支付宝 6微信 + "payDetailList": userAESData, + "callbackUrl": basic.CallbackUrl, + }) + if err != nil { + return err + } + var response struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + PlatformOrderNo string `json:"platformOrderNo"` + BizOrderNo string `json:"bizOrderNo"` + } `json:"data"` + } + + if err = json.Unmarshal(utils.Serialize(result), &response); err != nil { + return err + } + if response.Code != 200 { + flexibleEmploymentPupiaoOrd.BatchStatus = 3 + updateAck, err := flexibleEmploymentPupiaoOrdDb.Update(flexibleEmploymentPupiaoOrd.Id, flexibleEmploymentPupiaoOrd, "batch_status") + if err != nil { + return err + } + if updateAck <= 0 { + return errors.New("更新 new_flexible_employment_pupiao_ord 状态失败") + } + //TODO::制单失败,将处理提现失败状态 + finWithdrawApply, err := db.UserWithDrawApplyByUIDById(engine, utils.Int64ToStr(flexibleEmploymentPupiaoOrd.WithdrawApplyId)) + if err != nil { + return err + } + session := engine.NewSession() + defer session.Close() + session.Begin() + err = svc.DealFailResultForPuPiao(session, finWithdrawApply, msg.MasterId, response.Msg) + if err != nil { + _ = session.Rollback() + return err + } + return session.Commit() + } + return nil +}