添加蜂鸟配送

This commit is contained in:
邹宗楠
2022-03-25 09:33:46 +08:00
parent c71429a3fd
commit c112e5e282
21 changed files with 2117 additions and 500 deletions

View File

@@ -0,0 +1,102 @@
package fnpsapi
import (
"fmt"
"testing"
)
var api *API
func Init() {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
}
func TestClient(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
token, err := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
fmt.Println("token===", token.BusinessDataObj.AccessToken)
fmt.Println("err=====", err)
}
// 创建门店,
func TestCreateStore(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
err := api.CreateStore(&CreateStoreBaseInfo{
HeadShopName: "刘磊测试门店",
ContactPhone: "18981810340",
Address: "四川成都",
Longitude: 104.094555,
Latitude: 30.661382,
PositionSource: 3,
OutShopCode: "637910",
CategoryID: "12",
OwnerName: "刘磊",
OwnerIDNum: "511324199308263974",
HandheldLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
OwnerIDPicFrontHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
OwnerIDPicBackHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
CreditCode: "12345",
BusinessLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
BranchShopName: "",
ChainstoreType: 2,
SettlementModel: "1",
SettlementAccountID: "",
FoodLicensePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
SecondMedicalEquipmentLicensePicHash: "",
MedicalInstitutionLicensePicHash: "",
MedicalEquipmentLicensePicHash: "",
MedicineLicensePicHash: "",
TabacooLicensePicHash: "",
})
fmt.Println(err)
}
func TestUpdataStore(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
err := api.UpdateStore(&UpdateStoreParam{
ChainStoreID: "209636747",
HeadShopName: "刘磊测试门店",
ContactPhone: "18981810340",
Address: "四川成都",
Longitude: 104.094555,
Latitude: 30.661382,
PositionSource: 3,
OutShopCode: "637910",
CategoryID: "12",
OwnerName: "刘磊",
OwnerIDNum: "511324199308263974",
HandheldLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
OwnerIDPicFrontHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
OwnerIDPicBackHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
CreditCode: "12345",
BusinessLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
BranchShopName: "",
ChainstoreType: 2,
FoodLicensePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
SecondMedicalEquipmentLicensePicHash: "",
MedicalInstitutionLicensePicHash: "",
MedicalEquipmentLicensePicHash: "",
MedicineLicensePicHash: "",
TabacooLicensePicHash: "",
})
fmt.Println(err)
}
// 查询单个门店
func TestQueryOneStore(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
data, err := api.GetStore("637910")
fmt.Println(data)
fmt.Println(err)
}

View File

@@ -7,8 +7,10 @@ import (
)
const (
TokenURL = "https://open-anubis.ele.me/anubis-webapi/openapi/token"
ApiURL = "https://open-anubis.ele.me/anubis-webapi/v3/invoke/"
//TokenURL = "https://open-anubis.ele.me/anubis-webapi/openapi/token" // 正式环境
//ApiURL = "https://open-anubis.ele.me/anubis-webapi/v3/invoke"// 正式环境
TokenURL = "https://exam-anubis.ele.me/anubis-webapi/openapi/token" // 沙箱环境
ApiURL = "https://exam-anubis.ele.me/anubis-webapi/v3/invoke" // 沙箱环境
RequestPost = "POST"
RequestGet = "GET"
)
@@ -43,10 +45,11 @@ type BaseInfo struct {
// 获取token
type TokenInfo struct {
Sign string `json:"sign"` //返回值签名,详见开放平台侧返回值签名算法
Code string `json:"code"` //错误码,详见开放平台侧错误码映射表
Msg string `json:"msg"` //错误信息
BusinessData string `json:"business_data"` // string
Sign string `json:"sign"` //返回值签名,详见开放平台侧返回值签名算法
Code string `json:"code"` //错误码,详见开放平台侧错误码映射表
Msg string `json:"msg"` //错误信息
BusinessData string `json:"business_data"` // string
BusinessDataObj *BusinessData // BusinessData 对象
}
type BusinessData struct {
@@ -54,13 +57,13 @@ type BusinessData struct {
MerchantID string `json:"merchant_id"` //商户id
AccessToken string `json:"access_token"` //凭证token
RefreshToken string `json:"refresh_token"` //刷新token
ExpireIn string `json:"expire_in"` //access_token剩余有效时间,单位:秒,默认有效期是一年
ReExpireIn string `json:"re_expire_in"` //refresh_token剩余有效时间
ExpireIn int64 `json:"expire_in"` //access_token剩余有效时间,单位:秒,默认有效期是一年
ReExpireIn int64 `json:"re_expire_in"` //refresh_token剩余有效时间
}
//#endregion
//<------------------------------------门店--------------------------------------------------------------------------------------->
//<---------------------------------------------------门店--------------------------------------------------------------------------------------->
//#region 获取蜂鸟门店信息
// 获取单个门店查询
@@ -106,26 +109,26 @@ type GetOneStoreRespData struct {
// 更新蜂鸟门店信息
type UpdateStoreParam struct {
// 必填
ChainStoreID string `json:"chain_store_id"`
HeadShopName string `json:"head_shop_name"` // 门店主店名
ContactPhone string `json:"contact_phone"` // 门店联系方式
Address string `json:"address"` // 门店地址
Longitude string `json:"longitude"` // 纬度
Latitude string `json:"latitude"` // 门店纬度
PositionSource string `json:"position_source"` // 经纬度来源 坐标属性高德地图3目前只支持高德地图坐标
OutShopCode string `json:"out_shop_code"` // 外部门店编码
CategoryID string `json:"category_id"` // 门店类目
OwnerName string `json:"owner_name"` // 门店主店名
OwnerIDNum string `json:"owner_id_num"` // 门店拥有人身份证号
HandheldLicencePicHash string `json:"handheld_licence_pic_hash"` // 门店拥有人手持身份证、营业执照图片
OwnerIDPicFrontHash string `json:"owner_id_pic_front_hash"` // 身份证正面
OwnerIDPicBackHash string `json:"owner_id_pic_back_hash"` // 身份证反面
CreditCode string `json:"credit_code"` // 统一社会信用代码
BusinessLicencePicHash string `json:"business_licence_pic_hash"` // 营业执照图片
ChainStoreID string `json:"chain_store_id"`
HeadShopName string `json:"head_shop_name"` // 门店主店名
ContactPhone string `json:"contact_phone"` // 门店联系方式
Address string `json:"address"` // 门店地址
Longitude float64 `json:"longitude"` // 纬度
Latitude float64 `json:"latitude"` // 门店纬度
PositionSource int `json:"position_source"` // 经纬度来源 坐标属性高德地图3目前只支持高德地图坐标
OutShopCode string `json:"out_shop_code"` // 外部门店编码
CategoryID string `json:"category_id"` // 门店类目
OwnerName string `json:"owner_name"` // 门店主店名
OwnerIDNum string `json:"owner_id_num"` // 门店拥有人身份证号
HandheldLicencePicHash string `json:"handheld_licence_pic_hash"` // 门店拥有人手持身份证、营业执照图片
OwnerIDPicFrontHash string `json:"owner_id_pic_front_hash"` // 身份证正面
OwnerIDPicBackHash string `json:"owner_id_pic_back_hash"` // 身份证反面
CreditCode string `json:"credit_code"` // 统一社会信用代码
BusinessLicencePicHash string `json:"business_licence_pic_hash"` // 营业执照图片
// 选填
BranchShopName string `json:"branch_shop_name"` // 门店主店名
ChainstoreType string `json:"chainstore_type"`
ChainstoreType int `json:"chainstore_type"`
FoodLicensePicHash string `json:"food_license_pic_hash"` // 食品安全执照图片
SecondMedicalEquipmentLicensePicHash string `json:"second_medical_equipment_license_pic_hash"` // 第二类医疗器械类目必传
MedicalInstitutionLicensePicHash string `json:"medical_institution_license_pic_hash"` // 医疗机构必传
@@ -179,11 +182,11 @@ type PreCreateOrder struct {
OrderType int `json:"order_type"` // 订单类型1:即时单3:预约单)
PositionSource int `json:"position_source"` // 经纬度来源
ReceiverAddress string `json:"receiver_address"` // 收货人地址 文字描述
ReceiverLongitude string `json:"receiver_longitude"` // 收货人经度
ReceiverLatitude string `json:"receiver_latitude"` // 收货人纬度
ReceiverLongitude float64 `json:"receiver_longitude"` // 收货人经度
ReceiverLatitude float64 `json:"receiver_latitude"` // 收货人纬度
GoodsTotalAmountCent int `json:"goods_total_amount_cent"` // 订单商品总金额(分)
GoodsActualAmountCent int64 `json:"goods_actual_amount_cent"` // 订单商品客户实际支付金额
GoodsWeight string `json:"goods_weight"` // 订单总重量(kg)
GoodsWeight float64 `json:"goods_weight"` // 订单总重量(kg)
GoodsCount int `json:"goods_count"` // 货物件数
GoodsItemList []*GoodsItemsList // 货物列表
@@ -223,10 +226,11 @@ type GoodsItemsList struct {
// 蜂鸟请求预下单返回值
type PreCreateOrderResp struct {
Distance int64 `json:"distance"` //配送距离
CityId int64 `json:"city_id"` // 城市id
Time int64 `json:"time"` // 预询时间戳
GoodsInfos []*GoodsInfos // 服务商品明细
Distance int64 `json:"distance"` //配送距离
CityId int64 `json:"city_id"` // 城市id
Time int64 `json:"time"` // 预询时间戳
GoodsInfos []*GoodsInfos `json:"goods_infos"` // 服务商品明细
//GoodsInfos string `json:"goods_infos"` // 服务商品明细
}
// 预下单商品服务明细
@@ -279,13 +283,13 @@ type CreateOrderReqParam struct {
GoodsItemList []*GoodsItemsList `json:"goods_item_list,omitempty"` // 货物明细
ReceiverName string `json:"receiver_name,omitempty"` // 收货人姓名
ReceiverPrimaryPhone string `json:"receiver_primary_phone,omitempty"` // 只支持手机号400开头电话座机号码以及95013开头、长度13位的虚拟电话
OutShopCode string `json:"out_shop_code,omitempty"` // 外部门店id 当使用门店发单 out_shop_code和chain_store_id必填1个
ChainStoreId string `json:"chain_store_id,omitempty"` // 门店id
// 选传参数
TransportLongitude float64 `json:"transport_longitude,omitempty"` // 取货经度
TransportLatitude float64 `json:"transport_latitude,omitempty"` // 取货纬度
TransportTel string `json:"transport_tel,omitempty"` // 取货点联系人电话
OutShopCode string `json:"out_shop_code,omitempty"` // 外部门店id 当使用门店发单 out_shop_code和chain_store_id必填1个
ChainStoreId int64 `json:"chain_store_id,omitempty"` // 门店id
OrderSource string `json:"order_source,omitempty"` // 饿百订单传109 商户订单来源(如饿了么、美团等)手发单/未知来源: 0 或不传 美团: 2 口碑: 4 饿了么: 6支付宝: 7 饿百: 8
ServiceGoodsId int64 `json:"service_goods_id,omitempty"` // 服务商品id 校验预询配送费价格时 必传
BaseGoodsId int64 `json:"base_goods_id,omitempty"` // 基础商品id 校验预询配送费价格时 必传
@@ -323,33 +327,41 @@ type GetOrderDetailReq struct {
// 查询订单详情接口返回值
type GetOrderDetailRes struct {
OrderId int64 `json:"order_id"` // 订单id
TrackingId int64 `json:"tracking_id"` // 运单id
PartnerOrderCode string `json:"partner_order_code"` // 外部订单号
SerialNumber string `json:"serial_number"` // 商家订单流水号, 方便配送骑手 到店取货, 支持数字,字母及#等常见字符. 建议填写。长度<=6。
OrderStatus int `json:"order_status"` // 订单生成0运单生成成功120骑手接单80骑手到店2配送中3已完成4已取消5配送异常
CarrierDriverId string `json:"carrier_driver_id"` // 配送员id
CarrierDriverName string `json:"carrier_driver_name"` // 配送员姓名
CarrierDriverPhone string `json:"carrier_driver_phone"` // 配送员电话
EstimateArriveTime int64 `json:"estimate_arrive_time"` // 预计送达时间(毫秒)
OvertimeCompensationCostCent int64 `json:"overtime_compensation_cost_cent"` // 时效赔付
IfCanAddTip int `json:"if_can_add_tip"` // 是否支持添加调度费 1可以0不可以
OrderTipAmountCent int64 `json:"order_tip_amount_cent"` // 订单当前小费总金额 分
DeliveryFetchPhotos []interface{} `json:"delivery_fetch_photos"` // 骑手取货照片地址
OrderTotalAmountCent int64 `json:"order_total_amount_cent"` // 原始配送费金额(分)
OrderActualAmountCent int64 `json:"order_actual_amount_cent"` // 订单实际配送支付总金额关注这个字段即可(分)
PriceDetail []*struct{} `json:"price_detail"` // 配送费价格明细
AbnormalCode string `json:"abnormal_code"` // 运单异常原因code
AbnormalDesc string `json:"abnormal_desc"` // 运单异常原因描述
EventLogDetails []*struct{} `json:"event_log_details"` // 运单事件节点信息
ComplaintId int64 `json:"complaint_id"` // 投诉编号
ComplaintReasonDesc string `json:"complaint_reason_desc"` // 投诉原因描述
ComplaintStatus int `json:"complaint_status"` // 投诉状态 1待处理 2成功3失败
ClaimId int64 `json:"claim_id"` // 索赔id
ClaimReasonDesc string `json:"claim_reason_desc"` // 索赔原因描述
ClaimStatus int `json:"claim_status"` // 索赔状态 1待处理 2成功3失败
Temperature string `json:"temperature"` // 骑手体温
OrderDistance float64 `json:"order_distance"` // 配送距离(米)
OrderId int64 `json:"order_id"` // 订单id
TrackingId int64 `json:"tracking_id"` // 运单id
PartnerOrderCode string `json:"partner_order_code"` // 外部订单号
SerialNumber string `json:"serial_number"` // 商家订单流水号, 方便配送骑手 到店取货, 支持数字,字母及#等常见字符. 建议填写。长度<=6。
OrderStatus int `json:"order_status"` // 订单生成0运单生成成功120骑手接单80骑手到店2配送中3已完成4已取消5配送异常
CarrierDriverId string `json:"carrier_driver_id"` // 配送员id
CarrierDriverName string `json:"carrier_driver_name"` // 配送员姓名
CarrierDriverPhone string `json:"carrier_driver_phone"` // 配送员电话
EstimateArriveTime int64 `json:"estimate_arrive_time"` // 预计送达时间(毫秒)
OvertimeCompensationCostCent int64 `json:"overtime_compensation_cost_cent"` // 时效赔付
IfCanAddTip int `json:"if_can_add_tip"` // 是否支持添加调度费 1可以0不可以
OrderTipAmountCent int64 `json:"order_tip_amount_cent"` // 订单当前小费总金额 分
DeliveryFetchPhotos []interface{} `json:"delivery_fetch_photos"` // 骑手取货照片地址
OrderTotalAmountCent int64 `json:"order_total_amount_cent"` // 原始配送费金额(分)
OrderActualAmountCent int64 `json:"order_actual_amount_cent"` // 订单实际配送支付总金额关注这个字段即可(分)
PriceDetail []*PriceOpenapiDetail `json:"price_detail"` // 配送费价格明细
AbnormalCode string `json:"abnormal_code"` // 运单异常原因code
AbnormalDesc string `json:"abnormal_desc"` // 运单异常原因描述
EventLogDetails []*OrderNodeInfo `json:"event_log_details"` // 运单事件节点信息
ComplaintId int64 `json:"complaint_id"` // 投诉编号
ComplaintReasonDesc string `json:"complaint_reason_desc"` // 投诉原因描述
ComplaintStatus int `json:"complaint_status"` // 投诉状态 1待处理 2成功3失败
ClaimId int64 `json:"claim_id"` // 索赔id
ClaimReasonDesc string `json:"claim_reason_desc"` // 索赔原因描述
ClaimStatus int `json:"claim_status"` // 索赔状态 1待处理 2成功3失败
Temperature string `json:"temperature"` // 骑手体温
OrderDistance float64 `json:"order_distance"` // 配送距离(米)
}
// 点单详情信息,订单结点信息
type OrderNodeInfo struct {
OrderStatus int `json:"order_status"` // 订单状态
OccurTime int64 `json:"occur_time"` // 时间结点
CarrierDriverName string `json:"carrier_driver_name"` // 配送员姓名
CarrierDriverPhone string `json:"carrier_driver_phone"` // 配送电话
}
// getKnightInfo 查询骑手信息接口,参数 GetOrderDetailReq
@@ -370,9 +382,10 @@ type GetKnightInfoRes struct {
//另:联调环境使用加小费接口 需先使用联调工具->订单状态回调把订单状态改为1否则订单状态会不支持加小费
// 添加小费
type AddTipRes struct {
GetOrderDetailReq
AddTipAmountCent int64 `json:"add_tip_amount_cent"` // 小费金额分(必填)
ThirdIndexId int64 `json:"third_index_id"` // 本次加小费唯一标识 每个订单内 不可重复, 会用来做幂等相同third_index_id的后续请求会被忽略
OrderId string `json:"order_id"` // 订单号 订单号和外部订单号必填1个
PartnerOrderCode string `json:"partner_order_code"` // 外部订单号
AddTipAmountCent int64 `json:"add_tip_amount_cent"` // 小费金额分(必填)
ThirdIndexId int64 `json:"third_index_id"` // 本次加小费唯一标识 每个订单内 不可重复, 会用来做幂等相同third_index_id的后续请求会被忽略
}
// 业务出参 "business_data": "{\"result\":true}"
@@ -390,6 +403,12 @@ type GetCancelReasonListRes struct {
}
}
// preCancelOrder 预取消订单接口
type PreCancelOrderReq struct {
GetOrderDetailReq
OrderCancelCode int64 `json:"order_cancel_code"` // 从可用取消原因列表接口返回结果选择(必填)
}
// cancelOrder 正式取消订单接口
type CancelOrderReq struct {
GetOrderDetailReq
@@ -428,3 +447,5 @@ type OrderClaimSkuDto struct {
}
//#endregion
//#endregion

View File

@@ -2,17 +2,17 @@ package fnpsapi
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"sort"
"strings"
"sync"
"time"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
func (a *API) SetToken(token string) {
@@ -32,19 +32,20 @@ func (a *API) MakeFnRequestHead() map[string]interface{} {
return requestParam
}
func New(appID, appSecret, merchantId string, config ...*platformapi.APIConfig) *API {
func New(appID, appSecret, merchantId, code string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
grantType: "authorization_code", // 授权模式填固定值authorization_code
code: "cod3",
code: code,
appID: appID,
merchantId: merchantId,
signature: "",
timestamp: time.Now().UnixNano(),
accessToken: "",
version: "1.0",
appSecret: appSecret,
locker: sync.RWMutex{},
client: &http.Client{Timeout: curConfig.ClientTimeout},
@@ -52,25 +53,50 @@ func New(appID, appSecret, merchantId string, config ...*platformapi.APIConfig)
}
}
// signParam2 apiV3签名算法SHA-256
func (a *API) signParam2() (sig string) {
sb := new(strings.Builder)
sb.WriteString("grant_type=")
sb.WriteString(a.grantType)
sb.WriteString("&code=")
sb.WriteString(a.code) //todo
sb.WriteString("&app_id=")
sb.WriteString(a.appID)
sb.WriteString("&merchant_id=")
sb.WriteString(a.merchantId)
sb.WriteString("&timestamp=")
sb.WriteString(utils.Int64ToStr(a.timestamp))
sig = sb.String()
sig = base64.StdEncoding.EncodeToString(sha256.New().Sum([]byte(sig)))
return sig
func (a *API) signParam(params map[string]interface{}) (sig string) {
var valueList []string
for k, v := range params {
if k != "signature" {
if str := fmt.Sprint(v); str != "" {
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
}
}
}
sort.Sort(sort.StringSlice(valueList))
sig = strings.Join(valueList, "&")
sig = a.appSecret + sig
signature := sha256.Sum256([]byte(sig))
return hex.EncodeToString(signature[:])
}
// 获取access_token
func (a *API) GetAccessToken() (tokenInfo *TokenInfo, err error) {
parameter := make(map[string]interface{}, 6)
parameter["grant_type"] = a.grantType
parameter["code"] = a.code
parameter["app_id"] = a.appID
parameter["merchant_id"] = a.merchantId
parameter["timestamp"] = utils.Int64ToStr(a.timestamp)
result, err := a.AccessAPI(TokenURL, "", RequestPost, parameter)
if err != nil {
return nil, err
}
if err := utils.Map2StructByJson(result, &tokenInfo, false); err != nil {
return nil, err
}
businessData := &BusinessData{}
if err := json.Unmarshal([]byte(utils.Interface2String(result["business_data"])), businessData); err != nil {
return nil, err
}
tokenInfo.BusinessDataObj = businessData
return tokenInfo, err
}
func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
a.signature = a.signParam(bizParams)
bizParams["signature"] = a.signature
// 序列化
data, err := json.Marshal(bizParams)
if err != nil {
@@ -83,7 +109,7 @@ func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string]
// 发送请求
sendUrl := func() *http.Request {
var request *http.Request
if method == "POST" {
if RequestPost == method {
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(data)))
} else {
request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(baseUrl, actionApi, bizParams), nil)

View File

@@ -2,7 +2,9 @@ package fnpsapi
import (
"encoding/json"
"errors"
"git.rosy.net.cn/baseapi/utils"
"time"
)
const (
@@ -28,9 +30,13 @@ const (
// 蜂鸟预下单
func (a *API) PreCreateByShopFn(basicParams *PreCreateOrder) (deliveryFee, baseDeliveryFee int64, err error) {
preOrder := a.MakeFnRequestHead()
params := utils.Struct2MapByJson(basicParams)
preOrder["business_data"] = params
result, err := a.AccessAPI(ApiURL, "preCreateOrder", RequestPost, params)
bytes, err := json.Marshal(basicParams)
if err != nil {
return 0, 0, err
}
preOrder["business_data"] = string(bytes)
result, err := a.AccessAPI(ApiURL, "preCreateOrder", RequestPost, preOrder)
if err != nil {
return 0, 0, err
}
@@ -40,8 +46,19 @@ func (a *API) PreCreateByShopFn(basicParams *PreCreateOrder) (deliveryFee, baseD
return 0, 0, err
}
deliveryFee = utils.Float64TwoInt64(utils.MustInterface2Float64(preOrderResult.GoodsInfos[0].ActualDeliveryAmountCent)) // 订单配送价格
baseDeliveryFee = utils.Float64TwoInt64(utils.MustInterface2Float64(preOrderResult.GoodsInfos[0].TotalDeliveryAmountCent)) // 订单优惠价格
// 返回所有可选的商品列表,每项包含当前使用该商品下单时对应的价格等信息,(其中不可用的商品会返回不可用原因) 可挑选其中一个可用的商品进行正式下单。
for _, v := range preOrderResult.GoodsInfos {
if v.IsValid != 1 {
continue
}
deliveryFee = v.ActualDeliveryAmountCent
baseDeliveryFee = v.TotalDeliveryAmountCent
}
// 异常检测
if deliveryFee == 0 && baseDeliveryFee == 0 {
err = errors.New("门店数据异常")
}
return deliveryFee, baseDeliveryFee, nil
}
@@ -57,114 +74,193 @@ func (a *API) CreateOrder(createOrderParam *CreateOrderReqParam) (err error) {
return err
}
type ReceiverInfo struct {
ReceiverName string `json:"receiver_name,omitempty"`
ReceiverPrimaryPhone string `json:"receiver_primary_phone,omitempty"`
ReceiverSecondPhone string `json:"receiver_second_phone,omitempty"`
ReceiverAddress string `json:"receiver_address,omitempty"`
ReceiverLongitude float64 `json:"receiver_longitude,omitempty"`
ReceiverLatitude float64 `json:"receiver_latitude,omitempty"`
PositionSource int `json:"position_source,omitempty"` // 经纬度来源
// addTip 加小费接口
func (a *API) AddTip(req *AddTipRes) (err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return errors.New("内部订单号或者外部订单号比填写一个")
}
orderHead := a.MakeFnRequestHead()
addTipString, err := json.Marshal(req)
if err != nil {
return err
}
orderHead["businessData"] = string(addTipString)
if _, err = a.AccessAPI(ApiURL, "addTip", RequestPost, orderHead); err != nil {
return err
}
return nil
}
type TransportInfo struct {
TransportName string `json:"transport_name,omitempty"`
TransportAddress string `json:"transport_address,omitempty"`
TransportLongitude float64 `json:"transport_longitude,omitempty"`
TransportLatitude float64 `json:"transport_latitude,omitempty"`
PositionSource int `json:"position_source,omitempty"` // 经纬度来源
TransportTel string `json:"transport_tel,omitempty"`
TransportRemark string `json:"transport_remark,omitempty"`
// getCancelReasonList 获取可用取消原因列表(暂油前端写死)
func (a *API) GetCancelReasonList(req *GetOrderDetailReq) (result *GetCancelReasonListRes, err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return nil, errors.New("内部订单号或者外部订单号比填写一个")
}
a.timestamp = time.Now().Unix() * 1000
orderHead := a.MakeFnRequestHead()
business, err := json.Marshal(req)
if err != nil {
return nil, err
}
orderHead["businessData"] = string(business)
data, err := a.AccessAPI(ApiURL, "getCancelReasonList", RequestPost, orderHead)
if err != nil {
return nil, err
}
cancel := make(map[string]*GetCancelReasonListRes, 0)
if k, ok := data["business_data"]; ok {
if err := json.Unmarshal([]byte(utils.Interface2String(k)), cancel); err != nil {
return nil, err
}
}
return cancel["cancel_reason_list"], nil
}
type ItemsJSON struct {
ItemID string `json:"item_id,omitempty"`
ItemName string `json:"item_name,omitempty"`
ItemQuantity int `json:"item_quantity,omitempty"`
ItemPrice float64 `json:"item_price"`
ItemActualPrice float64 `json:"item_actual_price"`
ItemSize int `json:"item_size,omitempty"`
ItemRemark string `json:"item_remark,omitempty"`
IsNeedPackage int `json:"is_need_package"`
IsAgentPurchase int `json:"is_agent_purchase"`
AgentPurchasePrice float64 `json:"agent_purchase_price,omitempty"`
// preCancelOrder 预取消订单接口,获取取消订单需要扣除的金额
func (a *API) PreCancelOrder(req *PreCancelOrderReq) (actualCancelCostCent int64, err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return 0, errors.New("内部订单号或者外部订单号比填写一个")
}
orderHead := a.MakeFnRequestHead()
business, err := json.Marshal(req)
if err != nil {
return 0, err
}
orderHead["businessData"] = string(business)
data, err := a.AccessAPI(ApiURL, "preCancelOrder", RequestPost, orderHead)
if err != nil {
return 0, err
}
if k, ok := data["businessData"]; ok {
respParam := struct {
ActualCancelCostCent int64 `json:"actual_cancel_cost_cent"`
}{}
if err := json.Unmarshal([]byte(utils.Interface2String(k)), respParam); err != nil {
return 0, err
}
return respParam.ActualCancelCostCent, nil
}
return
}
//order_cancel_reason_code 订单取消原因代码(1:用户取消,2:商家取消)
// order_cancel_code 订单取消编码(
// 1:物流原因:订单长时间未分配骑手,
// 2:物流原因:分配骑手后,骑手长时间未取件 ,
// 3:物流原因:骑手告知不配送,让取消订单,
// 4:商品缺货/无法出货/已售完, 5:商户联系不上门店/门店关门了, 6:商户发错单,
// 7:商户/顾客自身定位错误, 8:商户改其他第三方配送, 9:顾客下错单/临时不想要了,
// 10:顾客自取/不在家/要求另改时间配送0类型已下线
// cancelOrder 取消订单
func (a *API) CancelOrder(req *CancelOrderReq) (err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return errors.New("内部订单号或者外部订单号比填写一个")
}
if req.OrderCancelCode == 0 && req.OrderCancelOtherReason == "" {
return errors.New("请补充退单原因")
}
type CancelOrderParam struct {
PartnerOrderCode string `json:"partner_order_code,omitempty"`
OrderCancelReasonCode int `json:"order_cancel_reason_code,omitempty"`
OrderCancelCode int `json:"order_cancel_code,omitempty"`
OrderCancelDescription string `json:"order_cancel_description,omitempty"`
OrderCancelTime int64 `json:"order_cancel_time,omitempty"`
orderHead := a.MakeFnRequestHead()
business, err := json.Marshal(req)
if err != nil {
return err
}
orderHead["business_data"] = string(business)
if _, err := a.AccessAPI(ApiURL, "cancelOrder", RequestPost, orderHead); err != nil {
return err
}
return
}
//
//func (a *API) CancelOrder(cancelOrderParam *CancelOrderParam) (err error) {
// params := utils.Struct2FlatMap(cancelOrderParam)
// _, err = a.AccessAPI("v2/order/cancel", URL, params, true)
// return err
//}
//
//func (a *API) ComplaintOrder(cancelOrderParam *CancelOrderParam) (err error) {
// params := utils.Struct2FlatMap(cancelOrderParam)
// _, err = a.AccessAPI("v2/order/complaint", URL, params, true)
// return err
//}
// 查询订单详情接口
func (a *API) QueryOrderDaile(req *GetOrderDetailReq) (result *GetOrderDetailRes, err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return nil, errors.New("内部订单号或者外部订单号比填写一个")
}
type QueryOrderResult struct {
AbnormalCode string `json:"abnormal_code"`
AbnormalDesc string `json:"abnormal_desc"`
CarrierDriverID int `json:"carrier_driver_id"`
CarrierDriverName string `json:"carrier_driver_name"`
CarrierDriverPhone string `json:"carrier_driver_phone"`
ComplaintDescription interface{} `json:"complaintDescription"`
ComplaintStatus interface{} `json:"complaintStatus"`
EstimateArriveTime int64 `json:"estimate_arrive_time"`
EventLogDetails []struct {
CarrierDriverName string `json:"carrier_driver_name"`
CarrierDriverPhone string `json:"carrier_driver_phone"`
OccurTime int64 `json:"occur_time"`
OrderStatus int `json:"order_status"`
} `json:"event_log_details"`
HandleID interface{} `json:"handleId"`
OrderID interface{} `json:"orderId"`
OrderStatus int `json:"order_status"`
OrderTotalDeliveryCost float64 `json:"order_total_delivery_cost"`
OrderTotalDeliveryDiscount interface{} `json:"order_total_delivery_discount"`
OvertimeCompensationCost float64 `json:"overtime_compensation_cost"`
Reason string `json:"reason"`
SupportClaims bool `json:"support_claims"`
TrackingID int64 `json:"trackingId"`
TrackingID2 int64 `json:"tracking_id"`
TransportStationID string `json:"transport_station_id"`
TransportStationTel string `json:"transport_station_tel"`
orderHead := a.MakeFnRequestHead()
bytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
orderHead["business_data"] = string(bytes)
data, err := a.AccessAPI(ApiURL, "getOrderDetail", RequestPost, orderHead)
if err != nil {
return nil, err
}
if err := json.Unmarshal([]byte(data["business_data"].(string)), &result); err != nil {
return nil, err
}
return
}
//
//func (a *API) QueryOrder(partnerOrderCode string) (queryOrderResult *QueryOrderResult, err error) {
// result, err := a.AccessAPI("v2/order/query", URL, map[string]interface{}{
// "partner_order_code": partnerOrderCode,
// }, true)
// if err == nil {
// utils.Map2StructByJson(result["data"], &queryOrderResult, false)
// }
// return queryOrderResult, err
//}
//
//func (a *API) ComplaintRider(partnerOrderCode string, orderComplaintCode int) (err error) {
// _, err = a.AccessAPI("v2/order/complaint", URL, map[string]interface{}{
// "partner_order_code": partnerOrderCode,
// "order_complaint_code": orderComplaintCode,
// "order_complaint_time": time.Now().UnixNano() / 1e6,
// }, true)
// return err
//}
// 查询骑手信息
func (a *API) GetKnightInfo(req *GetOrderDetailReq) (result *GetKnightInfoRes, err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return nil, errors.New("内部订单号或者外部订单号比填写一个")
}
orderHead := a.MakeFnRequestHead()
bytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
orderHead["business_data"] = string(bytes)
data, err := a.AccessAPI(ApiURL, "getKnightInfo", RequestPost, orderHead)
if err != nil {
return nil, err
}
if err := json.Unmarshal([]byte(utils.Interface2String(data["business_data"])), &result); err != nil {
return nil, err
}
return
}
// 余额查询
func (a *API) GetAmount() (outAmount map[string]interface{}, err error) {
orderHead := a.MakeFnRequestHead()
result, err := a.AccessAPI(ApiURL, "getAmount", RequestPost, orderHead)
if err != nil {
return nil, err
}
return result, err
}
// complaintOrder 投诉订单
func (a *API) ComplaintOrder(req *ComplaintOrderReq) (err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return errors.New("内部订单号或者外部订单号比填写一个")
}
orderHead := a.MakeFnRequestHead()
bytes, err := json.Marshal(req)
if err != nil {
return err
}
orderHead["businessData"] = string(bytes)
_, err = a.AccessAPI(ApiURL, "cancelOrder", RequestPost, orderHead)
return err
}
// claimOrder 索赔订单
func (a *API) ClaimOrder(req *ClaimOrderRes) (err error) {
if req.PartnerOrderCode == "" && req.OrderId == "" {
return errors.New("内部订单号或者外部订单号比填写一个")
}
orderHead := a.MakeFnRequestHead()
bytes, err := json.Marshal(req)
if err != nil {
return err
}
orderHead["business_data"] = string(bytes)
_, err = a.AccessAPI(ApiURL, "claimOrder", RequestPost, orderHead)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,98 @@
package fnpsapi
import (
"fmt"
"testing"
"time"
)
// 预下单
func TestPreOrder(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
aa := []*GoodsItemsList{
{"白菜", 1, 100, 100, "30011", 1, "备注:大白菜"},
{"白菜2", 1, 100, 100, "30012", 1, "备注:大白菜2"},
// {"白菜3", 1, 100, 100, "1004", 1, "备注:大白菜2"},
}
deliveryFee, baseDeliveryFee, err := api.PreCreateByShopFn(&PreCreateOrder{
PartnerOrderCode: "817102016000041",
OrderType: 1,
PositionSource: 3,
ReceiverAddress: "四川成都",
ReceiverLongitude: 104.093445,
ReceiverLatitude: 30.661585,
GoodsTotalAmountCent: 100,
GoodsActualAmountCent: 100,
GoodsWeight: 0.25,
GoodsCount: 1,
GoodsItemList: aa,
//OutShopCode: "637910",
ChainStoreID: "209476483",
})
fmt.Println(err)
fmt.Println(deliveryFee)
fmt.Println(baseDeliveryFee)
}
// 正式下单
func TestCreateOrder(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
aa := []*GoodsItemsList{
{"白菜", 1, 100, 100, "30011", 1, "备注:大白菜"},
//{"白菜2", 1, 100, 100, "30012", 1, "备注:大白菜2"},
// {"白菜3", 1, 100, 100, "1004", 1, "备注:大白菜2"},
}
err := api.CreateOrder(&CreateOrderReqParam{
PartnerOrderCode: "232232999uue21",
OrderType: 1,
PositionSource: 3,
ReceiverAddress: "四川成都",
ReceiverLongitude: 113.546508,
ReceiverLatitude: 22.188382,
GoodsTotalAmountCent: 100,
GoodsActualAmountCent: 100,
GoodsWeight: 0.25,
GoodsCount: 1,
GoodsItemList: aa,
ReceiverName: "刘磊",
ReceiverPrimaryPhone: "18981810340",
OutShopCode: "",
ChainStoreId: "200008235",
})
fmt.Println(err)
}
// 添加小费
func TestAddTip(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
param := &AddTipRes{}
param.OrderId = "817102016000041"
param.PartnerOrderCode = "817102016000041"
param.AddTipAmountCent = 100
param.ThirdIndexId = time.Now().Unix()
err := api.AddTip(param)
fmt.Println(err)
}
// 获取可用取消订单原因
func TestGetCancelReasonList(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691")
token, _ := api.GetAccessToken()
api.accessToken = token.BusinessDataObj.AccessToken
data, err := api.GetCancelReasonList(&GetOrderDetailReq{
OrderId: "300000219758073736",
//PartnerOrderCode: "817102016000041",
})
fmt.Println(err)
fmt.Println(data)
}

View File

@@ -4,43 +4,29 @@ import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"strings"
)
const (
StoreNotExist = "门店信息不存在"
StoreExist = "该门店已存在"
)
// 获取access_token
func (a *API) GetAccessToken() (tokenInfo *TokenInfo, err error) {
a.grantType = "authorization_code"
a.signature = a.signParam2()
result, err := a.AccessAPI(TokenURL, "", RequestPost, nil)
if err != nil {
return nil, err
}
if err := utils.Map2StructByJson(result["data"], &tokenInfo, false); err != nil {
return nil, err
}
return tokenInfo, err
}
// 创建门店.
func (a *API) CreateStore(createStoreParam *CreateStoreBaseInfo) (err error) {
requestHead := a.MakeFnRequestHead()
params := utils.Struct2FlatMap(createStoreParam)
requestHead["business_data"] = params
storeByte, err := json.Marshal(createStoreParam)
if err != nil {
return err
}
requestHead["business_data"] = string(storeByte)
_, err = a.AccessAPI(ApiURL, "chainstoreCreate", RequestPost, requestHead)
return err
}
// 更新门店
// 更新门店 209636747
func (a *API) UpdateStore(updateStore *UpdateStoreParam) (err error) {
requestHead := a.MakeFnRequestHead()
params := utils.Struct2FlatMap(updateStore)
requestHead["business_data"] = params
storeByte, err := json.Marshal(updateStore)
if err != nil {
return err
}
requestHead["business_data"] = string(storeByte)
_, err = a.AccessAPI(ApiURL, "chainstoreUpdate", RequestPost, requestHead)
return
}
@@ -67,7 +53,7 @@ func (a *API) GetStore(storeID string) (getStoreResult *GetOneStoreRespData, err
params.BusinessData = string(data)
paramsMap := utils.Struct2FlatMap(params)
result, err := a.AccessAPI(ApiURL, "chainstoreQuery", RequestGet, paramsMap)
result, err := a.AccessAPI(ApiURL, "chainstoreQuery", RequestPost, paramsMap)
if err != nil {
return nil, err
}
@@ -76,30 +62,12 @@ func (a *API) GetStore(storeID string) (getStoreResult *GetOneStoreRespData, err
return nil, fmt.Errorf("%s", result["msg"])
}
if data, ok := result["business_data"].([]interface{}); ok {
utils.Map2StructByJson(data[0], &getStoreResult, false)
if storeData, ok := result["business_data"]; ok {
if err := json.Unmarshal([]byte(utils.Interface2String(storeData)), &getStoreResult); err != nil {
return nil, err
}
} else {
err = fmt.Errorf(result["msg"].(string))
}
return getStoreResult, err
}
func IsErrShopNotExist(err error) bool {
if err != nil {
if strings.Contains(err.Error(), StoreNotExist) {
return true
}
}
return false
}
func IsErrShopExist(err error) bool {
if err != nil {
if strings.Contains(err.Error(), StoreExist) {
return true
}
}
return false
}
//todo商户门店接口,图片上传接口