- elm self delivery support.

This commit is contained in:
gazebo
2018-07-28 11:49:54 +08:00
parent ad93408e4c
commit 7734399392
4 changed files with 154 additions and 125 deletions

View File

@@ -278,11 +278,9 @@ func (c *OrderController) SelfDeliverDelievered(order *model.GoodsOrder) (err er
return api.ElmAPI.CompleteDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile) return api.ElmAPI.CompleteDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
} }
func (c *OrderController) GetStatusActionConfig(statusType, status int) *scheduler.StatusActionConfig { func (c *OrderController) GetStatusActionTimeout(statusType, status int) time.Duration {
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusNew { if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusNew {
return &scheduler.StatusActionConfig{ return acceptOrderDelay // 饿了么开了专送店的订单没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货
Timeout: acceptOrderDelay, // 饿了么没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货
}
} }
return nil return 0
} }

View File

@@ -3,8 +3,9 @@ package model
type Jxstorefeature struct { type Jxstorefeature struct {
Id int `orm:"column(storeid);pk"` Id int `orm:"column(storeid);pk"`
Autopickup int8 `orm:"column(autopickup);null"` Autopickup int8 `orm:"column(autopickup);null"`
Transmtzs int8 `orm:"column(transmtzs);null"` // 定义为饿了么平台的订单是否支持三方配送 Transmtzs int8 `orm:"column(transmtzs);null"` // 定义为饿了么平台的订单是否支持三方配送
Deliverycompetition int8 `orm:"column(deliverycompetition);null"` // 定义为京东到家 平台的订单是否支持三方配送 Deliverycompetition int8 `orm:"column(deliverycompetition);null"` // 定义为京东到家 平台的订单是否支持三方配送
ElmDeliveryType int8 `orm:"column(elm_delivery_type);default(0)"` // 饿了么店的配送方式
} }
func (t *Jxstorefeature) TableName() string { func (t *Jxstorefeature) TableName() string {

View File

@@ -32,6 +32,10 @@ const (
) )
type WatchOrderInfo struct { type WatchOrderInfo struct {
isNeedAutoPickup bool
storeDeliveryType int
isNeed3rdDelivery bool
order *model.GoodsOrder // order里的信息是保持更新的 order *model.GoodsOrder // order里的信息是保持更新的
waybills []*model.Waybill // 这个waybills里的状态信息是不真实的只使用id相关的信息 waybills []*model.Waybill // 这个waybills里的状态信息是不真实的只使用id相关的信息
@@ -42,24 +46,81 @@ type WatchOrderInfo struct {
retryCount int // 失败后尝试的次数,调试阶段可能出现死循化,阻止这种情况发生 retryCount int // 失败后尝试的次数,调试阶段可能出现死循化,阻止这种情况发生
} }
type StatusActionConfig struct {
TimerType int // 参见上面的相关常量定义
Timeout time.Duration // 超时时间0在GetStatusActionConfig返回时表示不修改缺省
TimeoutGap int // 以秒为单位的随机时间0在GetStatusActionConfig返回时表示不修改缺省
TimeoutAction func(savedOrderInfo *WatchOrderInfo) (err error) // 超时后需要执行的动作为nil表示此状态不需要执行监控 nil在GetStatusActionConfig返回时表示不修改缺省
}
// 重要:此调度器要求同一定单的处理逻辑必须是序列化了的,不然会有并发问题 // 重要:此调度器要求同一定单的处理逻辑必须是序列化了的,不然会有并发问题
type DefScheduler struct { type DefScheduler struct {
scheduler.BaseScheduler scheduler.BaseScheduler
defWorkflowConfig []map[int]*scheduler.StatusActionConfig defWorkflowConfig []map[int]*StatusActionConfig
orderMap jxutils.SyncMapWithTimeout orderMap jxutils.SyncMapWithTimeout
} }
func NewWatchOrderInfo(order *model.GoodsOrder) (retVal *WatchOrderInfo) {
retVal = &WatchOrderInfo{
isNeedAutoPickup: true,
isNeed3rdDelivery: false,
storeDeliveryType: scheduler.StoreDeliveryTypeCrowdSourcing,
}
retVal.SetOrder(order)
return retVal
}
func (s *WatchOrderInfo) SetOrder(order *model.GoodsOrder) (retVal *model.GoodsOrder) {
retVal = s.order
if s.order != order {
if order != nil {
s.updateOrderStoreFeature(order)
}
s.order = order
}
return retVal
}
func (s *WatchOrderInfo) updateOrderStoreFeature(order *model.GoodsOrder) (err error) {
storefeature := &model.Jxstorefeature{
Id: jxutils.GetJxStoreIDFromOrder(order),
}
if storefeature.Id > 0 {
db := orm.NewOrm()
utils.CallFuncLogError(func() error {
err = db.Read(storefeature, "Id")
if err == nil {
s.isNeedAutoPickup = (storefeature.Autopickup != 0)
if order.VendorID == model.VendorIDELM {
s.storeDeliveryType = int(storefeature.ElmDeliveryType)
}
if s.storeDeliveryType != scheduler.StoreDeliveryTypeByStore {
if (order.VendorID == model.VendorIDJD && storefeature.Deliverycompetition != 0) ||
(order.VendorID == model.VendorIDELM && storefeature.Transmtzs != 0) {
s.isNeed3rdDelivery = true
}
} else {
s.isNeed3rdDelivery = true
}
}
return err
}, "updateOrderStoreFeature")
}
return err
}
func init() { func init() {
sch := &DefScheduler{} sch := &DefScheduler{}
sch.IsReallyCallPlatformAPI = globals.ReallyCallPlatformAPI sch.IsReallyCallPlatformAPI = globals.ReallyCallPlatformAPI
sch.Init() sch.Init()
scheduler.CurrentScheduler = sch scheduler.CurrentScheduler = sch
sch.defWorkflowConfig = []map[int]*scheduler.StatusActionConfig{ sch.defWorkflowConfig = []map[int]*StatusActionConfig{
map[int]*scheduler.StatusActionConfig{ map[int]*StatusActionConfig{
model.OrderStatusNew: &scheduler.StatusActionConfig{ // 自动接单 model.OrderStatusNew: &StatusActionConfig{ // 自动接单
TimerType: scheduler.TimerTypeBaseNow, TimerType: scheduler.TimerTypeBaseNow,
Timeout: 1 * time.Second, Timeout: 1 * time.Second,
TimeoutAction: func(order *model.GoodsOrder) (err error) { TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
order := savedOrderInfo.order
_ = sch.handleAutoAcceptOrder(order.VendorOrderID, order.VendorID, order.ConsigneeMobile, jxutils.GetJxStoreIDFromOrder(order), nil, func(isAcceptIt bool) error { _ = sch.handleAutoAcceptOrder(order.VendorOrderID, order.VendorID, order.ConsigneeMobile, jxutils.GetJxStoreIDFromOrder(order), nil, func(isAcceptIt bool) error {
if err = sch.AcceptOrRefuseOrder(order, isAcceptIt); err != nil { if err = sch.AcceptOrRefuseOrder(order, isAcceptIt); err != nil {
// 为了解决京东新消息与接单消息乱序的问题 // 为了解决京东新消息与接单消息乱序的问题
@@ -77,21 +138,38 @@ func init() {
return nil return nil
}, },
}, },
model.OrderStatusAccepted: &scheduler.StatusActionConfig{ // 自动拣货 model.OrderStatusAccepted: &StatusActionConfig{ // 自动拣货
TimerType: scheduler.TimerTypeBaseExpectedDeliveredTime, TimerType: scheduler.TimerTypeBaseExpectedDeliveredTime,
Timeout: time2AutoPickupMin, Timeout: time2AutoPickupMin,
TimeoutGap: time2AutoPickupGap, TimeoutGap: time2AutoPickupGap,
TimeoutAction: func(order *model.GoodsOrder) (err error) { TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
return sch.autoPickupGood(order) if savedOrderInfo.isNeedAutoPickup {
return sch.autoPickupGood(savedOrderInfo.order)
}
return nil
},
},
model.OrderStatusFinishedPickup: &StatusActionConfig{
TimerType: scheduler.TimerTypeBaseNow,
Timeout: 1 * time.Second,
TimeoutGap: 0,
TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore { // 自配置商家使用
return sch.createWaybillOn3rdProviders(savedOrderInfo, nil)
}
return nil
}, },
}, },
}, },
map[int]*scheduler.StatusActionConfig{ map[int]*StatusActionConfig{
model.WaybillStatusNew: &scheduler.StatusActionConfig{ // 尝试召唤更多物流 model.WaybillStatusNew: &StatusActionConfig{
TimerType: scheduler.TimerTypeBaseStatusTime, TimerType: scheduler.TimerTypeBaseStatusTime,
Timeout: time2Schedule3rdCarrier, Timeout: time2Schedule3rdCarrier,
TimeoutAction: func(order *model.GoodsOrder) (err error) { TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
return sch.createWaybillOn3rdProviders(order, nil) if savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore { // 非自配置商家使用
return sch.createWaybillOn3rdProviders(savedOrderInfo, nil)
}
return nil
}, },
}, },
}, },
@@ -103,12 +181,10 @@ func (s *DefScheduler) OnOrderNew(order *model.GoodsOrder, isPending bool) (err
globals.SugarLogger.Debugf("OnOrderNew orderID:%s", order.VendorOrderID) globals.SugarLogger.Debugf("OnOrderNew orderID:%s", order.VendorOrderID)
savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), false) savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), false)
if savedOrderInfo == nil { if savedOrderInfo == nil {
savedOrderInfo = &WatchOrderInfo{ savedOrderInfo = NewWatchOrderInfo(order)
order: order,
}
s.orderMap.StoreWithTimeout(jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), savedOrderInfo, orderMapStoreMaxTime) s.orderMap.StoreWithTimeout(jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), savedOrderInfo, orderMapStoreMaxTime)
} else { } else {
savedOrderInfo.order = order // 调整单或消息错序都可能进到这里来 savedOrderInfo.SetOrder(order) // 调整单或消息错序都可能进到这里来
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeOrder, savedOrderInfo.order.Status, false) s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeOrder, savedOrderInfo.order.Status, false)
return err return err
@@ -147,9 +223,9 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
if !isPending { if !isPending {
if order.WaybillVendorID != model.VendorIDUnknown { if order.WaybillVendorID != model.VendorIDUnknown {
globals.SugarLogger.Debugf("OnWaybillStatusChanged multiple waybill created, bill:%v", bill) globals.SugarLogger.Debugf("OnWaybillStatusChanged multiple waybill created, bill:%v", bill)
if !(order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID) && bill.WaybillVendorID != order.VendorID { if !s.isBillCandidate(order, bill) && bill.WaybillVendorID != order.VendorID {
s.CancelWaybill(bill) s.CancelWaybill(bill)
} else if bill.WaybillVendorID == order.VendorID { } else if bill.WaybillVendorID == order.VendorID && order.WaybillVendorID != order.VendorID {
globals.SugarLogger.Warnf("OnWaybillStatusChanged bill:%v purchase platform bill came later than others, strange!!!", bill) globals.SugarLogger.Warnf("OnWaybillStatusChanged bill:%v purchase platform bill came later than others, strange!!!", bill)
} }
} }
@@ -161,61 +237,69 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
} else { } else {
switch bill.Status { switch bill.Status {
case model.WaybillStatusAccepted: case model.WaybillStatusAccepted:
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
if !isPending { if !isPending {
if order.WaybillVendorID == model.VendorIDUnknown || bill.WaybillVendorID == order.VendorID { // 购买平台的运单,优先级最高 if order.WaybillVendorID == model.VendorIDUnknown || bill.WaybillVendorID == order.VendorID { // 购买平台的运单,优先级最高
s.updateOrderByBill(order, bill, false) s.updateOrderByBill(order, bill, false)
s.cancelOtherWaybills(savedOrderInfo, bill) s.cancelOtherWaybills(savedOrderInfo, bill)
} else if !(order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID) && bill.WaybillVendorID != order.VendorID { if bill.WaybillVendorID != bill.OrderVendorID {
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore {
s.SelfDeliverDelievering(savedOrderInfo.order)
} else {
s.swtich2SelfDeliverWithRetry(savedOrderInfo.order, bill, 2, 10*time.Second)
}
}
} else if !s.isBillCandidate(order, bill) && bill.WaybillVendorID != order.VendorID {
// todo 当前逻辑加载PENDING的ORDER时正常状态也可能进这里 // todo 当前逻辑加载PENDING的ORDER时正常状态也可能进这里
s.CancelWaybill(bill) s.CancelWaybill(bill)
globals.SugarLogger.Warnf("OnWaybillStatusChanged Accepted orderID:%s got multiple bill:%v, order details:%v", order.VendorOrderID, bill, order) globals.SugarLogger.Warnf("OnWaybillStatusChanged Accepted orderID:%s got multiple bill:%v, order details:%v", order.VendorOrderID, bill, order)
} }
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
case model.WaybillStatusAcceptCanceled: case model.WaybillStatusAcceptCanceled:
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { if s.isBillCandidate(order, bill) {
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
if !isPending { if !isPending {
bill.WaybillVendorID = model.VendorIDUnknown bill.WaybillVendorID = model.VendorIDUnknown
s.updateOrderByBill(order, bill, false) s.updateOrderByBill(order, bill, false)
s.createWaybillOn3rdProviders(order, bill) s.createWaybillOn3rdProviders(savedOrderInfo, bill)
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
} else if order.WaybillVendorID != model.VendorIDUnknown { } else if order.WaybillVendorID != model.VendorIDUnknown {
s.CancelWaybill(bill) s.CancelWaybill(bill)
globals.SugarLogger.Warnf("OnWaybillStatusChanged AcceptCanceled orderID:%s got multiple bill:%v, order details:%v", order.VendorOrderID, bill, order) globals.SugarLogger.Warnf("OnWaybillStatusChanged AcceptCanceled orderID:%s got multiple bill:%v, order details:%v", order.VendorOrderID, bill, order)
} }
case model.WaybillStatusCourierArrived: // do nothing case model.WaybillStatusCourierArrived: // do nothing
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
if s.isBillCandidate(order, bill) {
} else { } else {
// s.CancelWaybill(bill) // s.CancelWaybill(bill)
globals.SugarLogger.Warnf("OnWaybillStatusChanged CourierArrived order(%d, %s) bill(%d, %s), bill:%v shouldn't got here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill) globals.SugarLogger.Warnf("OnWaybillStatusChanged CourierArrived order(%d, %s) bill(%d, %s), bill:%v shouldn't got here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
case model.WaybillStatusFailed: // todo WaybillStatusFailed理解成订单整个失败了不需要再尝试创建运单了注意这里应该加个zabbix日志的报警 case model.WaybillStatusFailed: // todo WaybillStatusFailed理解成订单整个失败了不需要再尝试创建运单了注意这里应该加个zabbix日志的报警
s.removeWaybillFromMap(savedOrderInfo, bill) s.removeWaybillFromMap(savedOrderInfo, bill)
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { if s.isBillCandidate(order, bill) {
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
if !isPending { if !isPending {
globals.SugarLogger.Infof("OnWaybillStatusChanged WaybillStatusFailed, bill:%v", bill) globals.SugarLogger.Infof("OnWaybillStatusChanged WaybillStatusFailed, bill:%v", bill)
bill.WaybillVendorID = model.VendorIDUnknown bill.WaybillVendorID = model.VendorIDUnknown
s.updateOrderByBill(order, bill, true) s.updateOrderByBill(order, bill, true)
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
} else { } else {
globals.SugarLogger.Warnf("OnWaybillStatusChanged Failed bill:%v shouldn't got here, order details:%v", bill, order) globals.SugarLogger.Warnf("OnWaybillStatusChanged Failed bill:%v shouldn't got here, order details:%v", bill, order)
} }
case model.WaybillStatusCanceled: case model.WaybillStatusCanceled:
s.removeWaybillFromMap(savedOrderInfo, bill) s.removeWaybillFromMap(savedOrderInfo, bill)
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { if s.isBillCandidate(order, bill) {
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
if !isPending { if !isPending {
bill.WaybillVendorID = model.VendorIDUnknown bill.WaybillVendorID = model.VendorIDUnknown
s.updateOrderByBill(order, bill, true) s.updateOrderByBill(order, bill, true)
s.createWaybillOn3rdProviders(order, nil) s.createWaybillOn3rdProviders(savedOrderInfo, nil)
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
} }
case model.WaybillStatusDelivering: case model.WaybillStatusDelivering:
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
if s.isBillCandidate(order, bill) {
if order.VendorID != bill.WaybillVendorID && !isPending { if order.VendorID != bill.WaybillVendorID && !isPending {
s.SelfDeliverDelievering(order) s.SelfDeliverDelievering(order)
} }
@@ -223,17 +307,16 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
// s.CancelWaybill(bill) // s.CancelWaybill(bill)
globals.SugarLogger.Warnf("OnWaybillStatusChanged Delivering order(%d, %s) bill(%d, %s), bill:%v shouldn't got here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill) globals.SugarLogger.Warnf("OnWaybillStatusChanged Delivering order(%d, %s) bill(%d, %s), bill:%v shouldn't got here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
case model.WaybillStatusDelivered: case model.WaybillStatusDelivered:
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
s.removeWaybillFromMap(savedOrderInfo, bill) s.removeWaybillFromMap(savedOrderInfo, bill)
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { if s.isBillCandidate(order, bill) {
if order.VendorID != bill.WaybillVendorID && !isPending { if order.VendorID != bill.WaybillVendorID && !isPending {
s.SelfDeliverDelievered(order) s.SelfDeliverDelievered(order)
} }
} else { } else {
globals.SugarLogger.Warnf("OnWaybillStatusChanged Delivered order(%d, %s) bill(%d, %s), bill:%v shouldn't got here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill) globals.SugarLogger.Warnf("OnWaybillStatusChanged Delivered order(%d, %s) bill(%d, %s), bill:%v shouldn't got here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
} }
s.resetTimer(savedOrderInfo, scheduler.TimerStatusTypeWaybill, bill.Status, false)
} }
} }
} }
@@ -261,13 +344,13 @@ func (s *DefScheduler) removeWaybillFromMap(savedOrderInfo *WatchOrderInfo, bill
} }
} }
func (s *DefScheduler) createWaybillOn3rdProviders(order *model.GoodsOrder, excludeBill *model.Waybill) (err error) { func (s *DefScheduler) createWaybillOn3rdProviders(savedOrderInfo *WatchOrderInfo, excludeBill *model.Waybill) (err error) {
order := savedOrderInfo.order
globals.SugarLogger.Debugf("createWaybillOn3rdProviders, orderID:%s, status:%d, excludeBill:%v", order.VendorOrderID, order.Status, excludeBill) globals.SugarLogger.Debugf("createWaybillOn3rdProviders, orderID:%s, status:%d, excludeBill:%v", order.VendorOrderID, order.Status, excludeBill)
savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), true)
savedOrderInfo.retryCount++ savedOrderInfo.retryCount++
if savedOrderInfo.retryCount <= maxWaybillRetryCount { if savedOrderInfo.retryCount <= maxWaybillRetryCount {
if order.Status == model.OrderStatusFinishedPickup { if order.Status == model.OrderStatusFinishedPickup {
if s.isOrderSupport3rdDelivery(order) { if savedOrderInfo.isNeed3rdDelivery || savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore {
successCount := 0 successCount := 0
for vendorID := range s.DeliveryPlatformHandlers { for vendorID := range s.DeliveryPlatformHandlers {
if (excludeBill == nil || vendorID != excludeBill.WaybillVendorID) && s.DeliveryPlatformHandlers[vendorID].Use4CreateWaybill { if (excludeBill == nil || vendorID != excludeBill.WaybillVendorID) && s.DeliveryPlatformHandlers[vendorID].Use4CreateWaybill {
@@ -299,9 +382,6 @@ func (s *DefScheduler) cancelOtherWaybills(savedOrderInfo *WatchOrderInfo, bill2
s.CancelWaybill(v) s.CancelWaybill(v)
} }
} }
if bill2Keep != nil && bill2Keep.WaybillVendorID != bill2Keep.OrderVendorID {
s.swtich2SelfDeliverWithRetry(savedOrderInfo.order, bill2Keep, 2, 10*time.Second)
}
return nil return nil
} }
@@ -312,7 +392,7 @@ func (s *DefScheduler) swtich2SelfDeliverWithRetry(order *model.GoodsOrder, bill
globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry failed, cancel bill:%v, err:%v", bill, err) globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry failed, cancel bill:%v, err:%v", bill, err)
if s.CancelWaybill(bill) == nil { if s.CancelWaybill(bill) == nil {
// 转自送失败的取消,要将订单中的运单状态更新 // 转自送失败的取消,要将订单中的运单状态更新
if order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID { if s.isBillCandidate(order, bill) {
bill.WaybillVendorID = model.VendorIDUnknown bill.WaybillVendorID = model.VendorIDUnknown
s.updateOrderByBill(order, bill, false) s.updateOrderByBill(order, bill, false)
} }
@@ -330,22 +410,22 @@ func (s *DefScheduler) loadSavedOrderFromMap(status *model.OrderStatus, isAutoLo
} }
if isAutoLoad && (realSavedInfo == nil || !model.IsOrderSolid(realSavedInfo.order)) { if isAutoLoad && (realSavedInfo == nil || !model.IsOrderSolid(realSavedInfo.order)) {
if realSavedInfo == nil { if realSavedInfo == nil {
realSavedInfo = new(WatchOrderInfo) realSavedInfo = NewWatchOrderInfo(nil)
s.orderMap.StoreWithTimeout(universalOrderID, realSavedInfo, orderMapStoreMaxTime) s.orderMap.StoreWithTimeout(universalOrderID, realSavedInfo, orderMapStoreMaxTime)
} else { } else {
globals.SugarLogger.Infof("loadSavedOrderFromMap order is incomplete, orderID:%s, load it", status.RefVendorOrderID) globals.SugarLogger.Infof("loadSavedOrderFromMap order is incomplete, orderID:%s, load it", status.RefVendorOrderID)
} }
if order, err := s.CurOrderManager.LoadOrder(status.RefVendorOrderID, status.RefVendorID); err == nil { if order, err := s.CurOrderManager.LoadOrder(status.RefVendorOrderID, status.RefVendorID); err == nil {
realSavedInfo.order = order realSavedInfo.SetOrder(order)
} else { } else {
realSavedInfo.order = &model.GoodsOrder{ realSavedInfo.SetOrder(&model.GoodsOrder{
VendorOrderID: status.RefVendorOrderID, VendorOrderID: status.RefVendorOrderID,
VendorID: status.RefVendorID, VendorID: status.RefVendorID,
Status: status.Status, Status: status.Status,
StatusTime: status.StatusTime, StatusTime: status.StatusTime,
OrderCreatedAt: status.StatusTime, OrderCreatedAt: status.StatusTime,
WaybillVendorID: model.VendorIDUnknown, WaybillVendorID: model.VendorIDUnknown,
} })
globals.SugarLogger.Infof("loadSavedOrderFromMap can not load order orderID:%s", status.VendorOrderID) globals.SugarLogger.Infof("loadSavedOrderFromMap can not load order orderID:%s", status.VendorOrderID)
} }
} }
@@ -365,9 +445,8 @@ func (s *DefScheduler) stopTimer(savedOrderInfo *WatchOrderInfo) {
func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, statusType, status int, isPending bool) { func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, statusType, status int, isPending bool) {
order := savedOrderInfo.order order := savedOrderInfo.order
globals.SugarLogger.Debugf("resetTimer, orderID:%s status:%v", order.VendorOrderID, status) globals.SugarLogger.Debugf("resetTimer, orderID:%s status:%v", order.VendorOrderID, status)
if statusType != savedOrderInfo.timerStatusType || status >= savedOrderInfo.timerStatus { // 新设置的TIMER不能覆盖状态在其后的TIMER如果状态回绕需要注意 if statusType != savedOrderInfo.timerStatusType || status >= savedOrderInfo.timerStatus { // 新设置的TIMER不能覆盖状态在其后的TIMER如果状态回绕需要注意
config := s.mergeOrderStatusConfig(statusType, status, s.GetPurchasePlatformFromVendorID(order.VendorID).GetStatusActionConfig(statusType, status)) config := s.mergeOrderStatusConfig(statusType, status, order.VendorID)
if config == nil || config.TimerType != scheduler.TimerTypeByPass { if config == nil || config.TimerType != scheduler.TimerTypeByPass {
s.stopTimer(savedOrderInfo) s.stopTimer(savedOrderInfo)
} }
@@ -396,7 +475,7 @@ func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, statusType, st
timeout = 0 timeout = 0
} }
if timeout == 0 { if timeout == 0 {
config.TimeoutAction(order) config.TimeoutAction(savedOrderInfo)
} else { } else {
timerName := "" timerName := ""
if statusType == scheduler.TimerStatusTypeOrder { if statusType == scheduler.TimerStatusTypeOrder {
@@ -409,7 +488,7 @@ func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, statusType, st
savedOrderInfo.timer = time.AfterFunc(timeout, func() { savedOrderInfo.timer = time.AfterFunc(timeout, func() {
jxutils.CallMsgHandlerAsync(func() { jxutils.CallMsgHandlerAsync(func() {
globals.SugarLogger.Debugf("fire timer:%s, orderID:%s", timerName, order.VendorOrderID) globals.SugarLogger.Debugf("fire timer:%s, orderID:%s", timerName, order.VendorOrderID)
config.TimeoutAction(order) config.TimeoutAction(savedOrderInfo)
savedOrderInfo.timerStatus = 0 savedOrderInfo.timerStatus = 0
savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown
}, order.VendorOrderID) }, order.VendorOrderID)
@@ -452,28 +531,18 @@ func (s *DefScheduler) handleAutoAcceptOrder(orderID string, vendorID int, userM
return handleType return handleType
} }
func (s *DefScheduler) mergeOrderStatusConfig(statusType, status int, config *scheduler.StatusActionConfig) (retVal *scheduler.StatusActionConfig) { func (s *DefScheduler) mergeOrderStatusConfig(statusType, status int, purchaseVendorID int) (retVal *StatusActionConfig) {
vendorTimeout := s.GetPurchasePlatformFromVendorID(purchaseVendorID).GetStatusActionTimeout(statusType, status)
defConfig := s.defWorkflowConfig[statusType][status] defConfig := s.defWorkflowConfig[statusType][status]
if defConfig == nil && config == nil { if defConfig == nil {
return nil return nil
} }
retVal = &scheduler.StatusActionConfig{} retVal = &StatusActionConfig{}
if defConfig != nil { if defConfig != nil {
*retVal = *defConfig *retVal = *defConfig
} }
if config != nil { if vendorTimeout != 0 {
if config.Timeout != 0 { retVal.Timeout = vendorTimeout
retVal.Timeout = config.Timeout
}
if config.TimerType != scheduler.TimerTypeNoOverride {
retVal.TimerType = config.TimerType
}
if config.TimeoutGap != 0 {
retVal.TimeoutGap = config.TimeoutGap
}
if config.TimeoutAction != nil {
retVal.TimeoutAction = config.TimeoutAction
}
} }
return retVal return retVal
} }
@@ -485,43 +554,6 @@ func (s *DefScheduler) updateOrderByStatus(order *model.GoodsOrder, status *mode
return order return order
} }
func (s *DefScheduler) isOrderSupport3rdDelivery(order *model.GoodsOrder) (retVal bool) {
storefeature := &model.Jxstorefeature{
Id: jxutils.GetJxStoreIDFromOrder(order),
}
db := orm.NewOrm()
utils.CallFuncLogError(func() error {
err := db.Read(storefeature, "Id")
if err == nil {
if (order.VendorID == model.VendorIDJD && storefeature.Deliverycompetition == 1) ||
(order.VendorID == model.VendorIDELM && storefeature.Transmtzs == 1) {
retVal = true
}
}
return err
}, "isOrderSupport3rdDelivery")
return retVal
}
func (s *DefScheduler) isOrderSupportAutoPickup(order *model.GoodsOrder) (retVal bool) {
retVal = true
storefeature := &model.Jxstorefeature{
Id: jxutils.GetJxStoreIDFromOrder(order),
}
db := orm.NewOrm()
utils.CallFuncLogError(func() error {
err := db.Read(storefeature, "Id")
if err == nil || err == orm.ErrNoRows {
if storefeature.Autopickup == 0 {
retVal = false
}
err = nil
}
return err
}, "isOrderSupportAutoPickup")
return retVal
}
func (s *DefScheduler) updateOrderByBill(order *model.GoodsOrder, bill *model.Waybill, revertStatus bool) { func (s *DefScheduler) updateOrderByBill(order *model.GoodsOrder, bill *model.Waybill, revertStatus bool) {
if bill.WaybillVendorID == model.VendorIDUnknown { if bill.WaybillVendorID == model.VendorIDUnknown {
bill.VendorWaybillID = "" bill.VendorWaybillID = ""
@@ -535,10 +567,9 @@ func (s *DefScheduler) updateOrderByBill(order *model.GoodsOrder, bill *model.Wa
} }
func (s *DefScheduler) autoPickupGood(order *model.GoodsOrder) (err error) { func (s *DefScheduler) autoPickupGood(order *model.GoodsOrder) (err error) {
if s.isOrderSupportAutoPickup(order) { return s.PickedUpGoods(order)
err = s.PickedUpGoods(order) }
} else {
globals.SugarLogger.Debugf("autoPickupGood orderID:%s doesn't support auto pickup", order.VendorOrderID) func (s *DefScheduler) isBillCandidate(order *model.GoodsOrder, bill *model.Waybill) bool {
} return order.WaybillVendorID == bill.WaybillVendorID && order.VendorWaybillID == bill.VendorWaybillID
return err
} }

View File

@@ -10,6 +10,12 @@ import (
"git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals"
) )
const (
StoreDeliveryTypeCrowdSourcing = 0 //缺省,平台众包配送,可转自送
StoreDeliveryTypeByPlatform = 1 //平台专送
StoreDeliveryTypeByStore = 2 //完全门店自送
)
const ( const (
TimerStatusTypeUnknown = -1 TimerStatusTypeUnknown = -1
TimerStatusTypeOrder = 0 TimerStatusTypeOrder = 0
@@ -36,17 +42,10 @@ var (
ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单") ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单")
) )
type StatusActionConfig struct {
TimerType int // 参见上面的相关常量定义
Timeout time.Duration // 超时时间0在GetStatusActionConfig返回时表示不修改缺省
TimeoutGap int // 以秒为单位的随机时间0在GetStatusActionConfig返回时表示不修改缺省
TimeoutAction func(order *model.GoodsOrder) (err error) // 超时后需要执行的动作为nil表示此状态不需要执行监控 nil在GetStatusActionConfig返回时表示不修改缺省
}
type PurchasePlatformHandler interface { type PurchasePlatformHandler interface {
GetStatusFromVendorStatus(vendorStatus string) int GetStatusFromVendorStatus(vendorStatus string) int
GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error) GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error)
GetStatusActionConfig(statusType, status int) *StatusActionConfig GetStatusActionTimeout(statusType, status int) time.Duration
AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error)
PickedUpGoods(order *model.GoodsOrder) (err error) PickedUpGoods(order *model.GoodsOrder) (err error)
@@ -236,6 +235,6 @@ func (c *BaseScheduler) CancelWaybill(bill *model.Waybill) (err error) {
type BasePurchasePlatform struct { type BasePurchasePlatform struct {
} }
func (p *BasePurchasePlatform) GetStatusActionConfig(statusType, status int) *StatusActionConfig { func (p *BasePurchasePlatform) GetStatusActionTimeout(statusType, status int) time.Duration {
return nil return 0
} }