Files
jx-callback/business/partner/purchase/mtwm/order.go

283 lines
11 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 mtwm
import (
"fmt"
"net/url"
"time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"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/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
FakeMsgTypeOrderReceived = "orderReceived"
FakeMsgTypeOrderDelivering = "orderDelivering"
)
const (
pickupOrderDelay = 4 * time.Minute
pickupOrderGap = 20
)
var (
VendorStatus2StatusMap = map[string]int{
mtwmapi.OrderStatusUserCommitted: model.OrderStatusUnknown,
mtwmapi.OrderStatusNew: model.OrderStatusNew,
mtwmapi.OrderStatusReceived: model.OrderStatusAccepted,
mtwmapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
mtwmapi.OrderStatusDelivering: model.OrderStatusDelivering,
mtwmapi.OrderStatusDelivered: model.OrderStatusDelivered,
mtwmapi.OrderStatusFinished: model.OrderStatusFinished,
mtwmapi.OrderStatusCanceled: model.OrderStatusCanceled,
mtwmapi.MsgTypeOrderModified: model.OrderStatusAdjust,
}
)
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, orderMap map[string]interface{}, err error) {
result, err := api.MtwmAPI.OrderGetOrderDetail(utils.Str2Int64(vendorOrderID), true)
if err == nil {
order = p.Map2Order(result)
}
return order, result, err
}
func (p *PurchaseHandler) GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error) {
order, _, err = p.getOrder(vendorOrderID)
return order, err
}
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
result := orderData
vendorOrderID := utils.Int64ToStr(utils.MustInterface2Int64(result["order_id"]))
deliveryTime := utils.Interface2Int64WithDefault(result["delivery_time"], 0)
// 因为美团外卖不能自动设置商家门店号,且只能通过商家门店号来访问门店,
// 为了在后台设置简单一致把app_poi_code直接当成平台门店号使用(即在后台设置时,平台门店号与商家门店号一样)
// 订单中wm_poi_id实际来平台门店号app_poi_code为商家门店号这样一来这两个就相同了
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
// VendorOrderID2: utils.Int64ToStr(utils.MustInterface2Int64(result["wm_order_id_view"])),
VendorID: model.VendorIDMTWM,
VendorStoreID: result["app_poi_code"].(string),
StoreID: 0,
// VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["wm_poi_id"])),
// StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["app_poi_code"]), 0)),
StoreName: result["wm_poi_name"].(string),
ConsigneeName: result["recipient_name"].(string),
ConsigneeMobile: result["recipient_phone"].(string),
ConsigneeAddress: result["recipient_address"].(string),
CoordinateType: model.CoordinateTypeMars,
BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["caution"])),
ExpectedDeliveredTime: getTimeFromTimestamp(deliveryTime),
PickDeadline: utils.DefaultTimeValue,
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["status"])),
OrderSeq: int(utils.MustInterface2Int64(result["day_seq"])),
StatusTime: getTimeFromTimestamp(utils.MustInterface2Int64(result["ctime"])),
OriginalData: string(utils.MustMarshal(result)),
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["total"])),
Skus: []*model.OrderSku{},
}
order.Status = p.GetStatusFromVendorStatus(order.VendorStatus)
if deliveryTime == 0 {
order.BusinessType = model.BusinessTypeImmediate
} else {
order.BusinessType = model.BusinessTypeDingshida
}
originalLng := utils.MustInterface2Float64(result["longitude"])
originalLat := utils.MustInterface2Float64(result["latitude"])
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
var detail []map[string]interface{}
if err := utils.UnmarshalUseNumber([]byte(result["detail"].(string)), &detail); err != nil {
panic(fmt.Sprintf("mtwm Map2Order vendorID:%s failed with error:%v", vendorOrderID, err))
}
// detail := result["detail"].([]interface{})
for _, product := range detail {
// product := product2.(map[string]interface{})
skuName := product["food_name"].(string)
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
skuID := utils.Interface2String(product["sku_id"])
sku := &model.OrderSku{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDMTWM,
Count: int(utils.MustInterface2Float64(product["quantity"])),
SkuID: int(utils.Str2Int64WithDefault(skuID, 0)),
VendorSkuID: skuID,
SkuName: skuName,
Weight: jxutils.FormatSkuWeight(specQuality, specUnit), // 订单信息里没有重量,只有名字里尝试找
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(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 (c *PurchaseHandler) onOrderMsg(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
var err error
if msg.Cmd == mtwmapi.MsgTypeNewOrder || msg.Cmd == mtwmapi.MsgTypeOrderModified {
order, orderMap, err2 := c.getOrder(GetOrderIDFromMsg(msg))
if err = err2; err == nil {
if msg.Cmd == mtwmapi.MsgTypeNewOrder {
err = partner.CurOrderManager.OnOrderNew(order, order.VendorStatus)
} else {
err = partner.CurOrderManager.OnOrderAdjust(order, order.VendorStatus)
}
if err == nil {
utils.CallFuncAsync(func() {
c.OnOrderDetail(orderMap)
})
}
}
} else {
// todo 好像没有“商家已收到”消息回调,是否需要模拟?
status := c.callbackMsg2Status(msg)
err = partner.CurOrderManager.OnOrderStatusChanged(status)
}
return mtwmapi.Err2CallbackResponse(err, "")
}
func (c *PurchaseHandler) callbackMsg2Status(msg *mtwmapi.CallbackMsg) *model.OrderStatus {
orderID := GetOrderIDFromMsg(msg)
vendorStatus := ""
remark := ""
statusTime := utils.Str2Int64(msg.Data.Get("timestamp"))
switch msg.Cmd {
case mtwmapi.MsgTypeUserUrgeOrder, mtwmapi.MsgTypeOrderModified, mtwmapi.MsgTypeOrderFinancial:
vendorStatus = msg.Cmd
case mtwmapi.MsgTypeOrderCanceled:
vendorStatus = mtwmapi.OrderStatusCanceled
remark = msg.Data.Get("reason")
case mtwmapi.MsgTypeNewOrder, FakeMsgTypeOrderReceived, mtwmapi.MsgTypeOrderAccepted, FakeMsgTypeOrderDelivering, mtwmapi.MsgTypeOrderFinished:
vendorStatus = msg.Data.Get("status")
statusTime = utils.Str2Int64(msg.Data.Get("utime"))
case mtwmapi.MsgTypeOrderRefund, mtwmapi.MsgTypeOrderPartialRefund:
vendorStatus = msg.Cmd
remark = msg.Data.Get("reason")
default:
globals.SugarLogger.Errorf("mtwm unkonw msg:%s", utils.Format4Output(msg, false))
}
orderStatus := &model.OrderStatus{
VendorOrderID: orderID,
VendorID: model.VendorIDMTWM,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: orderID,
RefVendorID: model.VendorIDMTWM,
VendorStatus: vendorStatus,
Status: c.GetStatusFromVendorStatus(vendorStatus),
StatusTime: getTimeFromTimestamp(statusTime),
Remark: remark,
}
return orderStatus
}
func (c *PurchaseHandler) postFakeFinishedPickupMsg(vendorOrderID string) {
msg := &mtwmapi.CallbackMsg{
Cmd: mtwmapi.MsgTypeOrderAccepted,
Data: make(url.Values),
}
timeStr := utils.Int64ToStr(time.Now().Unix())
msg.Data.Add(mtwmapi.KeyOrderID, vendorOrderID)
msg.Data.Add("status", mtwmapi.OrderStatusAccepted)
msg.Data.Add("timestamp", timeStr)
msg.Data.Add("utime", timeStr)
utils.CallFuncAsync(func() {
OnOrderCallbackMsg(msg)
})
}
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite {
if isAcceptIt {
if err = api.MtwmAPI.OrderReceived(utils.Str2Int64(order.VendorOrderID)); err == nil {
msg := &mtwmapi.CallbackMsg{
Cmd: FakeMsgTypeOrderReceived,
Data: url.Values{},
}
msg.Data.Set("timestamp", utils.Int64ToStr(time.Now().Unix()))
msg.Data.Set("utime", msg.Data.Get("timestamp"))
msg.Data.Set(mtwmapi.KeyOrderID, order.VendorOrderID)
msg.Data.Set("status", mtwmapi.OrderStatusReceived)
utils.CallFuncAsync(func() {
OnOrderCallbackMsg(msg)
})
}
} else {
err = api.MtwmAPI.OrderCancel(utils.Str2Int64(order.VendorOrderID))
}
}
return err
}
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDeilivery bool, userName string) (err error) {
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite && !isSelfDeilivery {
err = api.MtwmAPI.OrderConfirm(utils.Str2Int64(order.VendorOrderID))
} else {
c.postFakeFinishedPickupMsg(order.VendorOrderID)
}
return nil
}
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
return err
}
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
return nil
}
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
return err
}
func (c *PurchaseHandler) SelfDeliverDelievered(order *model.GoodsOrder, userName string) (err error) {
return err
}
func getTimeFromTimestamp(timeStamp int64) time.Time {
if timeStamp < 1538103149 { // 立即达订单给的是1而不是空01538103149不是特殊值只是一个任意之前的时间这样写可以处理
return utils.DefaultTimeValue
}
return utils.Timestamp2Time(timeStamp)
}
func (c *PurchaseHandler) RefreshRealMobile(ctx *jxcontext.Context, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
return hint, err
}
func (c *PurchaseHandler) GetStatusActionTimeout(statusType, status int) (params *partner.StatusActionParams) {
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusAccepted {
params = &partner.StatusActionParams{ // 美团外卖要求在5分钟内拣货不然订单会被取消
Timeout: pickupOrderDelay,
TimeoutGap: pickupOrderGap,
}
}
return params
}