diff --git a/platformapi/mtpsapi/riderInfo.go b/platformapi/mtpsapi/riderInfo.go index 10baaaba..af8b2e0b 100644 --- a/platformapi/mtpsapi/riderInfo.go +++ b/platformapi/mtpsapi/riderInfo.go @@ -5,6 +5,7 @@ const ( FnPsCode = "10004" // 蜂鸟配送 MTPsCode = "10032" // 美团配送 UUPTCode = "10006" //uu跑腿 + SFPSCode = "10007" //顺丰配送 DYPsCode = "10018" //抖音配送(小时达) MyselfPsCode = "10015" // 自送 ) diff --git a/platformapi/mtwmapi/mtwmapi_test.go b/platformapi/mtwmapi/mtwmapi_test.go index baa13a44..40bbc1ff 100644 --- a/platformapi/mtwmapi/mtwmapi_test.go +++ b/platformapi/mtwmapi/mtwmapi_test.go @@ -20,11 +20,11 @@ func init() { baseapi.Init(sugarLogger) // 菜市 - //api = New("589", "a81eb3df418d83d6a1a4b7c572156d2f", "", "") + api = New("589", "a81eb3df418d83d6a1a4b7c572156d2f", "", "") // 果园 // api = New("4123", "df2c88338b85f830cebce2a9eab56628", "", "") - api = New("4123", "df2c88338b85f830cebce2a9eab56628", "", "") + //api = New("4123", "df2c88338b85f830cebce2a9eab56628", "", "") //商超 //api = New("5873", "41c479790a76f86326f89e8048964739", "", "token_n4TwqCntWWuvQwAawzxC0w") //token_n4TwqCntWWuvQwAawzxC0w diff --git a/platformapi/sfps/sf_base.go b/platformapi/sfps/sf_base.go index bf5bab69..8d613ea5 100644 --- a/platformapi/sfps/sf_base.go +++ b/platformapi/sfps/sf_base.go @@ -59,12 +59,12 @@ type API struct { /************************************************订单*****************************************************/ //#region 获取蜂鸟门店信息 -// 创建订单 +// CreateOrder 创建订单(店铺) type CreateOrder struct { // 必填 DevId int64 `json:"dev_id"` // 同城开发者ID ShopId string `json:"shop_id"` // 店铺ID - ShopOrderId string `json:"shop_order_id"` // 商家订单号不允许重复 + ShopOrderId string `json:"shop_order_id"` // 不允许重复(使用相同商家订单号会幂等返回) OrderSource string `json:"order_source"` // 订单接入来源 1:美团;2:饿了么;3:百度;4:口碑;其他请直接填写中文字符串值 LbsType int `json:"lbs_type"` // 坐标类型 1:百度坐标,2:高德坐标 PayType int64 `json:"pay_type"` // 用户支付方式 1:已付款 0:货到付款 diff --git a/platformapi/sfps2/callback.go b/platformapi/sfps2/callback.go new file mode 100644 index 00000000..dd83ac6b --- /dev/null +++ b/platformapi/sfps2/callback.go @@ -0,0 +1,141 @@ +package sfps2 + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +const ( + // 回调url前缀 + UrlIndexRiderStatus = "rider_status" //配送状态更改回调 + UrlIndexRiderRecall = "rider_recall" //骑士撤单状态回调 + UrlIndexOrderComplete = "order_complete" //订单完成回调 + UrlIndexSFCancel = "sf_cancel" //顺丰原因订单取消回调 + UrlIndexRiderException = "rider_exception" //订单异常回调 +) + +// RiderStatus 配送状态更改回调 +type RiderStatus struct { + ShopId string `json:"shop_id"` // 店铺ID + SFOrderID string `json:"sf_order_id"` //顺丰订单ID + ShopOrderID string `json:"shop_order_id"` //商家订单ID + UrlIndex string `json:"url_index"` //回调url前缀 + OperatorName string `json:"operator_name"` //配送员姓名 + OperatorPhone string `json:"operator_phone"` //配送员电话 + RiderLng string `json:"rider_lng"` //配送员位置经度 + RiderLat string `json:"rider_lat"` //配送员位置纬度 + OrderStatus int `json:"order_status"` //10-配送员接单/改派;12:配送员到店;15:配送员配送中 + StatusDesc string `json:"status_desc"` //状态描述 + PushTime int `json:"push_time"` //状态变更时间 +} + +// RiderRecall 骑士撤单状态回调 +type RiderRecall struct { + ShopId string `json:"shop_id"` // 店铺ID + SFOrderID string `json:"sf_order_id"` //顺丰订单ID + ShopOrderID string `json:"shop_order_id"` //商家订单ID + UrlIndex string `json:"url_index"` //回调url前缀 + OrderStatus int `json:"order_status"` //22-配送员撤单 + StatusDesc string `json:"status_desc"` //状态描述 + PushTime int `json:"push_time"` //状态变更时间 +} + +// OrderComplete 订单完成回调 +type OrderComplete struct { + ShopId string `json:"shop_id"` // 店铺ID + SFOrderID string `json:"sf_order_id"` //顺丰订单ID + ShopOrderID string `json:"shop_order_id"` //商家订单ID + UrlIndex string `json:"url_index"` //回调url前缀 + OperatorName string `json:"operator_name"` //配送员姓名 + RiderLng string `json:"rider_lng"` //配送员位置经度 + RiderLat string `json:"rider_lat"` //配送员位置纬度 + OrderStatus int `json:"order_status"` //17配送员点击完成 + StatusDesc string `json:"status_desc"` //状态描述 + PickUpPic string `json:"pickup_pic"` //只有在店铺打开妥投照片回调开关且有妥投照片时才有此字段 + PushTime int `json:"push_time"` //完成时间 + ReceiptType int `json:"receipt_type"` //1:正常签收, 2:商家退回签收 +} + +// SFCancel 顺丰原因订单取消回调 +type SFCancel struct { + ShopId string `json:"shop_id"` // 店铺ID + SFOrderID string `json:"sf_order_id"` //顺丰订单ID + ShopOrderID string `json:"shop_order_id"` //商家订单ID + UrlIndex string `json:"url_index"` //回调url前缀 + OperatorName string `json:"operator_name"` //配送员姓名 + OperatorPhone string `json:"operator_phone"` //配送员电话 + OrderStatus int `json:"order_status"` //2:订单取消 + StatusDesc string `json:"status_desc"` //状态描述 + CancelReason string `json:"cancel_reason"` //取消原因 + CancelCode string `json:"cancel_code"` //取消码 + RiderLng string `json:"rider_lng"` //配送员位置经度 + RiderLat string `json:"rider_lat"` //配送员位置纬度 + PushTime int `json:"push_time"` //状态变更时间 +} + +// RiderException 配送状态更改回调 +type RiderException struct { + ShopId string `json:"shop_id"` // 店铺ID + SFOrderID string `json:"sf_order_id"` //顺丰订单ID + ShopOrderID string `json:"shop_order_id"` //商家订单ID + UrlIndex string `json:"url_index"` //回调url前缀 + OperatorName string `json:"operator_name"` //配送员姓名 + OperatorPhone string `json:"operator_phone"` //配送员电话 + OrderStatus int `json:"order_status"` //固定为91 + StatusDesc string `json:"status_desc"` //状态描述 + ExID int `json:"ex_id"` //异常ID + ExContent string `json:"ex_content"` //异常详情 + ExpectTime string `json:"expect_time"` //新的预计送达时间 + PushTime int `json:"push_time"` //顺丰推送时间 +} + +type CallbackResponse struct { + ErrorCode int `json:"error_code"` + ErrorMsg string `json:"error_msg"` +} + +var ( + SuccessResponse = &CallbackResponse{ErrorCode: SuccessCode, ErrorMsg: SuccessMsg} +) + +func Err2CallbackResponse(err error) *CallbackResponse { + if err == nil { + return SuccessResponse + } + return &CallbackResponse{ + ErrorCode: -1, + ErrorMsg: fmt.Sprint(err), + } +} + +// GetRiderStatusCallback 配送状态更改回调 +func (a *API) GetRiderStatusCallback(request *http.Request) (riderStatus *RiderStatus, response *CallbackResponse) { + data, err := ioutil.ReadAll(request.Body) + if err != nil { + response = &CallbackResponse{ErrorCode: -1} + return nil, response + } + + if err = json.Unmarshal(data, &riderStatus); err != nil { + response = &CallbackResponse{ErrorCode: -1} + return nil, response + } + return riderStatus, SuccessResponse +} + +// GetRiderExceptionCallback 订单异常回调 +func (a *API) GetRiderExceptionCallback(request *http.Request) (riderException *RiderException, response *CallbackResponse) { + data, err := ioutil.ReadAll(request.Body) + if err != nil { + response = &CallbackResponse{ErrorCode: -1} + return nil, response + } + + if err = json.Unmarshal(data, &riderException); err != nil { + response = &CallbackResponse{ErrorCode: -1} + return nil, response + } + return riderException, SuccessResponse +} diff --git a/platformapi/sfps2/order.go b/platformapi/sfps2/order.go new file mode 100644 index 00000000..9060fc28 --- /dev/null +++ b/platformapi/sfps2/order.go @@ -0,0 +1,140 @@ +package sfps2 + +import ( + "encoding/json" + "errors" + "fmt" + "time" +) + +// PreCreateOrder 预创建订单(店铺) +func (a *API) PreCreateOrder(preOrder *PreCreateOrderReq) (price float64, err error) { + //补全默认参数 + preOrder.PushTime = time.Now().Unix() + preOrder.DevId = a.devId + + resp := a.HttpPostJson("precreateorder", preOrder) + if resp.HttpStatusCode != HttpStatusSuccessCode { + return 0, errors.New("HTTP请求错误,请检查重试") + } + if resp.BaseRetVal.ErrorCode != SuccessCode { + return 0, fmt.Errorf("%s", resp.BaseRetVal.ErrorMsg) + } + retVal := PreCreateOrderResp{} + s, _ := json.Marshal(resp.BaseRetVal.Result) + if err = json.Unmarshal(s, &retVal); err == nil { + return retVal.EstimatePayMoney, nil + } else { + return 0, err + } +} + +// CreateOrder 创建订单(店铺) +func (a *API) CreateOrder(order *CreateOrderReq) (sfOrderID, sfBillID string, totalPrice int, err error) { + //补全默认参数 + order.PushTime = time.Now().Unix() + order.Version = DefaultVersion + order.DevId = a.devId + + resp := a.HttpPostJson("createorder", order) + if resp.HttpStatusCode != HttpStatusSuccessCode { + return "", "", 0, errors.New("HTTP请求错误,请检查重试") + } + if resp.BaseRetVal.ErrorCode != SuccessCode { + return "", "", 0, fmt.Errorf("%s", resp.BaseRetVal.ErrorMsg) + } + retVal := CreateOrderResp{} + s, _ := json.Marshal(resp.BaseRetVal.Result) + if err = json.Unmarshal(s, &retVal); err == nil { + return retVal.SFOrderID, retVal.SFBillID, retVal.TotalPrice, nil + } else { + return "", "", 0, err + } +} + +// PreCancelOrder 预取消订单 +func (a *API) PreCancelOrder(sfOrderID string) (isCancel bool, err error) { + param := PreCancelOrderReq{ + DevId: a.devId, + OrderID: sfOrderID, + PushTime: time.Now().Unix(), + } + resp := a.HttpPostJson("precancelorder", param) + if resp.HttpStatusCode != HttpStatusSuccessCode { + return false, errors.New("HTTP请求错误,请检查重试") + } + if resp.BaseRetVal.ErrorCode != SuccessCode { + return false, fmt.Errorf("%s", resp.BaseRetVal.ErrorMsg) + } + retVal := PreCancelOrderResp{} + s, _ := json.Marshal(resp.BaseRetVal.Result) + if err = json.Unmarshal(s, &retVal); err == nil { + return retVal.CouldCancel, nil + } else { + return false, err + } +} + +// CancelOrder 取消订单 +func (a *API) CancelOrder(sfOrderID string) (err error) { + param := &CancelOrderReq{ + DevId: a.devId, + OrderID: sfOrderID, + PushTime: time.Now().Unix(), + CancelCode: CancelCodeChangePlan, + } + resp := a.HttpPostJson("cancelorder", param) + if resp.HttpStatusCode != HttpStatusSuccessCode { + return errors.New("HTTP请求错误,请检查重试") + } + if resp.BaseRetVal.ErrorCode != SuccessCode { + return fmt.Errorf("%s", resp.BaseRetVal.ErrorMsg) + } + return nil +} + +// GetOrderStatus 订单实时信息查询 +func (a *API) GetOrderStatus(sfOrderID string) (retVal *GetOrderStatusResp, err error) { + param := &GetOrderStatusReq{ + DevId: a.devId, + OrderID: sfOrderID, + PushTime: time.Now().Unix(), + //OrderType: orderType, + } + resp := a.HttpPostJson("getorderstatus", param) + if resp.HttpStatusCode != HttpStatusSuccessCode { + return nil, errors.New("HTTP请求错误,请检查重试") + } + if resp.BaseRetVal.ErrorCode != SuccessCode { + return nil, fmt.Errorf("%s", resp.BaseRetVal.ErrorMsg) + } + s, _ := json.Marshal(resp.BaseRetVal.Result) + if err = json.Unmarshal(s, &retVal); err == nil { + return retVal, nil + } else { + return nil, err + } +} + +// GetRiderLatestPosition 获取骑手实时坐标 +func (a *API) GetRiderLatestPosition(sfOrderID string) (retVal *RiderLatestPositionResp, err error) { + param := &RiderLatestPositionReq{ + DevId: a.devId, + OrderID: sfOrderID, + PushTime: time.Now().Unix(), + OrderType: OrderTypeSF, //暂时默认 + } + resp := a.HttpPostJson("riderlatestposition", param) + if resp.HttpStatusCode != HttpStatusSuccessCode { + return nil, errors.New("HTTP请求错误,请检查重试") + } + if resp.BaseRetVal.ErrorCode != SuccessCode { + return nil, fmt.Errorf("%s", resp.BaseRetVal.ErrorMsg) + } + s, _ := json.Marshal(resp.BaseRetVal.Result) + if err = json.Unmarshal(s, &retVal); err == nil { + return retVal, nil + } else { + return nil, err + } +} diff --git a/platformapi/sfps2/sf_model.go b/platformapi/sfps2/sf_model.go new file mode 100644 index 00000000..c224242f --- /dev/null +++ b/platformapi/sfps2/sf_model.go @@ -0,0 +1,495 @@ +package sfps2 + +import ( + "git.rosy.net.cn/baseapi/platformapi" + "net/http" + "sync" +) + +const ( + BaseCatchUrl = "http://sfapi-proxy.jsonce.com" //抓包调试路由 + BaseURL = "https://openic.sf-express.com/open/api/external" // 正式环境 + RequestPost = "POST" + HttpStatusSuccessCode = 200 //http返回成功状态码 + SuccessCode = 0 //成功code + SuccessMsg = "success" //成功 msg + FailCode = -1 + FailMsg = "fail" + SFShopStoreID = "3243279847393" //默认以一个店铺发单 + DefaultVersion = 19 //参照文档主版本号填写 如:文档版本号1.9,version=19,推荐使用版本19 +) + +const ( + OrderTypeSF = 1 //1、顺丰订单号 + OrderTypeStore = 2 //2、商家订单号 + + // 物品类型product_type枚举值: + ProductTypeFastFood = 1 // 快餐 + ProductTypeDrugs = 2 // 药品 + ProductTypeDepartmentStore = 3 // 百货 + ProductTypeOldClothes = 4 // 脏衣服收 + ProductTypeNewClothes = 5 // 干净衣服派 + ProductTypeFresh = 6 // 生鲜 目前默认 + ProductTypeHighDrinks = 8 // 高端饮品 + ProductTypeSiteInspection = 9 // 现场勘验 + ProductTypeExpress = 10 // 快递 + ProductTypeFile = 12 // 文件 + ProductTypeCake = 13 // 蛋糕 + ProductTypeFlower = 14 // 鲜花 + ProductTypeDigital = 15 // 数码 + ProductTypeClothing = 16 // 服装 + ProductTypeCar = 17 // 汽配 + ProductTypeJewellery = 18 // 珠宝 + ProductTypePizza = 20 // 披萨 + ProductTypeChineseFood = 21 // 中餐 + ProductTypeFreshwaterFresh = 22 // 水产 + ProductTypeDirectDelivery = 27 // 专人直送 + ProductTypeMidRangeDrinks = 32 // 中端饮品 + ProductTypeConvenienceStore = 33 // 便利店 + ProductTypeBakeries = 34 // 面包糕点 + ProductTypeHotPot = 35 // 火锅 + ProductTypeLicence = 36 // 证照 + ProductTypeCrayfish = 40 // 烧烤小龙虾 + ProductTypeOtherInfo = 41 // 外部落地配 + ProductTypeAlcoholAndTobacco = 47 // 烟酒行 + ProductTypeAdultEroticaProducts = 48 // 成人用品 + ProductTypeOther = 99 // 其他 + + //订单接入来源 + OrderSourceMt = "1" //美团 + OrderSourceELM = "2" //饿了么 + OrderSourceEBAI = "3" //饿了么零售 + OrderSourceKB = "4" //口碑 + + //坐标类型 + LbsTypeBD = 1 //百度地图 + LbsTypeGD = 2 //高德地图 + + //物流流向 + RiderPickUpMethodSTU = 1 //从门店取件送至用户(默认) + RiderPickUpMethodUTS = 2 //从用户取件送至门店(仅连锁店铺支持) + + //取消代码 + CancelCodeChangePlan = 300 //计划有变,暂时不需要寄件了 + CancelCodeWrongInfo = 302 //填错订单信息,取消后重新提交 + CancelCodeRiderCancel = 303 //骑士要求取消 + CancelCodeCanNotDelivery = 304 //暂时无法提供待配送物品 + CancelCodeRepeatOrder = 306 //重复下单,取消此单 + CancelCodeRiderTooLong = 309 //骑士上门时间太长 + CancelCodeNoneTake = 312 //无人接单,换用其他平台寄件 + CancelCodeOther = 313 //其他,请注明原因 + + //订单状态 + OrderStatusNewOrder = 1 //1:订单创建 + OrderStatusTakeOrder = 10 //10:配送员接单 + OrderStatusArrivedStore = 12 //12:配送员到店 + OrderStatusRiderArriving = 15 //15:配送员配送中(已取货) + OrderStatusRiderCancel = 22 //配送员撤单 + OrderStatusFinished = 17 //17:配送员完成订单 + OrderStatusOrderCancel = 2 //订单取消 + OrderStatusError = 91 //订单异常 + //异常情况枚举 + ExIDLoseOrBroke = 4003 //托寄物丢失或损坏 + ExIDStoreSlow = 1001 //商家出货慢 + ExIDUserRefuseCertifying = 2010 //顾客拒绝实名认证 + ExIDCertifyingFail = 3004 //实名认证校验失败 + ExIDChangeStoreAddress = 1007 //更改取货地址 + ExIDUserDisconnect = 2001 //顾客电话无法接通 + ExIDChangeExpectTime = 2004 //更改期望送达时间 + ExIDUserReject = 2005 //顾客拒收 + ExIDUserNotHome = 2008 //顾客不在家 + ExIDChangeUserAddress = 2009 //更改送货地址 + ExIDWrongAddress = 4001 //配送地址错误 + ExIDOther = 4002 //其他 +) + +var CancelCode = map[int]string{ + CancelCodeChangePlan: "计划有变,暂时不需要寄件了", + CancelCodeWrongInfo: "填错订单信息,取消后重新提交", + CancelCodeRiderCancel: "骑士要求取消", + CancelCodeCanNotDelivery: "暂时无法提供待配送物品", + CancelCodeRepeatOrder: "重复下单,取消此单", + CancelCodeRiderTooLong: "骑士上门时间太长", + CancelCodeNoneTake: "无人接单,换用其他平台寄件", + CancelCodeOther: "其他,请注明原因", +} + +// API 注册请求api +type API struct { + devId int64 `json:"dev_id"` + devKey string `json:"dev_key"` + sign string `json:"sign"` + pushTime int64 `json:"push_time"` + locker sync.RWMutex + client *http.Client + config *platformapi.APIConfig +} + +/************************************************订单*****************************************************/ + +// PreCreateOrderReq 预创建订单(店铺)请求 +type PreCreateOrderReq struct { + // 必填 + DevId int64 `json:"dev_id"` // 同城开发者ID + ShopId string `json:"shop_id"` // 店铺ID + UserLng string `json:"user_lng"` //用户地址经度 + UserLat string `json:"user_lat"` //用户地址纬度 + UserAddress string `json:"user_address"` //用户详细地址 + Weight int64 `json:"weight"` //物品重量(单位:克) + ProductType int64 `json:"product_type"` //物品类型 + PushTime int64 `json:"push_time"` // 推单时间 秒级时间戳 + // 非必填 + ShopType int64 `json:"shop_type"` // 店铺ID类型 1:顺丰店铺ID ;2:接入方店铺ID + CityName string `json:"city_name"` //发单城市 用来校验是否跨城;请填写城市的中文名称,如北京市、深圳市 + TotalPrice int64 `json:"total_price"` //用户订单总金额(单位:分) + IsAppoint int `json:"is_appoint"` //是否是预约单 0:非预约单;1:预约单 + AppointType int `json:"appoint_type"` //预约单类型 预约单的时候传入,1:预约单送达单;2:预约单上门单 + ExpectTime int64 `json:"expect_time"` // 用户期望送达时间 若传入自此段且时间大于配送时效,则按照预约送达单处理,时间小于配送时效按照立即单处理;appoint_type=1时需必传,秒级时间戳; + //ExpectPickupTime int64 `json:"expect_pickup_time"` // 用户期望上门时间 appoint_type=2时需必传,秒级时间戳 + LbsType int `json:"lbs_type"` // 坐标类型 1:百度坐标,2:高德坐标 + IsInsured int64 `json:"is_insured"` // 是否保价,0:非保价;1:保价 + IsPersonDirect int64 `json:"is_person_direct"` // 是否是专人直送订单,0:否;1:是 + Vehicle int `json:"vehicle"` // 配送交通工具,0:否;1:电动车;2:小轿车 + DeclaredValue int64 `json:"declared_value"` // 保价金额(单位:分) + GratuityFee int64 `json:"gratuity_fee"` // 订单小费,不传或者传0为不加小费 单位分,加小费最低不能少于100分 + RiderPickMethod int64 `json:"rider_pick_method"` // 物流流向 1:从门店取件送至用户; 2:从用户取件送至门店 + ReturnFlag int `json:"return_flag"` // 返回字段控制标志位(二进制) 1:商品总价格,2:配送距离,4:物品重量,8:起送时间,16:期望送达时间,32:支付费用,64:实际支付金额,128:优惠券总金额,256:结算方式 例如全部返回为填入511 + Shop *SfShopInfo `json:"shop"` // 发货店铺信息 Obj,详见shop结构, 平台级开发者(如饿了么)需传入如无特殊说明此字段可忽略 + MultiPickupInfo []*MultiPickupInfo `json:"multi_pickup_info"` // 多点取货信息 +} + +// PreCreateOrderResp 预创建订单(店铺)响应 +type PreCreateOrderResp struct { + ChargePriceList *ChargePriceList `json:"charge_price_list"` + DeliveryType float64 `json:"delivery_type"` //0:预约送达单 1:立即单 3:预约上门单 + EstimateCouponDetail []interface{} `json:"estimate_coupon_detail"` + EstimateCouponTotalFee float64 `json:"estimate_coupon_total_fee"` + EstimatePayMoney float64 `json:"estimate_pay_money"` + ExpectTime float64 `json:"expect_time"` + OrderToken string `json:"order_token"` + OverflowExpectTime float64 `json:"overflow_expect_time"` + OverflowFee float64 `json:"overflow_fee"` + PromiseDeliveryTime float64 `json:"promise_delivery_time"` //预计配送时间(单位: 分) + GratuityFee float64 `json:"gratuity_fee"` //订单小费 + PushTime float64 `json:"push_time"` //时间戳 +} + +type ChargePriceList struct { + ChargeDetail *ChargeDetail `json:"charge_detail"` + InsuredCeilingRule *InsuredCeilingRule `json:"insured_ceiling_rule"` + ShopPayPrice float64 `json:"shop_pay_price"` //配送费总额(单位:分) + IsInsuredRule float64 `json:"is_insured_rule"` + ShopDeductionPrice float64 `json:"shop_deduction_price"` + Vehicle float64 `json:"vehicle"` +} + +type ChargeDetail struct { + BasicFee float64 `json:"basic_fee"` //常规配送费=起步价+超距离费+超重量费 + Basic float64 `json:"basic"` //起步价 + CancelExcessFee float64 `json:"cancel_excess_fee"` //拒收扣费 + ExtraFee float64 `json:"extra_fee"` //附加费 + ExtraFeeDetail struct { + GeographyFee float64 `json:"geography_fee"` + } + GratuityFee float64 `json:"gratuity_fee"` + OverDistance float64 `json:"over_distance"` //超距离费用 + OverWeight float64 `json:"over_weight"` //超重量费用 + OverflowFee float64 `json:"overflow_fee"` + SpecialTimeFee float64 `json:"special_time_fee"` //特殊时段费 + VasFee float64 `json:"vas_fee"` //增值服务费 + VasFeeDetail *VasFeeDetail `json:"vas_fee_detail"` //增值服务费详情 +} + +type InsuredCeilingRule struct { + End float64 `json:"end"` + InsuredType float64 `json:"insured_type"` + Start float64 `json:"start"` + Status float64 `json:"status"` + Type float64 `json:"type"` + Value string `json:"value"` +} + +// VasFeeDetail 增值服务费详情 +type VasFeeDetail struct { + AcceptFasterFee float64 `json:"accept_faster_fee"` + AddressChangeFee float64 `json:"address_change_fee"` + AppointmentFasterFee float64 `json:"appointment_faster_fee"` + AppointmentFee float64 `json:"appointment_fee"` + BigOrder struct { + Fee float64 `json:"fee"` //大额单费 + } `json:"big_order"` + Collection struct { + Fee float64 `json:"fee"` //代收货款费用 + } `json:"collection"` + Countersign struct { + Fee float64 `json:"fee"` + } `json:"countersign"` + DigitalServiceFee float64 `json:"digital_service_fee"` + DwPackageFee float64 `json:"dw_package_fee"` + ExpectFasterFee float64 `json:"expect_faster_fee"` + FileBagFee float64 `json:"file_bag_fee"` + Insured struct { + DeclaredPrice float64 `json:"declared_price"` + Fee float64 `json:"fee"` + } `json:"insured"` + LineupTimeFee float64 `json:"lineup_time_fee"` + LowTempFee float64 `json:"low_temp_fee"` + MultiPickup struct { + Fee int `json:"fee"` + } `json:"multipickup"` + OutOrderRateFee float64 `json:"out_order_rate_fee"` + PackageServiceFee float64 `json:"package_service_fee"` + PackingFee float64 `json:"packing_fee"` + PersonDirectFee float64 `json:"person_direct_fee"` + ResidentServiceFee float64 `json:"resident_service_fee"` + ScanPayFee float64 `json:"scan_pay_fee"` + ServiceFee float64 `json:"service_fee"` + TakeGoodsSmsFee float64 `json:"take_goods_sms_fee"` + UavFee float64 `json:"uav_fee"` + VehicleCarFee float64 `json:"vehicle_car_fee"` +} + +// CreateOrderReq 创建订单(店铺) +type CreateOrderReq struct { + // 必填 + DevId int64 `json:"dev_id"` // 同城开发者ID + ShopId string `json:"shop_id"` // 店铺ID + ShopOrderId string `json:"shop_order_id"` // 不允许重复(使用相同商家订单号会幂等返回) + OrderSource string `json:"order_source"` // 订单接入来源 1:美团;2:饿了么;3:百度;4:口碑;其他请直接填写中文字符串值 + PayType int64 `json:"pay_type"` // 用户支付方式 1:已付款 0:货到付款 + OrderTime int64 `json:"order_time"` // 用户下单时间 秒级时间戳 + IsAppoint int `json:"is_appoint"` // 是否是预约单 0:非预约单;1:预约单 + IsInsured int64 `json:"is_insured"` // 是否保价,0:非保价;1:保价 + IsPriorityAssign int64 `json:"is_priority_assign"` // 是否优先派单,0:否 1:是 + IsPersonDirect int64 `json:"is_person_direct"` // 是否是专人直送订单,0:否;1:是 + PushTime int64 `json:"push_time"` // 推单时间 秒级时间戳 + Version int64 `json:"version"` // 版本号 参照文档主版本号填写 如:文档版本号1.7,version=17 + Receive *ReceiveAddress `json:"receive"` // 收货人信息 + Shop *SfShopInfo `json:"shop"` // 发货店铺信息 Obj,详见shop结构, 平台级开发者(如饿了么)需传入如无特殊说明此字段可忽略 + OrderDetail *OrderDetail `json:"order_detail"` // 订单详情 + MultiPickupInfo []*MultiPickupDetails `json:"multi_pickup_info"` // 多点取货信息 + // 非必填 + //LbsType int `json:"lbs_type"` // 坐标类型 1:百度坐标,2:高德坐标 + //ShopType int64 `json:"shop_type"` // 店铺ID类型 1:顺丰店铺ID ;2:接入方店铺ID + ShopPreparationTime int64 `json:"shop_preparation_time"` // 商家预计备餐时长(分10) + OrderSequence string `json:"order_sequence"` // 取货序号 与order_source配合使用 如:饿了么10号单,表示如下:order_source=2;order_sequence=10。用于骑士快速寻找配送物 + AppointType int `json:"appoint_type"` // 预约单类型 预约单的时候传入,1:预约单送达单;2:预约单上门单 + ExpectTime int64 `json:"expect_time"` // 用户期望送达时间 若传入自此段且时间大于配送时效,则按照预约送达单处理,时间小于配送时效按照立即单处理;appoint_type=1时需必传,秒级时间戳; + ExpectPickupTime int64 `json:"expect_pickup_time"` // 用户期望上门时间 appoint_type=2时需必传,秒级时间戳 + ShopExpectTime int64 `json:"shop_expect_time"` // 商家期望送达时间 只展示给骑士,不参与时效考核;秒级时间戳 + Vehicle int `json:"vehicle"` // 配送交通工具,0:否;1:电动车;2:小轿车 + DeclaredValue int64 `json:"declared_value"` // 保价金额(单位:分) + GratuityFee int64 `json:"gratuity_fee"` // 订单小费,不传或者传0为不加小费 单位分,加小费最低不能少于100分 + Remark string `json:"remark"` // 订单备注 + RiderPickMethod int64 `json:"rider_pick_method"` // 物流流向 1:从门店取件送至用户; 2:从用户取件送至门店 + ReturnFlag int `json:"return_flag"` // 返回字段控制标志位(二进制) 1:商品总价格,2:配送距离,4:物品重量,8:起送时间,16:期望送达时间,32:支付费用,64:实际支付金额,128:优惠券总金额,256:结算方式 例如全部返回为填入511 + +} + +// CreateOrderResp 创建订单(店铺) +type CreateOrderResp struct { + SFOrderID string `json:"sf_order_id"` //顺丰订单号, 请注意:新版本V1.9及以后,该订单号升级为JS开头的15位订单号,类型为字符串(老版本仍为int类型) + SFBillID string `json:"sf_bill_id"` //顺丰运单号(需要在顺丰后台配置门店后返回此字段) + ShopOrderID string `json:"shop_order_id"` //商家订单号 + PushTime int `json:"push_time"` //推送时间 + //以下字段受请求参数中 return_flag 控制:return_flag中未包含的,此字段将不存在,请注意! + TotalPrice int `json:"total_price"` //配送费总额,当return_flag中包含1时返回,单位分(值为计算出来此单总价) + DeliveryDistanceMeter int `json:"delivery_distance_meter"` //配送距离,当return_flag中包含2时返回,单位米(值为计算出来实际配送距离) + WeightGram int `json:"weight_gram"` //商品重量,当return_flag中包含4时返回,单位克(值为下单传入参数回传) + StartTime int `json:"start_time"` //起送时间,当return_flag中包含8时返回,时间格式为Unix时间戳,注意转换 + ExpectTime int `json:"expect_time"` //预计送达时间,当return_flag中包含16时返回,时间格式为Unix时间戳,注意转换 + TotalPayMoney int `json:"total_pay_money"` //支付费用,当return_flag中包含32时返回,单位分 + RealPayMoney int `json:"real_pay_money"` //实际支付金额,当return_flag中包含64时返回,单位分(实际支付金额=总金额-优惠券总金额) + CouponsTotalFee int `json:"coupons_total_fee"` //优惠券总金额,当return_flag中包含128时返回,单位分 + SettlementType int `json:"settlement_type"` //结算方式,当return_flag中包含256时返回 + + PickUPCode int `json:"pick_up_code"` //取件码。在顺丰同城商户侧配置,配置后有此字段 + CompleteCode int `json:"complete_code"` //签收码。在顺丰同城商户侧配置,配置后有此字段 + OverflowFee int `json:"overflow_fee"` //爆单费,单位分 + InsureFee int `json:"insure_fee"` //保价费,单位分 +} + +// PreCancelOrderReq 预取消订单 +type PreCancelOrderReq struct { + //必填 + DevId int64 `json:"dev_id"` // 同城开发者ID + OrderID string `json:"order_id"` //新版本V1.9+升级为JS开头的15位字符串类型:“JS1234567890123”, 老版本int类型订单号会长期兼容 + PushTime int64 `json:"push_time"` //取消时间;秒级时间戳 + //非必填 + ShopId string `json:"shop_id"` // 店铺ID + ShopType int64 `json:"shop_type"` //1、顺丰店铺ID 2、接入方店铺ID + CancelReason string `json:"cancel_reason"` //其他取消原因 +} + +// PreCancelOrderResp 预取消订单 +type PreCancelOrderResp struct { + OrderType float64 `json:"order_type"` + PromiseDeliveryTime float64 `json:"promise_delivery_time"` //预计配送时间(单位: 分) + DeliveryType float64 `json:"delivery_type"` //订单类型 0:预约送达单,1:立即单,2:预约上门单 + ExpectPickUpTime float64 `json:"expect_pickup_time"` //原始期望上门时间 + ExpectTime float64 `json:"expect_time"` //预约时间 + ShopCancelTimes string `json:"shop_cancel_times"` //店铺每日取消次数 + FreeCancelTimes float64 `json:"free_cancel_times"` //每日免费取消次数 + IsCancelChargePriceRule float64 `json:"is_cancel_charge_price_rule"` //取消收费规则 + IsOverFreeCancelTimes float64 `json:"is_over_free_cancel_times"` //是否超出免费取消次数 + IsDeductionFee float64 `json:"is_deduction_fee"` //是否有取消收费 + DeductionFee float64 `json:"deduction_fee"` //取消收费 + //CancelChargePriceRule + CouldCancel bool `json:"could_cancel"` //能否取消 + PushTime float64 `json:"push_time"` //推单时间 + SFOrderID string `json:"sf_order_id"` //顺丰订单号, 请注意:新版本V1.9及以后,该订单号升级为JS开头的15位订单号,类型为字符串(老版本仍为int类型) + ShopOrderID string `json:"shop_order_id"` //商家订单号 +} + +// CancelOrderReq 取消订单 +type CancelOrderReq struct { + //必填 + DevId int64 `json:"dev_id"` // 同城开发者ID + OrderID string `json:"order_id"` //新版本V1.9+升级为JS开头的15位字符串类型:“JS1234567890123”, 老版本int类型订单号会长期兼容 + PushTime int64 `json:"push_time"` //取消时间;秒级时间戳 + //非必填 + OrderType int64 `json:"order_type"` //1、顺丰订单号 2、商家订单号 + ShopId string `json:"shop_id"` // 店铺ID + ShopType int64 `json:"shop_type"` //1、顺丰店铺ID 2、接入方店铺ID + CancelCode int64 `json:"cancel_code"` //不填时默认cancel_code=313,cancel_reason=商家发起取消 + CancelReason string `json:"cancel_reason"` //其他取消原因 +} + +// CancelOrderResp 取消订单 +type CancelOrderResp struct { + SFOrderID string `json:"sf_order_id"` //顺丰订单号, 请注意:新版本V1.9及以后,该订单号升级为JS开头的15位订单号,类型为字符串(老版本仍为int类型) + ShopOrderID string `json:"shop_order_id"` //商家订单号 + DeductionDetails struct { + DeductionFee int `json:"deduction_fee"` //取消收费金额(单位:分) + ShopCancelTimes int `json:"shop_cancel_times"` //店铺维度累计的取消次数 + FreeCancelTimes int `json:"free_cancel_times"` //配置的免费取消次数 + } + PushTime int `json:"push_time"` //接口返回时间 +} + +// GetOrderStatusReq 订单实时信息查询 +type GetOrderStatusReq struct { + //必填 + DevId int64 `json:"dev_id"` // 同城开发者ID + OrderID string `json:"order_id"` //新版本V1.9+升级为JS开头的15位字符串类型:“JS1234567890123”, 老版本int类型订单号会长期兼容 + PushTime int64 `json:"push_time"` //取消时间;秒级时间戳 + //非必填 + OrderType int64 `json:"order_type"` //1、顺丰订单号 2、商家订单号 + ShopId string `json:"shop_id"` // 店铺ID + ShopType int64 `json:"shop_type"` //1、顺丰店铺ID 2、接入方店铺ID +} + +// GetOrderStatusResp 订单实时信息查询 +type GetOrderStatusResp struct { + OrderID string `json:"order_id"` //新版本V1.9+升级为JS开头的15位字符串类型:“JS1234567890123”, 老版本int类型订单号会长期兼容 + ShopId int64 `json:"shop_id"` // 店铺ID + OutOrderID string `json:"out_order_id"` //商家订单ID + OrderStatus float64 `json:"order_status"` //当前状态 + StatusDesc string `json:"status_desc"` //当前状态描述 + RiderName string `json:"rider_name"` //骑士名称 + RiderPhone string `json:"rider_phone"` //骑手电话 + PushTime int64 `json:"push_time"` //订单推送生成的时间 + TotalPrice float64 `json:"total_price"` //配送费总额 + DeliveryDistanceMeter float64 `json:"delivery_distance_meter"` //配送距离 + WeightGram float64 `json:"weight_gram"` //商品重量 + StartTime int64 `json:"start_time"` //起送时间 + ExpectTime int64 `json:"expect_time"` //预计送达时间 + TotalPayMoney float64 `json:"total_pay_money"` //支付费用 + RealPayMoney float64 `json:"real_pay_money"` //实际支付金额 + CouponsTotalFee float64 `json:"coupons_total_fee"` //优惠券总金额 + SettlementType float64 `json:"settlement_type"` //结算方式 + PickUpCode float64 `json:"pick_up_code"` //取件码 + CompleteCode float64 `json:"complete_code"` //签收码 + OverflowFee float64 `json:"overflow_fee"` //爆单费,单位分 +} + +// RiderLatestPositionReq 获取配送员实时坐标接口 +type RiderLatestPositionReq struct { + DevId int64 `json:"dev_id"` // 同城开发者ID + OrderID string `json:"order_id"` //新版本V1.9+升级为JS开头的15位字符串类型:“JS1234567890123”, 老版本int类型订单号会长期兼容 + PushTime int64 `json:"push_time"` + //非必填 + OrderType int64 `json:"order_type"` //查询订单ID类型:1、顺丰订单号 2、商家订单号 + ShopID int64 `json:"shop_id"` //order_type=2时必传shop_id与shop_type + ShopType int64 `json:"shop_type"` //1、顺丰店铺ID 2、接入方店铺ID +} + +// RiderLatestPositionResp 获取配送员实时坐标接口 +type RiderLatestPositionResp struct { + SFOrderID string `json:"sf_order_id"` //顺丰订单号,新版本V1.9+升级为JS开头的15位字符串类型, 老版本为int类型 + ShopOrderID string `json:"shop_order_id"` //商家订单号 + RiderName string `json:"rider_name"` //配送员姓名 + RiderPhone string `json:"rider_phone"` //配送员联系方式 + RiderLng string `json:"rider_lng"` //配送员经度 + RiderLat string `json:"rider_lat"` //配送员纬度 + UploadTime string `json:"upload_time"` //坐标上传时间(秒级时间戳) +} + +// SfShopInfo 发货店铺信息,必填 +type SfShopInfo struct { + ShopName string `json:"shop_name"` // 店铺名称 + ShopPhone string `json:"shop_phone"` // 店铺电话 + ShopAddress string `json:"shop_address"` // 店铺地址 + ShopLng string `json:"shop_lng"` // 店铺经度 + ShopLat string `json:"shop_lat"` // 店铺纬度 +} + +// ReceiveAddress 收货人信息 +type ReceiveAddress struct { + // 必填 + UserName string `json:"user_name"` // 用户姓名 + UserPhone string `json:"user_phone"` // 用户电话 + UserAddress string `json:"user_address"` // 用户地址 + UserLng string `json:"user_lng"` // 用户经度 + UserLat string `json:"user_lat"` // 用户纬度 + // 非必填 + CityName string `json:"city_name"` // 发单城市 +} + +// OrderDetail 订单详情 +type OrderDetail struct { + // 必填 + TotalPrice int64 `json:"total_price"` // 订单金额 分 + ProductType int64 `json:"product_type"` // 物品类型 枚举值见下面定义 + WeightGram int64 `json:"weight_gram"` // 物品重量(单位:克) + ProductNum int64 `json:"product_num"` // 物品个数 + ProductTypeNum int64 `json:"product_type_num"` // 物品种类个数 + ProductDetail []*ProductDetail `json:"product_detail"` // 物品详情;数组结构,详见product_detail结构 + // 非必填 + UserMoney int64 `json:"user_money"` // 用户实付商家金额(单位:分) + ShopMoney int `json:"shop_money"` // 商家实收用户金额(单位:分) + VolumeLitre int64 `json:"volume_litre"` // 物品体积(单位:升) + DeliveryMoney int64 `json:"delivery_money"` // 商家收取用户的配送费(单位:分) +} + +// ProductDetail 购买物品详情清单 +type ProductDetail struct { + // 必填 + ProductName string `json:"product_name"` // 物品名称 + ProductNum int64 `json:"product_num"` // 物品数量 + // 非必填 + ProductId int64 `json:"product_id"` // 物品ID + ProductPrice int64 `json:"product_price"` // 物品价格 + ProductUnit string `json:"product_unit"` // 物品单位 + ProductRemark string `json:"product_remark"` // 备注 + ItemDetail string `json:"item_detail"` // 详情 +} + +// MultiPickupDetails 取货地址详情 +type MultiPickupDetails struct { + PickupShopAddress string `json:"pickup_shop_address"` // 取货点地址 + PickupShopPhone string `json:"pickup_shop_phone"` // 取货点店铺手机号 + PickupShopName string `json:"pickup_shop_name"` // 取货点店铺名称 + PickupLng string `json:"pickup_lng"` // 取货点经度 + PickupLat string `json:"pickup_lat"` // 取货点纬度 + PickupProducts string `json:"pickup_products"` // 取货点店铺物品信息 +} + +// MultiPickupInfo 多点取货信息 +type MultiPickupInfo struct { + PickupShopAddress string `json:"pickup_shop_address"` // 取货点地址 + PickupLng string `json:"pickup_lng"` // 取货点经度 + PickupLat string `json:"pickup_lat"` // 取货点纬度 +} + +//#endregion diff --git a/platformapi/sfps2/sf_test.go b/platformapi/sfps2/sf_test.go new file mode 100644 index 00000000..90af2d4a --- /dev/null +++ b/platformapi/sfps2/sf_test.go @@ -0,0 +1,109 @@ +package sfps2 + +import ( + "fmt" + "git.rosy.net.cn/baseapi/utils" + "testing" +) + +var api = New(AppID, AppKey) + +const ( + AppID = 1663705378 //开发者ID + AppKey = "0838426b310fd2530c57dd6e770ddff1" //开发者密钥 + TestSFStoreID = "3243279847393" //open测试平台型店铺 +) + +//预下单 +func TestPreCreateOrder(t *testing.T) { + param := &PreCreateOrderReq{ + DevId: AppID, + ShopId: TestSFStoreID, + UserLng: "116.339392", + UserLat: "40.002349", + UserAddress: "北京市海淀区学清嘉创大厦A座15层", + Weight: 1000, + ProductType: 4, + PushTime: 1684379930, + ShopType: 1, + LbsType: LbsTypeGD, + RiderPickMethod: 1, + ReturnFlag: 1, + //IsAppoint: 0, + //AppointType: 2, + //ExpectPickupTime: int64(time.Now().Unix()), + //RiderPickMethod: 1, + //MultiPickupInfo: []*MultiPickupInfo{{ + // PickupShopAddress: "海淀区清河龙岗路51号清润家园小区 永辉", + // PickupLat: "40.030613", + // PickupLng: "116.354787", + //}}, + } + resp, err := api.PreCreateOrder(param) + fmt.Println(resp) + fmt.Println(err) +} + +//正式下单 +func TestCreateOrder(t *testing.T) { + param := &CreateOrderReq{ + DevId: AppID, + ShopId: TestSFStoreID, + ShopOrderId: "20230518Test", + OrderSequence: "测试", + OrderSource: OrderSourceELM, + OrderTime: 1684302448, + PushTime: 1684399264, + Version: 19, + Receive: &ReceiveAddress{ + UserLng: "116.339392", + UserLat: "40.002349", + UserAddress: "北京市海淀区学清嘉创大厦A座15层", + UserName: "杨玺", + UserPhone: "17236456352", + }, + OrderDetail: &OrderDetail{ + TotalPrice: 890, + ProductType: 4, + WeightGram: 390, + ProductNum: 1, + ProductTypeNum: 1, + ProductDetail: []*ProductDetail{{ + ProductName: "新鲜水果拼盘", + ProductNum: 1, + }}, + }, + RiderPickMethod: 1, + } + sfOrderID, sfBillID, totalPrice, err := api.CreateOrder(param) + fmt.Println(sfOrderID, sfBillID) + fmt.Println(totalPrice) + fmt.Println(err) +} + +//预取消订单 +func TestPreCancelOrder(t *testing.T) { + resp, err := api.PreCancelOrder("JS4157196256886") + fmt.Println(resp) + fmt.Println(err) +} + +//取消订单 +func TestCancelOrder(t *testing.T) { + err := api.CancelOrder("JS4157196256886") + fmt.Println(err) +} + +//订单实时信息查询 +func TestGetOrderStatus(t *testing.T) { + resp, err := api.GetOrderStatus("JS4157196256886") + fmt.Println(utils.Format4Output(resp, false)) + fmt.Println(err) +} + +// +func TestGetRiderLatestPosition(t *testing.T) { + resp, err := api.GetRiderLatestPosition("JS4157196256886") + fmt.Println(utils.Format4Output(resp, false)) + fmt.Println(err) +} diff --git a/platformapi/sfps2/sfpsapi.go b/platformapi/sfps2/sfpsapi.go new file mode 100644 index 00000000..ebc51984 --- /dev/null +++ b/platformapi/sfps2/sfpsapi.go @@ -0,0 +1,98 @@ +package sfps2 + +import ( + "crypto/md5" + "encoding/base64" + "encoding/json" + "fmt" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" + "io/ioutil" + "net/http" + "strings" + "sync" +) + +type Response struct { + HttpStatusCode int `json:"http_status_code"` + BaseRetVal *BaseRetVal +} + +type BaseRetVal struct { + ErrorCode int `json:"error_code"` + ErrorMsg string `json:"error_msg"` + ErrorData interface{} `json:"error_data"` + Result interface{} `json:"result"` +} + +func New(devId int64, devKey string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + + return &API{ + devId: devId, + devKey: devKey, + locker: sync.RWMutex{}, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } +} + +func (a *API) signParam(params []byte) (sig string) { + sign := fmt.Sprintf("%s&%d&%s", string(params), a.devId, a.devKey) + md2sign := md5.Sum([]byte(sign)) + return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%x", md2sign))) +} + +func (a *API) HttpPostJson(url string, data interface{}) *Response { + //序列化参数 + b, err := json.Marshal(data) + if err != nil { + var msg = fmt.Sprintf("json serialize err:%+v", err) + fmt.Println(msg) + result := Response{ + HttpStatusCode: 500, + } + return &result + } + //签名 + sign := a.signParam(b) + + fullUrl := utils.GenerateGetURL(BaseURL, url, map[string]interface{}{"sign": sign}) + //fullUrl := utils.GenerateGetURL(BaseCatchUrl, url, map[string]interface{}{"sign": sign}) + + request, err := http.NewRequest(http.MethodPost, fullUrl, strings.NewReader(string(b))) + client := &http.Client{} + + request.Header.Set("Content-Type", "application/json;charset=UTF-8") + //request.Header.Set("Test-Group", "jx517") + + resp, err := client.Do(request) + if err != nil { + fmt.Println(err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + var msg = fmt.Sprintf("post json error:%+v", err) + fmt.Println(msg) + } + + result := Response{ + HttpStatusCode: resp.StatusCode, + } + + var content BaseRetVal + err = json.Unmarshal(body, &content) + if err == nil { + result.BaseRetVal = &content + } else { + var msg = fmt.Sprintf("unmarshal body failed, error:%+v", err) + fmt.Println(msg) + } + + return &result +}