diff --git a/business/controller/order.go b/business/jxcallback/orderman/order.go similarity index 91% rename from business/controller/order.go rename to business/jxcallback/orderman/order.go index 16cc181f0..0f5e51f1a 100644 --- a/business/controller/order.go +++ b/business/jxcallback/orderman/order.go @@ -1,4 +1,4 @@ -package controller +package orderman import ( "fmt" @@ -6,22 +6,14 @@ import ( "git.rosy.net.cn/baseapi" "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/model" - "git.rosy.net.cn/jx-callback/business/scheduler" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego/orm" ) -// 所有公共接口调用前,要求在order里或status中设置合适的Status -type OrderController struct { -} - -func NewOrderManager() *OrderController { - return &OrderController{} -} - -func (c *OrderController) LoadPendingOrders() []*model.GoodsOrder { +func (c *OrderManager) LoadPendingOrders() []*model.GoodsOrder { db := orm.NewOrm() var orders []*model.GoodsOrder tillTime := time.Now().Add(-pendingOrderGapMax) @@ -46,7 +38,7 @@ func (c *OrderController) LoadPendingOrders() []*model.GoodsOrder { // msgVendorStatus的意思是事件本身的类型,类似有时收到NewOrder事件去取,订单状态不一定就是New的 // OnOrderAdjust也类似,而OrderStatus要记录的是消息,所以添加这个 -func (c *OrderController) OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error) { +func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error) { // todo transaction db := orm.NewOrm() if order.Status == model.OrderStatusUnknown { @@ -65,7 +57,7 @@ func (c *OrderController) OnOrderNew(order *model.GoodsOrder, msgVendorStatus st } // todo 调整单的处理可能还需要再细化一点,当前只是简单的删除重建 -func (c *OrderController) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error) { +func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error) { // todo transaction db := orm.NewOrm() if order.Status == model.OrderStatusUnknown { @@ -99,7 +91,7 @@ func (c *OrderController) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus return err } -func (c *OrderController) OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error) { +func (c *OrderManager) OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error) { isDuplicated, err := c.addOrderStatus(orderStatus, nil) if err == nil && !isDuplicated { err = scheduler.CurrentScheduler.OnOrderStatusChanged(orderStatus, false) @@ -111,7 +103,7 @@ func (c *OrderController) OnOrderStatusChanged(orderStatus *model.OrderStatus) ( } // private -func (c *OrderController) saveOrder(order *model.GoodsOrder, isAdjust bool, db orm.Ormer) (isDuplicated bool, err error) { +func (c *OrderManager) saveOrder(order *model.GoodsOrder, isAdjust bool, db orm.Ormer) (isDuplicated bool, err error) { // 忽略查找JX信息错误 c.updateOrderOtherInfo(order, db) order.ID = 0 @@ -170,7 +162,7 @@ func (c *OrderController) saveOrder(order *model.GoodsOrder, isAdjust bool, db o return isDuplicated, err } -func (c *OrderController) updateOrderSkuOtherInfo(order *model.GoodsOrder, db orm.Ormer) (err error) { +func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db orm.Ormer) (err error) { jxStoreID := jxutils.GetJxStoreIDFromOrder(order) if jxStoreID == 0 { globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]订单在京西与平台都找不到京西门店信息orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID) @@ -245,7 +237,7 @@ func (c *OrderController) updateOrderSkuOtherInfo(order *model.GoodsOrder, db or return err } -func (c *OrderController) updateOrderOtherInfo(order *model.GoodsOrder, db orm.Ormer) (err error) { +func (c *OrderManager) updateOrderOtherInfo(order *model.GoodsOrder, db orm.Ormer) (err error) { var sql string if order.VendorID == model.VendorIDJD { sql = ` @@ -274,7 +266,7 @@ func (c *OrderController) updateOrderOtherInfo(order *model.GoodsOrder, db orm.O return err } -func (c *OrderController) addOrderStatus(orderStatus *model.OrderStatus, db orm.Ormer) (isDuplicated bool, err error) { +func (c *OrderManager) addOrderStatus(orderStatus *model.OrderStatus, db orm.Ormer) (isDuplicated bool, err error) { if db == nil { db = orm.NewOrm() } @@ -329,7 +321,7 @@ func (c *OrderController) addOrderStatus(orderStatus *model.OrderStatus, db orm. return isDuplicated, err } -func (c *OrderController) LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) { +func (c *OrderManager) LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) { db := orm.NewOrm() order = &model.GoodsOrder{ VendorOrderID: vendorOrderID, @@ -347,8 +339,17 @@ func (c *OrderController) LoadOrder(vendorOrderID string, vendorID int) (order * return order, err } +func (c *OrderManager) UpdateOrderStatusDirectly(order *model.GoodsOrder) (err error) { + db := orm.NewOrm() + utils.CallFuncLogError(func() error { + _, err = db.Update(order, "Status") + return err + }, "UpdateOrderStatusDirectly orderID:%s failed with error:%v", order.VendorOrderID, err) + return err +} + //Waybill -func (c *OrderController) UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error) { +func (c *OrderManager) UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error) { globals.SugarLogger.Debugf("UpdateWaybillVendorID bill:%v", bill) db := orm.NewOrm() params := orm.Params{ diff --git a/business/controller/order_legacy.go b/business/jxcallback/orderman/order_legacy.go similarity index 96% rename from business/controller/order_legacy.go rename to business/jxcallback/orderman/order_legacy.go index a6e61b179..b77f707c5 100644 --- a/business/controller/order_legacy.go +++ b/business/jxcallback/orderman/order_legacy.go @@ -1,4 +1,4 @@ -package controller +package orderman import ( "strings" @@ -124,7 +124,7 @@ func legacyMapWaybillStatus(status int) (retVal int8) { return retVal } -func (c *OrderController) legacyWriteJxOrder(order *model.GoodsOrder, db orm.Ormer, isDelFirst bool) (err error) { +func (c *OrderManager) legacyWriteJxOrder(order *model.GoodsOrder, db orm.Ormer, isDelFirst bool) (err error) { var result map[string]interface{} businessTags := "" if order.VendorID == model.VendorIDJD && utils.UnmarshalUseNumber([]byte(order.OriginalData), &result) == nil { @@ -223,7 +223,7 @@ func (c *OrderController) legacyWriteJxOrder(order *model.GoodsOrder, db orm.Orm return err } -func (c *OrderController) legacyJxOrderStatusChanged(status *model.OrderStatus, db orm.Ormer) (err error) { +func (c *OrderManager) legacyJxOrderStatusChanged(status *model.OrderStatus, db orm.Ormer) (err error) { orderStatus := legacyMapOrderStatus(status.Status) if orderStatus != JX_STATUS_UNKNOWN { if status.VendorID == model.VendorIDELM { @@ -268,7 +268,7 @@ func (c *OrderController) legacyJxOrderStatusChanged(status *model.OrderStatus, return err } -func (c *WaybillController) legacyWaybillStatusChanged(bill *model.Waybill, db orm.Ormer) (err error) { +func (c *OrderManager) legacyWaybillStatusChanged(bill *model.Waybill, db orm.Ormer) (err error) { deliveryStatus := legacyMapWaybillStatus(bill.Status) if deliveryStatus != JX_STATUS_UNKNOWN { if db == nil { diff --git a/business/controller/controller.go b/business/jxcallback/orderman/orderman.go similarity index 84% rename from business/controller/controller.go rename to business/jxcallback/orderman/orderman.go index 6edca7dc6..e07ed3879 100644 --- a/business/controller/controller.go +++ b/business/jxcallback/orderman/orderman.go @@ -1,14 +1,15 @@ -package controller +package orderman import ( "sort" "time" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" + _ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch" // 导入缺省订单调度器 "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" - _ "git.rosy.net.cn/jx-callback/business/scheduler/defsch" // 导入缺省订单调度器 + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego/orm" ) @@ -20,15 +21,22 @@ const ( ) var ( - OrderManager *OrderController - WaybillManager *WaybillController + FixedOrderManager *OrderManager ) -type StatusTimer interface { +// 所有公共接口调用前,要求在order里或status中设置合适的Status +type OrderManager struct { +} + +func NewOrderManager() *OrderManager { + return &OrderManager{} +} + +type IStatusTimer interface { GetStatusTime() time.Time } -type StatusTimerSlice []StatusTimer +type StatusTimerSlice []IStatusTimer func (s StatusTimerSlice) Len() int { return len(s) @@ -45,9 +53,8 @@ func (s StatusTimerSlice) Swap(i, j int) { } func init() { - OrderManager = NewOrderManager() - WaybillManager = NewWaybillManager() - scheduler.CurrentScheduler.RegisterOrderManager(OrderManager) + FixedOrderManager = NewOrderManager() + partner.Init(FixedOrderManager) } func addOrderOrWaybillStatus(status *model.OrderStatus, db orm.Ormer) (isDuplicated bool, err error) { @@ -79,12 +86,12 @@ func addOrderOrWaybillStatus(status *model.OrderStatus, db orm.Ormer) (isDuplica // todo 最好还是改成全事件回放算了 func LoadPendingOrders() { - orders := OrderManager.LoadPendingOrders() + orders := FixedOrderManager.LoadPendingOrders() globals.SugarLogger.Infof("LoadPendingOrders orders count:%d", len(orders)) ordersCount := len(orders) if ordersCount > 0 { - bills := WaybillManager.LoadPendingWaybills() + bills := FixedOrderManager.LoadPendingWaybills() globals.SugarLogger.Infof("LoadPendingOrders waybills count:%d", len(bills)) var sortOrders StatusTimerSlice for _, order := range orders { diff --git a/business/jxcallback/orderman/orderman_ext.go b/business/jxcallback/orderman/orderman_ext.go new file mode 100644 index 000000000..6889dbe76 --- /dev/null +++ b/business/jxcallback/orderman/orderman_ext.go @@ -0,0 +1,97 @@ +package orderman + +import ( + "errors" + "time" + + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" + + "github.com/astaxie/beego/orm" +) + +const ( + maxLastHours = 7 * 24 // 最多只能查询7天内的订单数据 + defLastHours = 2 * 24 // 缺省是两天内的订单 + defPageSize = 50 +) + +var ( + ErrCanNotFindOrder = errors.New("找不到相应订单") +) + +func (c *OrderManager) GetStoreOrderInfo(storeID string, lastHours int, fromStatus, toStatus, offset, pageSize int) (orders []*model.GoodsOrderExt, err error) { + if lastHours > maxLastHours { + lastHours = maxLastHours + } else if lastHours == 0 { + lastHours = defLastHours + } + if toStatus == 0 { + toStatus = fromStatus + } + if offset < 0 { + offset = 0 + } + if pageSize == 0 { + pageSize = defPageSize + } + + db := orm.NewOrm() + _, err = db.Raw(` + SELECT t1.*, t2.status waybill_status, t2.courier_name, t2.courier_mobile + FROM goods_order t1 + LEFT JOIN waybill t2 ON t1.vendor_waybill_id = t2.vendor_waybill_id AND t1.waybill_vendor_id = t2.waybill_vendor_id + WHERE IF(t1.jx_store_id != 0, t1.jx_store_id, t1.store_id) = ? + AND t1.order_created_at >= ? + AND t1.Status >= ? AND t1.Status <= ? + LIMIT ? OFFSET ? + `, storeID, time.Now().Add(-time.Duration(lastHours)*time.Hour), fromStatus, toStatus, pageSize, offset).QueryRows(&orders) + if err == nil { + return orders, nil + } + globals.SugarLogger.Infof("GetStoreOrderInfo storeID:%s failed with error:%v", storeID, err) + return nil, err +} + +func (c *OrderManager) GetStoreOrderCountInfo(storeID string, lastHours int) (countInfo []*model.GoodsOrderCountInfo, err error) { + if lastHours > maxLastHours { + lastHours = maxLastHours + } else if lastHours == 0 { + lastHours = defLastHours + } + + db := orm.NewOrm() + _, err = db.Raw(` + SELECT t1.status, COUNT(*) count + FROM goods_order t1 + WHERE IF(t1.jx_store_id != 0, t1.jx_store_id, t1.store_id) = ? + AND t1.order_created_at >= ? + GROUP BY 1 + `, storeID, time.Now().Add(-time.Duration(lastHours)*time.Hour)).QueryRows(&countInfo) + if err == nil { + return countInfo, nil + } + globals.SugarLogger.Infof("GetStoreOrderCountInfo storeID:%s failed with error:%v", storeID, err) + return nil, err +} + +func (c *OrderManager) GetOrderSkuInfo(vendorOrderID string, vendorID int) (skus []*model.OrderSkuExt, err error) { + db := orm.NewOrm() + num, err := db.Raw(` + SELECT t1.*, t3.img image + FROM order_sku t1 + LEFT JOIN jx_sku t2 ON IF(t1.jx_sku_id != 0, t1.jx_sku_id, t1.sku_id) = t2.id + LEFT JOIN jx_sku_name t3 ON t2.nameid = t3.id + WHERE vendor_order_id = ? AND vendor_id = ? + `, vendorOrderID, vendorID).QueryRows(&skus) + if err == nil && num > 0 { + return skus, nil + } + if err == nil { + err = ErrCanNotFindOrder + globals.SugarLogger.Infof("GetOrderSkuInfo orderID:%s vendorID:%d can not find order, num:%d", vendorOrderID, vendorID, num) + } else { + globals.SugarLogger.Infof("GetOrderSkuInfo orderID:%s vendorID:%d failed with error:%v", vendorOrderID, vendorID, err) + } + return nil, err +} diff --git a/business/controller/waybill.go b/business/jxcallback/orderman/waybill.go similarity index 74% rename from business/controller/waybill.go rename to business/jxcallback/orderman/waybill.go index d16e2f171..3269df500 100644 --- a/business/controller/waybill.go +++ b/business/jxcallback/orderman/waybill.go @@ -1,24 +1,16 @@ -package controller +package orderman import ( "time" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego/orm" ) -// 所有公共接口调用前,要求在order里或status中设置合适的Status -type WaybillController struct { -} - -func NewWaybillManager() *WaybillController { - return &WaybillController{} -} - -func (w *WaybillController) LoadPendingWaybills() []*model.Waybill { +func (w *OrderManager) LoadPendingWaybills() []*model.Waybill { db := orm.NewOrm() var bills []*model.Waybill tillTime := time.Now().Add(-pendingOrderGapMax) @@ -39,7 +31,7 @@ func (w *WaybillController) LoadPendingWaybills() []*model.Waybill { return bills } -func (w *WaybillController) onWaybillNew(bill2 *model.Waybill, db orm.Ormer) (isDuplicated bool, err error) { +func (w *OrderManager) onWaybillNew(bill2 *model.Waybill, db orm.Ormer) (isDuplicated bool, err error) { globals.SugarLogger.Debugf("onWaybillNew bill:%v", bill2) isDuplicated, err = addOrderOrWaybillStatus(model.Waybill2Status(bill2), db) if err == nil && !isDuplicated { @@ -71,19 +63,21 @@ func (w *WaybillController) onWaybillNew(bill2 *model.Waybill, db orm.Ormer) (is return isDuplicated, err } -func (w *WaybillController) OnWaybillStatusChanged(bill *model.Waybill) (err error) { +func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) { var isDuplicated bool db := orm.NewOrm() if bill.Status == model.WaybillStatusNew { isDuplicated, err = w.onWaybillNew(bill, db) } else { - var addParams orm.Params - if bill.Status == model.WaybillStatusAccepted { - addParams = orm.Params{ - "courier_name": bill.CourierName, - "courier_mobile": bill.CourierMobile, - "desired_fee": bill.DesiredFee, + addParams := orm.Params{} + if bill.Status >= model.WaybillStatusAccepted && bill.Status < model.WaybillStatusEndBegin { + if bill.Status == model.WaybillStatusAccepted { + addParams["desired_fee"] = bill.DesiredFee } + addParams["courier_name"] = bill.CourierName + addParams["courier_mobile"] = bill.CourierMobile + } else if bill.Status >= model.WaybillStatusEndBegin { + addParams["waybill_finished_at"] = bill.StatusTime } isDuplicated, err = w.addWaybillStatus(bill, db, addParams) } @@ -96,7 +90,7 @@ func (w *WaybillController) OnWaybillStatusChanged(bill *model.Waybill) (err err return err } -func (w *WaybillController) addWaybillStatus(bill *model.Waybill, db orm.Ormer, addParams orm.Params) (isDuplicated bool, err error) { +func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db orm.Ormer, addParams orm.Params) (isDuplicated bool, err error) { waybillStatus := model.Waybill2Status(bill) isDuplicated, err = addOrderOrWaybillStatus(waybillStatus, db) if err == nil && !isDuplicated && waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法,状态不能回绕 @@ -105,9 +99,6 @@ func (w *WaybillController) addWaybillStatus(bill *model.Waybill, db orm.Ormer, "vendor_status": bill.VendorStatus, "status_time": bill.StatusTime, }, addParams) - if bill.Status >= model.WaybillStatusEndBegin { - params["waybill_finished_at"] = bill.StatusTime - } utils.CallFuncLogError(func() error { _, err = db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Update(params) return err diff --git a/business/scheduler/scheduler.go b/business/jxcallback/scheduler/basesch/basesch.go similarity index 58% rename from business/scheduler/scheduler.go rename to business/jxcallback/scheduler/basesch/basesch.go index 21796d725..fe7271167 100644 --- a/business/scheduler/scheduler.go +++ b/business/jxcallback/scheduler/basesch/basesch.go @@ -1,114 +1,36 @@ -package scheduler +package basesch import ( "errors" "fmt" - "time" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner" "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) - - // 将订单从购物平台配送转为自送后又送达 - Swtich2SelfDelivered(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 + PurchasePlatformHandlers map[int]partner.IPurchasePlatformHandler + DeliveryPlatformHandlers map[int]*scheduler.DeliveryPlatformHandlerInfo IsReallyCallPlatformAPI bool } +var ( + FixedBaseScheduler *BaseScheduler +) + +var ( + ErrOrderStatusIsNotSuitable = errors.New("订单状态不适合当前操作") +) + func (c *BaseScheduler) Init() { - c.PurchasePlatformHandlers = make(map[int]PurchasePlatformHandler) - c.DeliveryPlatformHandlers = make(map[int]*DeliveryPlatformHandlerInfo) + c.PurchasePlatformHandlers = make(map[int]partner.IPurchasePlatformHandler) + c.DeliveryPlatformHandlers = make(map[int]*scheduler.DeliveryPlatformHandlerInfo) } -func (c *BaseScheduler) RegisterOrderManager(handler OrderManager) { - c.CurOrderManager = handler -} - -func (c *BaseScheduler) RegisterPurchasePlatform(vendorID int, handler PurchasePlatformHandler) { +func (c *BaseScheduler) RegisterPurchasePlatform(vendorID int, handler partner.IPurchasePlatformHandler) { if !(vendorID >= model.VendorIDPurchaseBegin && vendorID <= model.VendorIDPurchaseEnd) { panic(fmt.Sprintf("purchase vendor:%d is illegal", vendorID)) } @@ -118,33 +40,33 @@ func (c *BaseScheduler) RegisterPurchasePlatform(vendorID int, handler PurchaseP c.PurchasePlatformHandlers[vendorID] = handler } -func (c *BaseScheduler) RegisterDeliveryPlatform(vendorID int, handler DeliveryPlatformHandler, isUse4CreateWaybill bool) { +func (c *BaseScheduler) RegisterDeliveryPlatform(vendorID int, handler partner.IDeliveryPlatformHandler, 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{ + c.DeliveryPlatformHandlers[vendorID] = &scheduler.DeliveryPlatformHandlerInfo{ Handler: handler, Use4CreateWaybill: isUse4CreateWaybill, } } -func (c *BaseScheduler) GetPurchasePlatformFromVendorID(vendorID int) PurchasePlatformHandler { +func (c *BaseScheduler) GetPurchasePlatformFromVendorID(vendorID int) partner.IPurchasePlatformHandler { return c.PurchasePlatformHandlers[vendorID] } -func (c *BaseScheduler) GetDeliveryPlatformFromVendorID(vendorID int) *DeliveryPlatformHandlerInfo { +func (c *BaseScheduler) GetDeliveryPlatformFromVendorID(vendorID int) *scheduler.DeliveryPlatformHandlerInfo { return c.DeliveryPlatformHandlers[vendorID] } -func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) { +func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { globals.SugarLogger.Infof("AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt) if order.LockStatus == model.OrderStatusUnknown && order.Status == model.OrderStatusNew { if c.IsReallyCallPlatformAPI { err = utils.CallFuncLogErrorWithInfo(func() error { - return c.GetPurchasePlatformFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt) + return c.GetPurchasePlatformFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt, userName) }, "AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt) } } else { @@ -152,43 +74,50 @@ func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt } return err } -func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder) (err error) { + +func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Infof("PickupGoods orderID:%s", order.VendorOrderID) if order.LockStatus == model.OrderStatusUnknown && order.Status == model.OrderStatusAccepted { if c.IsReallyCallPlatformAPI { err = utils.CallFuncLogErrorWithInfo(func() error { - return c.GetPurchasePlatformFromVendorID(order.VendorID).PickupGoods(order) + return c.GetPurchasePlatformFromVendorID(order.VendorID).PickupGoods(order, userName) }, "PickupGoods orderID:%s", order.VendorOrderID) } } else { + if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusAccepted { + err = ErrOrderStatusIsNotSuitable + } 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) { +func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s", order.VendorOrderID) if order.LockStatus == model.OrderStatusUnknown && order.Status == model.OrderStatusFinishedPickup { if c.IsReallyCallPlatformAPI { err = utils.CallFuncLogErrorWithInfo(func() error { - return c.GetPurchasePlatformFromVendorID(order.VendorID).Swtich2SelfDeliver(order) + return c.GetPurchasePlatformFromVendorID(order.VendorID).Swtich2SelfDeliver(order, userName) }, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID) if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中 order.Status = model.OrderStatusDelivering } } } else { + if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup { + err = ErrOrderStatusIsNotSuitable + } globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status) } return err } -func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder) (err error) { +func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s", order.VendorOrderID) if order.LockStatus == model.OrderStatusUnknown && order.Status == model.OrderStatusDelivering { if c.IsReallyCallPlatformAPI { err = utils.CallFuncLogError(func() error { - return c.GetPurchasePlatformFromVendorID(order.VendorID).Swtich2SelfDelivered(order) + return c.GetPurchasePlatformFromVendorID(order.VendorID).Swtich2SelfDelivered(order, userName) }, "Swtich2SelfDelivered orderID:%s", order.VendorOrderID) } } else { @@ -197,12 +126,12 @@ func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder) (err error return err } -func (c *BaseScheduler) SelfDeliverDelievering(order *model.GoodsOrder) (err error) { +func (c *BaseScheduler) SelfDeliverDelievering(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Infof("SelfDeliverDelievering orderID:%s", order.VendorOrderID) if order.LockStatus == model.OrderStatusUnknown && order.Status == model.OrderStatusFinishedPickup { if c.IsReallyCallPlatformAPI { err = utils.CallFuncLogError(func() error { - return c.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelievering(order) + return c.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelievering(order, userName) }, "SelfDeliverDelievering orderID:%s", order.VendorOrderID) if err == nil { // 因为有些平台设置配送中后,不会发送订单在配送中消息过来,所以成功后就强制设置状态为配送中 order.Status = model.OrderStatusDelivering @@ -216,12 +145,12 @@ func (c *BaseScheduler) SelfDeliverDelievering(order *model.GoodsOrder) (err err return err } -func (c *BaseScheduler) SelfDeliverDelievered(order *model.GoodsOrder) (err error) { +func (c *BaseScheduler) SelfDeliverDelievered(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Infof("SelfDeliverDelievered orderID:%s", order.VendorOrderID) if order.LockStatus == model.OrderStatusUnknown && order.Status == model.OrderStatusDelivering { if c.IsReallyCallPlatformAPI { err = utils.CallFuncLogError(func() error { - return c.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelievered(order) + return c.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelievered(order, userName) }, "SelfDeliverDelievered orderID:%s", order.VendorOrderID) } } else { @@ -230,39 +159,35 @@ func (c *BaseScheduler) SelfDeliverDelievered(order *model.GoodsOrder) (err erro return err } -func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder) (err error) { +func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder, policy func(deliveryFee, addFee int64) error) (bill *model.Waybill, 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 + return nil, scheduler.ErrOrderIsNotSolid } if c.IsReallyCallPlatformAPI { handlerInfo := c.GetDeliveryPlatformFromVendorID(platformVendorID) - if handlerInfo.Use4CreateWaybill { - if err = handlerInfo.Handler.CreateWaybill(order); err != nil { + if handlerInfo != nil && handlerInfo.Use4CreateWaybill { + bill, err = handlerInfo.Handler.CreateWaybill(order, policy) + if err != nil { globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err) } + } else { + err = scheduler.ErrDeliverProviderWrong } } - return err + return bill, err } -func (c *BaseScheduler) CancelWaybill(bill *model.Waybill) (err error) { - globals.SugarLogger.Infof("CancelWaybill bill:%v", bill) +func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) { + globals.SugarLogger.Infof("CancelWaybill bill:%v, cancelReasonID:%d cancelReason:%s", bill, cancelReasonID, cancelReason) 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) + return handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason) }, "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 -} diff --git a/business/jxcallback/scheduler/basesch/basesch_ext.go b/business/jxcallback/scheduler/basesch/basesch_ext.go new file mode 100644 index 000000000..ccc7371c0 --- /dev/null +++ b/business/jxcallback/scheduler/basesch/basesch_ext.go @@ -0,0 +1,43 @@ +package basesch + +import ( + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner" +) + +func (c *BaseScheduler) CreateWaybillOnProviders(vendorOrderID string, vendorID int) (bills []*model.Waybill, err error) { + order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) + if err == nil { + bill, err2 := c.CreateWaybill(model.VendorIDMTPS, order, nil) + if err = err2; err == nil { + return []*model.Waybill{ + bill, + }, nil + } + } + return nil, err +} + +func (c *BaseScheduler) Swtich2SelfDeliverAndUpdateStatus(vendorOrderID string, vendorID int, userName string) (err error) { + order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) + if err == nil { + err = c.Swtich2SelfDeliver(order, userName) + if err == nil { + order.Status = model.OrderStatusDelivering + err = partner.CurOrderManager.UpdateOrderStatusDirectly(order) + } + } + return err +} + +func (c *BaseScheduler) PickupGoodsAndUpdateStatus(vendorOrderID string, vendorID int, userName string) (err error) { + order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) + if err == nil { + err = c.PickupGoods(order, userName) + if err == nil { + order.Status = model.OrderStatusFinishedPickup + err = partner.CurOrderManager.UpdateOrderStatusDirectly(order) + } + } + return err +} diff --git a/business/scheduler/defsch/defsch.go b/business/jxcallback/scheduler/defsch/defsch.go similarity index 90% rename from business/scheduler/defsch/defsch.go rename to business/jxcallback/scheduler/defsch/defsch.go index 5c3d8cec4..5ec3e05a6 100644 --- a/business/scheduler/defsch/defsch.go +++ b/business/jxcallback/scheduler/defsch/defsch.go @@ -1,17 +1,19 @@ package defsch import ( + "errors" "fmt" + "math/rand" "time" - "math/rand" - "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/basesch" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg" "git.rosy.net.cn/jx-callback/business/legacymodel" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego/orm" ) @@ -33,6 +35,14 @@ const ( orderMapStoreMaxTime = 4 * 24 * time.Hour // cache最长存储时间 ) +const ( + maxAddFee = 200 // 最大增加费用,单位为分,超过不发三方配送了 +) + +var ( + ErrAddFeeExceeded = errors.New("配送超过基准价太多") +) + type WatchOrderInfo struct { autoPickupTimeoutMinute int // 0表示禁用,1表示用缺省值time2AutoPickupMin,其它表示分钟数 storeDeliveryType int @@ -58,7 +68,7 @@ type StatusActionConfig struct { // 重要:此调度器要求同一定单的处理逻辑必须是序列化了的,不然会有并发问题 type DefScheduler struct { - scheduler.BaseScheduler + basesch.BaseScheduler defWorkflowConfig []map[int]*StatusActionConfig orderMap jxutils.SyncMapWithTimeout } @@ -87,7 +97,7 @@ func (s *WatchOrderInfo) SetOrder(order *model.GoodsOrder) (retVal *model.GoodsO } func (s *WatchOrderInfo) updateOrderStoreFeature(order *model.GoodsOrder) (err error) { - storefeature := &model.Jxstorefeature{ + storefeature := &legacymodel.Jxstorefeature{ Id: jxutils.GetJxStoreIDFromOrder(order), } if storefeature.Id > 0 { @@ -132,6 +142,7 @@ func init() { sch := &DefScheduler{} sch.IsReallyCallPlatformAPI = globals.ReallyCallPlatformAPI sch.Init() + basesch.FixedBaseScheduler = &sch.BaseScheduler scheduler.CurrentScheduler = sch sch.defWorkflowConfig = []map[int]*StatusActionConfig{ map[int]*StatusActionConfig{ @@ -141,7 +152,7 @@ func init() { 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 { - if err = sch.AcceptOrRefuseOrder(order, isAcceptIt); err != nil { + if err = sch.AcceptOrRefuseOrder(order, isAcceptIt, ""); err != nil { // 为了解决京东新消息与接单消息乱序的问题 if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 && errWithCode.IntCode() == -1 { if order2, err2 := sch.GetPurchasePlatformFromVendorID(order.VendorID).GetOrder(order.VendorOrderID); err2 == nil && order2.Status > order.Status { @@ -227,7 +238,7 @@ func (s *DefScheduler) OnOrderStatusChanged(status *model.OrderStatus, isPending globals.SugarLogger.Infof("OnOrderStatusChanged [运营2]订单orderID:%s可能被手动点击送达,会对程序状态产生不利影响,请通知门店不要这样操作!", status.VendorOrderID) } } - s.cancelOtherWaybills(savedOrderInfo, curWaybill) + s.cancelOtherWaybills(savedOrderInfo, curWaybill, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrOrderAlreadyFinished) s.orderMap.Delete(jxutils.GetUniversalOrderIDFromOrderStatus(status)) } } else if status.LockStatus != model.OrderStatusUnknown { @@ -255,11 +266,11 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo s.addWaybill2Map(savedOrderInfo, bill) if !isPending { if order.Status > model.OrderStatusEndBegin { - s.CancelWaybill(bill) + s.CancelWaybill(bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) } else if order.WaybillVendorID != model.VendorIDUnknown { globals.SugarLogger.Debugf("OnWaybillStatusChanged multiple waybill created, bill:%v", bill) if !s.isBillCandidate(order, bill) && bill.WaybillVendorID != order.VendorID { - s.CancelWaybill(bill) + s.CancelWaybill(bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) } 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) } @@ -282,10 +293,10 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo globals.SugarLogger.Infof("OnWaybillStatusChanged orderID:%s purchase platform waybill arrvied later, may case problem", order.VendorOrderID) } s.updateOrderByBill(order, bill, false) - s.cancelOtherWaybills(savedOrderInfo, bill) + s.cancelOtherWaybills(savedOrderInfo, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) if bill.WaybillVendorID != bill.OrderVendorID { if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore { - s.SelfDeliverDelievering(savedOrderInfo.order) + s.SelfDeliverDelievering(savedOrderInfo.order, "") } else { s.swtich2SelfDeliverWithRetry(savedOrderInfo, bill, 2, 10*time.Second) } @@ -295,7 +306,7 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo } } else if !s.isBillCandidate(order, bill) && bill.WaybillVendorID != order.VendorID { // 发生这种情况的原因就是两个接单事件几乎同时到达(来不及取消),也算正常 - s.CancelWaybill(bill) + s.CancelWaybill(bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) globals.SugarLogger.Infof("OnWaybillStatusChanged Accepted orderID:%s got multiple bill:%v", order.VendorOrderID, bill) } } @@ -309,14 +320,14 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo s.createWaybillOn3rdProviders(savedOrderInfo, bill) } } else if order.WaybillVendorID != model.VendorIDUnknown { - s.CancelWaybill(bill) + s.CancelWaybill(bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) globals.SugarLogger.Warnf("OnWaybillStatusChanged AcceptCanceled orderID:%s got multiple bill:%v, order details:%v", order.VendorOrderID, bill, order) } case model.WaybillStatusCourierArrived: // do nothing s.resetTimer(savedOrderInfo, bill, isPending) if s.isBillCandidate(order, bill) { } else { - // s.CancelWaybill(bill) + // s.CancelWaybill(bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) globals.SugarLogger.Infof("OnWaybillStatusChanged CourierArrived order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill) } case model.WaybillStatusFailed: // todo WaybillStatusFailed理解成订单整个失败了,不需要再尝试创建运单了,注意这里应该加个zabbix日志的报警 @@ -351,7 +362,7 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo if s.isBillCandidate(order, bill) { // do nothing } else { - // s.CancelWaybill(bill) + // s.CancelWaybill(bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime) globals.SugarLogger.Infof("OnWaybillStatusChanged Delivering order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill) } case model.WaybillStatusDelivered: @@ -359,9 +370,9 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo s.removeWaybillFromMap(savedOrderInfo, bill) if order.VendorID != bill.WaybillVendorID && !isPending { if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore { - s.SelfDeliverDelievered(order) + s.SelfDeliverDelievered(order, "") } else { - s.Swtich2SelfDelivered(order) + s.Swtich2SelfDelivered(order, "") } } if !s.isBillCandidate(order, bill) { @@ -404,8 +415,24 @@ func (s *DefScheduler) createWaybillOn3rdProviders(savedOrderInfo *WatchOrderInf if savedOrderInfo.retryCount <= maxWaybillRetryCount { successCount := 0 for _, vendorID := range savedOrderInfo.supported3rdCarriers { - if s.DeliveryPlatformHandlers[vendorID] != nil && s.DeliveryPlatformHandlers[vendorID].Use4CreateWaybill && savedOrderInfo.waybills[vendorID] == nil && (excludeBill == nil || vendorID != excludeBill.WaybillVendorID) { - if err = s.CreateWaybill(vendorID, order); err == nil { + handlerInfo := s.GetDeliveryPlatformFromVendorID(vendorID) + if handlerInfo != nil && handlerInfo.Use4CreateWaybill && savedOrderInfo.waybills[vendorID] == nil && (excludeBill == nil || vendorID != excludeBill.WaybillVendorID) { + if _, err = s.CreateWaybill(vendorID, order, func(deliveryFee, addFee int64) error { + if addFee > maxAddFee { + db := orm.NewOrm() + globals.SugarLogger.Infof("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee) + + tmpLog := &legacymodel.TempLog{ + VendorOrderID: order.VendorOrderID, + RefVendorOrderID: order.VendorOrderID, + IntValue1: addFee, + Msg: fmt.Sprintf("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee), + } + db.Insert(tmpLog) + return ErrAddFeeExceeded + } + return nil + }); err == nil { successCount++ } } @@ -437,11 +464,11 @@ func (s *DefScheduler) createWaybillOn3rdProviders(savedOrderInfo *WatchOrderInf return err } -func (s *DefScheduler) cancelOtherWaybills(savedOrderInfo *WatchOrderInfo, bill2Keep *model.Waybill) (err error) { +func (s *DefScheduler) cancelOtherWaybills(savedOrderInfo *WatchOrderInfo, bill2Keep *model.Waybill, cancelReasonID int, cancelReason string) (err error) { globals.SugarLogger.Debugf("cancelOtherWaybills, orderID:%s, bill:%v", savedOrderInfo.order.VendorOrderID, bill2Keep) for _, v := range savedOrderInfo.waybills { if (v.OrderVendorID != v.WaybillVendorID) && (bill2Keep == nil || !(v.WaybillVendorID == bill2Keep.WaybillVendorID && v.VendorWaybillID == bill2Keep.VendorWaybillID)) { - s.CancelWaybill(v) + s.CancelWaybill(v, cancelReasonID, cancelReason) } } return nil @@ -451,7 +478,7 @@ func (s *DefScheduler) swtich2SelfDeliverWithRetry(savedOrderInfo *WatchOrderInf order := savedOrderInfo.order globals.SugarLogger.Debugf("swtich2SelfDeliverWithRetry orderID:%s", order.VendorOrderID) if order.WaybillVendorID != order.VendorID { - if err := s.Swtich2SelfDeliver(order); err != nil { + if err := s.Swtich2SelfDeliver(order, ""); err != nil { globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry failed, bill:%v, err:%v", bill, err) if retryCount > 0 { time.AfterFunc(duration, func() { @@ -470,7 +497,7 @@ func (s *DefScheduler) swtich2SelfDeliverWithRetry(savedOrderInfo *WatchOrderInf db := orm.NewOrm() db.Insert(tmpLog) - if s.CancelWaybill(bill) == nil { + if s.CancelWaybill(bill, partner.CancelWaybillReasonSwitch2SelfFailed, partner.CancelWaybillReasonStrSwitch2SelfFailed) == nil { // 转自送失败的取消,要将订单中的运单状态更新 if s.isBillCandidate(order, bill) { bill.WaybillVendorID = model.VendorIDUnknown @@ -503,7 +530,7 @@ func (s *DefScheduler) loadSavedOrderFromMap(status *model.OrderStatus, isAutoLo } else { 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 := partner.CurOrderManager.LoadOrder(status.RefVendorOrderID, status.RefVendorID); err == nil { realSavedInfo.SetOrder(order) } else { realSavedInfo.SetOrder(&model.GoodsOrder{ @@ -661,7 +688,7 @@ func (s *DefScheduler) updateOrderByBill(order *model.GoodsOrder, bill *model.Wa if bill.WaybillVendorID == model.VendorIDUnknown { bill.VendorWaybillID = "" } - s.CurOrderManager.UpdateWaybillVendorID(bill, revertStatus) + partner.CurOrderManager.UpdateWaybillVendorID(bill, revertStatus) order.WaybillVendorID = bill.WaybillVendorID order.VendorWaybillID = bill.VendorWaybillID if revertStatus { @@ -670,7 +697,7 @@ func (s *DefScheduler) updateOrderByBill(order *model.GoodsOrder, bill *model.Wa } func (s *DefScheduler) autoPickupGood(order *model.GoodsOrder) (err error) { - return s.PickupGoods(order) + return s.PickupGoods(order, "") } func (s *DefScheduler) isBillCandidate(order *model.GoodsOrder, bill *model.Waybill) bool { diff --git a/business/jxcallback/scheduler/scheduler.go b/business/jxcallback/scheduler/scheduler.go new file mode 100644 index 000000000..b76c402e0 --- /dev/null +++ b/business/jxcallback/scheduler/scheduler.go @@ -0,0 +1,66 @@ +package scheduler + +import ( + "errors" + "time" + + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner" +) + +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 IScheduler +) + +var ( + ErrStatusIsNotOKForOperation = errors.New("当前状态操作无效") + ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建") + ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)") + ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)") + ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单") + ErrDeliverProviderWrong = errors.New("快递商不存在或不能用于创建运单") +) + +type DeliveryPlatformHandlerInfo struct { + Handler partner.IDeliveryPlatformHandler + Use4CreateWaybill bool +} + +type IScheduler interface { + RegisterPurchasePlatform(vendorID int, handler partner.IPurchasePlatformHandler) + RegisterDeliveryPlatform(vendorID int, handler partner.IDeliveryPlatformHandler, 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 BasePurchasePlatform struct { +} + +func (p *BasePurchasePlatform) GetStatusActionTimeout(statusType, status int) time.Duration { + return 0 +} diff --git a/business/jxstore/cms/cms.go b/business/jxstore/cms/cms.go new file mode 100644 index 000000000..ebaef5b20 --- /dev/null +++ b/business/jxstore/cms/cms.go @@ -0,0 +1,72 @@ +package cms + +import ( + "reflect" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/globals/gormdb" + "github.com/qor/admin" + "github.com/qor/qor" + "github.com/qor/qor/resource" +) + +var ( + curAdmin *admin.Admin +) + +func Init() { + gormdb.Init() + curAdmin = admin.New(&admin.AdminConfig{ + DB: gormdb.GetDB(), + SiteName: "京西管理系统v0.0.1", + }) + storeRes := curAdmin.AddResource(&model.Store{}) + lngMeta := storeRes.GetMeta("Lng") + lngMeta.Type = "float" + lngMeta.SetSetter(func(record interface{}, metaValue *resource.MetaValue, context *qor.Context) { + store := record.(*model.Store) + store.Lng = int(utils.Str2Float64((metaValue.Value.([]string))[0]) * 1000000) + globals.SugarLogger.Debugf("metaValue:%v", reflect.TypeOf(metaValue.Value)) + }) + lngMeta.SetValuer(func(record interface{}, context *qor.Context) (result interface{}) { + store := record.(*model.Store) + result = float64(store.Lng) / 1000000 + return result + }) + curAdmin.AddResource(&model.StoreSub{}) + + curAdmin.AddResource(&model.Sku{}) + curAdmin.AddResource(&model.SkuName{}) +} + +func GetAdmin() *admin.Admin { + return curAdmin +} + +// func SaveMapSlice2DB(db *gorm.DB, data []map[string]interface{}, tableName string, keyMaps map[string]string) { +// if len(data) == 0 { +// return +// } + +// sql := "INSERT INTO " + tableName + "(" +// for k := range data[0] { +// realK, ok := keyMaps[k] +// if !ok { +// realK = k +// } +// sql += realK + "," +// } +// sql = sql[:len(sql)-1] + ") " + +// for _, dataRow := range data { +// for k, v := range dataRow { +// realK, ok := keyMaps[k] +// if !ok { +// realK = k +// } +// sql += "(" +// } +// } +// } diff --git a/business/jxutils/jxutils.go b/business/jxutils/jxutils.go index 8f30abbea..d44325383 100644 --- a/business/jxutils/jxutils.go +++ b/business/jxutils/jxutils.go @@ -179,3 +179,15 @@ func MapValue2Scope(value, fromMin, fromMax, toMin, toMax int64) int64 { } return int64(math.Round(float64(value-fromMin)/float64(fromMax-fromMin)*float64(toMax-toMin) + float64(toMin))) } + +func Errs2Str(sep string, errs ...error) (retVal string) { + if sep == "" { + sep = "\n" + } + for _, err := range errs { + if err != nil { + retVal += err.Error() + sep + } + } + return retVal +} diff --git a/business/model/jxstorefeature.go b/business/legacymodel/jxstorefeature.go similarity index 98% rename from business/model/jxstorefeature.go rename to business/legacymodel/jxstorefeature.go index d1b0cb1bd..219fbc806 100644 --- a/business/model/jxstorefeature.go +++ b/business/legacymodel/jxstorefeature.go @@ -1,4 +1,4 @@ -package model +package legacymodel type Jxstorefeature struct { Id int `orm:"column(storeid);pk"` diff --git a/business/model/api.go b/business/model/api.go new file mode 100644 index 000000000..7d703af50 --- /dev/null +++ b/business/model/api.go @@ -0,0 +1,24 @@ +package model + +type CallResult struct { + Code string `json:"code"` + Desc string `json:"desc"` + Data string `json:"data"` +} + +type GoodsOrderExt struct { + GoodsOrder + WaybillStatus int `json:"waybillStatus"` + CourierName string `orm:"size(32)" json:"courierName"` + CourierMobile string `orm:"size(32)" json:"courierMobile"` +} + +type OrderSkuExt struct { + OrderSku + Image string `json:"image"` +} + +type GoodsOrderCountInfo struct { + Status int `json:"status"` + Count int `json:"count"` +} diff --git a/business/model/model.go b/business/model/model.go index c79569df4..801d5a656 100644 --- a/business/model/model.go +++ b/business/model/model.go @@ -2,49 +2,23 @@ package model import "time" -func Order2Status(order *GoodsOrder) (retVal *OrderStatus) { - retVal = &OrderStatus{ - VendorOrderID: order.VendorOrderID, - VendorID: order.VendorID, - OrderType: OrderTypeOrder, - RefVendorOrderID: order.VendorOrderID, - RefVendorID: order.VendorID, - Status: order.Status, - VendorStatus: order.VendorStatus, - StatusTime: order.StatusTime, - LockStatus: order.LockStatus, - } - return retVal +type ModelO struct { + ID int `gorm:"primary_key"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time `sql:"index"` + LastOperator string `gorm:"type:varchar(32)"` // 最后操作员 } -func Waybill2Status(bill *Waybill) (retVal *OrderStatus) { - retVal = &OrderStatus{ - VendorOrderID: bill.VendorWaybillID, - VendorID: bill.WaybillVendorID, - OrderType: OrderTypeWaybill, - RefVendorOrderID: bill.VendorOrderID, - RefVendorID: bill.OrderVendorID, - Status: bill.Status, - VendorStatus: bill.VendorStatus, - StatusTime: bill.StatusTime, - Remark: bill.Remark, - } - return retVal +type ModelIDCU struct { + ID int `gorm:"primary_key"` + CreatedAt time.Time + UpdatedAt time.Time } -// 判断订单是否是临时的,不是真实收到了new order消息后的订单 -func IsOrderSolid(order *GoodsOrder) bool { - return !(order.ConsigneeName == "" && order.ID == 0) -} - -func (o *GoodsOrder) GetStatusTime() time.Time { - return o.StatusTime -} - -func (o *Waybill) GetStatusTime() time.Time { - return o.StatusTime -} - -func (o *OrderStatus) GetStatusTime() time.Time { - return o.StatusTime +type ModelIDCUO struct { + ID int `gorm:"primary_key"` + CreatedAt time.Time + UpdatedAt time.Time + LastOperator string `gorm:"type:varchar(32)"` // 最后操作员 } diff --git a/business/model/order.go b/business/model/order.go index af90dce21..096d192e6 100644 --- a/business/model/order.go +++ b/business/model/order.go @@ -8,49 +8,49 @@ type ModelTimeInfo struct { } type GoodsOrder struct { - ID int64 `orm:"column(id)"` - VendorOrderID string `orm:"column(vendor_order_id);size(48)"` - VendorID int `orm:"column(vendor_id)"` - VendorStoreID string `orm:"column(vendor_store_id);size(48)"` - StoreID int `orm:"column(store_id)"` // 外部系统里记录的 jxstoreid - JxStoreID int `orm:"column(jx_store_id)"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid - StoreName string `orm:"size(64)"` - ShopPrice int64 // 单位为分 门店标价 - SalePrice int64 // 单位为分 售卖价 - ActualPayPrice int64 // 单位为分 顾客实际支付 - Weight int // 单位为克 - ConsigneeName string `orm:"size(32)"` - ConsigneeMobile string `orm:"size(32)"` - ConsigneeAddress string `orm:"size(255)"` - CoordinateType int - ConsigneeLng int // 坐标 * (10的六次方) - ConsigneeLat int // 坐标 * (10的六次方) - SkuCount int // 商品类别数量,即有多少种商品(注意在某些情况下,相同SKU的商品由于售价不同,也会当成不同商品在这个值里) - GoodsCount int // 商品个数 - Status int // 参见OrderStatus*相关的常量定义 - VendorStatus string `orm:"size(255)"` - LockStatus int - OrderSeq int // 门店订单序号 - BuyerComment string `orm:"size(255)"` - BusinessType int - ExpectedDeliveredTime time.Time `orm:"type(datetime)"` // 预期送达时间 - CancelApplyReason string `orm:"size(255)"` // ""表示没有申请,不为null表示用户正在取消申请 - VendorWaybillID string `orm:"column(vendor_waybill_id);size(48)"` - WaybillVendorID int `orm:"column(waybill_vendor_id)"` // 表示当前承运商,-1表示还没有安排 + ID int64 `orm:"column(id)" json:"_"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` + VendorID int `orm:"column(vendor_id)" json:"vendorID"` + VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` + StoreID int `orm:"column(store_id)" json:"storeID"` // 外部系统里记录的 jxstoreid + JxStoreID int `orm:"column(jx_store_id)" json:"jxStoreID"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid + StoreName string `orm:"size(64)" json:"_"` + ShopPrice int64 `json:"shopPrice"` // 单位为分 门店标价 + SalePrice int64 `json:"salePrice"` // 单位为分 售卖价 + ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付 + Weight int `json:"weight"` // 单位为克 + ConsigneeName string `orm:"size(32)" json:"consigneeName"` + ConsigneeMobile string `orm:"size(32)" json:"consigneeMobile"` + ConsigneeAddress string `orm:"size(255)" json:"consigneeAddress"` + CoordinateType int `json:"_"` + ConsigneeLng int `json:"_"` // 坐标 * (10的六次方) + ConsigneeLat int `json:"_"` // 坐标 * (10的六次方) + SkuCount int `json:"skuCount"` // 商品类别数量,即有多少种商品(注意在某些情况下,相同SKU的商品由于售价不同,也会当成不同商品在这个值里) + GoodsCount int `json:"goodsCount"` // 商品个数 + Status int `json:"status"` // 参见OrderStatus*相关的常量定义 + VendorStatus string `orm:"size(255)" json:"_"` + LockStatus int `json:"lockStatus"` + OrderSeq int `json:"orderSeq"` // 门店订单序号 + BuyerComment string `orm:"size(255)" json:"buyerComment"` + BusinessType int `json:"businessType"` + ExpectedDeliveredTime time.Time `orm:"type(datetime)" json:"expectedDeliveredTime"` // 预期送达时间 + CancelApplyReason string `orm:"size(255)" json:"_"` // ""表示没有申请,不为null表示用户正在取消申请 + VendorWaybillID string `orm:"column(vendor_waybill_id);size(48)" json:"vendorWaybillID"` + WaybillVendorID int `orm:"column(waybill_vendor_id)" json:"waybillVendorID"` // 表示当前承运商,-1表示还没有安排 DuplicatedCount int // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的 - OrderCreatedAt time.Time `orm:"type(datetime);index"` // 这里记录的是订单生效时间,即用户支付完成(货到付款即为下单时间) - OrderFinishedAt time.Time `orm:"type(datetime)"` - StatusTime time.Time `orm:"type(datetime)"` // last status time - ModelTimeInfo - OriginalData string `orm:"type(text)"` - Skus []*OrderSku `orm:"-"` - SkuPmFee int64 //门店商品促销总支出 - OrderPmFee int64 //门店订单促销支出 - SkuPmSubsidy int64 //平台商品促销总补贴 - OrderPmSubsidy int64 //平台订单促销补贴 - BoxFee int64 //餐盒费 - PlatformFeeRate int16 //平台费 - BillStoreFreightFee int64 //需要回调,门店所承担的运费 + OrderCreatedAt time.Time `orm:"type(datetime);index" json:"orderCreatedAt"` // 这里记录的是订单生效时间,即用户支付完成(货到付款即为下单时间) + OrderFinishedAt time.Time `orm:"type(datetime)" json:"orderFinishedAt"` + StatusTime time.Time `orm:"type(datetime)" json:"_"` // last status time + ModelTimeInfo `json:"_"` + OriginalData string `orm:"type(text)" json:"_"` + Skus []*OrderSku `orm:"-" json:"_"` + SkuPmFee int64 `json:"_"` //门店商品促销总支出 + OrderPmFee int64 `json:"_"` //门店订单促销支出 + SkuPmSubsidy int64 `json:"_"` //平台商品促销总补贴 + OrderPmSubsidy int64 `json:"_"` //平台订单促销补贴 + BoxFee int64 `json:"_"` //餐盒费 + PlatformFeeRate int16 `json:"_"` //平台费 + BillStoreFreightFee int64 `json:"_"` //需要回调,门店所承担的运费 } func (o *GoodsOrder) TableUnique() [][]string { @@ -60,24 +60,24 @@ func (o *GoodsOrder) TableUnique() [][]string { } type OrderSku struct { - ID int64 `orm:"column(id)"` - VendorOrderID string `orm:"column(vendor_order_id);size(48)"` - VendorID int `orm:"column(vendor_id)"` - StoreSubID int `orm:"column(store_sub_id)"` - StoreSubName string `orm:"size(64)"` - Count int - VendorSkuID string `orm:"column(vendor_sku_id);size(48)"` - SkuID int `orm:"column(sku_id)"` // 外部系统里记录的 jxskuid - JxSkuID int `orm:"column(jx_sku_id)"` // 根据VendorSkuID在本地系统里查询出来的 jxskuid - SkuName string `orm:"size(255)"` - ShopPrice int64 // 门店标价 - SalePrice int64 // 售卖价 - Weight int // 单位为克 - SkuType int // 当前如果为gift就为1,否则缺省为0 - PromotionType int // todo 当前是用于记录京东的PromotionType(生成jxorder用),没有做转换 - OrderCreatedAt time.Time `orm:"type(datetime);index"` // 分区考虑 - SkuPmSubsidy int64 //平台商品活动补贴 - SkuPmFee int64 //门店商品促销支出 + ID int64 `orm:"column(id)" json:"_"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` + VendorID int `orm:"column(vendor_id)" json:"vendorID"` + StoreSubID int `orm:"column(store_sub_id)" json:"storeSubID"` + StoreSubName string `orm:"size(64)" json:"storeSubName"` + Count int `json:"count"` + VendorSkuID string `orm:"column(vendor_sku_id);size(48)" json:"_"` + SkuID int `orm:"column(sku_id)" json:"skuID"` // 外部系统里记录的 jxskuid + JxSkuID int `orm:"column(jx_sku_id)" json:"jxSkuID"` // 根据VendorSkuID在本地系统里查询出来的 jxskuid + SkuName string `orm:"size(255)" json:"skuName"` + ShopPrice int64 `json:"shopPrice"` // 门店标价 + SalePrice int64 `json:"salePrice"` // 售卖价 + Weight int `json:"_"` // 单位为克 + SkuType int `json:"_"` // 当前如果为gift就为1,否则缺省为0 + PromotionType int `json:"_"` // todo 当前是用于记录京东的PromotionType(生成jxorder用),没有做转换 + OrderCreatedAt time.Time `orm:"type(datetime);index" json:"_"` // 分区考虑 + SkuPmSubsidy int64 `json:"_"` //平台商品活动补贴 + SkuPmFee int64 `json:"_"` //门店商品促销支出 } // 同样商品在一个订单中可能重复出现(比如搞活动时,相同商品价格不一样,第一个有优惠) @@ -89,25 +89,25 @@ func (o *OrderSku) TableIndex() [][]string { } type Waybill struct { - ID int64 `orm:"column(id)"` - VendorWaybillID string `orm:"column(vendor_waybill_id);size(48)"` - VendorWaybillID2 string `orm:"column(vendor_waybill_id2);size(48)"` // 某些平台有多个ID,比如美团配送,当前美团配送的 delivery_id存这里 - WaybillVendorID int `orm:"column(waybill_vendor_id)"` - VendorOrderID string `orm:"column(vendor_order_id);size(48)"` - OrderVendorID int `orm:"column(order_vendor_id)"` - CourierName string `orm:"size(32)"` - CourierMobile string `orm:"size(32)"` - Status int // 参见WaybillStatus*相关的常量定义 - VendorStatus string `orm:"size(255)"` - ActualFee int64 // 实际要支付给快递公司的实际费用 - DesiredFee int64 // 根据合同计算出来的预期费用 - DuplicatedCount int // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的 - WaybillCreatedAt time.Time `orm:"type(datetime);index"` - WaybillFinishedAt time.Time `orm:"type(datetime)"` - StatusTime time.Time `orm:"type(datetime)"` // last status time - ModelTimeInfo - OriginalData string `orm:"type(text)"` - Remark string `orm:"-"` // 用于传递remark + ID int64 `orm:"column(id)" json:"-"` + VendorWaybillID string `orm:"column(vendor_waybill_id);size(48)" json:"vendorWaybillID"` + VendorWaybillID2 string `orm:"column(vendor_waybill_id2);size(48)" json:"vendorWaybillID2"` // 某些平台有多个ID,比如美团配送,当前美团配送的 delivery_id存这里 + WaybillVendorID int `orm:"column(waybill_vendor_id)" json:"waybillVendorID"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` + OrderVendorID int `orm:"column(order_vendor_id)" json:"orderVendorID"` + CourierName string `orm:"size(32)" json:"-"` + CourierMobile string `orm:"size(32)" json:"-"` + Status int `json:"-"` // 参见WaybillStatus*相关的常量定义 + VendorStatus string `orm:"size(255)" json:"-"` + ActualFee int64 `json:"actual_fee"` // 实际要支付给快递公司的费用 + DesiredFee int64 `json:"desired_fee"` // 运单总费用 + DuplicatedCount int `json:"-"` // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的 + WaybillCreatedAt time.Time `orm:"type(datetime);index" json:"_"` + WaybillFinishedAt time.Time `orm:"type(datetime)" json:"-"` + StatusTime time.Time `orm:"type(datetime)" json:"-"` // last status time + ModelTimeInfo `json:"-"` + OriginalData string `orm:"type(text)" json:"-"` + Remark string `orm:"-" json:"-"` // 用于传递remark } func (w *Waybill) TableUnique() [][]string { @@ -144,3 +144,50 @@ func (v *OrderStatus) TableIndex() [][]string { []string{"VendorOrderID", "Status", "VendorStatus"}, } } + +func Order2Status(order *GoodsOrder) (retVal *OrderStatus) { + retVal = &OrderStatus{ + VendorOrderID: order.VendorOrderID, + VendorID: order.VendorID, + OrderType: OrderTypeOrder, + RefVendorOrderID: order.VendorOrderID, + RefVendorID: order.VendorID, + Status: order.Status, + VendorStatus: order.VendorStatus, + StatusTime: order.StatusTime, + LockStatus: order.LockStatus, + } + return retVal +} + +func Waybill2Status(bill *Waybill) (retVal *OrderStatus) { + retVal = &OrderStatus{ + VendorOrderID: bill.VendorWaybillID, + VendorID: bill.WaybillVendorID, + OrderType: OrderTypeWaybill, + RefVendorOrderID: bill.VendorOrderID, + RefVendorID: bill.OrderVendorID, + Status: bill.Status, + VendorStatus: bill.VendorStatus, + StatusTime: bill.StatusTime, + Remark: bill.Remark, + } + return retVal +} + +// 判断订单是否是临时的,不是真实收到了new order消息后的订单 +func IsOrderSolid(order *GoodsOrder) bool { + return !(order.ConsigneeName == "" && order.ID == 0) +} + +func (o *GoodsOrder) GetStatusTime() time.Time { + return o.StatusTime +} + +func (o *Waybill) GetStatusTime() time.Time { + return o.StatusTime +} + +func (o *OrderStatus) GetStatusTime() time.Time { + return o.StatusTime +} diff --git a/business/model/place.go b/business/model/place.go new file mode 100644 index 000000000..f5ef018e3 --- /dev/null +++ b/business/model/place.go @@ -0,0 +1,24 @@ +package model + +import "time" + +// https://github.com/videni/pcr +const ( + CityLevelProvince = 1 + CityLevelCity = 2 + CityLevelDistrict = 3 +) + +type Place struct { + ID int + Code int `gorm:"unique_index"` // 国家标准代码 + Name string `gorm:"type:varchar(16);index"` // 如果是直辖市,省的概念不加“市”来区别 + ParentCode int // 上级代码 + PostCode string `gorm:"type:varchar(8);index"` + Level int8 // 城市级别,参见相关常量定义 + TelCode string `gorm:"type:varchar(8);index"` + JdCode int `gorm:"index"` // 对应的京东代码 + Enabled int8 // 是否启用 + MtpsPrice int // 分为单位 + UpdatedAt time.Time +} diff --git a/business/model/product.go b/business/model/product.go new file mode 100644 index 000000000..bba0d315c --- /dev/null +++ b/business/model/product.go @@ -0,0 +1,124 @@ +package model + +const ( + SkuCategoryNormal = 0 + SkuCategorySpecial = 1 +) + +const ( + SpecUnitG = 0 + SpecUnitKG = 1 + SpecUnitL = 2 + SpecUnitML = 3 +) + +var ( + SpecUnitNames = []string{ + "g", + "kg", + "L", + "ml", + } +) + +var ( + UnitNames = []string{ + "份", + "袋", + "瓶", + "只", + "组", + "个", + "盒", + "把", + "半只", + "包", + "条", + "根", + "箱", + "听", + "套", + "罐", + "件", + "块", + "片", + "支", + "杯", + } +) + +// 这个指的是京东自已的商品分类,与商家自己的商品分类是两回事 +type SkuJdCategory struct { + ModelIDCUO + Name string `gorm:"type:varchar(255);unique_index"` + Status int + Level int + ParentID int64 +} + +type SkuCategory struct { + ModelIDCUO + Name string `gorm:"type:varchar(255);unique_index"` + ParentID int + Level int8 + Type int8 // 类别类型 + Seq int + + JdID int64 `gorm:"index"` // 这个是指商家自己的商品类别在京东平台上的ID + JdCategoryID int64 // 这个是指对应的京东商品类别 + ElmID string `gorm:"type:varchar(48);index"` + MtID string `gorm:"type:varchar(48);index"` + DidiID string `gorm:"type:varchar(48);index"` +} + +type StoreSkuCategoryMap struct { + ModelIDCUO + StoreID int + SkuCategoryID int + + ElmID string `gorm:"type:varchar(48)"` +} + +type SkuName struct { + ModelIDCUO + Prefix string `gorm:"type:varchar(255)"` + Name string `gorm:"type:varchar(255)"` + Comment string `gorm:"type:varchar(255)"` + + CategoryID int // 标准类别 + Status int + + IsGlobal int8 `gorm:"default:1"` // 是否是全部(全国)可见,如果否的话,可见性由SkuPlace决定 + Unit string `gorm:"type:varchar(8)"` + Price int // 单位为分,标准价,不为份的就为实际标准价,为份的为每市斤价,实际还要乘质量。todo 为份的确定必须有质量 + Img string `gorm:"type:varchar(255)"` + ElmImgHashCode string `gorm:"type:varchar(64)"` +} + +type Sku struct { + ModelIDCUO + CategoryID int // 特殊类别,一般用于秒杀,特价之类的特殊类别 + NameID int `gorm:"index:unique_index_name_Id_quality"` // todo 这个索引应该要求唯一 + SpecQuality float32 `gorm:"index:unique_index_name_Id_quality"` + SpecUnit string `gorm:"type:varchar(8)"` + + Weight int // 单位为克,当相应的SkuName的SpecUnit为g或kg时,必须等于SpecQuality + + JdID string `gorm:"type:varchar(48)"` +} + +type SkuNamePlaceBind struct { + ModelIDCUO + SkuNameID int `gorm:"unique_index:unique_sku_name_id_sku_place_id"` + PlaceID int `gorm:"unique_index:unique_sku_name_id_sku_place_id"` +} + +type StoreSkuBind struct { + ModelIDCUO + StoreID int `gorm:"unique_index:unique_store_id_sku_id"` + SkuID int `gorm:"unique_index:unique_store_id_sku_id"` + SubStoreID int + Price int // 单位为分,不用int64的原因是这里不需要累加 + Status int + ElmID string `gorm:"type:varchar(48)"` +} diff --git a/business/model/store.go b/business/model/store.go new file mode 100644 index 000000000..e5f9c7352 --- /dev/null +++ b/business/model/store.go @@ -0,0 +1,59 @@ +package model + +const ( + StoreStatusDisabled = -1 + StoreStatusClosed = 0 + StoreStatusOpened = 1 +) + +const ( + MainSubStoreName = "本店" + MainSubStoreAddress = "本店" +) + +type Store struct { + ModelIDCUO + Name string `gorm:"type:varchar(255);unique_index"` + CityCode int + DistrictCode int + Address string `gorm:"type:varchar(255)"` + OpenTime1 int // 930就表示9点半,用两个的原因是为了支持中午休息,1与2的时间段不能交叉,为0表示没有 + CloseTime1 int // 格式同上 + OpenTime2 int // 格式同上 + CloseTime2 int // 格式同上 + Lng int // 乘了10的6次方 + Lat int // 乘了10的6次方 + Status int +} + +type StoreSub struct { + ModelIDCUO + StoreID int `gorm:"unique_index:unique_index1"` + Index int `gorm:"unique_index:unique_index1"` // 子店序号,为0表示主店 + Name string `gorm:"type:varchar(255)"` + Address string `gorm:"type:varchar(255)"` + Status int + Mobile1 string `gorm:"type:varchar(32)"` + Mobile2 string `gorm:"type:varchar(32)"` + Mobile3 string `gorm:"type:varchar(32)"` +} + +type StoreMap struct { + ModelIDCUO + StoreID int `gorm:"unique_index:storemap1"` + VendorID int `gorm:"unique_index:storemap1"` + VendorStoreID string `gorm:"type:varchar(48);unique_index"` + Status int + + AutoPickup int8 // 是否自动拣货 + DeliveryType int8 // 配送类型 + DeliveryCompetition int8 // 是否支持配送竞争 +} + +type StoreCourierMap struct { + ModelIDCUO + StoreID int `gorm:"unique_index:storemap1"` + VendorID int `gorm:"unique_index:storemap1"` + VendorStoreID string `gorm:"type:varchar(48);unique_index"` + Status int +} diff --git a/business/controller/dada/waybill.go b/business/partner/delivery/dada/waybill.go similarity index 68% rename from business/controller/dada/waybill.go rename to business/partner/delivery/dada/waybill.go index abeaebb9e..0c42a25e6 100644 --- a/business/controller/dada/waybill.go +++ b/business/partner/delivery/dada/waybill.go @@ -6,10 +6,10 @@ import ( "git.rosy.net.cn/baseapi/platformapi/dadaapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego/orm" @@ -23,21 +23,30 @@ var ( ErrCanNotFindDadaCityCode = errors.New("不能找到美团配送站点配置") ) -type WaybillController struct { +var ( + curDeliveryHandler *DeliveryHandler +) + +type DeliveryHandler struct { } func init() { - scheduler.CurrentScheduler.RegisterDeliveryPlatform(model.VendorIDDada, new(WaybillController), true) + curDeliveryHandler = new(DeliveryHandler) + scheduler.CurrentScheduler.RegisterDeliveryPlatform(model.VendorIDDada, curDeliveryHandler, true) } -func (c *WaybillController) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { +func OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return curDeliveryHandler.OnWaybillMsg(msg) +} + +func (c *DeliveryHandler) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onWaybillMsg(msg) }, msg.OrderID) return retVal } -func (c *WaybillController) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { +func (c *DeliveryHandler) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { order := c.callbackMsg2Waybill(msg) switch msg.OrderStatus { case dadaapi.OrderStatusWaitingForAccept: @@ -58,10 +67,10 @@ func (c *WaybillController) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dada default: order.Status = model.WaybillStatusUnknown } - return dadaapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), utils.Int2Str(order.Status)) + return dadaapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), utils.Int2Str(order.Status)) } -func (c *WaybillController) callbackMsg2Waybill(msg *dadaapi.CallbackMsg) (retVal *model.Waybill) { +func (c *DeliveryHandler) callbackMsg2Waybill(msg *dadaapi.CallbackMsg) (retVal *model.Waybill) { retVal = &model.Waybill{ VendorWaybillID: msg.ClientID, WaybillVendorID: model.VendorIDDada, @@ -81,8 +90,8 @@ func (c *WaybillController) callbackMsg2Waybill(msg *dadaapi.CallbackMsg) (retVa return retVal } -// DeliveryPlatformHandler -func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { +// IDeliveryPlatformHandler +func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy func(deliveryFee, addFee int64) error) (bill *model.Waybill, err error) { billParams := &dadaapi.OperateOrderRequiredParams{ ShopNo: utils.Int2Str(order.StoreID), // 当前达达的门店号与京西是一样的 OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), @@ -102,6 +111,9 @@ func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { "info": order.BuyerComment, // "origin_mark": model.VendorNames[order.VendorID], "origin_mark_no": fmt.Sprintf("%d", order.OrderSeq), + "cargo_type": 13, + "cargo_weight": float64(order.Weight) / 1000.0, + "cargo_num": order.GoodsCount, } // 达达要求第二次创建运单,调用函数不同。所以查找两天内有无相同订单号的运单 @@ -113,34 +125,43 @@ func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { AND vendor_order_id = ? AND waybill_vendor_id = ? `, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), model.VendorIDDada).ValuesList(&lists) + var result *dadaapi.CreateOrderResponse if err2 == nil && num > 0 { globals.SugarLogger.Debugf("CreateWaybill orderID:%s num=%d use ReaddOrder", order.VendorOrderID, num) - _, err = api.DadaAPI.ReaddOrder(billParams, addParams) + result, err = api.DadaAPI.ReaddOrder(billParams, addParams) } else { if err2 != nil { globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err2) } - _, err = api.DadaAPI.AddOrder(billParams, addParams) + result, err = api.DadaAPI.AddOrder(billParams, addParams) + } + if err == nil && result != nil { + bill = &model.Waybill{ + VendorOrderID: order.VendorOrderID, + OrderVendorID: order.VendorID, + WaybillVendorID: model.VendorIDDada, + DesiredFee: jxutils.StandardPrice2Int(result.DeliverFee), + ActualFee: jxutils.StandardPrice2Int(result.Fee), + } } } - return err + return bill, err } -func (c *WaybillController) CancelWaybill(bill *model.Waybill) (err error) { - reasonID := dadaapi.ReasonIDOther - reasonMsg := "send not in time" - if bill.Status < model.WaybillStatusAccepted { - reasonID = dadaapi.ReasonIDNobodyAccept - reasonMsg = "ReasonIDNobodyAccept" - } else if bill.Status < model.WaybillStatusCourierArrived { - reasonID = dadaapi.ReasonIDNobodyPickup - reasonMsg = "ReasonIDNobodyPickup" +func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) { + switch cancelReasonID { + case partner.CancelWaybillReasonNotAcceptIntime: + cancelReasonID = dadaapi.ReasonIDNobodyAccept + case partner.CancelWaybillReasonSwitch2SelfFailed: + cancelReasonID = dadaapi.ReasonIDClientDontWantItAnymore + default: + cancelReasonID = dadaapi.ReasonIDOther } - _, err = api.DadaAPI.CancelOrder(bill.VendorOrderID, reasonID, reasonMsg) + _, err = api.DadaAPI.CancelOrder(bill.VendorOrderID, cancelReasonID, cancelReason) return err } -func (c *WaybillController) getDataCityCodeFromOrder(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) { +func (c *DeliveryHandler) getDataCityCodeFromOrder(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) { var sql string if order.VendorID == model.VendorIDJD { sql = ` diff --git a/business/controller/dada/waybill_test.go b/business/partner/delivery/dada/waybill_test.go similarity index 72% rename from business/controller/dada/waybill_test.go rename to business/partner/delivery/dada/waybill_test.go index 6d68f1f93..2bd0031aa 100644 --- a/business/controller/dada/waybill_test.go +++ b/business/partner/delivery/dada/waybill_test.go @@ -4,11 +4,12 @@ import ( "testing" "time" - "git.rosy.net.cn/jx-callback/business/controller" + _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" "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" - "git.rosy.net.cn/jx-callback/globals/db" + "git.rosy.net.cn/jx-callback/globals/beegodb" "github.com/astaxie/beego" ) @@ -17,16 +18,17 @@ func init() { beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test globals.Init() - db.Init() + beegodb.Init() api.Init() } func TestCreateWaybill(t *testing.T) { orderID := "817540316000041" - if order, err := controller.OrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil { + if order, err := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil { // globals.SugarLogger.Debug(order) - c := new(WaybillController) - if err = c.CreateWaybill(order); err == nil { + c := new(DeliveryHandler) + _, err = c.CreateWaybill(order, nil) + if err == nil { time.Sleep(1 * time.Second) bill := &model.Waybill{ VendorOrderID: orderID, diff --git a/business/controller/mtps/waybill.go b/business/partner/delivery/mtps/waybill.go similarity index 74% rename from business/controller/mtps/waybill.go rename to business/partner/delivery/mtps/waybill.go index 1ff11f829..2be20852d 100644 --- a/business/controller/mtps/waybill.go +++ b/business/partner/delivery/mtps/waybill.go @@ -8,43 +8,51 @@ import ( "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/legacymodel" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego" "github.com/astaxie/beego/orm" ) -const ( - maxAddFee = 200 // 最大增加费用,单位为分,超过不发美团了 -) - var ( ErrCanNotFindMTPSStore = errors.New("不能找到美团配送站点配置") - ErrAddFeeExceeded = errors.New("美团配送超过基准价太多") ErrStoreNoPriceInfo = errors.New("找不到门店的美团配送价格信息") ErrStoreNoCoordinate = errors.New("找不到门店的坐标信息") ) -type WaybillController struct { +var ( + curDeliveryHandler *DeliveryHandler +) + +type DeliveryHandler struct { } func init() { - scheduler.CurrentScheduler.RegisterDeliveryPlatform(model.VendorIDMTPS, new(WaybillController), true) + curDeliveryHandler = new(DeliveryHandler) + scheduler.CurrentScheduler.RegisterDeliveryPlatform(model.VendorIDMTPS, curDeliveryHandler, true) } -func (c *WaybillController) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { +func OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + return curDeliveryHandler.OnWaybillMsg(msg) +} + +func OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) { + return curDeliveryHandler.OnWaybillExcept(msg) +} + +func (c *DeliveryHandler) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onWaybillMsg(msg) }, msg.OrderID) return retVal } -func (c *WaybillController) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) { +func (c *DeliveryHandler) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) { jxutils.CallMsgHandler(func() { order := &model.Waybill{ VendorWaybillID: msg.MtPeisongID, @@ -57,12 +65,12 @@ func (c *WaybillController) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionM StatusTime: utils.Timestamp2Time(msg.Timestamp), } order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID) - retVal = mtpsapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept") + retVal = mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept") }, msg.OrderID) return retVal } -func (c *WaybillController) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { +func (c *DeliveryHandler) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { order := c.callbackMsg2Waybill(msg) switch msg.Status { case mtpsapi.OrderStatusWaitingForSchedule: @@ -80,10 +88,10 @@ func (c *WaybillController) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal globals.SugarLogger.Warnf("onWaybillMsg unknown msg:%v", msg) return mtpsapi.SuccessResponse } - return mtpsapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), order.VendorStatus) + return mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus) } -func (c *WaybillController) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) (retVal *model.Waybill) { +func (c *DeliveryHandler) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) (retVal *model.Waybill) { retVal = &model.Waybill{ VendorWaybillID: msg.MtPeisongID, VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID), @@ -98,7 +106,7 @@ func (c *WaybillController) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) ( return retVal } -func (c *WaybillController) calculateOrderDeliveryFee(order *model.GoodsOrder, billTime time.Time, db orm.Ormer) (deliveryFee, addFee int64, err error) { +func (c *DeliveryHandler) calculateOrderDeliveryFee(order *model.GoodsOrder, billTime time.Time, db orm.Ormer) (deliveryFee, addFee int64, err error) { var lists []orm.ParamsList if db == nil { db = orm.NewOrm() @@ -153,8 +161,8 @@ func (c *WaybillController) calculateOrderDeliveryFee(order *model.GoodsOrder, b return deliveryFee + addFee, addFee, nil } -func (c *WaybillController) calculateBillDeliveryFee(bill *model.Waybill) (deliveryFee, addFee int64) { - order, err := controller.OrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID) +func (c *DeliveryHandler) calculateBillDeliveryFee(bill *model.Waybill) (deliveryFee, addFee int64) { + order, err := partner.CurOrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID) if err != nil { return 0, 0 } @@ -162,12 +170,15 @@ func (c *WaybillController) calculateBillDeliveryFee(bill *model.Waybill) (deliv return deliveryFee, addFee } -// DeliveryPlatformHandler -func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { +// IDeliveryPlatformHandler +func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy func(deliveryFee, addFee int64) error) (bill *model.Waybill, err error) { db := orm.NewOrm() - _, addFee, err := c.calculateOrderDeliveryFee(order, time.Now(), db) + deliveryFee, addFee, err := c.calculateOrderDeliveryFee(order, time.Now(), db) if err == nil { - if addFee <= maxAddFee { + if policy != nil { + err = policy(deliveryFee, addFee) + } + if err == nil { // 忽略坐标转换错误,即使是转换出错,也只能当成转换成功来处理,底层会有错误日志输出 lngFloat, latFloat, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) billParams := &mtpsapi.CreateOrderByShopParam{ @@ -206,8 +217,8 @@ func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { } } addParams := utils.Params2Map("note", order.BuyerComment, "goods_detail", string(utils.MustMarshal(goods)), "poi_seq", fmt.Sprintf("#%d", order.OrderSeq)) - _, err = api.MtpsAPI.CreateOrderByShop(billParams, addParams) - if err != nil { + result, err2 := api.MtpsAPI.CreateOrderByShop(billParams, addParams) + if err = err2; err != nil { globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err) tmpLog := &legacymodel.TempLog{ @@ -217,46 +228,43 @@ func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { Msg: fmt.Sprintf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err), } db.Insert(tmpLog) + } else { + bill = &model.Waybill{ + VendorOrderID: order.VendorOrderID, + OrderVendorID: order.VendorID, + VendorWaybillID: result.MtPeisongID, + VendorWaybillID2: utils.Int64ToStr(result.DeliveryID), + WaybillVendorID: model.VendorIDMTPS, + DesiredFee: deliveryFee, + } } } } - } else { - err = ErrAddFeeExceeded - globals.SugarLogger.Infof("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee) - - tmpLog := &legacymodel.TempLog{ - VendorOrderID: order.VendorOrderID, - RefVendorOrderID: order.VendorOrderID, - IntValue1: addFee, - Msg: fmt.Sprintf("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee), - } - db.Insert(tmpLog) } } - return err + return bill, err } -func (c *WaybillController) CancelWaybill(bill *model.Waybill) (err error) { - reasonID := mtpsapi.CancelReasonRidderSendNotIntime - reasonMsg := "CancelReasonRidderSendNotIntime" - if bill.Status < model.WaybillStatusAccepted { - reasonID = mtpsapi.CancelReasonMerchantOther - reasonMsg = "nobody accept order" - } else if bill.Status < model.WaybillStatusCourierArrived { - reasonID = mtpsapi.CancelReasonRideerGetGoodNotIntime - reasonMsg = "CancelReasonRideerGetGoodNotIntime" +func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) { + switch cancelReasonID { + case partner.CancelWaybillReasonNotAcceptIntime: + cancelReasonID = mtpsapi.CancelReasonRideerMtpsOther + case partner.CancelWaybillReasonSwitch2SelfFailed: + cancelReasonID = mtpsapi.CancelReasonMerchantOther + default: + cancelReasonID = mtpsapi.CancelReasonRideerOther } - _, err = api.MtpsAPI.CancelOrder(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, reasonID, reasonMsg) + _, err = api.MtpsAPI.CancelOrder(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, cancelReasonID, cancelReason) return nil } -func (c *WaybillController) getDeliveryID(order *model.GoodsOrder, db orm.Ormer) (retVal int64, err error) { +func (c *DeliveryHandler) getDeliveryID(order *model.GoodsOrder, db orm.Ormer) (retVal int64, err error) { // jxorder表当前已经有50多万条记录了,加100万避免冲突 // 508505 return order.ID + 1000000, nil } -func (c *WaybillController) getMTPSShopID(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) { +func (c *DeliveryHandler) getMTPSShopID(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) { sql := "SELECT zs_store_id FROM jx_to_zs_store_map WHERE jx_store_id = ?" var lists []orm.ParamsList JxStoreID := jxutils.GetJxStoreIDFromOrder(order) diff --git a/business/controller/mtps/waybill_test.go b/business/partner/delivery/mtps/waybill_test.go similarity index 68% rename from business/controller/mtps/waybill_test.go rename to business/partner/delivery/mtps/waybill_test.go index a5f6cdc52..64a12d88d 100644 --- a/business/controller/mtps/waybill_test.go +++ b/business/partner/delivery/mtps/waybill_test.go @@ -3,11 +3,12 @@ package mtps import ( "testing" - "git.rosy.net.cn/jx-callback/business/controller" + _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" "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" - "git.rosy.net.cn/jx-callback/globals/db" + "git.rosy.net.cn/jx-callback/globals/beegodb" "github.com/astaxie/beego" ) @@ -16,16 +17,17 @@ func init() { beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test globals.Init() - db.Init() + beegodb.Init() api.Init() } func TestCreateWaybill(t *testing.T) { orerID := "817109342000022" - order, _ := controller.OrderManager.LoadOrder(orerID, model.VendorIDJD) + order, _ := partner.CurOrderManager.LoadOrder(orerID, model.VendorIDJD) // globals.SugarLogger.Debug(order) - c := new(WaybillController) - if err := c.CreateWaybill(order); err != nil { + c := new(DeliveryHandler) + _, err := c.CreateWaybill(order, nil) + if err != nil { t.Fatal(err.Error()) } } @@ -35,7 +37,7 @@ func TestCancelWaybill(t *testing.T) { VendorWaybillID: "1532332342088966", VendorWaybillID2: "55", } - c := new(WaybillController) + c := new(DeliveryHandler) if err := c.CancelWaybill(bill); err != nil { t.Fatal(err.Error()) } diff --git a/business/partner/partner.go b/business/partner/partner.go new file mode 100644 index 000000000..b7448ae1e --- /dev/null +++ b/business/partner/partner.go @@ -0,0 +1,65 @@ +package partner + +import ( + "time" + + "git.rosy.net.cn/jx-callback/business/model" +) + +const ( + CancelWaybillReasonNotAcceptIntime = 1 + CancelWaybillReasonSwitch2SelfFailed = 2 + CancelWaybillReasonOther = 10 +) + +var ( + CancelWaybillReasonStrNotAcceptIntime = "没有及时抢单" + CancelWaybillReasonStrSwitch2SelfFailed = "转自送失败" + CancelWaybillReasonStrOrderAlreadyFinished = "订单已经结束" +) + +var ( + CurOrderManager IOrderManager +) + +type IOrderManager interface { + OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error) + OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error) + OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error) + + OnWaybillStatusChanged(bill *model.Waybill) (err error) + + LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) + UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error) + UpdateOrderStatusDirectly(order *model.GoodsOrder) (err error) +} + +type IPurchasePlatformHandler 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, userName string) (err error) + PickupGoods(order *model.GoodsOrder, userName string) (err error) + + // 将订单从购物平台配送转为自送 + Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) + + // 将订单从购物平台配送转为自送后又送达 + Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) + + // 完全自送的门店表示开始配送 + SelfDeliverDelievering(order *model.GoodsOrder, userName string) (err error) + + // 完全自送的门店表示配送完成 + SelfDeliverDelievered(order *model.GoodsOrder, userName string) (err error) +} + +type IDeliveryPlatformHandler interface { + CreateWaybill(order *model.GoodsOrder, policy func(deliveryFee, addFee int64) error) (bill *model.Waybill, err error) + CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) +} + +func Init(curOrderManager IOrderManager) { + CurOrderManager = curOrderManager +} diff --git a/business/controller/elm/elm.go b/business/partner/purchase/elm/elm.go similarity index 71% rename from business/controller/elm/elm.go rename to business/partner/purchase/elm/elm.go index 79b1f20ab..a28638554 100644 --- a/business/controller/elm/elm.go +++ b/business/partner/purchase/elm/elm.go @@ -3,14 +3,29 @@ package elm import ( "git.rosy.net.cn/baseapi/platformapi/elmapi" "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/model" ) -type Controller struct { +var ( + curPurchaseHandler *PurchaseHandler +) + +type PurchaseHandler struct { + scheduler.BasePurchasePlatform } -func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) { +func init() { + curPurchaseHandler = new(PurchaseHandler) + scheduler.CurrentScheduler.RegisterPurchasePlatform(model.VendorIDELM, curPurchaseHandler) +} + +func OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) { + return curPurchaseHandler.OnCallbackMsg(msg) +} + +func (c *PurchaseHandler) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) { if msg.Type == elmapi.MsgTypeOrderValid { innerMsg := make(map[string]interface{}) err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg) @@ -18,7 +33,7 @@ func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.Call retVal = elmapi.Err2CallbackResponse(err, "") } else { innerMsg["msgType"] = msg.Type - retVal = new(OrderController).OnOrderNewMsg(innerMsg) + retVal = c.OnOrderNewMsg(innerMsg) } } else if msg.Type > elmapi.MsgTypeOrderValid && msg.Type < elmapi.MsgTypeUserApplyCancel { var innerMsg elmapi.CallbackOrderStatusMsg @@ -27,7 +42,7 @@ func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.Call retVal = elmapi.Err2CallbackResponse(err, "") } else { innerMsg.MsgType = msg.Type - retVal = new(OrderController).OnOrderStatusMsg(&innerMsg) + retVal = c.OnOrderStatusMsg(&innerMsg) } } else if msg.Type >= elmapi.MsgTypeUserApplyCancel && msg.Type < elmapi.MsgTypeUserUrgeOrder { var innerMsg elmapi.CallbackOrderCancelRefundMsg @@ -36,7 +51,7 @@ func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.Call retVal = elmapi.Err2CallbackResponse(err, "") } else { innerMsg.MsgType = msg.Type - retVal = new(OrderController).OnOrderCancelRefundMsg(&innerMsg) + retVal = c.OnOrderCancelRefundMsg(&innerMsg) } } else if msg.Type == elmapi.MsgTypeUserUrgeOrder { var innerMsg elmapi.CallbackOrderUrgeMsg @@ -46,7 +61,7 @@ func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.Call } else { innerMsg.MsgType = msg.Type jxutils.CallMsgHandler(func() { - retVal = new(OrderController).onOrderUserUrgeOrder(&innerMsg) + retVal = c.onOrderUserUrgeOrder(&innerMsg) }, jxutils.ComposeUniversalOrderID(innerMsg.OrderID, model.VendorIDELM)) } } else if msg.Type >= elmapi.MsgTypeWaybillWait4DeliveryVendor && msg.Type <= elmapi.MsgTypeRejectedSystemError { @@ -56,7 +71,7 @@ func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.Call retVal = elmapi.Err2CallbackResponse(err, "") } else { innerMsg.MsgType = msg.Type - retVal = new(WaybillController).OnWaybillStatusMsg(&innerMsg) + retVal = c.OnWaybillStatusMsg(&innerMsg) } } else { retVal = elmapi.SuccessResponse diff --git a/business/controller/elm/order.go b/business/partner/purchase/elm/order.go similarity index 83% rename from business/controller/elm/order.go rename to business/partner/purchase/elm/order.go index cd6da03ea..807a19512 100644 --- a/business/controller/elm/order.go +++ b/business/partner/purchase/elm/order.go @@ -11,10 +11,10 @@ import ( "git.rosy.net.cn/baseapi/platformapi/elmapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/legacy/freshfood" ) @@ -34,36 +34,28 @@ var ( } ) -type OrderController struct { - scheduler.BasePurchasePlatform -} - -func init() { - scheduler.CurrentScheduler.RegisterPurchasePlatform(model.VendorIDELM, new(OrderController)) -} - -func (c *OrderController) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onOrderStatusMsg(msg) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM)) return retVal } -func (c *OrderController) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onOrderNew(msg) }, jxutils.ComposeUniversalOrderID(msg["orderId"].(string), model.VendorIDELM)) return retVal } -func (c *OrderController) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onOrderCancelRefundMsg(msg) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM)) return retVal } -func (c *OrderController) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusMsg) *model.OrderStatus { +func (c *PurchaseHandler) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusMsg) *model.OrderStatus { orderStatus := &model.OrderStatus{ VendorOrderID: msg.OrderID, VendorID: model.VendorIDELM, @@ -76,7 +68,7 @@ func (c *OrderController) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusM return orderStatus } -func (c *OrderController) cancelRefundMsg2Status(msg *elmapi.CallbackOrderCancelRefundMsg) *model.OrderStatus { +func (c *PurchaseHandler) cancelRefundMsg2Status(msg *elmapi.CallbackOrderCancelRefundMsg) *model.OrderStatus { orderStatus := &model.OrderStatus{ VendorOrderID: msg.OrderID, VendorID: model.VendorIDELM, @@ -89,7 +81,7 @@ func (c *OrderController) cancelRefundMsg2Status(msg *elmapi.CallbackOrderCancel return orderStatus } -func (c *OrderController) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { status := c.orderStatusMsg2Status(msg) switch msg.MsgType { case elmapi.MsgTypeOrderAccepted: @@ -102,13 +94,13 @@ func (c *OrderController) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) ( globals.SugarLogger.Warnf("onOrderStatusMsg elm msg:%v not handled", msg) return elmapi.SuccessResponse } - err := controller.OrderManager.OnOrderStatusChanged(status) + err := partner.CurOrderManager.OnOrderStatusChanged(status) // 直接跳到拣货完成 if msg.MsgType == elmapi.MsgTypeOrderAccepted { status.Status = model.OrderStatusFinishedPickup status.VendorStatus = fakePickedUp - err = controller.OrderManager.OnOrderStatusChanged(status) + err = partner.CurOrderManager.OnOrderStatusChanged(status) } // if globals.HandleLegacyJxOrder && err == nil { // c.legacyElmOrderStatusChanged(status) @@ -116,7 +108,7 @@ func (c *OrderController) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) ( return elmapi.Err2CallbackResponse(err, status.VendorStatus) } -func (c *OrderController) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { status := c.cancelRefundMsg2Status(msg) switch msg.MsgType { case elmapi.MsgTypeUserApplyCancel: @@ -126,10 +118,10 @@ func (c *OrderController) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancel default: status.Status = model.OrderStatusUnknown } - return elmapi.Err2CallbackResponse(controller.OrderManager.OnOrderStatusChanged(status), status.VendorStatus) + return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged(status), status.VendorStatus) } -func (c *OrderController) GetOrder(orderID string) (order *model.GoodsOrder, err error) { +func (c *PurchaseHandler) GetOrder(orderID string) (order *model.GoodsOrder, err error) { result, err := api.ElmAPI.GetOrder(orderID) if err == nil { phoneList := result["phoneList"].([]interface{}) @@ -191,8 +183,8 @@ func (c *OrderController) GetOrder(orderID string) (order *model.GoodsOrder, err order.Weight += sku.Weight * sku.Count } } + setOrederDetailFee(result, order) } - setOrederDetailFee(result, order) return order, err } @@ -217,12 +209,12 @@ func setOrederDetailFee(result map[string]interface{}, order *model.GoodsOrder) } // -func (c *OrderController) onOrderNew(msg map[string]interface{}) (response *elmapi.CallbackResponse) { +func (c *PurchaseHandler) onOrderNew(msg map[string]interface{}) (response *elmapi.CallbackResponse) { // todo 这里应该可以直接用msg里的内容,而不用再次去查 order, err := c.GetOrder(msg["orderId"].(string)) if err == nil { order.VendorStatus = c.stateAndType2Str(order.VendorStatus, elmapi.MsgTypeOrderValid) - err = controller.OrderManager.OnOrderNew(order, c.stateAndType2Str(msg["status"].(string), elmapi.MsgTypeOrderValid)) + err = partner.CurOrderManager.OnOrderNew(order, c.stateAndType2Str(msg["status"].(string), elmapi.MsgTypeOrderValid)) // if globals.HandleLegacyJxOrder && err == nil { // c.legacyWriteElmOrder(order) // } @@ -230,7 +222,7 @@ func (c *OrderController) onOrderNew(msg map[string]interface{}) (response *elma return elmapi.Err2CallbackResponse(err, "elm onOrderNew") } -func (c *OrderController) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) *elmapi.CallbackResponse { +func (c *PurchaseHandler) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) *elmapi.CallbackResponse { status := &model.OrderStatus{ VendorOrderID: msg.OrderID, VendorID: model.VendorIDELM, @@ -244,14 +236,14 @@ func (c *OrderController) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) if globals.ReallyCallPlatformAPI { freshfood.FreshFoodAPI.ELMClientUrgeOrder(msg.OrderID) } - return elmapi.Err2CallbackResponse(controller.OrderManager.OnOrderStatusChanged(status), status.VendorStatus) + return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged(status), status.VendorStatus) } -func (c *OrderController) stateAndType2Str(state string, msgType int) string { +func (c *PurchaseHandler) stateAndType2Str(state string, msgType int) string { return fmt.Sprintf("%s-%d", state, msgType) } -func (c *OrderController) spliltCompositeState(compositeState string) (state string, msgType int) { +func (c *PurchaseHandler) spliltCompositeState(compositeState string) (state string, msgType int) { index := strings.Index(compositeState, "-") if index >= 0 { msgType = int(utils.Str2Int64(compositeState[index+1:])) @@ -263,8 +255,8 @@ func (c *OrderController) spliltCompositeState(compositeState string) (state str return compositeState, 0 } -// PurchasePlatformHandler -func (c *OrderController) GetStatusFromVendorStatus(vendorStatus string) int { +// IPurchasePlatformHandler +func (c *PurchaseHandler) GetStatusFromVendorStatus(vendorStatus string) int { state, _ := c.spliltCompositeState(vendorStatus) if status, ok := VendorStatus2StatusMap[state]; ok { return status @@ -272,7 +264,7 @@ func (c *OrderController) GetStatusFromVendorStatus(vendorStatus string) int { return model.OrderStatusUnknown } -func (c *OrderController) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) { +func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { if isAcceptIt { err = api.ElmAPI.ConfirmOrder(order.VendorOrderID) } else { @@ -283,29 +275,29 @@ func (c *OrderController) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptI // 饿了么没有拣货这个状态,直接返回成功 // 真实流程中也不会调用这个方法,因为接收订单后状态会直接转移到已拣货 -func (c *OrderController) PickupGoods(order *model.GoodsOrder) (err error) { +func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, userName string) (err error) { return nil } -func (c *OrderController) Swtich2SelfDeliver(order *model.GoodsOrder) (err error) { +func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { err = api.ElmAPI.DeliveryBySelfLite(order.VendorOrderID) return err } // 饿了么转商家自送后,没有确认送达的概念,空操作 -func (c *OrderController) Swtich2SelfDelivered(order *model.GoodsOrder) (err error) { +func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { return nil } -func (c *OrderController) SelfDeliverDelievering(order *model.GoodsOrder) (err error) { +func (c *PurchaseHandler) SelfDeliverDelievering(order *model.GoodsOrder, userName string) (err error) { return api.ElmAPI.StartDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile) } -func (c *OrderController) SelfDeliverDelievered(order *model.GoodsOrder) (err error) { +func (c *PurchaseHandler) SelfDeliverDelievered(order *model.GoodsOrder, userName string) (err error) { return api.ElmAPI.CompleteDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile) } -func (c *OrderController) GetStatusActionTimeout(statusType, status int) time.Duration { +func (c *PurchaseHandler) GetStatusActionTimeout(statusType, status int) time.Duration { if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusNew { return acceptOrderDelay // 饿了么开了专送店的订单没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货 } diff --git a/business/controller/elm/order_legacy.go b/business/partner/purchase/elm/order_legacy.go similarity index 90% rename from business/controller/elm/order_legacy.go rename to business/partner/purchase/elm/order_legacy.go index 18640703c..91976d239 100644 --- a/business/controller/elm/order_legacy.go +++ b/business/partner/purchase/elm/order_legacy.go @@ -1,18 +1,15 @@ package elm import ( - "github.com/astaxie/beego/orm" - - "git.rosy.net.cn/jx-callback/business/legacymodel" - - "git.rosy.net.cn/jx-callback/globals" - "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/legacymodel" "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" + "github.com/astaxie/beego/orm" ) // 为了兼容之前的表,造出原来需要的数据 -func (c *OrderController) legacyWriteElmOrder(order *model.GoodsOrder) (err error) { +func (c *PurchaseHandler) legacyWriteElmOrder(order *model.GoodsOrder) (err error) { db := orm.NewOrm() _, msgType := c.spliltCompositeState(order.VendorStatus) legacyOrder := &legacymodel.Elemeorder2{ @@ -29,7 +26,7 @@ func (c *OrderController) legacyWriteElmOrder(order *model.GoodsOrder) (err erro return err } -func (c *OrderController) legacyElmOrderStatusChanged(status *model.OrderStatus) (err error) { +func (c *PurchaseHandler) legacyElmOrderStatusChanged(status *model.OrderStatus) (err error) { db := orm.NewOrm() legacyOrder := &legacymodel.Elemeorder2{ Orderid: status.VendorOrderID, diff --git a/business/controller/elm/order_test.go b/business/partner/purchase/elm/order_test.go similarity index 62% rename from business/controller/elm/order_test.go rename to business/partner/purchase/elm/order_test.go index 2968fa458..6e1c729d3 100644 --- a/business/controller/elm/order_test.go +++ b/business/partner/purchase/elm/order_test.go @@ -3,30 +3,31 @@ package elm import ( "testing" + _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" - "git.rosy.net.cn/jx-callback/globals/db" + "git.rosy.net.cn/jx-callback/globals/beegodb" "github.com/astaxie/beego" ) func init() { //E:/goprojects/src/git.rosy.net.cn/jx-callback/conf/app.conf ///Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf - beego.InitBeegoBeforeTest("Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf") + beego.InitBeegoBeforeTest("/Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf") beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test globals.Init() - db.Init() + beegodb.Init() api.Init() } func TestGetOrder(t *testing.T) { orderID := "3025427524410871880" - order, err := new(OrderController).GetOrder(orderID) + order, err := new(PurchaseHandler).GetOrder(orderID) if err != nil { - panic(err.Error()) + t.Fatal(err.Error()) } if order.VendorOrderID != orderID { - panic(err.Error()) + t.Fatal(err.Error()) } } diff --git a/business/controller/elm/waybill.go b/business/partner/purchase/elm/waybill.go similarity index 77% rename from business/controller/elm/waybill.go rename to business/partner/purchase/elm/waybill.go index 3ea36014e..7d4dd4213 100644 --- a/business/controller/elm/waybill.go +++ b/business/partner/purchase/elm/waybill.go @@ -5,23 +5,20 @@ import ( "git.rosy.net.cn/baseapi/platformapi/elmapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals/api" ) -type WaybillController struct { -} - -func (c *WaybillController) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onWaybillStatusMsg(msg) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM)) return retVal } -func (c *WaybillController) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { +func (c *PurchaseHandler) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { order := c.callbackMsg2Waybill(msg) if msg.MsgType == elmapi.MsgTypeWaybillWait4Courier { //MsgTypeWaybillWait4Courier事件与JD的新运单事件的时间机制更相似 order.Status = model.WaybillStatusNew @@ -48,10 +45,10 @@ func (c *WaybillController) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatus // MsgTypeDeiverBySelf order.Status = model.WaybillStatusUnknown } - return elmapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), order.VendorStatus) + return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus) } -func (c *WaybillController) callbackMsg2Waybill(msg *elmapi.CallbackWaybillStatusMsg) (retVal *model.Waybill) { +func (c *PurchaseHandler) callbackMsg2Waybill(msg *elmapi.CallbackWaybillStatusMsg) (retVal *model.Waybill) { retVal = &model.Waybill{ VendorOrderID: msg.OrderID, OrderVendorID: model.VendorIDELM, @@ -65,6 +62,6 @@ func (c *WaybillController) callbackMsg2Waybill(msg *elmapi.CallbackWaybillStatu return retVal } -func (c *WaybillController) composeState(state, subState string, msgType int) string { +func (c *PurchaseHandler) composeState(state, subState string, msgType int) string { return fmt.Sprintf("%s-%d", state, msgType) } diff --git a/business/partner/purchase/jd/jd.go b/business/partner/purchase/jd/jd.go new file mode 100644 index 000000000..011d6cf22 --- /dev/null +++ b/business/partner/purchase/jd/jd.go @@ -0,0 +1,60 @@ +package jd + +import ( + "git.rosy.net.cn/baseapi/platformapi/jdapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" + "git.rosy.net.cn/jx-callback/business/model" +) + +var ( + curPurchaseHandler *PurchaseHandler +) + +type PurchaseHandler struct { + scheduler.BasePurchasePlatform +} + +func init() { + curPurchaseHandler = new(PurchaseHandler) + scheduler.CurrentScheduler.RegisterPurchasePlatform(model.VendorIDJD, curPurchaseHandler) +} + +func OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { + return curPurchaseHandler.OnOrderMsg(msg) +} + +func OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return curPurchaseHandler.OnWaybillMsg(msg) +} + +func JdOperationTime2JxOperationTime(value1 interface{}) int { + value := int(utils.Interface2Int64WithDefault(value1, 0)) + return (value/2)*100 + (value%2)*30 +} + +func JxOperationTime2JdOperationTime(value int) int { + return (value/100)*2 + (value % 30) +} + +func JdStoreStatus2JxStatus(yn, closeStatus interface{}) int { + yn2 := utils.Interface2Int64WithDefault(yn, 0) + closeStatus2 := utils.Interface2Int64WithDefault(closeStatus, 0) + if yn2 == 1 { + return model.StoreStatusDisabled + } else if closeStatus2 == 1 { + return model.StoreStatusClosed + } + return model.StoreStatusOpened +} + +func JxStoreStatus2JdStatus(status int) (yn, closeStatus int) { + switch status { + case model.StoreStatusDisabled: + return 1, 0 + case model.StoreStatusClosed: + return 0, 1 + default: + return 0, 0 + } +} diff --git a/business/controller/jd/order.go b/business/partner/purchase/jd/order.go similarity index 80% rename from business/controller/jd/order.go rename to business/partner/purchase/jd/order.go index 64a9d371d..466950661 100644 --- a/business/controller/jd/order.go +++ b/business/partner/purchase/jd/order.go @@ -6,10 +6,9 @@ import ( "git.rosy.net.cn/baseapi/platformapi/autonavi" "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/business/scheduler" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/legacy/freshfood" @@ -32,22 +31,14 @@ var ( } ) -type OrderController struct { - scheduler.BasePurchasePlatform -} - -func init() { - scheduler.CurrentScheduler.RegisterPurchasePlatform(model.VendorIDJD, new(OrderController)) -} - -func (c *OrderController) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { +func (c *PurchaseHandler) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onOrderMsg(msg) }, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD)) return retVal } -func (c *OrderController) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { +func (c *PurchaseHandler) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { if jdapi.OrderStatusNew == msg.StatusID { retVal = c.onOrderNew(msg) } else if jdapi.OrderStatusAdjust == msg.StatusID { @@ -59,7 +50,7 @@ func (c *OrderController) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi freshfood.FreshFoodAPI.JDOrderComment(msg) } } - err := controller.OrderManager.OnOrderStatusChanged(status) + err := partner.CurOrderManager.OnOrderStatusChanged(status) // if globals.HandleLegacyJxOrder && err == nil { // c.legacyJdOrderStatusChanged(status) // } @@ -68,7 +59,7 @@ func (c *OrderController) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi return retVal } -func (c *OrderController) GetOrder(orderID string) (order *model.GoodsOrder, err error) { +func (c *PurchaseHandler) GetOrder(orderID string) (order *model.GoodsOrder, err error) { result, err := api.JdAPI.QuerySingleOrder(orderID) // globals.SugarLogger.Info(result) if err == nil { @@ -136,8 +127,8 @@ func (c *OrderController) GetOrder(orderID string) (order *model.GoodsOrder, err order.SalePrice += sku.SalePrice * int64(sku.Count) order.Weight += sku.Weight * sku.Count } + setOrederDetailFee(result, order) } - setOrederDetailFee(result, order) return order, err } @@ -148,10 +139,10 @@ func setOrederDetailFee(result map[string]interface{}, order *model.GoodsOrder) } // -func (c *OrderController) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) { +func (c *PurchaseHandler) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) { order, err := c.GetOrder(msg.BillID) if err == nil { - err = controller.OrderManager.OnOrderNew(order, msg.StatusID) + err = partner.CurOrderManager.OnOrderNew(order, msg.StatusID) // if err == nil { // c.legacyWriteJdOrder(order, false) // } @@ -159,10 +150,10 @@ func (c *OrderController) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jda return jdapi.Err2CallbackResponse(err, "jd onOrderNew") } -func (c *OrderController) onOrderAdjust(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { +func (c *PurchaseHandler) onOrderAdjust(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { order, err := c.GetOrder(msg.BillID) if err == nil { - err = controller.OrderManager.OnOrderAdjust(order, msg.StatusID) + err = partner.CurOrderManager.OnOrderAdjust(order, msg.StatusID) // if globals.HandleLegacyJxOrder && err == nil { // c.legacyWriteJdOrder(order, true) // } @@ -170,7 +161,7 @@ func (c *OrderController) onOrderAdjust(msg *jdapi.CallbackOrderMsg) *jdapi.Call return jdapi.Err2CallbackResponse(err, "jd onOrderAdjust") } -func (c *OrderController) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus { +func (c *PurchaseHandler) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus { orderStatus := &model.OrderStatus{ VendorOrderID: msg.BillID, VendorID: model.VendorIDJD, @@ -185,26 +176,26 @@ func (c *OrderController) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model return orderStatus } -// PurchasePlatformHandler -func (c *OrderController) GetStatusFromVendorStatus(vendorStatus string) int { +// IPurchasePlatformHandler +func (c *PurchaseHandler) GetStatusFromVendorStatus(vendorStatus string) int { if status, ok := VendorStatus2StatusMap[vendorStatus]; ok { return status } return model.OrderStatusUnknown } -func (c *OrderController) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) { - _, err = api.JdAPI.OrderAcceptOperate(order.VendorOrderID, isAcceptIt) +func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { + _, err = api.JdAPI.OrderAcceptOperate(order.VendorOrderID, isAcceptIt, userName) return err } -func (c *OrderController) PickupGoods(order *model.GoodsOrder) (err error) { - _, err = api.JdAPI.OrderJDZBDelivery(order.VendorOrderID) +func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, userName string) (err error) { + _, err = api.JdAPI.OrderJDZBDelivery(order.VendorOrderID, userName) return err } -func (c *OrderController) Swtich2SelfDeliver(order *model.GoodsOrder) (err error) { - _, err = api.JdAPI.ModifySellerDelivery(order.VendorOrderID) +func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { + _, err = api.JdAPI.ModifySellerDelivery(order.VendorOrderID, userName) if err != nil { if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 { globals.SugarLogger.Infof("Swtich2SelfDeliver failed with error:%v try get current status", err) @@ -221,17 +212,17 @@ func (c *OrderController) Swtich2SelfDeliver(order *model.GoodsOrder) (err error return err } -func (c *OrderController) Swtich2SelfDelivered(order *model.GoodsOrder) (err error) { - _, err = api.JdAPI.DeliveryEndOrder(order.VendorOrderID) +func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { + _, err = api.JdAPI.DeliveryEndOrder(order.VendorOrderID, userName) return err } -func (c *OrderController) SelfDeliverDelievering(order *model.GoodsOrder) (err error) { - _, err = api.JdAPI.OrderSerllerDelivery(order.VendorOrderID) +func (c *PurchaseHandler) SelfDeliverDelievering(order *model.GoodsOrder, userName string) (err error) { + _, err = api.JdAPI.OrderSerllerDelivery(order.VendorOrderID, userName) return err } // 京东送达接口都是一样的 -func (c *OrderController) SelfDeliverDelievered(order *model.GoodsOrder) (err error) { - return c.Swtich2SelfDelivered(order) +func (c *PurchaseHandler) SelfDeliverDelievered(order *model.GoodsOrder, userName string) (err error) { + return c.Swtich2SelfDelivered(order, userName) } diff --git a/business/controller/jd/order_legacy.go b/business/partner/purchase/jd/order_legacy.go similarity index 92% rename from business/controller/jd/order_legacy.go rename to business/partner/purchase/jd/order_legacy.go index 587b2f1fe..d3a20cf28 100644 --- a/business/controller/jd/order_legacy.go +++ b/business/partner/purchase/jd/order_legacy.go @@ -9,7 +9,7 @@ import ( ) // 为了兼容之前的表,造出原来需要的数据 -func (c *OrderController) legacyWriteJdOrder(order *model.GoodsOrder, delOldFirst bool) (err error) { +func (c *PurchaseHandler) legacyWriteJdOrder(order *model.GoodsOrder, delOldFirst bool) (err error) { db := orm.NewOrm() if delOldFirst { db.Raw("DELETE FROM jdorder2 WHERE jdorderid = ?", utils.Str2Int64(order.VendorOrderID)).Exec() @@ -29,7 +29,7 @@ func (c *OrderController) legacyWriteJdOrder(order *model.GoodsOrder, delOldFirs return err } -func (c *OrderController) legacyJdOrderStatusChanged(status *model.OrderStatus) (err error) { +func (c *PurchaseHandler) legacyJdOrderStatusChanged(status *model.OrderStatus) (err error) { db := orm.NewOrm() legacyOrder := &legacymodel.Jdorder2{ Jdorderid: utils.Str2Int64(status.VendorOrderID), diff --git a/business/controller/jd/order_test.go b/business/partner/purchase/jd/order_test.go similarity index 64% rename from business/controller/jd/order_test.go rename to business/partner/purchase/jd/order_test.go index 92d1a9664..05890349e 100644 --- a/business/controller/jd/order_test.go +++ b/business/partner/purchase/jd/order_test.go @@ -3,11 +3,12 @@ package jd import ( "testing" - "git.rosy.net.cn/jx-callback/business/controller" + _ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" "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" - "git.rosy.net.cn/jx-callback/globals/db" + "git.rosy.net.cn/jx-callback/globals/beegodb" "github.com/astaxie/beego" ) @@ -16,15 +17,15 @@ func init() { beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test globals.Init() - db.Init() + beegodb.Init() api.Init() } func TestSwitch2SelfDeliver(t *testing.T) { orderID := "817540316000041" - if order, err := controller.OrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil { + if order, err := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil { // globals.SugarLogger.Debug(order) - c := new(OrderController) + c := new(PurchaseHandler) if err = c.Swtich2SelfDeliver(order); err == nil { } else { t.Fatal(err.Error()) @@ -34,9 +35,9 @@ func TestSwitch2SelfDeliver(t *testing.T) { } } -func Test_GetOrder(t *testing.T) { - _, err := new(OrderController).GetOrder("815536199000222") +func TestGetOrder(t *testing.T) { + _, err := new(PurchaseHandler).GetOrder("815536199000222") if err != nil { - panic(err.Error()) + t.Fatal(err.Error()) } } diff --git a/business/partner/purchase/jd/sku.go b/business/partner/purchase/jd/sku.go new file mode 100644 index 000000000..bcaaa7726 --- /dev/null +++ b/business/partner/purchase/jd/sku.go @@ -0,0 +1,13 @@ +package jd + +import ( + "git.rosy.net.cn/jx-callback/business/model" +) + +func (p *PurchaseHandler) AddSku(sku *model.Sku) error { + // params := map[string]interface{}{ + // "outSkuId": utils.Int2Str(int(sku.ID)), + // "categoryId": + // } + return nil +} diff --git a/business/partner/purchase/jd/store.go b/business/partner/purchase/jd/store.go new file mode 100644 index 000000000..05a9fd753 --- /dev/null +++ b/business/partner/purchase/jd/store.go @@ -0,0 +1,67 @@ +package jd + +import ( + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals/api" +) + +func (p *PurchaseHandler) GetAllStoreIDsFromRemote() ([]string, error) { + result, err := api.JdAPI.GetStationsByVenderId() + return result, err +} + +func (p *PurchaseHandler) GetAllStoresFromRemote() ([]*model.Store, error) { + ids, err := p.GetAllStoreIDsFromRemote() + if err == nil { + retVal := make([]*model.Store, len(ids)) + for index, id := range ids { + store, err2 := p.GetStoreFromRemote(id) + if err2 == nil { + retVal[index] = store + } else { + return nil, err2 + } + } + return retVal, nil + } + return nil, err +} + +func (p *PurchaseHandler) GetStoreFromRemote(vendorStoreID string) (*model.Store, error) { + result, err := api.JdAPI.GetStoreInfoByStationNo(vendorStoreID) + if err == nil { + retVal := &model.Store{ + Name: utils.Interface2String(result["stationName"]), + Address: utils.Interface2String(result["stationAddress"]), + OpenTime1: JdOperationTime2JxOperationTime(result["serviceTimeStart1"]), + CloseTime1: JdOperationTime2JxOperationTime(result["serviceTimeEnd1"]), + OpenTime2: JdOperationTime2JxOperationTime(result["serviceTimeStart2"]), + CloseTime2: JdOperationTime2JxOperationTime(result["serviceTimeEnd2"]), + Status: JdStoreStatus2JxStatus(result["yn"], result["closeStatus"]), + } + retVal.ID = int(utils.Str2Int64WithDefault(utils.Interface2String(result["outSystemId"]), 0)) + return retVal, nil + } + return nil, err +} + +func (p *PurchaseHandler) SaveStore2Remote(vendorStoreID string, store *model.Store) error { + params := map[string]interface{}{ + "outSystemId": utils.Int2Str(int(store.ID)), + "stationName": store.Name, + "stationAddress": store.Address, + "serviceTimeStart1": JxOperationTime2JdOperationTime(store.OpenTime1), + "serviceTimeEnd1": JxOperationTime2JdOperationTime(store.CloseTime1), + "serviceTimeStart2": JxOperationTime2JdOperationTime(store.OpenTime2), + "serviceTimeEnd2": JxOperationTime2JdOperationTime(store.CloseTime2), + } + params["yn"], params["closeStatus"] = JxStoreStatus2JdStatus(store.Status) + _, err := api.JdAPI.UpdateStoreInfo4Open(vendorStoreID, "", params) + return err +} + +func (p *PurchaseHandler) EnableAutoAcceptOrder(vendorStoreID string, isEnabled bool) error { + _, err := api.JdAPI.UpdateStoreConfig4Open(vendorStoreID, isEnabled) + return err +} diff --git a/business/controller/jd/waybill.go b/business/partner/purchase/jd/waybill.go similarity index 79% rename from business/controller/jd/waybill.go rename to business/partner/purchase/jd/waybill.go index 0aacb59bd..b2237bd6f 100644 --- a/business/controller/jd/waybill.go +++ b/business/partner/purchase/jd/waybill.go @@ -3,23 +3,20 @@ package jd import ( "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals/api" ) -type WaybillController struct { -} - -func (c *WaybillController) OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { +func (c *PurchaseHandler) OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onWaybillMsg(msg) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDJD)) return retVal } -func (c *WaybillController) onWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { +func (c *PurchaseHandler) onWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { order := c.callbackMsg2Waybill(msg) switch msg.DeliveryStatus { case jdapi.DeliveryStatusWait4Grap: @@ -46,10 +43,10 @@ func (c *WaybillController) onWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) ( default: order.Status = model.WaybillStatusUnknown } - return jdapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), order.VendorStatus) + return jdapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus) } -func (c *WaybillController) callbackMsg2Waybill(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *model.Waybill) { +func (c *PurchaseHandler) callbackMsg2Waybill(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *model.Waybill) { retVal = &model.Waybill{ VendorOrderID: msg.OrderID, OrderVendorID: model.VendorIDJD, diff --git a/conf/app.conf b/conf/app.conf index b13505cdc..74e402168 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -14,9 +14,8 @@ dadaAppSecret = "2c717ad914767d6e2beb3f743db9e477" autonaviKey = "4427170f870af2110becb8852d36ab08" -callLegacyMsgHandler = false -callNewMsgHandler = true generateLegacyJxOrder = false +enableStore = true [dev] freshFoodServerURL = "http://portal.beta.jxc4.com" @@ -40,7 +39,7 @@ dadaSourceID = "73753" weixinAppID = "wxbf235770edaabc5c" weixinSecret = "ba32b269a068a5b72486a0beafd171e8" -dbConnectStr = "root:WebServer@1@tcp(127.0.0.1:3306)/jxd_dev_0?charset=utf8&loc=Local" +dbConnectStr = "root:WebServer@1@tcp(127.0.0.1:3306)/jxd_dev_0?charset=utf8&loc=Local&parseTime=true" [prod] freshFoodServerURL = "http://portal.int.jxc4.com" @@ -64,7 +63,9 @@ dadaSourceID = "6660" weixinAppID = "wx2bb99eb5d2c9b82c" weixinSecret = "6bbbed1443cc062c20a015a64c07a531" -dbConnectStr = "root:WebServer@1@tcp(db1.int.jxc4.com:3306)/jxd_dev_0?charset=utf8&loc=Local" +dbConnectStr = "root:WebServer@1@tcp(db1.int.jxc4.com:3306)/jxd_dev_0?charset=utf8&loc=Local&parseTime=true" + +enableStore = false [test] freshFoodServerURL = "http://portal.alpha.int.jxc4.com" @@ -88,4 +89,4 @@ dadaSourceID = "6660" weixinAppID = "wx2bb99eb5d2c9b82c" weixinSecret = "6bbbed1443cc062c20a015a64c07a531" -dbConnectStr = "root:WebServer@1@tcp(127.0.0.1:3306)/jxd_dev_0?charset=utf8&loc=Local" +dbConnectStr = "root:WebServer@1@tcp(127.0.0.1:3306)/jxd_dev_0?charset=utf8&loc=Local&parseTime=true" diff --git a/controllers/dada_order.go b/controllers/dada_order.go index 0984b6e78..bf9a258e6 100644 --- a/controllers/dada_order.go +++ b/controllers/dada_order.go @@ -1,50 +1,32 @@ package controllers import ( + "net/http" + "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller/dada" - "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/business/partner/delivery/dada" "git.rosy.net.cn/jx-callback/globals/api" - "git.rosy.net.cn/jx-callback/legacy/dada/controller" "github.com/astaxie/beego" ) // Operations about ELMOrder -type DadaOrderController struct { +type DadaDeliveryController struct { beego.Controller } -func (c *DadaOrderController) URLMapping() { - c.Mapping("OrderStatusChanged", c.OrderStatusChanged) -} - -// @Title all msg -// @Description create object -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /msg [post] -func (c *DadaOrderController) OrderStatusChanged() { - obj, callbackResponse := api.DadaAPI.GetOrderCallbackMsg(c.Ctx.Input.RequestBody) - if callbackResponse == nil { - if globals.CallLegacyMsgHandler { - cc := &controller.OrderController{} - callbackResponse = cc.OrderStatusChanged(obj) +func (c *DadaDeliveryController) Msg() { + if c.Ctx.Input.Method() == http.MethodPost { + obj, callbackResponse := api.DadaAPI.GetOrderCallbackMsg(c.Ctx.Input.RequestBody) + if callbackResponse == nil { + callbackResponse = dada.OnWaybillMsg(obj) } - if globals.CallNewMsgHandler { - cc2 := &dada.WaybillController{} - if globals.CallLegacyMsgHandler { - utils.CallFuncAsync(func() { - cc2.OnWaybillMsg(obj) - }) - } else { - callbackResponse = cc2.OnWaybillMsg(obj) - } + if callbackResponse != nil && callbackResponse.Code != 200 { + c.CustomAbort(callbackResponse.Code, string(utils.MustMarshal(callbackResponse))) + } else { + c.Data["json"] = callbackResponse + c.ServeJSON() } - } - if callbackResponse != nil && callbackResponse.Code != 200 { - c.CustomAbort(callbackResponse.Code, string(utils.MustMarshal(callbackResponse))) } else { - c.Data["json"] = callbackResponse - c.ServeJSON() + c.Abort("404") } } diff --git a/controllers/elm_order.go b/controllers/elm_order.go index e33df6d00..bc8bdc8b1 100644 --- a/controllers/elm_order.go +++ b/controllers/elm_order.go @@ -1,57 +1,32 @@ package controllers import ( + "net/http" + "git.rosy.net.cn/baseapi/platformapi/elmapi" - "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller/elm" - "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/business/partner/purchase/elm" "git.rosy.net.cn/jx-callback/globals/api" - "git.rosy.net.cn/jx-callback/legacy/elm/controller" "github.com/astaxie/beego" ) // Operations about ELMOrder -type ELMOrderController struct { +type ElemeController struct { beego.Controller } -func (c *ELMOrderController) URLMapping() { - c.Mapping("MsgPost", c.MsgPost) - c.Mapping("MsgGet", c.MsgGet) -} - -// @Title all msg -// @Description create object -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /msg [post] -func (c *ELMOrderController) MsgPost() { - obj, callbackResponse := api.ElmAPI.GetCallbackMsg(c.Ctx.Input.RequestBody) - if callbackResponse == nil { - if globals.CallLegacyMsgHandler { - cc := &controller.OrderController{} - callbackResponse = cc.OrderMessage(obj) - } - if globals.CallNewMsgHandler { - cc2 := &elm.Controller{} - if globals.CallLegacyMsgHandler { - utils.CallFuncAsync(func() { - cc2.OnCallbackMsg(obj) - }) - } else { - callbackResponse = cc2.OnCallbackMsg(obj) - } +// https://open.shop.ele.me/openapi/documents/httppushmethod +func (c *ElemeController) Msg() { + if c.Ctx.Input.Method() == http.MethodPost { + obj, callbackResponse := api.ElmAPI.GetCallbackMsg(c.Ctx.Input.RequestBody) + if callbackResponse == nil { + callbackResponse = elm.OnCallbackMsg(obj) } + c.Data["json"] = callbackResponse + c.ServeJSON() + } else if c.Ctx.Input.Method() == http.MethodGet { // 应用需要支持推送地址的GET访问,当GET请求访问时,请直接返回{“message”:“ok”},用于推送地址的可用性测试。 + c.Data["json"] = elmapi.SuccessResponse + c.ServeJSON() + } else { + c.Abort("404") } - c.Data["json"] = callbackResponse - c.ServeJSON() -} - -// @Title all msg test -// @Description create object -// @Success 200 {string} models.Object.Id -// @router /msg [get] -func (c *ELMOrderController) MsgGet() { - c.Data["json"] = elmapi.SuccessResponse - c.ServeJSON() } diff --git a/controllers/jd_order.go b/controllers/jd_order.go index 99955466c..70dbeb560 100644 --- a/controllers/jd_order.go +++ b/controllers/jd_order.go @@ -1,185 +1,88 @@ package controllers import ( + "net/http" + "git.rosy.net.cn/baseapi/platformapi/jdapi" - "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller/jd" - "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/business/partner/purchase/jd" "git.rosy.net.cn/jx-callback/globals/api" - "git.rosy.net.cn/jx-callback/legacy/jd/controller" "github.com/astaxie/beego" ) // Operations about JDOrder -type JDOrderController struct { +type DjswController struct { beego.Controller } -func (c *JDOrderController) URLMapping() { - c.Mapping("NewOrder", c.NewOrder) - c.Mapping("OrderAdjust", c.OrderAdjust) - c.Mapping("OrderWaitOutStore", c.OrderWaitOutStore) - c.Mapping("PickFinishOrder", c.PickFinishOrder) - c.Mapping("DeliveryOrder", c.DeliveryOrder) - c.Mapping("LockOrder", c.LockOrder) - c.Mapping("UserCancelOrder", c.UserCancelOrder) - c.Mapping("ApplyCancelOrder", c.ApplyCancelOrder) - c.Mapping("PushDeliveryStatus", c.PushDeliveryStatus) -} +func (c *DjswController) orderStatus(isCancelOrder bool) { + if c.Ctx.Input.Method() == http.MethodPost { + var obj *jdapi.CallbackOrderMsg + var callbackResponse *jdapi.CallbackResponse -func (c *JDOrderController) orderStatus(isCancelOrder bool) { - var obj *jdapi.CallbackOrderMsg - var callbackResponse *jdapi.CallbackResponse - - if isCancelOrder { - obj, callbackResponse = api.JdAPI.GetOrderApplyCancelCallbackMsg(c.Ctx.Input.RequestBody) + if isCancelOrder { + obj, callbackResponse = api.JdAPI.GetOrderApplyCancelCallbackMsg(c.Ctx.Input.RequestBody) + } else { + obj, callbackResponse = api.JdAPI.GetOrderCallbackMsg(c.Ctx.Input.RequestBody) + } + if callbackResponse == nil { + callbackResponse = jd.OnOrderMsg(obj) + } + c.Data["json"] = callbackResponse + c.ServeJSON() } else { - obj, callbackResponse = api.JdAPI.GetOrderCallbackMsg(c.Ctx.Input.RequestBody) + c.Abort("404") } - if callbackResponse == nil { - if globals.CallLegacyMsgHandler { - cc := controller.OrderController{} - callbackResponse = cc.OrderStatus(obj) - } - if globals.CallNewMsgHandler { - cc2 := &jd.OrderController{} - if globals.CallLegacyMsgHandler { - utils.CallFuncAsync(func() { - cc2.OnOrderMsg(obj) - }) - } else { - callbackResponse = cc2.OnOrderMsg(obj) - } - } - } - c.Data["json"] = callbackResponse - c.ServeJSON() } -// @Title newOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /newOrder [post] -func (c *JDOrderController) NewOrder() { +func (c *DjswController) NewOrder() { c.orderStatus(false) } -// @Title AdjustOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /orderAdjust [post] -func (c *JDOrderController) OrderAdjust() { +func (c *DjswController) OrderAdjust() { c.orderStatus(false) } -// @Title orderWaitOutStore -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /orderWaitOutStore [post] -func (c *JDOrderController) OrderWaitOutStore() { +func (c *DjswController) OrderWaitOutStore() { c.orderStatus(false) } -// @Title pickFinishOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /pickFinishOrder [post] -func (c *JDOrderController) PickFinishOrder() { +func (c *DjswController) PickFinishOrder() { c.orderStatus(false) } -// @Title deliveryOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /deliveryOrder [post] -func (c *JDOrderController) DeliveryOrder() { +func (c *DjswController) DeliveryOrder() { c.orderStatus(false) } -// @Title finishOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /finishOrder [post] -func (c *JDOrderController) FinishOrder() { +func (c *DjswController) FinishOrder() { c.orderStatus(false) } -// @Title lockOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /lockOrder [post] -func (c *JDOrderController) LockOrder() { +func (c *DjswController) LockOrder() { c.orderStatus(false) } -// @Title userCancelOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /userCancelOrder [post] -func (c *JDOrderController) UserCancelOrder() { +func (c *DjswController) UserCancelOrder() { c.orderStatus(false) } -// @Title applyCancelOrder -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /applyCancelOrder [post] -func (c *JDOrderController) ApplyCancelOrder() { +func (c *DjswController) ApplyCancelOrder() { c.orderStatus(true) } -// @Title pushDeliveryStatus -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /pushDeliveryStatus [post] -func (c *JDOrderController) PushDeliveryStatus() { - obj, callbackResponse := api.JdAPI.GetOrderDeliveryCallbackMsg(c.Ctx.Input.RequestBody) - if callbackResponse == nil { - if globals.CallLegacyMsgHandler { - cc := controller.OrderController{} - callbackResponse = cc.OrderDeliveryStatus(obj) - } - if globals.CallNewMsgHandler { - cc2 := &jd.WaybillController{} - if globals.CallLegacyMsgHandler { - utils.CallFuncAsync(func() { - cc2.OnWaybillMsg(obj) - }) - } else { - callbackResponse = cc2.OnWaybillMsg(obj) - } +func (c *DjswController) PushDeliveryStatus() { + if c.Ctx.Input.Method() == http.MethodPost { + obj, callbackResponse := api.JdAPI.GetOrderDeliveryCallbackMsg(c.Ctx.Input.RequestBody) + if callbackResponse == nil { + callbackResponse = jd.OnWaybillMsg(obj) } + c.Data["json"] = callbackResponse + c.ServeJSON() + } else { + c.Abort("404") } - c.Data["json"] = callbackResponse - c.ServeJSON() } -// @Title pushDeliveryStatus -// @Description create object -// @Param jd_param_json formData string true "应用级别输入参数" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /orderCommentPush [post] -func (c *JDOrderController) OrderComment() { +func (c *DjswController) OrderCommentPush() { c.orderStatus(false) } diff --git a/controllers/jx_order.go b/controllers/jx_order.go new file mode 100644 index 000000000..274ca5224 --- /dev/null +++ b/controllers/jx_order.go @@ -0,0 +1,209 @@ +package controllers + +import ( + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" + "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/basesch" + "git.rosy.net.cn/jx-callback/business/jxutils" + "git.rosy.net.cn/jx-callback/business/model" + "github.com/astaxie/beego" +) + +type OrderController struct { + beego.Controller +} + +func GetUserNameFromToken(token string) string { + userName := token + if len(userName) > 10 { + userName = userName[:10] + } + return userName +} + +func (c *OrderController) URLMapping() { + c.Mapping("FinishedPickup", c.FinishedPickup) + c.Mapping("GetStoreOrderInfo", c.GetStoreOrderInfo) + c.Mapping("GetOrderSkuInfo", c.GetOrderSkuInfo) + c.Mapping("CreateWaybillOnProviders", c.CreateWaybillOnProviders) + c.Mapping("Swtich2SelfDeliver", c.Swtich2SelfDeliver) +} + +func (c *OrderController) orderOperate(handler func(vendorOrderID string, vendorID int, userName string) (interface{}, error)) { + var ( + vendorOrderID, token string + vendorID int + err error + ) + token = c.Ctx.Input.Header("token") + vendorOrderID = c.GetString("vendorOrderID") + vendorID, err1 := c.GetInt("vendorID", 0) + if vendorOrderID != "" && token != "" && err1 == nil { + result, err2 := handler(vendorOrderID, vendorID, GetUserNameFromToken(token)) + if err = err2; err == nil { + retObj := &model.CallResult{ + Code: "0", + } + if result != nil { + retObj.Data = string(utils.MustMarshal(result)) + } + c.Data["json"] = retObj + } + } + errMsg := jxutils.Errs2Str("", err1, err) + if vendorOrderID == "" { + errMsg += "vendorOrderID is empty\n" + } + if token == "" { + errMsg += "token is empty\n" + } + if errMsg != "" { + c.Data["json"] = &model.CallResult{ + Code: "-1", + Desc: errMsg, + } + } + c.ServeJSON() +} + +// @Title 完成拣货 +// @Description 完成拣货 +// @Param token header string true "认证toke" +// @Param vendorOrderID formData string true "订单ID" +// @Param vendorID formData int true "订单所属的厂商ID" +// @Success 200 {object} business.model.CallResult +// @Failure 200 {object} business.model.CallResult +// @router /FinishedPickup [post] +func (c *OrderController) FinishedPickup() { + c.orderOperate(func(vendorOrderID string, vendorID int, userName string) (interface{}, error) { + return nil, basesch.FixedBaseScheduler.PickupGoodsAndUpdateStatus(vendorOrderID, vendorID, userName) + }) +} + +// @Title 转自送 +// @Description 转自送 +// @Param token header string true "认证toke" +// @Param vendorOrderID formData string true "订单ID" +// @Param vendorID formData int true "订单所属的厂商ID" +// @Success 200 {object} business.model.CallResult +// @Failure 200 {object} business.model.CallResult +// @router /Swtich2SelfDeliver [post] +func (c *OrderController) Swtich2SelfDeliver() { + c.orderOperate(func(vendorOrderID string, vendorID int, userName string) (interface{}, error) { + return nil, basesch.FixedBaseScheduler.Swtich2SelfDeliverAndUpdateStatus(vendorOrderID, vendorID, userName) + }) +} + +// @Title 创建三方运单 +// @Description 创建三方运单 +// @Param token header string true "认证toke" +// @Param vendorOrderID formData string true "订单ID" +// @Param vendorID formData int true "订单所属的厂商ID" +// @Success 200 {object} business.model.CallResult +// @Failure 200 {object} business.model.CallResult +// @router /CreateWaybillOnProviders [post] +func (c *OrderController) CreateWaybillOnProviders() { + c.orderOperate(func(vendorOrderID string, vendorID int, userName string) (interface{}, error) { + return basesch.FixedBaseScheduler.CreateWaybillOnProviders(vendorOrderID, vendorID) + }) +} + +// @Title 得到门店订单信息 +// @Description 得到门店订单信息 +// @Param token header string true "认证toke" +// @Param storeID query string true "京西门店ID" +// @Param lastHours query int false "最近多少小时的信息(缺省为两天)" +// @Success 200 {object} business.model.CallResult +// @Failure 200 {object} business.model.CallResult +// @router /GetStoreOrderCountInfo [get] +func (c *OrderController) GetStoreOrderCountInfo() { + var ( + storeID string + lastHours int + err error + ) + storeID = c.GetString("storeID") + lastHours, err1 := c.GetInt("lastHours", 0) + if storeID != "" && err1 == nil { + result, err2 := orderman.FixedOrderManager.GetStoreOrderCountInfo(storeID, lastHours) + if err = err2; err == nil { + c.Data["json"] = &model.CallResult{ + Code: "0", + Data: string(utils.MustMarshal(result)), + } + } + } + errMsg := jxutils.Errs2Str("", err1, err) + if storeID == "" { + errMsg += "storeID is empty\n" + } + if errMsg != "" { + c.Data["json"] = &model.CallResult{ + Code: "-1", + Desc: errMsg, + } + } + c.ServeJSON() +} + +// @Title 得到门店订单状态信息 +// @Description 得到门店订单状态信息 +// @Param token header string true "认证toke" +// @Param storeID query string true "京西门店ID" +// @Param lastHours query int false "最近多少小时的信息(缺省为两天)" +// @Param fromStatus query int true "起始状态(包括)" +// @Param toStatus query int false "结束状态(包括)" +// @Param offset query int false "订单列表起始序号(以0开始,缺省为0)" +// @Param pageSize query int false "订单列表页大小(缺省为50)" +// @Success 200 {object} business.model.CallResult +// @Failure 200 {object} business.model.CallResult +// @router /GetStoreOrderInfo [get] +func (c *OrderController) GetStoreOrderInfo() { + var ( + storeID string + lastHours, fromStatus, toStatus, offset, pageSize int + err error + ) + storeID = c.GetString("storeID") + lastHours, err1 := c.GetInt("lastHours", 0) + fromStatus, err2 := c.GetInt("fromStatus", 0) + toStatus, err3 := c.GetInt("toStatus", 0) + offset, err4 := c.GetInt("offset", 0) + pageSize, err5 := c.GetInt("pageSize", 0) + + if storeID != "" && err1 == nil && err2 == nil && err3 == nil && err4 == nil && err5 == nil { + result, err2 := orderman.FixedOrderManager.GetStoreOrderInfo(storeID, lastHours, fromStatus, toStatus, offset, pageSize) + if err = err2; err == nil { + c.Data["json"] = &model.CallResult{ + Code: "0", + Data: string(utils.MustMarshal(result)), + } + } + } + errMsg := jxutils.Errs2Str("", err1, err2, err3, err) + if storeID == "" { + errMsg += "storeID is empty\n" + } + if errMsg != "" { + c.Data["json"] = &model.CallResult{ + Code: "-1", + Desc: errMsg, + } + } + c.ServeJSON() +} + +// @Title 得到订单SKU信息 +// @Description 得到订单SKU信息 +// @Param token header string true "认证toke" +// @Param vendorOrderID query string true "订单ID" +// @Param vendorID query int true "订单所属的厂商ID" +// @Success 200 {object} business.model.CallResult +// @Failure 200 {object} business.model.CallResult +// @router /GetOrderSkuInfo [get] +func (c *OrderController) GetOrderSkuInfo() { + c.orderOperate(func(vendorOrderID string, vendorID int, userName string) (interface{}, error) { + // globals.SugarLogger.Debugf("userName:%s", userName) + return orderman.FixedOrderManager.GetOrderSkuInfo(vendorOrderID, vendorID) + }) +} diff --git a/controllers/mtps_order.go b/controllers/mtps_order.go index b8ce08002..9b583a1d2 100644 --- a/controllers/mtps_order.go +++ b/controllers/mtps_order.go @@ -1,74 +1,40 @@ package controllers import ( - "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/controller/mtps" - "git.rosy.net.cn/jx-callback/globals" + "net/http" + + "git.rosy.net.cn/jx-callback/business/partner/delivery/mtps" "git.rosy.net.cn/jx-callback/globals/api" - "git.rosy.net.cn/jx-callback/legacy/mtps/controller" "github.com/astaxie/beego" ) // Operations about ELMOrder -type MTPSOrderController struct { +type MtpsController struct { beego.Controller } -func (c *MTPSOrderController) URLMapping() { - c.Mapping("Status", c.Status) - c.Mapping("Except", c.Except) +func (c *MtpsController) Status() { + if c.Ctx.Input.Method() == http.MethodPost { + obj, callbackResponse := api.MtpsAPI.GetOrderCallbackMsg(c.Ctx.Request) + if callbackResponse == nil { + callbackResponse = mtps.OnWaybillMsg(obj) + } + c.Data["json"] = callbackResponse + c.ServeJSON() + } else { + c.Abort("404") + } } -// @Title all msg -// @Description create object -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /status [post] -func (c *MTPSOrderController) Status() { - obj, callbackResponse := api.MtpsAPI.GetOrderCallbackMsg(c.Ctx.Request) - if callbackResponse == nil { - if globals.CallLegacyMsgHandler { - cc := &controller.OrderController{} - callbackResponse = cc.OrderStatusChanged(obj) - } - if globals.CallNewMsgHandler { - cc2 := &mtps.WaybillController{} - if globals.CallLegacyMsgHandler { - utils.CallFuncAsync(func() { - cc2.OnWaybillMsg(obj) - }) - } else { - callbackResponse = cc2.OnWaybillMsg(obj) - } +func (c *MtpsController) Except() { + if c.Ctx.Input.Method() == http.MethodPost { + obj, callbackResponse := api.MtpsAPI.GetOrderExceptionCallbackMsg(c.Ctx.Request) + if callbackResponse == nil { + callbackResponse = mtps.OnWaybillExcept(obj) } + c.Data["json"] = callbackResponse + c.ServeJSON() + } else { + c.Abort("404") } - c.Data["json"] = callbackResponse - c.ServeJSON() -} - -// @Title all msg test -// @Description create object -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router /except [Post] -func (c *MTPSOrderController) Except() { - obj, callbackResponse := api.MtpsAPI.GetOrderExceptionCallbackMsg(c.Ctx.Request) - if callbackResponse == nil { - if globals.CallLegacyMsgHandler { - cc := &controller.OrderController{} - callbackResponse = cc.OrderException(obj) - } - if globals.CallNewMsgHandler { - cc2 := &mtps.WaybillController{} - if globals.CallLegacyMsgHandler { - utils.CallFuncAsync(func() { - cc2.OnWaybillExcept(obj) - }) - } else { - callbackResponse = cc2.OnWaybillExcept(obj) - } - } - } - c.Data["json"] = callbackResponse - c.ServeJSON() } diff --git a/controllers/object.go b/controllers/object.go deleted file mode 100644 index 014ea0f5c..000000000 --- a/controllers/object.go +++ /dev/null @@ -1,92 +0,0 @@ -package controllers - -import ( - "encoding/json" - - "git.rosy.net.cn/jx-callback/models" - - "github.com/astaxie/beego" -) - -// Operations about object -type ObjectController struct { - beego.Controller -} - -// @Title Create -// @Description create object -// @Param body body models.Object true "The object content" -// @Success 200 {string} models.Object.Id -// @Failure 403 body is empty -// @router / [post] -func (o *ObjectController) Post() { - var ob models.Object - json.Unmarshal(o.Ctx.Input.RequestBody, &ob) - objectid := models.AddOne(ob) - o.Data["json"] = map[string]string{"ObjectId": objectid} - o.ServeJSON() -} - -// @Title Get -// @Description find object by objectid -// @Param objectId path string true "the objectid you want to get" -// @Success 200 {object} models.Object -// @Failure 403 :objectId is empty -// @router /:objectId [get] -func (o *ObjectController) Get() { - objectId := o.Ctx.Input.Param(":objectId") - if objectId != "" { - ob, err := models.GetOne(objectId) - if err != nil { - o.Data["json"] = err.Error() - } else { - o.Data["json"] = ob - } - } - o.ServeJSON() -} - -// @Title GetAll -// @Description get all objects -// @Success 200 {object} models.Object -// @Failure 403 :objectId is empty -// @router / [get] -func (o *ObjectController) GetAll() { - obs := models.GetAll() - o.Data["json"] = obs - o.ServeJSON() -} - -// @Title Update -// @Description update the object -// @Param objectId path string true "The objectid you want to update" -// @Param body body models.Object true "The body" -// @Success 200 {object} models.Object -// @Failure 403 :objectId is empty -// @router /:objectId [put] -func (o *ObjectController) Put() { - objectId := o.Ctx.Input.Param(":objectId") - var ob models.Object - json.Unmarshal(o.Ctx.Input.RequestBody, &ob) - - err := models.Update(objectId, ob.Score) - if err != nil { - o.Data["json"] = err.Error() - } else { - o.Data["json"] = "update success!" - } - o.ServeJSON() -} - -// @Title Delete -// @Description delete the object -// @Param objectId path string true "The objectId you want to delete" -// @Success 200 {string} delete success! -// @Failure 403 objectId is empty -// @router /:objectId [delete] -func (o *ObjectController) Delete() { - objectId := o.Ctx.Input.Param(":objectId") - models.Delete(objectId) - o.Data["json"] = "delete success!" - o.ServeJSON() -} diff --git a/controllers/user.go b/controllers/user.go deleted file mode 100644 index b9d178c6e..000000000 --- a/controllers/user.go +++ /dev/null @@ -1,119 +0,0 @@ -package controllers - -import ( - "encoding/json" - - "git.rosy.net.cn/jx-callback/models" - - "github.com/astaxie/beego" -) - -// Operations about Users -type UserController struct { - beego.Controller -} - -// @Title CreateUser -// @Description create users -// @Param body body models.User true "body for user content" -// @Success 200 {int} models.User.Id -// @Failure 403 body is empty -// @router / [post] -func (u *UserController) Post() { - var user models.User - json.Unmarshal(u.Ctx.Input.RequestBody, &user) - uid := models.AddUser(user) - u.Data["json"] = map[string]string{"uid": uid} - u.ServeJSON() -} - -// @Title GetAll -// @Description get all Users -// @Success 200 {object} models.User -// @router / [get] -func (u *UserController) GetAll() { - users := models.GetAllUsers() - u.Data["json"] = users - u.ServeJSON() -} - -// @Title Get -// @Description get user by uid -// @Param uid path string true "The key for staticblock" -// @Success 200 {object} models.User -// @Failure 403 :uid is empty -// @router /:uid [get] -func (u *UserController) Get() { - uid := u.GetString(":uid") - if uid != "" { - user, err := models.GetUser(uid) - if err != nil { - u.Data["json"] = err.Error() - } else { - u.Data["json"] = user - } - } - u.ServeJSON() -} - -// @Title Update -// @Description update the user -// @Param uid path string true "The uid you want to update" -// @Param body body models.User true "body for user content" -// @Success 200 {object} models.User -// @Failure 403 :uid is not int -// @router /:uid [put] -func (u *UserController) Put() { - uid := u.GetString(":uid") - if uid != "" { - var user models.User - json.Unmarshal(u.Ctx.Input.RequestBody, &user) - uu, err := models.UpdateUser(uid, &user) - if err != nil { - u.Data["json"] = err.Error() - } else { - u.Data["json"] = uu - } - } - u.ServeJSON() -} - -// @Title Delete -// @Description delete the user -// @Param uid path string true "The uid you want to delete" -// @Success 200 {string} delete success! -// @Failure 403 uid is empty -// @router /:uid [delete] -func (u *UserController) Delete() { - uid := u.GetString(":uid") - models.DeleteUser(uid) - u.Data["json"] = "delete success!" - u.ServeJSON() -} - -// @Title Login -// @Description Logs user into the system -// @Param username query string true "The username for login" -// @Param password query string true "The password for login" -// @Success 200 {string} login success -// @Failure 403 user not exist -// @router /login [get] -func (u *UserController) Login() { - username := u.GetString("username") - password := u.GetString("password") - if models.Login(username, password) { - u.Data["json"] = "login success" - } else { - u.Data["json"] = "user not exist" - } - u.ServeJSON() -} - -// @Title logout -// @Description Logs out current logged in user session -// @Success 200 {string} logout success -// @router /logout [get] -func (u *UserController) Logout() { - u.Data["json"] = "logout success" - u.ServeJSON() -} diff --git a/globals/api/api.go b/globals/api/api.go index 4ae374e7e..d858f8bd0 100644 --- a/globals/api/api.go +++ b/globals/api/api.go @@ -8,7 +8,6 @@ import ( "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "git.rosy.net.cn/baseapi/platformapi/weixinapi" "git.rosy.net.cn/baseapi/utils" - _ "git.rosy.net.cn/jx-callback/globals/db" "github.com/astaxie/beego" "github.com/astaxie/beego/orm" diff --git a/globals/beegodb/beegodb.go b/globals/beegodb/beegodb.go new file mode 100644 index 000000000..61cd61797 --- /dev/null +++ b/globals/beegodb/beegodb.go @@ -0,0 +1,29 @@ +package beegodb + +import ( + "git.rosy.net.cn/jx-callback/business/legacymodel" + "git.rosy.net.cn/jx-callback/business/model" + "github.com/astaxie/beego" + "github.com/astaxie/beego/orm" +) + +func Init() { + // set default database + orm.RegisterDataBase("default", "mysql", beego.AppConfig.String("dbConnectStr"), 30) + orm.RegisterModel(new(legacymodel.Config)) + orm.RegisterModel(new(legacymodel.BlackClient)) + + orm.RegisterModel(new(model.GoodsOrder)) + orm.RegisterModel(new(model.OrderSku)) + orm.RegisterModel(new(model.Waybill)) + orm.RegisterModel(new(model.OrderStatus)) + + orm.RegisterModel(new(legacymodel.Jxstorefeature)) + + orm.RegisterModel(new(legacymodel.TempLog)) + orm.RegisterModel(new(legacymodel.Jxorder2)) + orm.RegisterModel(new(legacymodel.Jxordersku2)) + + // create table + orm.RunSyncdb("default", false, true) +} diff --git a/globals/db/db.go b/globals/db/db.go deleted file mode 100644 index 4033ddac2..000000000 --- a/globals/db/db.go +++ /dev/null @@ -1,37 +0,0 @@ -package db - -import ( - "git.rosy.net.cn/jx-callback/business/legacymodel" - "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/globals" - "git.rosy.net.cn/jx-callback/legacy/models" - "github.com/astaxie/beego" - "github.com/astaxie/beego/orm" - _ "github.com/go-sql-driver/mysql" // import your used driver -) - -func Init() { - // set default database - orm.RegisterDataBase("default", "mysql", beego.AppConfig.String("dbConnectStr"), 30) - if globals.CallLegacyMsgHandler { - models.RegisterModels() - } - orm.RegisterModel(new(legacymodel.Config)) - orm.RegisterModel(new(legacymodel.BlackClient)) - if globals.CallNewMsgHandler { - orm.RegisterModel(new(model.GoodsOrder)) - orm.RegisterModel(new(model.OrderSku)) - orm.RegisterModel(new(model.Waybill)) - orm.RegisterModel(new(model.OrderStatus)) - - orm.RegisterModel(new(model.Jxstorefeature)) - - orm.RegisterModel(new(legacymodel.TempLog)) - orm.RegisterModel(new(legacymodel.Jxorder2)) - orm.RegisterModel(new(legacymodel.Jxordersku2)) - // orm.RegisterModel(new(legacymodel.Elemeorder2)) - // orm.RegisterModel(new(legacymodel.Jdorder2)) - } - // create table - orm.RunSyncdb("default", false, true) -} diff --git a/globals/globals.go b/globals/globals.go index 4f9789676..570cd3c33 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -4,6 +4,7 @@ import ( "git.rosy.net.cn/baseapi" "github.com/astaxie/beego" "github.com/astaxie/beego/logs" + _ "github.com/go-sql-driver/mysql" // import your used driver "go.uber.org/zap" ) @@ -12,8 +13,6 @@ const ( ) var ( - CallLegacyMsgHandler bool - CallNewMsgHandler bool GenerateLegacyJxOrder bool ReallyCallPlatformAPI bool @@ -39,20 +38,11 @@ func init() { } func Init() { - CallLegacyMsgHandler = beego.AppConfig.DefaultBool("callLegacyMsgHandler", true) - CallNewMsgHandler = beego.AppConfig.DefaultBool("callNewMsgHandler", false) + ReallyCallPlatformAPI = true GenerateLegacyJxOrder = beego.AppConfig.DefaultBool("generateLegacyJxOrder", false) - ReallyCallPlatformAPI = !CallLegacyMsgHandler - if ReallyCallPlatformAPI { - JxorderTableName = "jxorder" - JxorderskuTableName = "jxordersku" - ElemeorderTableName = "elemeorder" - JdorderTableName = "jdorder" - } else { - JxorderTableName = "jxorder2" - JxorderskuTableName = "jxordersku2" - ElemeorderTableName = "elemeorder2" - JdorderTableName = "jdorder2" - } + JxorderTableName = "jxorder" + JxorderskuTableName = "jxordersku" + ElemeorderTableName = "elemeorder" + JdorderTableName = "jdorder" } diff --git a/globals/gormdb/gormdb.go b/globals/gormdb/gormdb.go new file mode 100644 index 000000000..eb5075b86 --- /dev/null +++ b/globals/gormdb/gormdb.go @@ -0,0 +1,41 @@ +package gormdb + +import ( + "fmt" + + "git.rosy.net.cn/jx-callback/business/model" + "github.com/astaxie/beego" + "github.com/jinzhu/gorm" +) + +var ( + dbStr string +) + +func Init() { + dbStr = beego.AppConfig.String("dbConnectStr") + AutoMigrate() + // globals.SugarLogger.Debug("fuck") +} + +func GetDB() *gorm.DB { + db, err := gorm.Open("mysql", dbStr) + if err == nil { + return db + } + panic(fmt.Sprintf("AutoMigrate failed with error:%v", err)) +} + +func AutoMigrate() { + db := GetDB() + db.SingularTable(true) + + // db.DropTableIfExists(&model.Place{}) + // db.DropTableIfExists(&model.Store{}, &model.StoreSub{}, &model.StoreMap{}) + // db.DropTableIfExists(&model.SkuCategory{}, &model.StoreSkuCategoryMap{}, &model.SkuName{}, &model.Sku{}, &model.SkuNamePlaceBind{}, &model.StoreSkuBind{}) + + db.AutoMigrate(&model.Place{}) + db.AutoMigrate(&model.Store{}, &model.StoreSub{}, &model.StoreMap{}) + db.AutoMigrate(&model.StoreSkuCategoryMap{}, &model.SkuName{}, &model.Sku{}, &model.SkuNamePlaceBind{}, &model.StoreSkuBind{}) + db.Set("gorm:table_options", "CHARSET=utf8mb4").AutoMigrate(&model.SkuCategory{}) +} diff --git a/main.go b/main.go index e4ddc5521..51a70d28a 100644 --- a/main.go +++ b/main.go @@ -3,13 +3,14 @@ package main import ( "flag" "fmt" + "net/http" "os" - bzcon "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" + "git.rosy.net.cn/jx-callback/business/jxstore/cms" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" - "git.rosy.net.cn/jx-callback/globals/db" - "git.rosy.net.cn/jx-callback/legacy/jd/controller" + "git.rosy.net.cn/jx-callback/globals/beegodb" "git.rosy.net.cn/jx-callback/legacy/tasks" _ "git.rosy.net.cn/jx-callback/routers" "github.com/astaxie/beego" @@ -26,7 +27,7 @@ var ( func Init() { // globals.Init() - db.Init() + beegodb.Init() api.Init() } @@ -83,11 +84,15 @@ func main() { globals.SugarLogger.Errorf("RefreshElmToken failed with error:%s", err) return } - if globals.CallLegacyMsgHandler { - controller.InitOrder() - } + orderman.LoadPendingOrders() + } + if beego.AppConfig.DefaultBool("enableStore", false) { + cms.Init() + mux := http.NewServeMux() + curAdmin := cms.GetAdmin() + curAdmin.MountTo("/admin", mux) + beego.Handler("/admin/*", mux) } - bzcon.LoadPendingOrders() if beego.BConfig.RunMode == "dev" { beego.BConfig.WebConfig.DirectoryIndex = true diff --git a/models/object.go b/models/object.go deleted file mode 100644 index 3ffb60850..000000000 --- a/models/object.go +++ /dev/null @@ -1,53 +0,0 @@ -package models - -import ( - "errors" - "strconv" - "time" -) - -var ( - Objects map[string]*Object -) - -type Object struct { - ObjectId string - Score int64 - PlayerName string -} - -func init() { - Objects = make(map[string]*Object) - Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} - Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} -} - -func AddOne(object Object) (ObjectId string) { - object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) - Objects[object.ObjectId] = &object - return object.ObjectId -} - -func GetOne(ObjectId string) (object *Object, err error) { - if v, ok := Objects[ObjectId]; ok { - return v, nil - } - return nil, errors.New("ObjectId Not Exist") -} - -func GetAll() map[string]*Object { - return Objects -} - -func Update(ObjectId string, Score int64) (err error) { - if v, ok := Objects[ObjectId]; ok { - v.Score = Score - return nil - } - return errors.New("ObjectId Not Exist") -} - -func Delete(ObjectId string) { - delete(Objects, ObjectId) -} - diff --git a/models/user.go b/models/user.go deleted file mode 100644 index d4bebb207..000000000 --- a/models/user.go +++ /dev/null @@ -1,86 +0,0 @@ -package models - -import ( - "errors" - "strconv" - "time" -) - -var ( - UserList map[string]*User -) - -func init() { - UserList = make(map[string]*User) - u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}} - UserList["user_11111"] = &u -} - -type User struct { - Id string - Username string - Password string - Profile Profile -} - -type Profile struct { - Gender string - Age int - Address string - Email string -} - -func AddUser(u User) string { - u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10) - UserList[u.Id] = &u - return u.Id -} - -func GetUser(uid string) (u *User, err error) { - if u, ok := UserList[uid]; ok { - return u, nil - } - return nil, errors.New("User not exists") -} - -func GetAllUsers() map[string]*User { - return UserList -} - -func UpdateUser(uid string, uu *User) (a *User, err error) { - if u, ok := UserList[uid]; ok { - if uu.Username != "" { - u.Username = uu.Username - } - if uu.Password != "" { - u.Password = uu.Password - } - if uu.Profile.Age != 0 { - u.Profile.Age = uu.Profile.Age - } - if uu.Profile.Address != "" { - u.Profile.Address = uu.Profile.Address - } - if uu.Profile.Gender != "" { - u.Profile.Gender = uu.Profile.Gender - } - if uu.Profile.Email != "" { - u.Profile.Email = uu.Profile.Email - } - return u, nil - } - return nil, errors.New("User Not Exist") -} - -func Login(username, password string) bool { - for _, u := range UserList { - if u.Username == username && u.Password == password { - return true - } - } - return false -} - -func DeleteUser(uid string) { - delete(UserList, uid) -} diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 5e2004625..1a30ac29c 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -7,228 +7,52 @@ import ( func init() { - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:DadaOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:DadaOrderController"], + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ - Method: "OrderStatusChanged", - Router: `/msg`, + Method: "CreateWaybillOnProviders", + Router: `/CreateWaybillOnProviders`, AllowHTTPMethods: []string{"post"}, MethodParams: param.Make(), Params: nil}) - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ELMOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ELMOrderController"], + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ - Method: "MsgPost", - Router: `/msg`, + Method: "FinishedPickup", + Router: `/FinishedPickup`, AllowHTTPMethods: []string{"post"}, MethodParams: param.Make(), Params: nil}) - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ELMOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ELMOrderController"], + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ - Method: "MsgGet", - Router: `/msg`, + Method: "GetOrderSkuInfo", + Router: `/GetOrderSkuInfo`, AllowHTTPMethods: []string{"get"}, MethodParams: param.Make(), Params: nil}) - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ - Method: "ApplyCancelOrder", - Router: `/applyCancelOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "DeliveryOrder", - Router: `/deliveryOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "FinishOrder", - Router: `/finishOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "LockOrder", - Router: `/lockOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "NewOrder", - Router: `/newOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "OrderAdjust", - Router: `/orderAdjust`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "OrderComment", - Router: `/orderCommentPush`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "OrderWaitOutStore", - Router: `/orderWaitOutStore`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "PickFinishOrder", - Router: `/pickFinishOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "PushDeliveryStatus", - Router: `/pushDeliveryStatus`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:JDOrderController"], - beego.ControllerComments{ - Method: "UserCancelOrder", - Router: `/userCancelOrder`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:MTPSOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:MTPSOrderController"], - beego.ControllerComments{ - Method: "Except", - Router: `/except`, - AllowHTTPMethods: []string{"Post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:MTPSOrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:MTPSOrderController"], - beego.ControllerComments{ - Method: "Status", - Router: `/status`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, - AllowHTTPMethods: []string{"post"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, + Method: "GetStoreOrderCountInfo", + Router: `/GetStoreOrderCountInfo`, AllowHTTPMethods: []string{"get"}, MethodParams: param.Make(), Params: nil}) - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"], + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ - Method: "Get", - Router: `/:objectId`, + Method: "GetStoreOrderInfo", + Router: `/GetStoreOrderInfo`, AllowHTTPMethods: []string{"get"}, MethodParams: param.Make(), Params: nil}) - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"], + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ - Method: "Put", - Router: `/:objectId`, - AllowHTTPMethods: []string{"put"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:ObjectController"], - beego.ControllerComments{ - Method: "Delete", - Router: `/:objectId`, - AllowHTTPMethods: []string{"delete"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "Post", - Router: `/`, + Method: "Swtich2SelfDeliver", + Router: `/Swtich2SelfDeliver`, AllowHTTPMethods: []string{"post"}, MethodParams: param.Make(), Params: nil}) - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "GetAll", - Router: `/`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "Get", - Router: `/:uid`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "Put", - Router: `/:uid`, - AllowHTTPMethods: []string{"put"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "Delete", - Router: `/:uid`, - AllowHTTPMethods: []string{"delete"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "Login", - Router: `/login`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Params: nil}) - - beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], - beego.ControllerComments{ - Method: "Logout", - Router: `/logout`, - AllowHTTPMethods: []string{"get"}, - MethodParams: param.Make(), - Params: nil}) - } diff --git a/routers/router.go b/routers/router.go index 23c0ec4f1..ec0c4455b 100644 --- a/routers/router.go +++ b/routers/router.go @@ -15,31 +15,21 @@ import ( ) func init() { - nsJd := beego.NewNamespace("/djsw", - beego.NSInclude( - &controllers.JDOrderController{}, + ns := beego.NewNamespace("/v2", + beego.NSNamespace("/order", + beego.NSInclude( + &controllers.OrderController{}, + ), ), ) - nsElm := beego.NewNamespace("/eleme", - beego.NSInclude( - &controllers.ELMOrderController{}, - ), - ) - nsMtps := beego.NewNamespace("/mtps", - beego.NSInclude( - &controllers.MTPSOrderController{}, - ), - ) - nsDada := beego.NewNamespace("/dadadelivery", - beego.NSInclude( - &controllers.DadaOrderController{}, - ), - ) - beego.AddNamespace(nsJd, nsElm, nsMtps, nsDada) - beego.Get("/", func(ctx *beecontext.Context) { - ctx.WriteString("pong\n") - }) - beego.Head("/", func(ctx *beecontext.Context) { + beego.AddNamespace(ns) + + beego.AutoRouter(&controllers.DjswController{}) + beego.AutoRouter(&controllers.MtpsController{}) + beego.AutoRouter(&controllers.ElemeController{}) + beego.AutoRouter(&controllers.DadaDeliveryController{}) + + beego.Any("/", func(ctx *beecontext.Context) { ctx.WriteString("pong\n") }) }