Accept Merge Request #6: (jxstore -> master)

Merge Request: jxstore初始版本
Created By: @XJH-Rosy
Accepted By: @XJH-Rosy
URL: https://coding.net/u/XJH-Rosy/p/jx-callback/git/merge/6
This commit is contained in:
XJH-Rosy
2018-08-22 17:16:04 +08:00
53 changed files with 1686 additions and 1437 deletions

View File

@@ -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{

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
addParams := orm.Params{}
if bill.Status >= model.WaybillStatusAccepted && bill.Status < model.WaybillStatusEndBegin {
if bill.Status == model.WaybillStatusAccepted {
addParams = orm.Params{
"courier_name": bill.CourierName,
"courier_mobile": bill.CourierMobile,
"desired_fee": bill.DesiredFee,
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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 += "("
// }
// }
// }

View File

@@ -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
}

View File

@@ -1,4 +1,4 @@
package model
package legacymodel
type Jxstorefeature struct {
Id int `orm:"column(storeid);pk"`

24
business/model/api.go Normal file
View File

@@ -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"`
}

View File

@@ -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)"` // 最后操作员
}

View File

@@ -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
}

24
business/model/place.go Normal file
View File

@@ -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
}

124
business/model/product.go Normal file
View File

@@ -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)"`
}

59
business/model/store.go Normal file
View File

@@ -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
}

View File

@@ -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 bill, err
}
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, cancelReasonID, cancelReason)
return 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"
}
_, err = api.DadaAPI.CancelOrder(bill.VendorOrderID, reasonID, reasonMsg)
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 = `

View File

@@ -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,

View File

@@ -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 policy != nil {
err = policy(deliveryFee, addFee)
}
if err == nil {
if addFee <= maxAddFee {
// 忽略坐标转换错误,即使是转换出错,也只能当成转换成功来处理,底层会有错误日志输出
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 {
err = ErrAddFeeExceeded
globals.SugarLogger.Infof("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee)
tmpLog := &legacymodel.TempLog{
bill = &model.Waybill{
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)
OrderVendorID: order.VendorID,
VendorWaybillID: result.MtPeisongID,
VendorWaybillID2: utils.Int64ToStr(result.DeliveryID),
WaybillVendorID: model.VendorIDMTPS,
DesiredFee: deliveryFee,
}
}
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)

View File

@@ -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())
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)
}
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 // 饿了么开了专送店的订单没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货
}

View File

@@ -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,

View File

@@ -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())
}
}

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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)
}
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)
}

View File

@@ -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),

View File

@@ -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())
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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,

View File

@@ -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"

View File

@@ -1,45 +1,24 @@
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() {
func (c *DadaDeliveryController) Msg() {
if c.Ctx.Input.Method() == http.MethodPost {
obj, callbackResponse := api.DadaAPI.GetOrderCallbackMsg(c.Ctx.Input.RequestBody)
if callbackResponse == nil {
if globals.CallLegacyMsgHandler {
cc := &controller.OrderController{}
callbackResponse = cc.OrderStatusChanged(obj)
}
if globals.CallNewMsgHandler {
cc2 := &dada.WaybillController{}
if globals.CallLegacyMsgHandler {
utils.CallFuncAsync(func() {
cc2.OnWaybillMsg(obj)
})
} else {
callbackResponse = cc2.OnWaybillMsg(obj)
}
}
callbackResponse = dada.OnWaybillMsg(obj)
}
if callbackResponse != nil && callbackResponse.Code != 200 {
c.CustomAbort(callbackResponse.Code, string(utils.MustMarshal(callbackResponse)))
@@ -47,4 +26,7 @@ func (c *DadaOrderController) OrderStatusChanged() {
c.Data["json"] = callbackResponse
c.ServeJSON()
}
} else {
c.Abort("404")
}
}

View File

@@ -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() {
// 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 {
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)
}
}
callbackResponse = elm.OnCallbackMsg(obj)
}
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() {
} else if c.Ctx.Input.Method() == http.MethodGet { // 应用需要支持推送地址的GET访问当GET请求访问时请直接返回{“message”:“ok”},用于推送地址的可用性测试。
c.Data["json"] = elmapi.SuccessResponse
c.ServeJSON()
} else {
c.Abort("404")
}
}

View File

@@ -1,33 +1,21 @@
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 *JDOrderController) orderStatus(isCancelOrder bool) {
func (c *DjswController) orderStatus(isCancelOrder bool) {
if c.Ctx.Input.Method() == http.MethodPost {
var obj *jdapi.CallbackOrderMsg
var callbackResponse *jdapi.CallbackResponse
@@ -37,149 +25,64 @@ func (c *JDOrderController) orderStatus(isCancelOrder bool) {
obj, callbackResponse = api.JdAPI.GetOrderCallbackMsg(c.Ctx.Input.RequestBody)
}
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)
}
}
callbackResponse = jd.OnOrderMsg(obj)
}
c.Data["json"] = callbackResponse
c.ServeJSON()
} else {
c.Abort("404")
}
}
// @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() {
func (c *DjswController) PushDeliveryStatus() {
if c.Ctx.Input.Method() == http.MethodPost {
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)
}
}
callbackResponse = jd.OnWaybillMsg(obj)
}
c.Data["json"] = callbackResponse
c.ServeJSON()
} else {
c.Abort("404")
}
}
// @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)
}

209
controllers/jx_order.go Normal file
View File

@@ -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)
})
}

View File

@@ -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)
}
// @Title all msg
// @Description create object
// @Success 200 {string} models.Object.Id
// @Failure 403 body is empty
// @router /status [post]
func (c *MTPSOrderController) Status() {
func (c *MtpsController) Status() {
if c.Ctx.Input.Method() == http.MethodPost {
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)
}
}
callbackResponse = mtps.OnWaybillMsg(obj)
}
c.Data["json"] = callbackResponse
c.ServeJSON()
} else {
c.Abort("404")
}
}
// @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() {
func (c *MtpsController) Except() {
if c.Ctx.Input.Method() == http.MethodPost {
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)
}
}
callbackResponse = mtps.OnWaybillExcept(obj)
}
c.Data["json"] = callbackResponse
c.ServeJSON()
} else {
c.Abort("404")
}
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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"

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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"
}
}

41
globals/gormdb/gormdb.go Normal file
View File

@@ -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{})
}

19
main.go
View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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})
}

View File

@@ -15,31 +15,21 @@ import (
)
func init() {
nsJd := beego.NewNamespace("/djsw",
ns := beego.NewNamespace("/v2",
beego.NSNamespace("/order",
beego.NSInclude(
&controllers.JDOrderController{},
&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")
})
}