Files
jx-callback/business/partner/purchase/ebai/order.go
2019-04-03 17:49:30 +08:00

350 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package ebai
import (
"math"
"time"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
// acceptOrderDelay = 180 * time.Second
pickupOrderDelay = 260 * time.Second
callDeliveryDelay = 10 * time.Minute
callDeliveryDelayGap = 30
// fakePickedUp = "9527"
fakeUserApplyCancel = "fake_user_apply_cancel"
fakeAcceptOrder = "fake_accept_order"
)
// 饿百的接单会直接召唤配送,为了统一将饿百的接单影射成拣货完成,然后模拟一个接单消息
var (
VendorStatus2StatusMap = map[string]int{
ebaiapi.OrderStatusNew: model.OrderStatusNew,
fakeAcceptOrder: model.OrderStatusAccepted,
ebaiapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
fakeUserApplyCancel: model.OrderStatusApplyCancel,
ebaiapi.OrderStatusCourierAccepted: model.OrderStatusDelivering,
ebaiapi.OrderStatusCourierPickedup: model.OrderStatusDelivering,
ebaiapi.OrderStatusFinished: model.OrderStatusFinished,
ebaiapi.OrderStatusCanceled: model.OrderStatusCanceled,
}
)
func (p *PurchaseHandler) GetStatusFromVendorStatus(vendorStatus string) int {
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
return status
}
return model.OrderStatusUnknown
}
func (p *PurchaseHandler) GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error) {
order, _, err = p.getOrder(vendorOrderID)
return order, err
}
func (p *PurchaseHandler) getOrder(vendorOrderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
result, err := api.EbaiAPI.OrderGet(vendorOrderID)
if err == nil {
order = p.Map2Order(result)
}
return order, result, err
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
shopMap := result["shop"].(map[string]interface{})
orderMap := result["order"].(map[string]interface{})
userMap := result["user"].(map[string]interface{})
vendorOrderID := orderMap["order_id"].(string)
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorOrderID2: orderMap["eleme_order_id"].(string),
VendorID: model.VendorIDEBAI,
VendorStoreID: shopMap["baidu_shop_id"].(string),
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(shopMap["id"]), 0)),
StoreName: shopMap["name"].(string),
ConsigneeName: userMap["name"].(string),
ConsigneeMobile: jxutils.FormalizeMobile(userMap["phone"].(string)),
ConsigneeAddress: userMap["address"].(string),
CoordinateType: model.CoordinateTypeBaiDu,
BuyerComment: utils.TrimBlankChar(utils.Interface2String(orderMap["remark"])),
ExpectedDeliveredTime: getTimeFromInterface(orderMap["send_time"]),
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(orderMap["status"])),
OrderSeq: int(utils.Str2Int64(utils.Interface2String(orderMap["order_index"]))),
StatusTime: getTimeFromInterface(orderMap["create_time"]),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: utils.MustInterface2Int64(orderMap["user_fee"]),
Skus: []*model.OrderSku{},
}
if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) {
order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 饿百要求在5分钟内拣货不然订单会被取消
}
if order.ConsigneeMobile == "" {
if mobileInfo, err := api.EbaiAPI.OrderPrivateInfo(vendorOrderID); err == nil {
order.ConsigneeMobile = jxutils.FormalizeMobile(mobileInfo.ShortNumber)
}
}
if order.StoreID > math.MaxInt32 {
order.StoreID = 0
}
order.Status = p.GetStatusFromVendorStatus(order.VendorStatus)
if utils.MustInterface2Int64(orderMap["send_immediately"]) == 1 {
order.BusinessType = model.BusinessTypeImmediate
} else {
order.BusinessType = model.BusinessTypeDingshida
if utils.IsTimeZero(order.ExpectedDeliveredTime) {
order.ExpectedDeliveredTime = getTimeFromInterface(orderMap["latest_send_time"])
}
}
deliveryGeo := userMap["coord"].(map[string]interface{})
originalLng := utils.Interface2Float64WithDefault(deliveryGeo["longitude"], 0.0) // 饿百的订单在过一段时间后,经纬度信息会变成字符串"**"
originalLat := utils.Interface2Float64WithDefault(deliveryGeo["latitude"], 0.0)
lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysBaidu)
if err2 == nil {
originalLng = lng
originalLat = lat
order.CoordinateType = model.CoordinateTypeMars
}
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
products := result["products"].([]interface{})[0].([]interface{})
// discounts := result["discount"].(map[string]interface{})
for _, product2 := range products {
product := product2.(map[string]interface{})
skuName := product["product_name"].(string)
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDEBAI,
Count: int(utils.MustInterface2Int64(product["product_amount"])),
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
VendorSkuID: utils.Interface2String(product["baidu_product_id"]),
SkuName: skuName,
Weight: jxutils.FormatSkuWeight(specQuality, specUnit), // 订单信息里没有重量,只有名字里尝试找
SalePrice: utils.MustInterface2Int64(product["product_price"]),
// PromotionType: int(utils.MustInterface2Int64(product["promotionType"])),
}
if sku.Weight == 0 {
sku.Weight = 222 // 如果名字里找不到缺省给半斤左右的一个特别值
}
// if product["isGift"].(bool) {
// sku.SkuType = 1
// }
order.Skus = append(order.Skus, sku)
order.SkuCount++
order.GoodsCount += sku.Count
order.SalePrice += sku.SalePrice * int64(sku.Count)
order.Weight += sku.Weight * sku.Count
}
// setOrederDetailFee(result, order)
return order
}
func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Debugf("ebai AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if isAcceptIt {
p.postFakeMsg(order.VendorOrderID, fakeAcceptOrder)
} else {
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, "bu")
}
}
return err
}
func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
globals.SugarLogger.Debugf("ebai PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderConfirm(order.VendorOrderID)
} else {
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusAccepted)
}
return err
}
// 将订单从购物平台配送转为自送
func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderSwitchselfdelivery(order.VendorOrderID)
}
if err == nil {
// 饿百不会发送配送中,模拟发送
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted)
}
return err
}
// 将订单从购物平台配送转为自送后又送达
func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
// todo 饿百转商家自送后,没有确认送达的概念,空操作
return err
}
// 完全自送的门店表示开始配送
func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderSendOut(order.VendorOrderID, userName)
}
if err == nil {
// 饿百不会发送配送中,模拟发送
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted)
}
return err
}
// 完全自送的门店表示配送完成
func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Debugf("ebai SelfDeliverDelivered orderID:%s", order.VendorOrderID)
if globals.EnableEbaiStoreWrite {
err = api.EbaiAPI.OrderComplete(order.VendorOrderID, userName)
}
return err
}
//
func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
if ebaiapi.CmdOrderCreate == msg.Cmd {
retVal = c.onOrderNew(msg)
} else {
status := c.callbackMsg2Status(msg)
var err error
if status != nil {
err = partner.CurOrderManager.OnOrderStatusChanged(status)
}
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
}
return retVal
}
func (c *PurchaseHandler) onOrderNew(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
vendorOrderID := GetOrderIDFromMsg(msg)
order, orderMap, err := c.getOrder(vendorOrderID)
if err == nil {
if err = partner.CurOrderManager.OnOrderNew(order, order.VendorStatus); err == nil {
utils.CallFuncAsync(func() {
c.OnOrderDetail(orderMap, partner.CreatedPeration)
})
}
}
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, map[string]interface{}{
"source_order_id": vendorOrderID,
})
}
func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) {
orderID := GetOrderIDFromMsg(msg)
orderStatus = &model.OrderStatus{
VendorOrderID: orderID,
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: orderID,
RefVendorID: model.VendorIDEBAI,
StatusTime: utils.Timestamp2Time(msg.Timestamp),
}
if msg.Cmd == ebaiapi.CmdOrderUserCancel {
cancelType := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["type"]))
if cancelType == ebaiapi.OrderUserApplyCancel {
orderStatus.VendorStatus = fakeUserApplyCancel
orderStatus.Status = c.GetStatusFromVendorStatus(orderStatus.VendorStatus)
orderStatus.Remark = utils.Interface2String(msg.Body["cancel_reason"])
} else {
orderStatus = nil
}
} else if status, ok := msg.Body["status"]; ok {
if vendorStatus, ok := status.(string); ok {
orderStatus.VendorStatus = vendorStatus
} else {
orderStatus.VendorStatus = utils.Int64ToStr(utils.MustInterface2Int64(status))
}
orderStatus.Status = c.GetStatusFromVendorStatus(orderStatus.VendorStatus)
orderStatus.Remark = utils.Interface2String(msg.Body["reason"])
} else {
orderStatus = nil
globals.SugarLogger.Infof("ebai callbackMsg2Status can not find status field in msg:%s", utils.Format4Output(msg, false))
}
return orderStatus
}
func (c *PurchaseHandler) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *partner.StatusActionParams) {
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusAccepted {
params = &partner.StatusActionParams{ // PickDeadline没有设置时才有效饿百要求在5分钟内拣货不然订单会被取消
Timeout: pickupOrderDelay,
}
} else if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusFinishedPickup {
params = &partner.StatusActionParams{ // 立即达订单有效,自配送延时召唤配送
Timeout: callDeliveryDelay,
TimeoutGap: callDeliveryDelayGap,
}
}
return params
}
func (c *PurchaseHandler) getOrderStoreDeliveryType(order *model.GoodsOrder) (deliveryType int) {
sql := `
SELECT *
FROM store_map t1
WHERE t1.vendor_store_id = ?
AND t1.vendor_id = ?
AND t1.deleted_at = ?
`
db := dao.GetDB()
var storeMap *model.StoreMap
if err := dao.GetRow(db, &storeMap, sql, order.VendorStoreID, model.VendorIDEBAI, utils.DefaultTimeValue); err == nil {
return int(storeMap.DeliveryType)
} else if !dao.IsNoRowsError(err) {
globals.SugarLogger.Warnf("getOrderStoreDeliveryType orderID:%s failed with error:%v", order.VendorOrderID, err)
}
return scheduler.StoreDeliveryTypeByPlatform
}
func (c *PurchaseHandler) postFakeMsg(vendorOrderID, vendorStatus string) {
msg := &ebaiapi.CallbackMsg{
Cmd: ebaiapi.CmdOrderStatus,
Timestamp: time.Now().Unix(),
Body: map[string]interface{}{
"status": vendorStatus,
"order_id": vendorOrderID,
},
}
utils.CallFuncAsync(func() {
OnCallbackMsg(msg)
})
}
func getTimeFromInterface(timeValue interface{}) time.Time {
var timeStamp int64
if timeStr, ok := timeValue.(string); ok {
timeStamp = utils.Str2Int64WithDefault(timeStr, 0)
} else {
timeStamp = utils.Interface2Int64WithDefault(timeValue, 0)
}
if timeStamp < 1538103149 { // 立即达订单给的是1而不是空01538103149不是特殊值只是一个任意之前的时间这样写可以处理
return utils.DefaultTimeValue
}
return utils.Timestamp2Time(timeStamp)
}
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
mobile, err = api.EbaiAPI.GetRealMobile4Order(order.VendorOrderID)
return mobile, err
}