Files
jx-callback/business/scheduler/scheduler.go
gazebo cd3a4b651a - change jx-callback.service Requires MySQL to Wants MySQL.
- don't treat CreateWaybill fail as warning.
2018-08-01 10:23:59 +08:00

241 lines
9.3 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 scheduler
import (
"errors"
"fmt"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
)
const (
StoreDeliveryTypeCrowdSourcing = 0 //缺省,平台众包配送,可转自送
StoreDeliveryTypeByPlatform = 1 //平台专送
StoreDeliveryTypeByStore = 2 //完全门店自送
)
const (
TimerStatusTypeUnknown = -1
TimerStatusTypeOrder = 0
TimerStatusTypeWaybill = 1
)
const (
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
TimerTypeByPass = 1
TimerTypeBaseNow = 2
TimerTypeBaseStatusTime = 3
TimerTypeBaseExpectedDeliveredTime = 4 // 如果是定时达以expected delivery time倒推的时间当成statusTime之后与TimerTypeBaseStatusTime一样否则与TimerTypeBaseStatusTime相同
)
var (
CurrentScheduler Scheduler
)
var (
ErrStatusIsNotOKForOperation = errors.New("当前状态操作无效")
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)")
ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)")
ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单")
)
type PurchasePlatformHandler interface {
GetStatusFromVendorStatus(vendorStatus string) int
GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error)
GetStatusActionTimeout(statusType, status int) time.Duration
AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error)
PickupGoods(order *model.GoodsOrder) (err error)
Swtich2SelfDeliver(order *model.GoodsOrder) (err error)
SelfDeliverDelievering(order *model.GoodsOrder) (err error)
SelfDeliverDelievered(order *model.GoodsOrder) (err error)
}
type DeliveryPlatformHandler interface {
CreateWaybill(order *model.GoodsOrder) (err error)
CancelWaybill(bill *model.Waybill) (err error)
}
type DeliveryPlatformHandlerInfo struct {
Handler DeliveryPlatformHandler
Use4CreateWaybill bool
}
type OrderManager interface {
LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error)
// OnOrderStatusChanged(status *model.OrderStatus) (err error) // 此消息是否使用还不确定
UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error)
}
type Scheduler interface {
RegisterOrderManager(handler OrderManager)
RegisterPurchasePlatform(vendorID int, handler PurchasePlatformHandler)
RegisterDeliveryPlatform(vendorID int, handler DeliveryPlatformHandler, isUse4CreateWaybill bool)
// 以下是订单
OnOrderNew(order *model.GoodsOrder, isPending bool) (err error)
OnOrderStatusChanged(status *model.OrderStatus, isPending bool) (err error)
// 以下是运单
OnWaybillStatusChanged(bill *model.Waybill, isPending bool) (err error)
}
type BaseScheduler struct {
CurOrderManager OrderManager
PurchasePlatformHandlers map[int]PurchasePlatformHandler
DeliveryPlatformHandlers map[int]*DeliveryPlatformHandlerInfo
IsReallyCallPlatformAPI bool
}
func (c *BaseScheduler) Init() {
c.PurchasePlatformHandlers = make(map[int]PurchasePlatformHandler)
c.DeliveryPlatformHandlers = make(map[int]*DeliveryPlatformHandlerInfo)
}
func (c *BaseScheduler) RegisterOrderManager(handler OrderManager) {
c.CurOrderManager = handler
}
func (c *BaseScheduler) RegisterPurchasePlatform(vendorID int, handler PurchasePlatformHandler) {
if !(vendorID >= model.VendorIDPurchaseBegin && vendorID <= model.VendorIDPurchaseEnd) {
panic(fmt.Sprintf("purchase vendor:%d is illegal", vendorID))
}
if _, ok := c.PurchasePlatformHandlers[vendorID]; ok {
panic(fmt.Sprintf("purchase vendor:%d, already exists", vendorID))
}
c.PurchasePlatformHandlers[vendorID] = handler
}
func (c *BaseScheduler) RegisterDeliveryPlatform(vendorID int, handler DeliveryPlatformHandler, isUse4CreateWaybill bool) {
if !(vendorID >= model.VendorIDDeliveryBegin && vendorID <= model.VendorIDDeliveryEnd) {
panic(fmt.Sprintf("delivery vendor:%d is illegal", vendorID))
}
if _, ok := c.DeliveryPlatformHandlers[vendorID]; ok {
panic(fmt.Sprintf("delivery vendor:%d, already exists", vendorID))
}
c.DeliveryPlatformHandlers[vendorID] = &DeliveryPlatformHandlerInfo{
Handler: handler,
Use4CreateWaybill: isUse4CreateWaybill,
}
}
func (c *BaseScheduler) GetPurchasePlatformFromVendorID(vendorID int) PurchasePlatformHandler {
return c.PurchasePlatformHandlers[vendorID]
}
func (c *BaseScheduler) GetDeliveryPlatformFromVendorID(vendorID int) *DeliveryPlatformHandlerInfo {
return c.DeliveryPlatformHandlers[vendorID]
}
func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) {
globals.SugarLogger.Infof("AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if order.Status == model.OrderStatusNew {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return c.GetPurchasePlatformFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt)
}, "AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
}
} else {
globals.SugarLogger.Infof("AcceptOrRefuseOrder orderID:%s, status:%d is not suitable, isAcceptIt:%t", order.VendorOrderID, order.Status, isAcceptIt)
}
return err
}
func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder) (err error) {
globals.SugarLogger.Infof("PickupGoods orderID:%s", order.VendorOrderID)
if order.Status == model.OrderStatusAccepted {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return c.GetPurchasePlatformFromVendorID(order.VendorID).PickupGoods(order)
}, "PickupGoods orderID:%s", order.VendorOrderID)
}
} else {
globals.SugarLogger.Infof("PickupGoods orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
}
return err
}
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder) (err error) {
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if order.Status == model.OrderStatusFinishedPickup {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return c.GetPurchasePlatformFromVendorID(order.VendorID).Swtich2SelfDeliver(order)
}, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
}
} else {
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
}
return err
}
func (c *BaseScheduler) SelfDeliverDelievering(order *model.GoodsOrder) (err error) {
globals.SugarLogger.Infof("SelfDeliverDelievering orderID:%s", order.VendorOrderID)
if order.Status == model.OrderStatusFinishedPickup {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return c.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelievering(order)
}, "SelfDeliverDelievering orderID:%s", order.VendorOrderID)
}
} else if order.Status == model.OrderStatusDelivering {
globals.SugarLogger.Debugf("SelfDeliverDelievering orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
} else {
globals.SugarLogger.Infof("SelfDeliverDelievering orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
}
return err
}
func (c *BaseScheduler) SelfDeliverDelievered(order *model.GoodsOrder) (err error) {
globals.SugarLogger.Infof("SelfDeliverDelievered orderID:%s", order.VendorOrderID)
if order.Status == model.OrderStatusDelivering {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return c.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelievered(order)
}, "SelfDeliverDelievered orderID:%s", order.VendorOrderID)
}
} else {
globals.SugarLogger.Infof("SelfDeliverDelievered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
}
return err
}
func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder) (err error) {
globals.SugarLogger.Infof("CreateWaybill orderID:%s, vendorID:%d", order.VendorOrderID, platformVendorID)
if !model.IsOrderSolid(order) { // 如果订单是不完整的
globals.SugarLogger.Warnf("CreateWaybill orderID:%s, vendorID:%d is not solid!!!", order.VendorOrderID, platformVendorID)
return ErrOrderIsNotSolid
}
if c.IsReallyCallPlatformAPI {
handlerInfo := c.GetDeliveryPlatformFromVendorID(platformVendorID)
if handlerInfo.Use4CreateWaybill {
if err = handlerInfo.Handler.CreateWaybill(order); err != nil {
globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err)
}
}
}
return err
}
func (c *BaseScheduler) CancelWaybill(bill *model.Waybill) (err error) {
globals.SugarLogger.Infof("CancelWaybill bill:%v", bill)
if c.IsReallyCallPlatformAPI && bill.OrderVendorID != bill.WaybillVendorID {
if handlerInfo := c.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID); handlerInfo != nil {
err = utils.CallFuncLogError(func() error {
return handlerInfo.Handler.CancelWaybill(bill)
}, "CancelWaybill bill:%v", bill)
globals.SugarLogger.Debugf("CancelWaybill bill:%v canceled by myself", bill)
}
}
return err
}
type BasePurchasePlatform struct {
}
func (p *BasePurchasePlatform) GetStatusActionTimeout(statusType, status int) time.Duration {
return 0
}