package lakala import ( "encoding/json" "errors" "fmt" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/globals" "net/http" "time" ) // CreateSeparate 进件成功的门店创建分账 func (a *API) CreateSeparate(param *CreateSeparateReq) (string, error) { if (param.SplitLaunchMode == SplitLaunchModeAuto || param.SplitLaunchMode == SplitLaunchModePointRule) && param.SplitRuleSource == "" { return "", fmt.Errorf("当分账发起方式为%s/%s时,分账规则来源不能为空", SplitLaunchModeAuto, SplitLaunchModePointRule) } reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(param, "", false), "reqId": param.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateAccountApplyAction, http.MethodPost, "", reqParameter) if err != nil { return "", err } bodyResult, err := json.Marshal(result) if err != nil { return "", err } resp := &CreateSeparateResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return "", err } if resp.RetCode != Success { return "", fmt.Errorf(resp.RetMsg) } return utils.Int64ToStr(resp.RespData.ApplyId), nil } // SeparateModify 商户申请变更分账商户 func (a *API) SeparateModify(modify *SeparateModifyReq) (string, error) { if modify.MerInnerNo == "" && modify.MerCupNo == "" { return "", fmt.Errorf("k卡拉卡内部账号或银联账号不能同时为空") } reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(modify, "", false), "reqId": modify.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateAccountModifyAction, http.MethodPost, "", reqParameter) if err != nil { return "", err } bodyResult, err := json.Marshal(result) if err != nil { return "", err } resp := &CreateSeparateResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return "", err } if resp.RetCode != Success { return "", fmt.Errorf(resp.RetMsg) } return utils.Int64ToStr(resp.RespData.ApplyId), nil } // SeparateQuery 商户分账信息查询 func (a *API) SeparateQuery(query *SeparateQueryReq) (*SeparateQueryResp, error) { if query.MerInnerNo == "" && query.MerCupNo == "" { return nil, fmt.Errorf("卡卡拉卡内部账号或银联账号不能同时为空") } reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(query, "", false), "reqId": query.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateAccountQueryAction, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["retCode"].(string) != Success { return nil, fmt.Errorf(result["retMsg"].(string)) } bodyResult, err := json.Marshal(result["respData"]) if err != nil { return nil, err } resp := &SeparateQueryResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } return resp, nil } // CreateSeparateRecipient 创建分账接收方 func (a *API) CreateSeparateRecipient(recipient *CreateSeparateRecipientReq) (string, error) { switch recipient.AcctTypeCode { case BankTypeEnterprise: if recipient.AcctNo == "" { return "", fmt.Errorf("收款账户账户类型为对公,必须上送[营业执照编号]") } if recipient.LicenseName == "" { return "", fmt.Errorf("收款账户账户类型为对公,必须上送[营业执照名称]") } if recipient.LegalPersonName == "" { return "", fmt.Errorf("收款账户账户类型为对公,必须上送[法人姓名]") } if recipient.LegalPersonCertificateType == "" { return "", fmt.Errorf("收款账户账户类型为对公,必须上送[法人证件类型]") } if recipient.LegalPersonCertificateNo == "" { return "", fmt.Errorf("收款账户账户类型为对公,必须上送[法人证件号]") } default: } reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(recipient, "", false), "reqId": recipient.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateReceiverApplyAction, http.MethodPost, "", reqParameter) if err != nil { return "", err } bodyResult, err := json.Marshal(result) if err != nil { return "", err } resp := &CreateSeparateRecipientResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return "", err } if resp.RetCode != Success { return "", fmt.Errorf(resp.RetMsg) } return resp.RespData.ReceiverNo, nil } // UpdateSeparateRecipient 分账接收方变更申请 func (a *API) UpdateSeparateRecipient(param *UpdateSeparateRecipientReq) (string, error) { if param.ReceiverNo == "" { return "", fmt.Errorf("分账接收方编号不能为空") } reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(param, "", false), "reqId": param.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateReceiverModifyAction, http.MethodPost, "", reqParameter) if err != nil { return "", err } bodyResult, err := json.Marshal(result) if err != nil { return "", err } resp := &CreateSeparateRecipientResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return "", err } if resp.RetCode != Success { return "", fmt.Errorf(resp.RetMsg) } return resp.RespData.OrderNo, nil } // QuerySeparateRecipient 分账方详细信息查询 func (a *API) QuerySeparateRecipient(orderNo, receiverNo string) (*QuerySeparateRecipientResp, error) { reqParameter := map[string]interface{}{ "reqData": map[string]string{ "version": Version, "orderNo": orderNo, "orgCode": a.orgCode, "receiverNo": receiverNo, }, } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateReceiverQueryAction, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["retCode"] != Success { return nil, errors.New(result["retMsg"].(string)) } bodyResult, err := json.Marshal(result["respData"]) if err != nil { return nil, err } resp := &QuerySeparateRecipientResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } return resp, nil } // ApplyBind 申请绑定分账关系 func (a *API) ApplyBind(param *SeparateApplyBindReq) (*SeparateApplyBindResp, error) { reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(param, "", false), "reqId": param.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateBindAction, http.MethodPost, "", reqParameter) if err != nil { return nil, err } bodyResult, err := json.Marshal(result) if err != nil { return nil, err } resp := &SeparateApplyBindResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } if resp.RetCode != Success { return nil, fmt.Errorf(resp.RetMsg) } return resp, nil } // SeparateUnBind 申请解除绑定 func (a *API) SeparateUnBind(param *SeparateUnBindReq) (string, error) { reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(param, "", false), "reqId": param.OrderNo, "version": Version, "reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateUnBindAction, http.MethodPost, "", reqParameter) if err != nil { return "", err } bodyResult, err := json.Marshal(result) if err != nil { return "", err } resp := &SeparateApplyBindResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return "", err } if resp.RetCode != Success { return "", fmt.Errorf(resp.RetMsg) } return utils.Int64ToStr(resp.RespData.ApplyId), nil } // Separate 分账 func (a *API) Separate(param *OrderSeparateReq) (*OrderSeparateResp, error) { reqParameter := map[string]interface{}{ "req_data": utils.Struct2Map(param, "", false), "version": Version, "req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateProd, SeparateOrder, http.MethodPost, "", reqParameter) if err != nil { return nil, err } bodyResult, err := json.Marshal(result) if err != nil { return nil, err } resp := &OrderSeparateResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } if resp.Code != SeparateSuccess { return nil, fmt.Errorf(resp.Msg) } return resp, nil } // SeparateCancel 订单分账撤销 func (a *API) SeparateCancel(param *SeparateCancelReq) (*SeparateCancelResp, error) { reqParameter := map[string]interface{}{ "req_data": utils.Struct2Map(param, "", false), "version": Version, "req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateProd, SeparateCancel, http.MethodPost, "", reqParameter) if err != nil { return nil, err } bodyResult, err := json.Marshal(result) if err != nil { return nil, err } resp := &SeparateCancelResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } if resp.Code != SeparateSuccess { return nil, fmt.Errorf(resp.Msg) } return resp, err } // SeparateFallBack 分账退回 func (a *API) SeparateFallBack(param *SeparateFallReq) (*SeparateFallResp, error) { reqParameter := map[string]interface{}{ "req_data": utils.Struct2Map(param, "", false), "version": Version, "req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } globals.SugarLogger.Debugf("------SeparateFallBack param := %s", utils.Format4Output(param, false)) result, err := a.AccessAPISign(SeparateProd, SeparateFallBack, http.MethodPost, "", reqParameter) globals.SugarLogger.Debugf("------SeparateFallBack result := %s", utils.Format4Output(result, false)) globals.SugarLogger.Debugf("------SeparateFallBack err := %v", err) if err != nil { return nil, err } bodyResult, err := json.Marshal(result) if err != nil { return nil, err } resp := &SeparateFallResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } if resp.Code != SeparateSuccess { return nil, fmt.Errorf(resp.Msg) } return resp, err } // SeparateResultQuery 分账结果查询 func (a *API) SeparateResultQuery(merchantNo, separateNo string) (*SeparateResultQueryResp, error) { reqData := map[string]string{ "merchant_no": merchantNo, "separate_no": separateNo, } reqParameter := map[string]interface{}{ "req_data": reqData, "version": Version, "req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateProd, SeparateQuery, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["code"].(string) != SeparateSuccess { return nil, fmt.Errorf(result["msg"].(string)) } bodyResult, err := json.Marshal(result["resp_data"]) if err != nil { return nil, err } resp := &SeparateResultQueryResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } return resp, err } // SeparateQueryAmt 可分账金额查询 func (a *API) SeparateQueryAmt(merchantNo, logNo, logDate string) (*SeparateQueryAmtResp, error) { reqData := map[string]string{ "merchant_no": merchantNo, "log_no": logNo, "log_date": logDate, } reqParameter := map[string]interface{}{ "req_data": reqData, "version": Version, "req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat), } result, err := a.AccessAPISign(SeparateProd, SeparateQueryAmt, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["code"].(string) != SeparateSuccess { return nil, fmt.Errorf(result["msg"].(string)) } bodyResult, err := json.Marshal(result["resp_data"]) if err != nil { return nil, err } resp := &SeparateQueryAmtResp{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } return resp, err } // QueryCarBin 卡BIN查询 func (a *API) QueryCarBin(orderNo, orgCode, cardNo string) (*BinInfo, error) { reqData := map[string]string{ "version": "1.0", "orderNo": orderNo, "orgCode": orgCode, "cardNo": cardNo, } reqParameter := map[string]interface{}{ "reqData": reqData, "ver": Version, "timestamp": utils.Int64ToStr(time.Now().Unix()), "reqId": utils.GetUUID(), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SeparateCardBinAction, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["retCode"].(string) != Success { return nil, fmt.Errorf(result["retMsg"].(string)) } bodyResult, err := json.Marshal(result["respData"]) if err != nil { return nil, err } resp := &BinInfo{} if err = json.Unmarshal(bodyResult, resp); err != nil { return nil, err } return resp, err } // SaveAuthentication 微信支付宝认证 func (a *API) SaveAuthentication(param *AuthenticationInfo, authType string) error { reqData := utils.Struct2Map(param, "", false) activityUrl := WeChatAuthentication if authType == AuthenticationType { reqData["realNameType"] = AuthenticationType activityUrl = AlibabaAuthentication } reqParameter := map[string]interface{}{ "reqData": reqData, "ver": Version, "timestamp": utils.Int64ToStr(time.Now().Unix()), "reqId": utils.GetUUID(), } result, err := a.AccessAPISign(SeparateAccountProdUrl, activityUrl, http.MethodPost, "", reqParameter) if err != nil { return err } if result["retCode"].(string) != Success { return errors.New(result["retMsg"].(string)) } return nil } // UpdateAuthentication 实名认证修改 // https://o.lakala.com/#/home/document/detail?id=183 func (a *API) UpdateAuthentication(param *UpdateAuthentication, authType string) error { reqData := utils.Struct2Map(param, "", false) activityUrl := WeChatUpdateAuthentication if authType == AuthenticationType { activityUrl = AlibabaUpdateAuthentication } reqParameter := map[string]interface{}{ "reqData": reqData, "ver": Version, "timestamp": utils.Int64ToStr(time.Now().Unix()), "reqId": utils.GetUUID(), } result, err := a.AccessAPISign(SeparateAccountProdUrl, activityUrl, http.MethodPost, "", reqParameter) if err != nil { return err } if result["retCode"].(string) != Success { return errors.New(result["retMsg"].(string)) } return nil } // QueryAuthentication 实名认证查询 // https://o.lakala.com/#/home/document/detail?id=181 func (a *API) QueryAuthentication(param *QueryAuthentication, authType string) (*QueryAuthenticationResp, error) { reqData := utils.Struct2Map(param, "", false) activityUrl := WeChatQueryAuthentication if authType == AuthenticationType { reqData["realNameType"] = AuthenticationType activityUrl = AlibabaQueryAuthentication } reqParameter := map[string]interface{}{ "reqData": reqData, "ver": Version, "timestamp": utils.Int64ToStr(time.Now().Unix()), "reqId": utils.GetUUID(), } result, err := a.AccessAPISign(SeparateAccountProdUrl, activityUrl, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["retCode"].(string) != Success { return nil, errors.New(result["retMsg"].(string)) } body, err := json.Marshal(result["respData"]) if err != nil { return nil, err } resp := &QueryAuthenticationResp{} if err = json.Unmarshal(body, resp); err != nil { return nil, err } return resp, nil } // AccountStatusQuery 开户状态查询 // https://o.lakala.com/#/home/document/detail?id=528 func (a *API) AccountStatusQuery(tradeMode, subMerchantId, merchantNo string) (map[string]interface{}, error) { reqParameter := map[string]interface{}{ "reqData": map[string]interface{}{"tradeMode": tradeMode, "subMerchantId": subMerchantId, "merchantNo": merchantNo}, "ver": Version, "timestamp": utils.Int64ToStr(time.Now().Unix()), "reqId": utils.GetUUID(), } result, err := a.AccessAPISign(PayAccountProdUrl, WeChatAccountStatusQuery, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["retCode"].(string) != Success { return nil, errors.New(result["retMsg"].(string)) } return result["respData"].(map[string]interface{}), nil } // SubMerchantInfoQuery 报备查询 // https://o.lakala.com/#/home/document/detail?id=326 func (a *API) SubMerchantInfoQuery(param *SubMerchantInfoQueryReq) ([]*SubMerchantInfoQueryResp, error) { reqParameter := map[string]interface{}{ "reqData": utils.Struct2Map(param, "", false), } result, err := a.AccessAPISign(SeparateAccountProdUrl, SubMerchantQuery, http.MethodPost, "", reqParameter) if err != nil { return nil, err } if result["retCode"].(string) != Success { return nil, errors.New(result["retMsg"].(string)) } if result["respData"] != nil && result["respData"].(map[string]interface{}) != nil { list := make([]*SubMerchantInfoQueryResp, 0, 0) data, err := json.Marshal(result["respData"].(map[string]interface{})["list"]) if err != nil { return nil, err } if err = json.Unmarshal(data, &list); err != nil { return nil, err } return list, nil } return nil, errors.New("返回值为空") } // SubMerchantInfoQueryReq 报备查询 type SubMerchantInfoQueryReq struct { Version string `json:"version"` // 必传 String 8 接口版本号 1.0 OrderNo string `json:"orderNo"` // 必传 String 32 订单编号,保证唯一(便于后续跟踪排查问题及核对报文) 14位年月日时(24小时制)分秒+8位的随机数(不重复)如:2021020112000012345678 OrgCode string `json:"orgCode"` // 必传 String 32 机构代码 (合作方在拉卡拉的标识,请联系业务员) 1 MerInnerNo string `json:"merInnerNo"` // 可传 String 32 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准。 5002022050550024285 MerCupNo string `json:"merCupNo"` // 可传 String 32 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准。 8222900581207ET RegisterChannel string `json:"registerChannel"` // 可选 String 8 报备渠道 UNIONPAY RegisterType string `json:"registerType"` // 可选 String 64 报备类型 WXZF RegisterStatus string `json:"registerStatus"` // 可选 String 64 报备状态 SUCCESS:成功;FAIL:失败 SUCCESS SubMchId string `json:"subMchId"` // 可选 String 64 子商户号 } // SubMerchantInfoQueryResp 报备查询返回值 type SubMerchantInfoQueryResp struct { MerInnerNo string `json:"merInnerNo"` // 内部商户号 SubMchId string `json:"subMchId"` // 子商户号 SubMchIdBank string `json:"subMchIdBank"` // 交易子商户号 DcWalletId string `json:"dcWalletId"` // 数币钱包ID RegisterType string `json:"registerType"` // 报备类型 RegisterTypeText string `json:"registerTypeText"` RegisterChannel string `json:"registerChannel"` // 报备渠道 RegisterChannelText string `json:"registerChannelText"` ChannelId string `json:"channelId"` // 渠道号 ReceOrgNo string `json:"receOrgNo"` // 从业机构号 RegisterTm string `json:"registerTm"` // 报备时间 RegisterStatus string `json:"registerStatus"` // 报备状态 ResultCode string `json:"resultCode"` // 结果返回码 ResultMessage string `json:"resultMessage"` // 结果描述 }