241 lines
9.3 KiB
Go
241 lines
9.3 KiB
Go
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
|
||
}
|