- weixin msg added.
- elm sometimes have no delivery msg - elm sometimes delivery msg arrvied before finished pickup - the gap between finished pickup and first delivery msg is big
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
"git.rosy.net.cn/baseapi"
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||||
"git.rosy.net.cn/jx-callback/business/model"
|
"git.rosy.net.cn/jx-callback/business/model"
|
||||||
"git.rosy.net.cn/jx-callback/globals"
|
"git.rosy.net.cn/jx-callback/globals"
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
@@ -27,6 +28,7 @@ func (c *OrderController) OnOrderNew(order *model.GoodsOrder) (err error) {
|
|||||||
if err == nil && !isDuplicated {
|
if err == nil && !isDuplicated {
|
||||||
if err = c.saveOrder(order, false, db); err == nil {
|
if err = c.saveOrder(order, false, db); err == nil {
|
||||||
err = scheduler.CurrentScheduler.OnOrderNew(order)
|
err = scheduler.CurrentScheduler.OnOrderNew(order)
|
||||||
|
weixinmsg.NotifyNewOrder(order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||||
"git.rosy.net.cn/jx-callback/business/model"
|
"git.rosy.net.cn/jx-callback/business/model"
|
||||||
"git.rosy.net.cn/jx-callback/business/scheduler"
|
"git.rosy.net.cn/jx-callback/business/scheduler"
|
||||||
"git.rosy.net.cn/jx-callback/globals"
|
"git.rosy.net.cn/jx-callback/globals"
|
||||||
@@ -55,6 +56,11 @@ func (w *WaybillController) OnWaybillStatusChanged(bill *model.Waybill) (err err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if bill.Status == model.WaybillStatusAccepted || bill.Status == model.WaybillStatusDelivered {
|
||||||
|
if order, err2 := OrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID); err2 == nil {
|
||||||
|
weixinmsg.NotifyWaybillStatus(bill, order)
|
||||||
|
}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
"git.rosy.net.cn/jx-callback/business/model"
|
"git.rosy.net.cn/jx-callback/business/model"
|
||||||
"git.rosy.net.cn/jx-callback/globals"
|
|
||||||
"git.rosy.net.cn/jx-callback/globals/api"
|
"git.rosy.net.cn/jx-callback/globals/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -127,7 +126,7 @@ func IntCoordinate2MarsStandard(gpsLng, gpsLat int, coordinateType int) (marsLng
|
|||||||
case model.CoordinateTypeMapbar:
|
case model.CoordinateTypeMapbar:
|
||||||
coordSys = autonavi.CoordSysMapbar
|
coordSys = autonavi.CoordSysMapbar
|
||||||
default:
|
default:
|
||||||
globals.SugarLogger.Errorf("known coordinate type:%d", coordinateType)
|
panic(fmt.Sprintf("known coordinate type:%d", coordinateType))
|
||||||
}
|
}
|
||||||
return api.AutonaviAPI.CoordinateConvert(marsLng, marsLat, coordSys)
|
return api.AutonaviAPI.CoordinateConvert(marsLng, marsLat, coordSys)
|
||||||
}
|
}
|
||||||
@@ -139,3 +138,7 @@ func IntPrice2Standard(value int64) float64 {
|
|||||||
func StandardPrice2Int(value float64) int64 {
|
func StandardPrice2Int(value float64) int64 {
|
||||||
return int64(math.Round(value * 100))
|
return int64(math.Round(value * 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IntPrice2StandardString(value int64) string {
|
||||||
|
return fmt.Sprintf("%.2f", IntPrice2Standard(value))
|
||||||
|
}
|
||||||
|
|||||||
183
business/jxutils/weixinmsg/weixinmsg.go
Normal file
183
business/jxutils/weixinmsg/weixinmsg.go
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package weixinmsg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||||
|
"git.rosy.net.cn/jx-callback/business/model"
|
||||||
|
"git.rosy.net.cn/jx-callback/globals"
|
||||||
|
"github.com/astaxie/beego/orm"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WX_TO_ORDER_PAGE_URL = "http://www.jxc4.com/jx/h5/#/?jxStoreId="
|
||||||
|
WX_TO_SHOW_COMMENTS_DETAIL_URL = "http://www.jxc4.com/jx/h5/#/assess-list?jxStoreId=" //展示差评详情的页面
|
||||||
|
//新订单模板消息文字颜色
|
||||||
|
WX_NEW_ORDER_TEMPLATE_COLOR = "#173177"
|
||||||
|
WX_HIGHLEVEL_TEMPLATE_COLOR = "#FF0000" //红色
|
||||||
|
WX_TEMPLATE_VENDERCOLOR_JDDJ = "#47B34F"
|
||||||
|
WX_TEMPLATE_VENDERCOLOR_MT = "#F4A800"
|
||||||
|
WX_TEMPLATE_VENDERCOLOR_ELM = "#0191EA" //蓝色
|
||||||
|
WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS = "#4F4DA0"
|
||||||
|
|
||||||
|
WX_NEWORDER_TEMPLATE_ID = "_DtNGwmOeR6TkkTVUblxLIlkV2MAPOX57TkvfdqG6nY" //微信新订单推送
|
||||||
|
WX_MTPS_DELIVERY_GRABDONE_TEMPLATE_ID = "h4dkON6AgnHz1XmaksEUB_8Bcir4V8MSexUhC149pPE" //微信美团配送员接单推送
|
||||||
|
WX_MTPS_DELIVERY_DONE_TEMPLATE_ID = "YXdCrQAHZlcZX1htYUiarrLmtkmKAjp7rynjwObgODo" //微信美团配送员配送完成推送
|
||||||
|
WX_MTPS_UNABLE_DELIVER_TEMPLATE_ID = "ZFph5Hp7oLlrzVRXbsKIC_StmaBeB9Dlp4tlHeAmUQ8" //微信美团配送配送能力不足推送
|
||||||
|
WX_MTPS_DELIVERY_EXCEPTION_TEMPLATE_ID = "RkfOFHgR1N75L4-a6Gv0DljpCsVfOHhLm_vyXh8MR-w" //微信美团配送异常推送
|
||||||
|
WX_BAD_COMMENT_PUSH_TEMPLATE_ID = "zMZH5Ek0k1OHlWnsDb98UaHEOlkJZYok2QOJUfwfJWs" //微信差评消息推送
|
||||||
|
|
||||||
|
WX_DADA_DELIVERY_GRABDONE_TEMPLATE_ID = "h4dkON6AgnHz1XmaksEUB_8Bcir4V8MSexUhC149pPE" //微信达达众包配送员接单推送
|
||||||
|
WX_DADA_DELIVERY_DONE_TEMPLATE_ID = "YXdCrQAHZlcZX1htYUiarrLmtkmKAjp7rynjwObgODo" //微信达达众包配送员配送完成推送
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWeixinOpenIDsFromStoreID(storeID int) (retVal []string) {
|
||||||
|
db := orm.NewOrm()
|
||||||
|
var lists []orm.ParamsList
|
||||||
|
num, err := db.Raw(`
|
||||||
|
SELECT openid
|
||||||
|
FROM weixins t1
|
||||||
|
JOIN
|
||||||
|
(SELECT id
|
||||||
|
FROM weixins
|
||||||
|
WHERE jxstoreid = ? AND parentid = -1) t2 ON t2.id = t1.parentid
|
||||||
|
UNION
|
||||||
|
SELECT openid
|
||||||
|
FROM weixins
|
||||||
|
WHERE jxstoreid = ? AND parentid = -1
|
||||||
|
`, storeID, storeID).ValuesList(&lists)
|
||||||
|
if err != nil || num == 0 {
|
||||||
|
globals.SugarLogger.Infof("can not find openid for store:%s, error:%v", storeID, err)
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
for _, v := range lists {
|
||||||
|
retVal = append(retVal, v[0].(string))
|
||||||
|
}
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendMsgToStore(storeID int, templateID, downloadURL string, data interface{}) (err error) {
|
||||||
|
openIDs := GetWeixinOpenIDsFromStoreID(storeID)
|
||||||
|
errCount := 0
|
||||||
|
for _, openID := range openIDs {
|
||||||
|
globals.SugarLogger.Debugf("send to:%s, templateID:%s, msg:%s", openID, templateID, string(utils.MustMarshal(data)))
|
||||||
|
// todo
|
||||||
|
// err2 := api.WeixinAPI.MessageTemplateSend(openID, templateID, downloadURL, nil, data)
|
||||||
|
// if err2 != nil {
|
||||||
|
// err = err2
|
||||||
|
// errCount++
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if errCount < len(openIDs) {
|
||||||
|
err = nil // 只要成功一个都当成成功
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NotifyNewOrder(order *model.GoodsOrder) (err error) {
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
sb.WriteString("老板")
|
||||||
|
sb.WriteString(order.ConsigneeName)
|
||||||
|
sb.WriteString("购买了商品")
|
||||||
|
sb.WriteString(order.Skus[0].SkuName)
|
||||||
|
sb.WriteString("共")
|
||||||
|
sb.WriteString(utils.Int2Str(order.Skus[0].Count))
|
||||||
|
sb.WriteString("份(")
|
||||||
|
sb.WriteString(jxutils.IntPrice2StandardString(order.Skus[0].SalePrice))
|
||||||
|
sb.WriteString("元/份)等,共支付了")
|
||||||
|
sb.WriteString(jxutils.IntPrice2StandardString(order.SalePrice))
|
||||||
|
sb.WriteString("元")
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"first": map[string]interface{}{
|
||||||
|
"value": sb.String(),
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"day": map[string]interface{}{
|
||||||
|
"value": FormatDeliveryTime(order),
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"orderId": map[string]interface{}{
|
||||||
|
"value": order.VendorOrderID,
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"orderType": map[string]interface{}{
|
||||||
|
"value": fmt.Sprintf("%s第%d号订单", model.VendorChineseNames[order.VendorID], order.OrderSeq),
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"customerName": map[string]interface{}{
|
||||||
|
"value": order.ConsigneeName,
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"customerPhone": map[string]interface{}{
|
||||||
|
"value": order.ConsigneeMobile,
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
storeID := jxutils.GetJxStoreIDFromOrder(order)
|
||||||
|
return SendMsgToStore(storeID, fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_NEWORDER_TEMPLATE_ID, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NotifyWaybillStatus(bill *model.Waybill, order *model.GoodsOrder) error {
|
||||||
|
var title string
|
||||||
|
var templateID string
|
||||||
|
switch bill.Status {
|
||||||
|
case model.WaybillStatusAccepted:
|
||||||
|
if bill.WaybillVendorID == model.VendorIDMTPS {
|
||||||
|
templateID = WX_MTPS_DELIVERY_GRABDONE_TEMPLATE_ID
|
||||||
|
} else if bill.WaybillVendorID == model.VendorIDDada {
|
||||||
|
templateID = WX_DADA_DELIVERY_GRABDONE_TEMPLATE_ID
|
||||||
|
}
|
||||||
|
title = fmt.Sprintf("%s %s#订单长时间无人配送,我们已安排%s配送员%s电话号码%s负责配送。^_^", model.VendorChineseNames[bill.OrderVendorID], bill.VendorOrderID, model.VendorChineseNames[bill.WaybillVendorID], bill.CourierName, bill.CourierMobile)
|
||||||
|
case model.WaybillStatusDelivered:
|
||||||
|
if bill.WaybillVendorID == model.VendorIDMTPS {
|
||||||
|
templateID = WX_MTPS_DELIVERY_DONE_TEMPLATE_ID
|
||||||
|
} else if bill.WaybillVendorID == model.VendorIDDada {
|
||||||
|
templateID = WX_DADA_DELIVERY_DONE_TEMPLATE_ID
|
||||||
|
}
|
||||||
|
title = fmt.Sprintf("%s 第%d号订单的配送完成", model.VendorChineseNames[bill.OrderVendorID], order.OrderSeq)
|
||||||
|
}
|
||||||
|
if title != "" {
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"first": map[string]interface{}{
|
||||||
|
"value": title,
|
||||||
|
"color": WX_HIGHLEVEL_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"keyword1": map[string]interface{}{
|
||||||
|
"value": bill.VendorOrderID,
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"keyword2": map[string]interface{}{
|
||||||
|
"value": bill.CourierName,
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"keyword3": map[string]interface{}{
|
||||||
|
"value": bill.CourierMobile,
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
"remark": map[string]interface{}{
|
||||||
|
"value": FormatDeliveryTime(order),
|
||||||
|
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return SendMsgToStore(jxutils.GetJxStoreIDFromOrder(order), templateID, "", data)
|
||||||
|
} else {
|
||||||
|
globals.SugarLogger.Infof("NotifyWaybillStatus wrong, bill:%v", bill)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatDeliveryTime(order *model.GoodsOrder) string {
|
||||||
|
var tmpTime time.Time
|
||||||
|
if order.ExpectedDeliveredTime == utils.DefaultTimeValue {
|
||||||
|
tmpTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||||
|
} else {
|
||||||
|
tmpTime = order.ExpectedDeliveredTime
|
||||||
|
}
|
||||||
|
left := tmpTime.Sub(time.Now()) / time.Minute
|
||||||
|
leftHours := left / 60
|
||||||
|
leftMinutes := left % 60
|
||||||
|
return fmt.Sprintf("请于%s前送达(剩余时间%d小时%d分钟", utils.Time2Str(tmpTime), leftHours, leftMinutes)
|
||||||
|
}
|
||||||
@@ -18,8 +18,17 @@ const (
|
|||||||
var (
|
var (
|
||||||
VendorNames = map[int]string{
|
VendorNames = map[int]string{
|
||||||
VendorIDJD: "JD",
|
VendorIDJD: "JD",
|
||||||
VendorIDELM: "ELEME",
|
|
||||||
VendorIDMTWM: "MT",
|
VendorIDMTWM: "MT",
|
||||||
|
VendorIDELM: "ELEME",
|
||||||
|
VendorIDDada: "Dada",
|
||||||
|
VendorIDMTPS: "MTPS",
|
||||||
|
}
|
||||||
|
VendorChineseNames = map[int]string{
|
||||||
|
VendorIDJD: "京东",
|
||||||
|
VendorIDMTWM: "美团",
|
||||||
|
VendorIDELM: "饿了么",
|
||||||
|
VendorIDDada: "达达众包",
|
||||||
|
VendorIDMTPS: "美团配送",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ const (
|
|||||||
defTime2Delivered = 1 * time.Hour // 正常订单都是1小时达
|
defTime2Delivered = 1 * time.Hour // 正常订单都是1小时达
|
||||||
defTime2Schedule3rdCarrier = 330 * time.Second // 京东要求5分钟后才能转自送,保险起见,设置为5分半钟
|
defTime2Schedule3rdCarrier = 330 * time.Second // 京东要求5分钟后才能转自送,保险起见,设置为5分半钟
|
||||||
time2Schedule3rdCarrierGap4OrderStatus = 3 * time.Minute // 京东要求是运单状态为待抢单且超时5分钟,但为了防止没有运单事件,所以就拣货完成事件开始算,添加3分钟
|
time2Schedule3rdCarrierGap4OrderStatus = 3 * time.Minute // 京东要求是运单状态为待抢单且超时5分钟,但为了防止没有运单事件,所以就拣货完成事件开始算,添加3分钟
|
||||||
defTime2AutoPickupMin = 25 * time.Minute
|
defTime2AutoPickupMin = 10 * time.Minute
|
||||||
time2AutoPickupGap = 5 * time.Minute
|
time2AutoPickupGap = 2 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
type WatchOrderInfo struct {
|
type WatchOrderInfo struct {
|
||||||
@@ -72,25 +72,37 @@ func (s *DefScheduler) OnOrderNew(order *model.GoodsOrder) (err error) {
|
|||||||
order: order,
|
order: order,
|
||||||
}
|
}
|
||||||
s.orderMap.Store(jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), watchInfo)
|
s.orderMap.Store(jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), watchInfo)
|
||||||
s.resetTimer(model.OrderStatusNew, watchInfo, 0)
|
s.resetTimer(watchInfo, model.OrderStatusNew, order.OrderCreatedAt, 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefScheduler) OnOrderStatusChanged(status *model.OrderStatus) (err error) {
|
func (s *DefScheduler) OnOrderStatusChanged(status *model.OrderStatus) (err error) {
|
||||||
globals.SugarLogger.Debugf("OnOrderStatusChanged, status:%v", status)
|
if status.Status > model.OrderStatusUnknown {
|
||||||
if savedOrderInfo := s.loadWatchOrderFromMap(status.VendorOrderID, status.VendorID); savedOrderInfo != nil {
|
globals.SugarLogger.Debugf("OnOrderStatusChanged, status:%v", status)
|
||||||
if status.Status > model.OrderStatusUnknown && status.Status < model.OrderStatusEndBegin {
|
if savedOrderInfo := s.loadWatchOrderFromMap(status.VendorOrderID, status.VendorID); savedOrderInfo != nil {
|
||||||
s.updateOrderByStatus(savedOrderInfo.order, status)
|
s.updateOrderByStatus(savedOrderInfo.order, status)
|
||||||
gap := 0 * time.Second
|
if status.Status > model.OrderStatusUnknown && status.Status < model.OrderStatusEndBegin {
|
||||||
if status.Status == model.OrderStatusAccepted {
|
if !(status.Status == model.OrderStatusFinishedPickup && len(savedOrderInfo.waybills) > 0) { //饿了么还观察到运单消息早于拣货完成消息
|
||||||
gap = time.Duration(rand.Int63n(int64(time2AutoPickupGap)))
|
gap := 0 * time.Second
|
||||||
} else if status.Status == model.OrderStatusFinishedPickup {
|
beginTime := status.StatusTime
|
||||||
gap = time2Schedule3rdCarrierGap4OrderStatus
|
if status.Status == model.OrderStatusNew {
|
||||||
|
beginTime = time.Now()
|
||||||
|
} else if status.Status == model.OrderStatusAccepted {
|
||||||
|
gap = time.Duration(rand.Int63n(int64(time2AutoPickupGap)))
|
||||||
|
beginTime = s.getBeginTime4LatestPickup(savedOrderInfo.order)
|
||||||
|
} else if status.Status == model.OrderStatusFinishedPickup {
|
||||||
|
// 召唤三方配送
|
||||||
|
// 正常应该是只依赖于购物平台的第一个运单消息,但饿了么有观察到极少数情况下没有此事件,所以还是需要在这里加个保险的TIMER来驱动运单调度
|
||||||
|
gap = time2Schedule3rdCarrierGap4OrderStatus
|
||||||
|
}
|
||||||
|
s.resetTimer(savedOrderInfo, status.Status, beginTime, gap)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.stopTimer(savedOrderInfo)
|
||||||
|
s.orderMap.Delete(jxutils.GetUniversalOrderIDFromOrderStatus(status))
|
||||||
}
|
}
|
||||||
s.resetTimer(status.Status, savedOrderInfo, gap)
|
|
||||||
} else {
|
} else {
|
||||||
s.stopTimer(savedOrderInfo)
|
err = scheduler.ErrCanNotFindOrder
|
||||||
s.orderMap.Delete(jxutils.GetUniversalOrderIDFromOrderStatus(status))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -98,60 +110,65 @@ func (s *DefScheduler) OnOrderStatusChanged(status *model.OrderStatus) (err erro
|
|||||||
|
|
||||||
// 以下是运单
|
// 以下是运单
|
||||||
func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||||
globals.SugarLogger.Debugf("OnWaybillStatusChanged, bill:%v", bill)
|
if bill.Status > model.WaybillStatusUnknown {
|
||||||
if savedOrderInfo := s.loadWatchOrderFromMap(bill.VendorOrderID, bill.OrderVendorID); savedOrderInfo != nil {
|
globals.SugarLogger.Debugf("OnWaybillStatusChanged, bill:%v", bill)
|
||||||
s.addWaybill2Map(savedOrderInfo, bill) // 这样写的原因是因为调试时,程度从中途运行,没有接受到WaybillStatusNew事件
|
if savedOrderInfo := s.loadWatchOrderFromMap(bill.VendorOrderID, bill.OrderVendorID); savedOrderInfo != nil {
|
||||||
if bill.Status == model.WaybillStatusNew {
|
s.addWaybill2Map(savedOrderInfo, bill) // 这样写的原因是因为调试时,程度从中途运行,没有接受到WaybillStatusNew事件
|
||||||
if bill.OrderVendorID == bill.WaybillVendorID {
|
if bill.Status == model.WaybillStatusNew {
|
||||||
if savedOrderInfo.timerStatus == model.OrderStatusFinishedPickup {
|
if bill.OrderVendorID == bill.WaybillVendorID {
|
||||||
s.resetTimer(model.OrderStatusFinishedPickup, savedOrderInfo, 0)
|
if savedOrderInfo.timerStatus == model.OrderStatusFinishedPickup { // 如果当前TIMER还是OrderStatusFinishedPickup(在OnOrderStatusChanged中设置的),则重置
|
||||||
} else {
|
s.resetTimer(savedOrderInfo, model.OrderStatusFinishedPickup, bill.WaybillCreatedAt, 0)
|
||||||
globals.SugarLogger.Infof("OnWaybillStatusChanged met other timer, status:%d", savedOrderInfo.timerStatus)
|
} else {
|
||||||
|
globals.SugarLogger.Infof("OnWaybillStatusChanged met other timer, status:%d", savedOrderInfo.timerStatus)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if savedOrderInfo.order.WaybillVendorID != model.VendorIDUnknown {
|
||||||
if savedOrderInfo.order.WaybillVendorID != model.VendorIDUnknown {
|
globals.SugarLogger.Infof("OnWaybillStatusChanged multiple waybill created, bill:%v", bill)
|
||||||
globals.SugarLogger.Infof("OnWaybillStatusChanged multiple waybill created, bill:%v", bill)
|
if bill.WaybillVendorID != bill.WaybillVendorID {
|
||||||
if bill.WaybillVendorID != bill.WaybillVendorID {
|
s.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID).CancelWaybill(bill)
|
||||||
s.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID).CancelWaybill(bill)
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch bill.Status {
|
||||||
|
case model.WaybillStatusAccepted:
|
||||||
|
s.stopTimer(savedOrderInfo) // todo 这里应该另外启动一个TIMER
|
||||||
|
s.cancelOtherWaybills(savedOrderInfo, bill)
|
||||||
|
|
||||||
|
s.CurOrderManager.UpdateWaybillVendorID(bill)
|
||||||
|
savedOrderInfo.order.WaybillVendorID = bill.WaybillVendorID
|
||||||
|
case model.WaybillStatusAcceptCanceled:
|
||||||
|
if savedOrderInfo.order.WaybillVendorID == bill.WaybillVendorID {
|
||||||
|
s.createWaybillOn3rdProviders(savedOrderInfo.order, bill)
|
||||||
|
|
||||||
|
bill.WaybillVendorID = model.VendorIDUnknown
|
||||||
|
s.CurOrderManager.UpdateWaybillVendorID(bill)
|
||||||
|
savedOrderInfo.order.WaybillVendorID = bill.WaybillVendorID
|
||||||
|
}
|
||||||
|
case model.WaybillStatusCanceled, model.WaybillStatusFailed:
|
||||||
|
s.removeWaybillFromMap(savedOrderInfo, bill)
|
||||||
|
if savedOrderInfo.order.WaybillVendorID == bill.WaybillVendorID {
|
||||||
|
s.createWaybillOn3rdProviders(savedOrderInfo.order, nil)
|
||||||
|
|
||||||
|
bill.WaybillVendorID = model.VendorIDUnknown
|
||||||
|
s.CurOrderManager.UpdateWaybillVendorID(bill)
|
||||||
|
savedOrderInfo.order.WaybillVendorID = bill.WaybillVendorID
|
||||||
|
}
|
||||||
|
case model.WaybillStatusDelivering:
|
||||||
|
if savedOrderInfo.order.VendorID != bill.WaybillVendorID {
|
||||||
|
s.GetPurchasePlatformFromVendorID(bill.OrderVendorID).SelfDeliverDelievering(savedOrderInfo.order)
|
||||||
|
}
|
||||||
|
case model.WaybillStatusDelivered:
|
||||||
|
if savedOrderInfo.order.VendorID != bill.WaybillVendorID {
|
||||||
|
s.GetPurchasePlatformFromVendorID(bill.OrderVendorID).SelfDeliverDelievered(savedOrderInfo.order)
|
||||||
|
}
|
||||||
|
s.removeWaybillFromMap(savedOrderInfo, bill)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch bill.Status {
|
err = scheduler.ErrCanNotFindOrder
|
||||||
case model.WaybillStatusAccepted:
|
|
||||||
s.stopTimer(savedOrderInfo) // todo 这里应该另外启动一个TIMER
|
|
||||||
s.cancelOtherWaybills(savedOrderInfo, bill)
|
|
||||||
|
|
||||||
s.CurOrderManager.UpdateWaybillVendorID(bill)
|
|
||||||
savedOrderInfo.order.WaybillVendorID = bill.WaybillVendorID
|
|
||||||
case model.WaybillStatusAcceptCanceled:
|
|
||||||
s.createWaybillOn3rdProviders(savedOrderInfo.order, bill)
|
|
||||||
if savedOrderInfo.order.WaybillVendorID == bill.WaybillVendorID {
|
|
||||||
bill.WaybillVendorID = model.VendorIDUnknown
|
|
||||||
s.CurOrderManager.UpdateWaybillVendorID(bill)
|
|
||||||
savedOrderInfo.order.WaybillVendorID = bill.WaybillVendorID
|
|
||||||
}
|
|
||||||
case model.WaybillStatusCanceled, model.WaybillStatusFailed:
|
|
||||||
s.removeWaybillFromMap(savedOrderInfo, bill)
|
|
||||||
if savedOrderInfo.order.WaybillVendorID == bill.WaybillVendorID {
|
|
||||||
s.createWaybillOn3rdProviders(savedOrderInfo.order, nil)
|
|
||||||
|
|
||||||
bill.WaybillVendorID = model.VendorIDUnknown
|
|
||||||
s.CurOrderManager.UpdateWaybillVendorID(bill)
|
|
||||||
savedOrderInfo.order.WaybillVendorID = bill.WaybillVendorID
|
|
||||||
}
|
|
||||||
case model.WaybillStatusDelivering:
|
|
||||||
if savedOrderInfo.order.VendorID != bill.WaybillVendorID {
|
|
||||||
s.GetPurchasePlatformFromVendorID(bill.OrderVendorID).SelfDeliverDelievering(savedOrderInfo.order)
|
|
||||||
}
|
|
||||||
case model.WaybillStatusDelivered:
|
|
||||||
if savedOrderInfo.order.VendorID != bill.WaybillVendorID {
|
|
||||||
s.GetPurchasePlatformFromVendorID(bill.OrderVendorID).SelfDeliverDelievered(savedOrderInfo.order)
|
|
||||||
}
|
|
||||||
s.removeWaybillFromMap(savedOrderInfo, bill)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefScheduler) addWaybill2Map(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) {
|
func (s *DefScheduler) addWaybill2Map(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) {
|
||||||
@@ -165,6 +182,15 @@ func (s *DefScheduler) addWaybill2Map(savedOrderInfo *WatchOrderInfo, bill *mode
|
|||||||
savedOrderInfo.waybills = append(savedOrderInfo.waybills, bill)
|
savedOrderInfo.waybills = append(savedOrderInfo.waybills, bill)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DefScheduler) removeWaybillFromMap(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) {
|
||||||
|
for k, v := range savedOrderInfo.waybills {
|
||||||
|
if v.VendorWaybillID == bill.VendorWaybillID && v.WaybillVendorID == bill.WaybillVendorID {
|
||||||
|
savedOrderInfo.waybills = append(savedOrderInfo.waybills[0:k], savedOrderInfo.waybills[k+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DefScheduler) createWaybillOn3rdProviders(order *model.GoodsOrder, excludeBill *model.Waybill) (err error) {
|
func (s *DefScheduler) createWaybillOn3rdProviders(order *model.GoodsOrder, excludeBill *model.Waybill) (err error) {
|
||||||
globals.SugarLogger.Debugf("createWaybillOn3rdProviders, order:%v", order)
|
globals.SugarLogger.Debugf("createWaybillOn3rdProviders, order:%v", order)
|
||||||
successCount := 0
|
successCount := 0
|
||||||
@@ -224,26 +250,11 @@ func (s *DefScheduler) loadWatchOrderFromMap(vendorOrderID string, vendorID int)
|
|||||||
return realSavedInfo
|
return realSavedInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefScheduler) removeWaybillFromMap(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) {
|
func (s *DefScheduler) getBeginTime4LatestPickup(order *model.GoodsOrder) (retVal time.Time) {
|
||||||
if savedOrderInfo == nil {
|
|
||||||
savedOrderInfo = s.loadWatchOrderFromMap(bill.VendorOrderID, bill.OrderVendorID)
|
|
||||||
}
|
|
||||||
if savedOrderInfo != nil {
|
|
||||||
for k, v := range savedOrderInfo.waybills {
|
|
||||||
if v.VendorWaybillID == bill.VendorWaybillID && v.WaybillVendorID == bill.WaybillVendorID {
|
|
||||||
savedOrderInfo.waybills = append(savedOrderInfo.waybills[0:k], savedOrderInfo.waybills[k+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefScheduler) getLatestPickupTimeout(order *model.GoodsOrder, configTimeout time.Duration) (retVal time.Duration) {
|
|
||||||
beginTime := order.StatusTime
|
|
||||||
if order.ExpectedDeliveredTime != utils.DefaultTimeValue {
|
if order.ExpectedDeliveredTime != utils.DefaultTimeValue {
|
||||||
beginTime = order.ExpectedDeliveredTime.Add(-defTime2Delivered)
|
return order.ExpectedDeliveredTime.Add(-defTime2Delivered)
|
||||||
}
|
}
|
||||||
return jxutils.GetRealTimeout(beginTime, configTimeout)
|
return order.StatusTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefScheduler) stopTimer(savedOrderInfo *WatchOrderInfo) {
|
func (s *DefScheduler) stopTimer(savedOrderInfo *WatchOrderInfo) {
|
||||||
@@ -253,24 +264,17 @@ func (s *DefScheduler) stopTimer(savedOrderInfo *WatchOrderInfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefScheduler) resetTimer(status int, savedOrderInfo *WatchOrderInfo, gap time.Duration) {
|
func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, status int, beginTime time.Time, gap time.Duration) {
|
||||||
globals.SugarLogger.Debugf("resetTimer status:%v, orderid:%v", status, savedOrderInfo.order.VendorOrderID)
|
globals.SugarLogger.Debugf("resetTimer status:%v, orderid:%v", status, savedOrderInfo.order.VendorOrderID)
|
||||||
s.stopTimer(savedOrderInfo)
|
s.stopTimer(savedOrderInfo)
|
||||||
config := s.mergeOrderStatusConfig(status, s.GetPurchasePlatformFromVendorID(savedOrderInfo.order.VendorID).GetStatusActionConfig(status))
|
config := s.mergeOrderStatusConfig(status, s.GetPurchasePlatformFromVendorID(savedOrderInfo.order.VendorID).GetStatusActionConfig(status))
|
||||||
if config != nil && config.TimeoutAction != nil {
|
if config != nil && config.TimeoutAction != nil {
|
||||||
var timeout time.Duration
|
timeout := jxutils.GetRealTimeout(beginTime, config.Timeout) + gap
|
||||||
if status == model.OrderStatusNew {
|
|
||||||
timeout = config.Timeout // 绝对值
|
|
||||||
} else if status == model.OrderStatusAccepted {
|
|
||||||
timeout = s.getLatestPickupTimeout(savedOrderInfo.order, config.Timeout)
|
|
||||||
} else {
|
|
||||||
timeout = jxutils.GetRealTimeout(savedOrderInfo.order.StatusTime, config.Timeout)
|
|
||||||
}
|
|
||||||
timeout += gap
|
|
||||||
globals.SugarLogger.Debugf("resetTimer timeout:%v, orderid:%v", timeout, savedOrderInfo.order.VendorOrderID)
|
globals.SugarLogger.Debugf("resetTimer timeout:%v, orderid:%v", timeout, savedOrderInfo.order.VendorOrderID)
|
||||||
savedOrderInfo.timerStatus = status
|
savedOrderInfo.timerStatus = status
|
||||||
savedOrderInfo.timer = time.AfterFunc(timeout, func() {
|
savedOrderInfo.timer = time.AfterFunc(timeout, func() {
|
||||||
config.TimeoutAction(savedOrderInfo.order)
|
config.TimeoutAction(savedOrderInfo.order)
|
||||||
|
savedOrderInfo.timerStatus = 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ var (
|
|||||||
var (
|
var (
|
||||||
ErrStatusIsNotOKForOperation = errors.New("当前状态操作无效")
|
ErrStatusIsNotOKForOperation = errors.New("当前状态操作无效")
|
||||||
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
|
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
|
||||||
|
ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)")
|
||||||
|
ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)")
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatusActionConfig struct {
|
type StatusActionConfig struct {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
|
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
_ "github.com/go-sql-driver/mysql" // import your used driver
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
Reference in New Issue
Block a user