diff --git a/platformapi/q_bida/QBiDa_test.go b/platformapi/q_bida/QBiDa_test.go new file mode 100644 index 00000000..0f2955be --- /dev/null +++ b/platformapi/q_bida/QBiDa_test.go @@ -0,0 +1,53 @@ +package q_bida + +import ( + "fmt" + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/jx-callback/globals" + "go.uber.org/zap" + "testing" +) + +var ( + api *Api + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + globals.SugarLogger.Debug("加载配置") +} + +// 获取登录 +func TestLogin(t *testing.T) { + api := NewQBiDa("18048531223", "18080188338") + fmt.Println("api=========", api.expirationTime) + fmt.Println("api=========", api.password) + fmt.Println("api=========", api.account) + fmt.Println("api=========", api.token) +} + +// 获取所有的快递费接口 +func TestGatAllFee(t *testing.T) { + api := NewQBiDa("18048531223", "18080188338") + for i := 1; i <= 14; i++ { + result, err := api.GetExpressPrice(&GetExpressPriceReq{ + PromiseTimeType: 0, + DeliveryType: 0, + GoodsValue: 1000, + SendAddress: "四川省成都市金牛区二环北路一段10号万科加州湾V派616", + ReceiveAddress: "北京市北京市朝阳区来广营地区中铁国际城乐享汇大厦3号楼1132", + Type: i, + Weight: 1, + Length: 100, + Height: 100, + Width: 100, + SendPhone: "18981810340", + }) + globals.SugarLogger.Debug("err==="+fmt.Sprintf("%d", i), err) + globals.SugarLogger.Debug("data===", &result) + } + +} diff --git a/platformapi/q_bida/q_bida_access.go b/platformapi/q_bida/q_bida_access.go new file mode 100644 index 00000000..11089e5e --- /dev/null +++ b/platformapi/q_bida/q_bida_access.go @@ -0,0 +1,120 @@ +package q_bida + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" + "net/http" + "sync" + "time" +) + +type Api struct { + token string // 登录凭证 + expirationTime int64 // 过期时间 + account string // 账号 + password string // 密码 + locker sync.RWMutex + client *http.Client + config *platformapi.APIConfig +} + +// SetToken 设置token +func (a *Api) SetToken(token string) { + a.locker.Lock() + defer a.locker.Unlock() + a.token = token +} + +// SetExpirationTime 设置过期时间 +func (a *Api) SetExpirationTime(expiration int64) { + a.locker.Lock() + defer a.locker.Unlock() + a.expirationTime = expiration +} + +// NewQBiDa 初始化token +func NewQBiDa(account, password string, config ...*platformapi.APIConfig) *Api { + if account == "" || password == "" { + panic("账号密码不能为空") + } + // 获取token,设置token和过期时间 + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + api := &Api{ + token: "", + expirationTime: 0, + account: account, + password: password, + locker: sync.RWMutex{}, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } + if err := api.CheckTokenExpiration(); err != nil { + panic(err) + } + + return api +} + +// CheckTokenExpiration 检查token是否存在,或者是否过期 +func (a *Api) CheckTokenExpiration() error { + if a.account == "" || a.password == "" { + return errors.New("账号或者密码为空") + } + + // 获取token NewQBiDa + if a.token == "" || a.expirationTime < time.Now().Unix() { + return a.GetToken() + } + + return nil +} + +// AccessInfo 发送请求 +func (a *Api) AccessInfo(baseUrl, url, requestMethods string, param map[string]interface{}) (retVal map[string]interface{}, err error) { + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + var request *http.Request + if requestMethods == http.MethodPost { + fullURL := utils.GenerateGetURL(baseUrl, url, nil) + // 获取json结构体的参数体 + requestBody := new(bytes.Buffer) + json.NewEncoder(requestBody).Encode(param) + // 发送请求 + request, _ = http.NewRequest(http.MethodPost, fullURL, requestBody) + request.Header.Set("Content-Type", "application/json") + } else { + request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(baseUrl, url, param), nil) + } + if url != LogInUrl { + request.Header.Set("token", a.token) + } + return request + }, + a.config, + func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) { + if jsonResult1 == nil { + return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil") + } + retVal = jsonResult1 + if jsonResult1["code"] == nil { + return platformapi.ErrLevelGeneralFail, fmt.Errorf("返回结果格式不正常") + } + code := int(utils.MustInterface2Int64(jsonResult1["code"])) + if code == ResponseCodeSuccess { + retVal, _ = jsonResult1["data"].(map[string]interface{}) + return platformapi.ErrLevelSuccess, nil + } + newErr := utils.NewErrorIntCode(jsonResult1["msg"].(string), code) + baseapi.SugarLogger.Debugf("QBiDa AccessUserPage failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true)) + return platformapi.ErrLevelCodeIsNotOK, newErr + }) + return retVal, err +} diff --git a/platformapi/q_bida/q_bida_client.go b/platformapi/q_bida/q_bida_client.go new file mode 100644 index 00000000..0866e688 --- /dev/null +++ b/platformapi/q_bida/q_bida_client.go @@ -0,0 +1,125 @@ +package q_bida + +import ( + "errors" + "git.rosy.net.cn/baseapi/utils" + "net/http" + "strings" + "time" +) + +// GetToken 获取登录状态 +func (a *Api) GetToken() error { + if a.account == "" { + a.account = Account + } + if a.password == "" { + a.password = Password + } + if a.token != "" && a.expirationTime > time.Now().Unix() { + return nil + } + + data := &LoginParamsRes{} + result, err := a.AccessInfo(BaseQBiDaUrl, LogInUrl, http.MethodPost, map[string]interface{}{"account": a.account, "password": a.password}) + if err != nil && !strings.Contains(err.Error(), "成功") { + return err + } + + if err := utils.Map2StructByJson(result, data, false); err != nil { + return err + } + + if data.Code != 0 { + return errors.New(data.Msg) + } + + a.SetToken(data.Data.Token) + a.SetExpirationTime(time.Now().AddDate(0, 0, 7).Unix()) + return nil +} + +// GetExpressPrice 获取快递费用 +func (a *Api) GetExpressPrice(param *GetExpressPriceReq) (*GetExpressPriceRes, error) { + if err := a.CheckTokenExpiration(); err != nil { + return nil, err + } + result, err := a.AccessInfo(BaseQBiDaUrl, GetWayBailMoneyUrl, http.MethodPost, utils.Struct2FlatMap(param)) + if err != nil && !strings.Contains(err.Error(), "成功") { + return nil, err + } + + resultData := &GetExpressPriceRes{} + if err := utils.Map2StructByJson(result, resultData, false); err != nil { + return nil, err + } + if resultData.Code != 0 { + return nil, errors.New(resultData.Msg) + } + return resultData, nil +} + +// CreateOrder 创建订单 +func (a *Api) CreateOrder(param *MakeOrderReq) (string, error) { + if err := a.CheckTokenExpiration(); err != nil { + return "", err + } + + result, err := a.AccessInfo(BaseQBiDaUrl, MakeWayBailOrderUrl, http.MethodPost, utils.Struct2FlatMap(param)) + if err != nil && !strings.Contains(err.Error(), "成功") { + return "", err + } + + resultData := &MakeOrderRes{} + if err := utils.Map2StructByJson(result, resultData, false); err != nil { + return "", err + } + if resultData.Code != 0 { + return "", errors.New(resultData.Msg) + } + + return resultData.OrderNo, nil +} + +// CancelOrder 取消订单 +func (a *Api) CancelOrder(param *CancelOrderReq) error { + if err := a.CheckTokenExpiration(); err != nil { + return err + } + + result, err := a.AccessInfo(BaseQBiDaUrl, CancelWayBailOrderUrl, http.MethodPost, utils.Struct2FlatMap(param)) + if err != nil && !strings.Contains(err.Error(), "成功") { + return err + } + + resultData := &PublicParams{} + if err := utils.Map2StructByJson(result, resultData, false); err != nil { + return err + } + if resultData.Code != 0 { + return errors.New(resultData.Msg) + } + return nil +} + +// GetOrderDetail 获取订单详情 +func (a *Api) GetOrderDetail(param *GetOrderDetailReq) (*OrderDetail, error) { + if err := a.CheckTokenExpiration(); err != nil { + return nil, err + } + + result, err := a.AccessInfo(BaseQBiDaUrl, GetOrderDetailUrl, http.MethodGet, utils.Struct2FlatMap(param)) + if err != nil && !strings.Contains(err.Error(), "成功") { + return nil, err + } + + resultData := &GetOrderDetailRes{} + if err := utils.Map2StructByJson(result, resultData, false); err != nil { + return nil, err + } + if resultData.Code != 0 { + return nil, err + } + + return resultData.Data, nil +} diff --git a/platformapi/q_bida/q_bida_model.go b/platformapi/q_bida/q_bida_model.go new file mode 100644 index 00000000..cd6c5736 --- /dev/null +++ b/platformapi/q_bida/q_bida_model.go @@ -0,0 +1,106 @@ +package q_bida + +// type 快递公司枚举 +const ( + JDExpress = "1" // 京东快递 + DBExpress = "2" // 德邦快递 + JDLogisticsExpress = "3" // 京东物流 + DBLogisticsExpress = "4" // 德邦物流 + STExpress = "5" // 申通快递 + YTExpress = "6" // 圆通快递 + DBAirCraftExpress = "7" // 德邦航空 + SFExpress = "8" // 顺丰快递 + JDDWExpress = "9" // 京东得物 + JDStoreExpress = "10" // 京东商家 + KYExpress = "11" // 跨越速运 + ZTExpress = "12" // 中通快递 + JSTExpress = "13" // 急速兔快递 + YDExpress = "14" // 韵达快递 +) + +const ( + JDExpressInt = 1 // 京东快递 + DBExpressInt = 2 // 德邦快递 + JDLogisticsExpressInt = 3 // 京东物流 + DBLogisticsExpressInt = 4 // 德邦物流 + STExpressInt = 5 // 申通快递 + YTExpressInt = 6 // 圆通快递 + DBAirCraftExpressInt = 7 // 德邦航空 + SFExpressInt = 8 // 顺丰快递 + JDDWExpressInt = 9 // 京东得物 + JDStoreExpressInt = 10 // 京东商家 + KYExpressInt = 11 // 跨越速运 + ZTExpressInt = 12 // 中通快递 + JSTExpressInt = 13 // 急速兔快递 + YDExpressInt = 14 // 韵达快递 +) + +// 快递时效产品 promiseTimeType字段说明 +const ( + // JDPromiseTimeTypeDefault type = 1 京东快递 + JDPromiseTimeTypeDefault = 1 // 默认特惠送 + JDPromiseTimeTypeFile = 20 //京东文件 + + // DBPromiseTimeTypeDefault type = 2 德邦快递 + DBPromiseTimeTypeDefault = 101 // 普通产品(默认值) + DBPromiseTimeTypeDW = 102 // 得物 + DBPromiseTimeTypeWeight = 103 // 重包入户 + DBPromiseTimeTypeAirCraft = 104 // 航空件 + DBPromiseTimeTypeStore = 105 // 商家 + + // JDPromiseTimeTypeWeight type = 3 京东重货 + JDPromiseTimeTypeWeight = 100 // 普通重货(默认值) + JDPromiseTimeTypeStore = 101 // 重货商家 + + // SFPromiseTimeTypePublic type = 8 顺丰快递 + SFPromiseTimeTypePublic = 1 // 标快(默认值) + SFPromiseTimeTypeDiscount = 2 // 特惠 + SFPromiseTimeTypeDW = 3 // 得物 + SFPromiseTimeTypeStore = 4 // 商家 + + // JDPromiseTimeTypStoreDefault type = 10 京东商家 + JDPromiseTimeTypStoreDefault = 1 // 标快(默认值) + JDPromiseTimeTypeSeafoodFast = 16 // 生鲜特快 + JDPromiseTimeTypeSeafoodDiscount = 17 // 生鲜特惠 +) + +// 产品类型 deliveryType字段说明 +const ( + // JDDeliveryTypeFast type=3 京东物流 + JDDeliveryTypeFast = 6 // 特快零担 + JDDeliveryTypeWeightFast = 25 // 特快重货 + + // DBDeliveryTypeCart type=4 德邦物流 + DBDeliveryTypeCart = 1 // 精准汽运 + DBDeliveryTypeAirCraft = 1 // 精准卡航 + + // KYDeliveryTypeCart type=11 跨越速运 + KYDeliveryTypeCart = 40 // 省外陆运件 + KYDeliveryTypeCityTomorrow = 50 // 同城次日 + KYDeliveryTypeProvince = 160 // 省内次日 +) + +const ( + ResponseCodeSuccess = 200 // 成功返回 + ResponseCodeFail = -1 // 失败返回 +) + +// url物流请求地址 +const ( + BaseQBiDaUrl = "http://qbd.ulifego.com/ht" // 基础访问域名 + + LogInUrl = "web/login/loginNew" // 登录获取token【post】 + GetOrderDetailUrl = "web/orderDetailByOrderNo" // 获取订单详情【get】 + CancelWayBailOrderUrl = "web/cancelOrderByOrderNo" // 取消运单【post】 + MakeWayBailOrderUrl = "web/createOrder" // 下单【Post】 + GetWayBailMoneyUrl = "web/estimate" // 获取快递费【Post】 +) + +// 默认账号 +const ( + Password = "18080188338" // 密码 + Account = "18048531223" // 账号 +) + +// ChannelFee 渠道费加价两毛 +const ChannelFee = 2 diff --git a/platformapi/q_bida/q_bida_params.go b/platformapi/q_bida/q_bida_params.go new file mode 100644 index 00000000..40da9ec4 --- /dev/null +++ b/platformapi/q_bida/q_bida_params.go @@ -0,0 +1,165 @@ +package q_bida + +// PublicParams 公共参数 +type PublicParams struct { + Code int64 `json:"code"` + Msg string `json:"msg"` +} + +// LoginParamsRes 登录返回参数 +type LoginParamsRes struct { + PublicParams + Data *struct { + Genre int64 `json:"genre"` // genre + Token string `json:"token"` // token + IsVerify interface{} `json:"is_verify"` // isVerify + } `json:"data"` +} + +//#region 获取快递费 + +// GetExpressPriceReq 获取快递费请求参数 +type GetExpressPriceReq struct { + Type int `json:"type"` // 快递公司 + PromiseTimeType int `json:"promiseTimeType"` // 快递时效产品 + DeliveryType int `json:"deliveryType"` // 产品类型 + GoodsValue float64 `json:"goodsValue"` // 保价金额 + ReceiveAddress string `json:"receiveAddress"` // 收件人地址 + SendAddress string `json:"sendAddress"` // 寄件人地址 + Weight int `json:"weight"` // 重量kg + Length int `json:"length"` // 所有包裹累计长cm + Height int `json:"height"` // 所有包裹累计高cm + Width int `json:"width"` // 所有包裹累计宽cm(向上取整) + SendPhone string `json:"sendPhone"` // 寄件人手机号 +} + +// GetExpressPriceRes 获取快递费返回值 +type GetExpressPriceRes struct { + PublicParams + Data *GetExpressPriceData `json:"data"` +} + +// GetExpressPriceData 获取正儿八经返回值 +type GetExpressPriceData struct { + ChannelFee float64 `json:"channel_fee"` // 渠道价 + Bulk int64 `json:"bulk"` // 体积抛比系数 + ServiceCharge float64 `json:"service_charge"` // 服务费 + GuarantFee float64 `json:"guarant_fee"` // 保价费用 + OriginalFee float64 `json:"original_fee"` // 原价 +} + +//#endregion + +//#region 下单 + +// MakeOrderReq 下订单请求参数 +type MakeOrderReq struct { + PromiseTimeType int `json:"promiseTimeType"` // 快递时效产品 + DeliveryType int `json:"deliveryType"` // 产品类型 + Goods string `json:"goods"` // 商品名称 + GuaranteeValueAmount float64 `json:"guaranteeValueAmount"` // 保价金额 + Weight int `json:"weight"` // 重量kg + Length int `json:"length"` // 所有包裹累计长cm + Height int `json:"height"` // 所有包裹累计高cm + Width int `json:"width"` // 所有包裹累计宽cm(向上取整) + OrderSendTime string `json:"orderSendTime"` // 预约时间 + PackageNum int `json:"packageNum"` // 包裹数量 + ReceiveAddress string `json:"receiveAddress"` // 收件人地址 + ReceiveName string `json:"receiveName"` // 收件人姓名 + ReceivePhone string `json:"receivePhone"` // 收件人手机号 + Remark string `json:"remark"` // 运单备注 + SenderAddress string `json:"senderAddress"` // 寄件人地址 + SenderName string `json:"senderName"` // 寄件人姓名 + SenderPhone string `json:"senderPhone"` // 寄件人手机号 + ThirdPlatform int `json:"thirdPlatform"` // 第三方平台-京东商家下单传3 + Type int `json:"type"` // 快递公司 + Img string `json:"img"` // 包裹图片 +} + +// MakeOrderRes 下订单返回参数 +type MakeOrderRes struct { + PublicParams + OrderNo string `json:"order_no"` // 订单编号 +} + +//#endregion + +//#region 取消订单 + +// CancelOrderReq 取消订单参数 +type CancelOrderReq struct { + Genre int `json:"genre"` // 1-取消,2-关闭 + OrderNo string `json:"orderNo"` // 订单编号 + Type int `json:"type"` // 快递公司 +} + +//#endregion + +//#region 订单详情 + +// GetOrderDetailReq 获取订单详情 +type GetOrderDetailReq struct { + Type int `json:"type"` // 快递公司 + OrderNo string `json:"orderNo"` // 订单号 +} + +// GetOrderDetailRes 订单详情返回值 +type GetOrderDetailRes struct { + PublicParams + Data *OrderDetail +} + +type OrderDetail struct { + ChangeFee float64 // 转寄费用 + ConsumeFee float64 // 耗材费元 + CopyText string // 复制信息 + CreateDate string // 下单时间 + ExpressFee string // 快递费元 (元) + FeeStatus string // 费用状态0下单费用冻结中 ,非0下单费用已扣 + Goods string // 物品 + GuaranteeValueAmount float64 // 保价金额 + InsuranceFee float64 // 保价费元 + IsForward bool // 是否转寄单0否1是(转寄单额外收取50%运费) + IsLimit bool // 是否超限0否1是 + OriginalFee float64 // 官方原价 + OtherFee float64 // 其他费用 + OverWeightStatus int // 超重状态 + PackageNum int // 包裹数 + ReceiveAddress string // 收件人地址 + ReceiveCity string // 收件人地址城市 + ReceiveName string // 收件人名称 + ReceivePhone string // 收件人电话 + SenderAddress string // 寄件人地址 + SenderCity string // 寄件人地址城市 + SenderName string // 寄件人姓名 + SenderPhone string // 寄件人电话 + Soliciter string // 揽件员 + Status int // 状态0预下单1待取件2运输中5已签收6取消订单7终止揽收 + StatusName string // 状态名称 + TotalFee string // 总费用元 + PayFee float64 // 实际支付费用元 + TraceList []*TraceListDetail // 快递详情列表 + TrackingNum string // 运单号 + Type int // 快递公司 0:京东 1:德邦 + Volume int // 体积cm3 + VolumeRemark string // 体积重量计算说明 + VolumeWeight int // 体积重量Kg + Weight int // 下单重量Kg + WeightActual int // 实际重量Kg + WeightBill int // 计费重量Kg + WeightStatus int // 超重状态 + Yuanjia int // 快递费 +} + +type TraceListDetail struct { + Courier string // 快递员 + CourierTel string // 快递员电话 + OpeName string // 操作人 + OpeRemark string // 操作详情 + OpeTime string // 操作时间 + OpeTimeAll string // + OpeTitle string // + WaybillCode string // 运单号 +} + +//#endregion