Files
jx-callback/business/controller/order.go
2018-08-10 15:21:33 +08:00

371 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controller
import (
"fmt"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"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 {
db := orm.NewOrm()
var orders []*model.GoodsOrder
tillTime := time.Now().Add(-pendingOrderGapMax)
_, err := db.Raw(`
SELECT *
FROM goods_order
WHERE order_created_at >= ?
AND status < ?
`, tillTime, model.OrderStatusEndBegin).QueryRows(&orders)
if err != nil {
globals.SugarLogger.Warnf("LoadPendingOrders load pending orders error:%v", err)
return nil
}
for _, order := range orders {
utils.CallFuncLogError(func() error {
_, err = db.QueryTable("order_sku").Filter("vendor_order_id", order.VendorOrderID).Filter("vendor_id", order.VendorID).All(&order.Skus)
return err
}, "LoadPendingOrders order:%v", order)
}
return orders
}
// msgVendorStatus的意思是事件本身的类型类似有时收到NewOrder事件去取订单状态不一定就是New的
// OnOrderAdjust也类似而OrderStatus要记录的是消息所以添加这个
func (c *OrderController) OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error) {
// todo transaction
db := orm.NewOrm()
if order.Status == model.OrderStatusUnknown {
order.Status = model.OrderStatusNew
}
status := model.Order2Status(order)
status.Status = model.OrderStatusNew
status.VendorStatus = msgVendorStatus
isDuplicated, err := addOrderOrWaybillStatus(status, db)
if err == nil && !isDuplicated {
if isDuplicated, err = c.saveOrder(order, false, db); err == nil && !isDuplicated {
err = scheduler.CurrentScheduler.OnOrderNew(order, false)
weixinmsg.NotifyNewOrder(order)
}
}
return err
}
// todo 调整单的处理可能还需要再细化一点,当前只是简单的删除重建
func (c *OrderController) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error) {
// todo transaction
db := orm.NewOrm()
if order.Status == model.OrderStatusUnknown {
order.Status = model.OrderStatusNew
}
status := model.Order2Status(order)
status.Status = model.OrderStatusAdjust
status.VendorStatus = msgVendorStatus
isDuplicated, err := addOrderOrWaybillStatus(status, db)
if err == nil && !isDuplicated {
err = utils.CallFuncLogError(func() error {
_, err = db.Raw("DELETE FROM order_sku WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec()
return err
}, "OnAdjustOrder delete order, orderID:%s", order.VendorOrderID)
if err != nil {
return err
}
err = utils.CallFuncLogError(func() error {
_, err = db.Raw("DELETE FROM goods_order WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec()
return err
}, "OnAdjustOrder delete order_sku, orderID:%s", order.VendorOrderID)
if err != nil {
return err
}
if isDuplicated, err = c.saveOrder(order, true, db); err == nil && !isDuplicated {
// 因为订单调度器需要的是真实状态所以用order的状态
err = scheduler.CurrentScheduler.OnOrderNew(order, false)
err = scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(order), false)
weixinmsg.NotifyNewOrder(order)
}
}
return err
}
func (c *OrderController) OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
isDuplicated, err := c.addOrderStatus(orderStatus, nil)
if err == nil && !isDuplicated {
err = scheduler.CurrentScheduler.OnOrderStatusChanged(orderStatus, false)
if globals.GenerateLegacyJxOrder {
c.legacyJxOrderStatusChanged(orderStatus, nil)
}
}
return err
}
// private
func (c *OrderController) saveOrder(order *model.GoodsOrder, isAdjust bool, db orm.Ormer) (isDuplicated bool, err error) {
// 忽略查找JX信息错误
c.updateOrderOtherInfo(order, db)
order.ID = 0
order.WaybillVendorID = model.VendorIDUnknown
order.OrderFinishedAt = utils.DefaultTimeValue
order.OrderCreatedAt = order.StatusTime
// hardcode 兼容京东消息错序问题
orderStatus := &model.OrderStatus{}
if db.Raw(`
SELECT *
FROM order_status
WHERE order_type = ? AND vendor_order_id = ? AND vendor_id = ?
ORDER BY status_time DESC
LIMIT 1
`, model.OrderTypeOrder, order.VendorOrderID, order.VendorID).QueryRow(orderStatus) == nil {
order.Status = orderStatus.Status
order.VendorStatus = orderStatus.VendorStatus
order.StatusTime = orderStatus.StatusTime
}
globals.SugarLogger.Debugf("saveOrder isAdjust:%t, order:%v", isAdjust, order)
db.Begin()
created, _, err2 := db.ReadOrCreate(order, "VendorOrderID", "VendorID")
if err = err2; err == nil {
if created {
sql := `INSERT INTO order_sku(vendor_order_id, vendor_id, count, vendor_sku_id, sku_id, jx_sku_id, sku_name,
shop_price, sale_price, weight, sku_type, promotion_type, order_created_at) VALUES`
params := []interface{}{}
for _, sku := range order.Skus {
sql += "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),"
params = append(params, sku.VendorOrderID, sku.VendorID, sku.Count, sku.VendorSkuID, sku.SkuID, sku.JxSkuID, sku.SkuName,
sku.ShopPrice, sku.SalePrice, sku.Weight, sku.SkuType, sku.PromotionType, order.StatusTime)
}
sql = sql[:len(sql)-1] + ";"
if _, err = db.Raw(sql, params...).Exec(); err != nil {
db.Rollback()
baseapi.SugarLogger.Infof("saveOrder insert order:%v, order_sku error:%v", order, err)
} else {
db.Commit()
if globals.GenerateLegacyJxOrder {
c.legacyWriteJxOrder(order, db, isAdjust)
}
}
} else {
isDuplicated = true
order.DuplicatedCount++
db.Update(order, "DuplicatedCount")
db.Commit()
baseapi.SugarLogger.Infof("saveOrder duplicated orderid:%s msg received", order.VendorOrderID)
}
} else {
db.Rollback()
globals.SugarLogger.Warnf("saveOrder create order:%v, error:%v", order, err)
}
return isDuplicated, err
}
func (c *OrderController) updateOrderSkuOtherInfo(order *model.GoodsOrder, db orm.Ormer) (err error) {
jxStoreID := jxutils.GetJxStoreIDFromOrder(order)
if jxStoreID == 0 {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]订单找不到京西门店信息orderID:%s", order.VendorOrderID)
return nil
}
orderSkus := order.Skus
var sql string
if orderSkus[0].VendorID == model.VendorIDJD {
sql = `
SELECT t1.jdskuid, t1.skuid, t2.price
FROM skumapper t1
LEFT JOIN jx_sku_store_bind t2 ON t1.skuid = t2.jxskuid AND t2.jxstoreid = ?
WHERE t1.jdskuid IN (-1,
`
} else if orderSkus[0].VendorID == model.VendorIDELM {
sql = `
SELECT t2.jxskuid, t2.jxskuid, t2.price
FROM jx_sku_store_bind t2
WHERE t2.jxstoreid = ? AND t2.jxskuid IN (-1,
`
} else {
panic(fmt.Sprintf("wrong vendorid:%d", orderSkus[0].VendorID))
}
sqlParams := []interface{}{jxStoreID}
for _, v := range orderSkus {
if orderSkus[0].VendorID == model.VendorIDJD {
sql += "?,"
sqlParams = append(sqlParams, int(utils.Str2Int64(v.VendorSkuID)))
} else if v.SkuID != 0 {
sql += "?,"
sqlParams = append(sqlParams, v.SkuID)
}
}
sql = sql[:len(sql)-1] + ")"
var lists []orm.ParamsList
if num, err := db.Raw(sql, sqlParams...).ValuesList(&lists); err == nil {
skumapper := make(map[string]orm.ParamsList)
for _, v := range lists {
skumapper[v[0].(string)] = v
}
// globals.SugarLogger.Debug(skumapper)
for _, v := range orderSkus {
if orderSkus[0].VendorID == model.VendorIDJD {
if values, ok := skumapper[v.VendorSkuID]; ok {
v.JxSkuID = int(utils.Str2Int64(utils.Interface2String(values[1])))
v.ShopPrice = utils.Str2Int64WithDefault(utils.Interface2String(values[2]), 0)
order.ShopPrice += v.ShopPrice
if v.ShopPrice == 0 {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]京东订单sku门店价格为零orderID:%s sku:%v", order.VendorOrderID, v)
}
} else {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]京东订单sku找不到门店价格orderID:%s sku:%v", order.VendorOrderID, v)
}
} else {
if v.SkuID != 0 {
if values, ok := skumapper[utils.Int2Str(v.SkuID)]; ok {
v.ShopPrice = utils.Str2Int64WithDefault(utils.Interface2String(values[2]), 0)
order.ShopPrice += v.ShopPrice
if v.ShopPrice == 0 {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]饿了么订单sku门店价格为零orderID:%s sku:%v", order.VendorOrderID, v)
}
} else {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]饿了么订单sku找不到门店价格orderID:%s sku:%v", order.VendorOrderID, v)
}
} else {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营]饿了么订单sku没有京西信息orderID:%s sku:%v", order.VendorOrderID, v)
}
}
}
} else {
globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku info for orderID:%s, num:%d, error:%v", order.VendorOrderID, num, err)
}
return err
}
func (c *OrderController) updateOrderOtherInfo(order *model.GoodsOrder, db orm.Ormer) (err error) {
var sql string
if order.VendorID == model.VendorIDJD {
sql = `
SELECT t1.jxstoreid
FROM jxstoremap t1
/* JOIN jxstore t2 ON t1.jxstoreid = t2.storeid */
WHERE t1.jdstoreid = ?
`
} else if order.VendorID == model.VendorIDELM {
sql = `
SELECT t1.jx_store_id
FROM jx_to_elm_store_map t1
/* JOIN jxstore t2 ON t1.jx_store_id = t2.storeid */
WHERE t1.elm_store_id = ?
`
} else {
panic(fmt.Sprintf("wrong vendorid:%d", order.VendorID))
}
var lists []orm.ParamsList
if num, err := db.Raw(sql, utils.Str2Int64(order.VendorStoreID)).ValuesList(&lists); err == nil && num == 1 {
order.JxStoreID = int(utils.Str2Int64(lists[0][0].(string)))
} else {
globals.SugarLogger.Infof("updateOrderOtherInfo [运营]订单orderID:%s找不到相应的京西门店信息请处理, store:%s, num:%d, error:%v", order.VendorOrderID, order.VendorStoreID, num, err)
}
err = c.updateOrderSkuOtherInfo(order, db)
return err
}
func (c *OrderController) addOrderStatus(orderStatus *model.OrderStatus, db orm.Ormer) (isDuplicated bool, err error) {
if db == nil {
db = orm.NewOrm()
}
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated && orderStatus.Status > model.OrderStatusUnknown {
order := &model.GoodsOrder{
VendorOrderID: orderStatus.VendorOrderID,
VendorID: orderStatus.VendorID,
}
if err = db.ReadForUpdate(order, "VendorOrderID", "VendorID"); err == nil {
if (orderStatus.Status == model.OrderStatusUnlocked || orderStatus.Status == model.OrderStatusLocked || orderStatus.Status == model.OrderStatusApplyCancel) ||
(orderStatus.Status > model.OrderStatusUnknown && orderStatus.Status >= order.Status) { // todo 要求status不能回绕
order.VendorStatus = orderStatus.VendorStatus
order.StatusTime = orderStatus.StatusTime
updateFields := []string{
"VendorStatus", "StatusTime",
}
if orderStatus.Status > model.OrderStatusUnknown {
order.LockStatus = model.OrderStatusUnknown
order.Status = orderStatus.Status
updateFields = append(updateFields, "Status", "LockStatus")
} else {
if orderStatus.Status == model.OrderStatusUnlocked {
order.LockStatus = model.OrderStatusUnknown
updateFields = append(updateFields, "LockStatus")
} else if orderStatus.Status == model.OrderStatusLocked || orderStatus.Status == model.OrderStatusApplyCancel {
order.LockStatus = orderStatus.Status
updateFields = append(updateFields, "LockStatus")
}
}
if orderStatus.Status >= model.OrderStatusEndBegin {
order.OrderFinishedAt = orderStatus.StatusTime
updateFields = append(updateFields, "OrderFinishedAt")
}
utils.CallFuncLogError(func() error {
_, err = db.Update(order, updateFields...)
return err
}, "addOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
} else {
isDuplicated = true
}
} else {
if err == orm.ErrNoRows { // todo 消息错序
err = nil
} else {
globals.SugarLogger.Warnf("addOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
}
}
}
return isDuplicated, err
}
func (c *OrderController) LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) {
db := orm.NewOrm()
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorID: vendorID,
}
if err = db.Read(order, "VendorOrderID", "VendorID"); err == nil {
err = utils.CallFuncLogError(func() error {
_, err = db.QueryTable("order_sku").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).All(&order.Skus)
return err
}, "LoadOrder orderID:%s", vendorOrderID)
}
if err != nil {
globals.SugarLogger.Infof("LoadOrder orderID:%s failed with error:%v", vendorOrderID, err)
}
return order, err
}
//Waybill
func (c *OrderController) UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error) {
globals.SugarLogger.Debugf("UpdateWaybillVendorID bill:%v", bill)
db := orm.NewOrm()
params := orm.Params{
"vendor_waybill_id": bill.VendorWaybillID,
"waybill_vendor_id": bill.WaybillVendorID,
}
// 如果运单被取消,则要保持在已拣货状态
if revertStatus && bill.WaybillVendorID == model.VendorIDUnknown {
params["status"] = model.OrderStatusFinishedPickup
}
utils.CallFuncLogError(func() error {
_, err = db.QueryTable("goods_order").Filter("vendor_order_id", bill.VendorOrderID).Filter("vendor_id", bill.OrderVendorID).Update(params)
return err
}, "UpdateWaybillVendorID update order, bill:%v", bill)
return err
}