Files
jx-callback/business/jxcallback/orderman/order.go
2019-08-17 16:23:51 +08:00

551 lines
20 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 orderman
import (
"fmt"
"time"
"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/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/orm"
)
type tStoreSkuBindAndVendorSkuID struct {
VendorSkuID int64 `orm:"column(vendor_sku_id)"`
SkuID int `orm:"column(sku_id)"`
Weight int
Price int
}
func init() {
}
func (c *OrderManager) 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 *OrderManager) OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) {
globals.SugarLogger.Debugf("OnOrderNew orderID:%s", order.VendorOrderID)
if order.ConsigneeMobile2 == "" && !jxutils.IsMobileFake(order.ConsigneeMobile) {
order.ConsigneeMobile2 = order.ConsigneeMobile
}
db := dao.GetDB()
dao.Begin(db)
defer func() {
globals.SugarLogger.Debugf("OnOrderNew exit orderID:%s", order.VendorOrderID)
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if order.Status == model.OrderStatusUnknown {
order.Status = model.OrderStatusNew
}
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated {
isDuplicated, err = c.SaveOrder(order, false, db)
}
if err == nil {
dao.Commit(db)
if !isDuplicated {
err = scheduler.CurrentScheduler.OnOrderNew(order, false)
}
} else {
dao.Rollback(db)
}
return err
}
// todo 调整单的处理可能还需要再细化一点,当前只是简单的删除重建
func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) {
if order.ConsigneeMobile2 == "" && !jxutils.IsMobileFake(order.ConsigneeMobile) {
order.ConsigneeMobile2 = order.ConsigneeMobile
}
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
// 出现过调整单后状态回到新订单状态比如911350836000622
// 不完全确定,加一个处理
if order.Status < model.OrderStatusAccepted {
order.Status = model.OrderStatusAccepted
}
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated {
err = utils.CallFuncLogError(func() error {
_, err = db.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.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
}
isDuplicated, err = c.SaveOrder(order, true, db)
}
if err == nil {
dao.Commit(db)
if !isDuplicated {
// 因为订单调度器需要的是真实状态所以用order的状态
_ = scheduler.CurrentScheduler.OnOrderNew(order, false)
_ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false)
}
} else {
dao.Rollback(db)
}
return err
}
func (c *OrderManager) OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
isDuplicated, order, err := c.addOrderStatus(orderStatus, db)
if err == nil {
dao.Commit(db)
if !isDuplicated {
_ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false)
}
} else {
dao.Rollback(db)
}
return err
}
func (c *OrderManager) OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark string) (err error) {
_, _, err = c.addOrderStatus(&model.OrderStatus{
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: order.VendorOrderID,
RefVendorID: order.VendorID,
VendorStatus: vendorStatus,
Status: model.OrderStatusMsg,
StatusTime: time.Now(),
Remark: utils.LimitUTF8StringLen(remark, 255),
}, nil)
return err
}
func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error) {
globals.SugarLogger.Debugf("SaveOrder orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
// 忽略查找JX信息错误
c.updateOrderOtherInfo(order, db)
order.ID = 0
order.WaybillVendorID = model.VendorIDUnknown
order.OrderFinishedAt = utils.DefaultTimeValue
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
// todo hardcode 兼容京东消息错序问题
if true { //order.VendorID == model.VendorIDJD {
orderStatus := &model.OrderStatus{}
if dao.GetRow(db, orderStatus, `
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) == nil {
if orderStatus.Status > order.Status {
order.Status = orderStatus.Status
order.VendorStatus = orderStatus.VendorStatus
order.StatusTime = orderStatus.StatusTime
jxutils.RefreshOrderSkuRelated(order)
}
}
}
order.ConsigneeName = utils.LimitUTF8StringLen(order.ConsigneeName, 32)
// globals.SugarLogger.Debugf("saveOrder isAdjust:%t, order:%v", isAdjust, order)
created, _, err2 := db.Db.ReadOrCreate(order, "VendorOrderID", "VendorID")
if err = err2; err == nil {
originalOrder := &model.GoodsOrderOriginal{
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
OrderCreatedAt: order.OrderCreatedAt,
OriginalData: order.OriginalData,
}
if _, _, err = db.Db.ReadOrCreate(originalOrder, "VendorOrderID", "VendorID"); err == nil {
if created {
if err = dao.CreateMultiEntities(db, order.Skus); err != nil {
baseapi.SugarLogger.Warnf("saveOrder orderID:%s, save order_sku failed with error:%v", order.VendorOrderID, err)
}
} else {
isDuplicated = true
order.DuplicatedCount++
db.Db.Update(order, "DuplicatedCount")
baseapi.SugarLogger.Infof("saveOrder duplicated orderid:%s msg received", order.VendorOrderID)
}
}
} else {
globals.SugarLogger.Warnf("saveOrder create order:%v, error:%v", order, err)
}
if err == nil {
dao.Commit(db)
}
return isDuplicated, err
}
func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.DaoDB, storePayPercentage int) (err error) {
globals.SugarLogger.Debugf("updateOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
jxStoreID := jxutils.GetShowStoreIDFromOrder(order)
var opNumStr string
if time.Now().Sub(order.OrderCreatedAt) < 48*time.Hour && order.VendorID != model.VendorIDJD {
opNumStr = "2"
} else {
opNumStr = "2"
}
if jxStoreID == 0 {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营%s]订单在京西与平台都找不到京西门店信息orderID:%s, VendorStoreID:%s", opNumStr, order.VendorOrderID, order.VendorStoreID)
return nil
}
orderSkus := order.Skus
vendorSkuIDs := make([]int64, 0)
skuIDMap := make(map[int]int)
for _, v := range orderSkus {
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
if intVendorSkuID != 0 {
vendorSkuIDs = append(vendorSkuIDs, intVendorSkuID)
}
if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 {
skuIDMap[skuID] = 1
}
}
if len(vendorSkuIDs) > 0 {
tableName := "t2"
if model.MultiStoresVendorMap[order.VendorID] == 1 {
tableName = "t1"
}
fieldPrefix := dao.ConvertDBFieldPrefix(model.VendorNames[order.VendorID])
sql := `
SELECT %s.%s_id vendor_sku_id, t1.id sku_id, t2.price, t1.weight
FROM sku t1
LEFT JOIN store_sku_bind t2 ON t1.id = t2.sku_id AND t2.deleted_at = ? AND t2.store_id = ?
WHERE t1.deleted_at = ? AND %s.%s_id IN (-1, ` + dao.GenQuestionMarks(len(vendorSkuIDs)) + ")"
sql = fmt.Sprintf(sql, tableName, fieldPrefix, tableName, fieldPrefix)
var skuInfos []*tStoreSkuBindAndVendorSkuID
if err = dao.GetRows(db, &skuInfos, sql, utils.DefaultTimeValue, jxStoreID, utils.DefaultTimeValue, vendorSkuIDs); err != nil {
globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku info for orderID:%s, error:%v", order.VendorOrderID, err)
return err
}
skumapper := make(map[int64]*tStoreSkuBindAndVendorSkuID)
for _, v := range skuInfos {
skumapper[v.VendorSkuID] = v
}
// var skuPriceMap map[int64]*dao.PromotionStoreSku
var actStoreSkuMap *jxutils.ActStoreSkuMap
if len(skuIDMap) > 0 {
// skuPriceMap, err = dao.GetPromotionSkuPriceMap(db, model.VendorIDJX, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order.OrderCreatedAt, order.OrderCreatedAt)
// if err != nil {
// globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku promotion info for orderID:%s, error:%v", order.VendorOrderID, err)
// return err
// }
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order.OrderCreatedAt, order.OrderCreatedAt)
if err != nil {
globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku promotion info for error:%v", err)
return err
}
actStoreSkuMap = jxutils.NewActStoreSkuMap(actStoreSkuList, false)
}
for _, v := range orderSkus {
v.VendorOrderID = order.VendorOrderID
v.VendorID = order.VendorID
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
skuBindInfo := skumapper[intVendorSkuID]
if skuBindInfo == nil {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格或商品映射orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
} else {
v.JxSkuID = skuBindInfo.SkuID
v.ShopPrice = int64(skuBindInfo.Price)
v.Weight = skuBindInfo.Weight // 以本地信息中的WEIGHT为准
if skuBindInfo.Price == 0 {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营%s]%s订单sku门店价格为零一般原因为没有门店价格信息orderID:%s, StoreID:%d, SkuID:%d, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.JxSkuID, v)
}
// v.EarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, v.SalePrice, storePayPercentage)
}
}
// if skuPriceMap != nil {
// if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 /*&& v.StoreSubName != ""*/ {
// index := dao.GenSkuPriceMapKey(jxStoreID, v.SkuID)
// if skuPriceMap[index] != nil && skuPriceMap[index].EarningPrice > 0 {
// v.EarningPrice = int64(skuPriceMap[index].EarningPrice)
// }
// }
// } else
if actStoreSkuMap != nil {
if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 {
if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
v.EarningPrice = actStoreSku.EarningPrice
if true { //v.StoreSubName != "" { // 之前这里为什么要加判断?
v.StoreSubID = actStoreSku.ActID
}
}
}
}
}
}
return nil
}
func (c *OrderManager) updateOrderOtherInfo(order *model.GoodsOrder, db *dao.DaoDB) (err error) {
globals.SugarLogger.Debugf("updateOrderOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
payPercentage := 0
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, order.VendorID)
if err != nil {
globals.SugarLogger.Warnf("updateOrderOtherInfo GetStoreDetailByVendorStoreID orderID:%s, VendorStoreID:%s, error:%v", order.VendorOrderID, order.VendorStoreID, err)
if !dao.IsNoRowsError(err) {
return err
}
err = nil
} else {
order.JxStoreID = storeDetail.Store.ID
payPercentage = storeDetail.PayPercentage
}
if err = c.updateOrderSkuOtherInfo(order, db, payPercentage); err == nil {
jxutils.RefreshOrderSkuRelated(order)
caculateOrderEarningPrice(order, payPercentage)
}
return err
}
// 计算结算给门店的金额
func caculateOrderEarningPrice(order *model.GoodsOrder, storePayPercentage int) {
order.EarningPrice = 0
for _, v := range order.Skus {
skuEarningPrice := v.EarningPrice
if skuEarningPrice == 0 {
skuEarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, v.SalePrice, storePayPercentage)
}
order.EarningPrice += skuEarningPrice * int64(v.Count)
}
}
func (c *OrderManager) addOrderStatus(orderStatus *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, order *model.GoodsOrder, err error) {
globals.SugarLogger.Debugf("addOrderStatus refOrderID:%s, orderID:%s", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID)
if db == nil {
db = dao.GetDB()
}
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
order = &model.GoodsOrder{
VendorOrderID: orderStatus.VendorOrderID,
VendorID: orderStatus.VendorID,
}
if err = db.Db.ReadForUpdate(order, "VendorOrderID", "VendorID"); err == nil {
if (model.IsOrderLockStatus(orderStatus.Status) || model.IsOrderUnlockStatus(orderStatus.Status)) ||
(model.IsOrderMainStatus(orderStatus.Status) && orderStatus.Status >= order.Status) { // todo 要求status不能回绕
order.VendorStatus = orderStatus.VendorStatus
updateFields := []string{
"VendorStatus",
}
if model.IsOrderMainStatus(orderStatus.Status) {
order.Status = orderStatus.Status
order.StatusTime = orderStatus.StatusTime
updateFields = append(updateFields, "Status", "StatusTime")
if order.LockStatus != model.OrderStatusUnknown {
order.LockStatus = model.OrderStatusUnknown
updateFields = append(updateFields, "LockStatus")
}
} else {
if model.IsOrderUnlockStatus(orderStatus.Status) {
order.LockStatus = model.OrderStatusUnknown
updateFields = append(updateFields, "LockStatus")
} else if !model.IsOrderFinalStatus(orderStatus.Status) {
if order.LockStatus != model.OrderStatusUnknown {
globals.SugarLogger.Warnf("addOrderStatus refOrderID:%s, orderID:%s, order.LockStatus:%d, status.LockStatus:%d", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, order.LockStatus, orderStatus.Status)
}
order.Flag &= ^model.OrderFlagMaskUserApplyCancel
order.LockStatus = orderStatus.Status
order.LockStatusTime = orderStatus.StatusTime
updateFields = append(updateFields, "LockStatus", "LockStatusTime", "Flag")
}
}
if model.IsOrderFinalStatus(orderStatus.Status) {
order.OrderFinishedAt = orderStatus.StatusTime
updateFields = append(updateFields, "OrderFinishedAt")
}
utils.CallFuncLogError(func() error {
_, err = db.Db.Update(order, updateFields...)
return err
}, "addOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
} else {
isDuplicated = true
}
} else {
if dao.IsNoRowsError(err) { // todo 消息错序
err = nil
} else {
globals.SugarLogger.Warnf("addOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
}
}
}
return isDuplicated, order, err
}
func (c *OrderManager) loadOrder(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) {
db := orm.NewOrm()
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorOrderID2: vendorOrderID2,
VendorID: vendorID,
}
keyFields := []string{
model.FieldVendorID,
}
if vendorOrderID != "" {
keyFields = append(keyFields, model.FieldVendorOrderID)
}
if vendorOrderID2 != "" {
keyFields = append(keyFields, model.FieldVendorOrderID2)
}
if err = db.Read(order, keyFields...); err == nil {
vendorOrderID = order.VendorOrderID
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 {
order = nil
if err == orm.ErrNoRows {
err = ErrCanNotFindOrder
}
globals.SugarLogger.Infof("LoadOrder orderID:%s failed with error:%v", vendorOrderID, err)
}
return order, err
}
func (c *OrderManager) LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) {
return c.loadOrder(vendorOrderID, "", vendorID)
}
func (c *OrderManager) LoadOrder2(vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) {
return c.loadOrder("", vendorOrderID2, vendorID)
}
func (c *OrderManager) LoadOrderFinancial(vendorOrderID string, vendorID int) (order *model.OrderFinancial, err error) {
return c.loadOrderFinancial(vendorOrderID, "", vendorID)
}
func (c *OrderManager) LoadOrderFinancial2(vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error) {
return c.loadOrderFinancial("", vendorOrderID2, vendorID)
}
func (c *OrderManager) loadOrderFinancial(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error) {
db := orm.NewOrm()
order = &model.OrderFinancial{
VendorOrderID: vendorOrderID,
VendorOrderID2: vendorOrderID2,
VendorID: vendorID,
}
keyFields := []string{
model.FieldVendorID,
}
if vendorOrderID != "" {
keyFields = append(keyFields, model.FieldVendorOrderID)
}
if vendorOrderID2 != "" {
keyFields = append(keyFields, model.FieldVendorOrderID2)
}
// 这块不知道怎么写了、、、标注一下
if err = db.Read(order, keyFields...); err == nil {
vendorOrderID = order.VendorOrderID
err = utils.CallFuncLogError(func() error {
_, err = db.QueryTable("order_sku_financial").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).Filter("is_afs_order", 0).All(&order.Skus)
return err
}, "LoadOrder orderID:%s", vendorOrderID)
}
if err != nil {
order = nil
if err == orm.ErrNoRows {
err = ErrCanNotFindOrder
}
globals.SugarLogger.Infof("LoadOrderFinancial orderID:%s failed with error:%v", vendorOrderID, err)
}
return order, err
}
func (c *OrderManager) UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error) {
return c.UpdateOrderFields(order, []string{"Status", "DeliveryFlag"})
}
func (c *OrderManager) UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error) {
db := dao.GetDB()
utils.CallFuncLogError(func() error {
if order.ID == 0 {
order2 := *order
if err = dao.GetEntity(db, &order2, model.FieldVendorOrderID, model.FieldVendorID); err == nil {
order.ID = order2.ID
}
err = nil // 强制忽略订单不存在错误
}
if err == nil && order.ID != 0 {
_, err = db.Db.Update(order, fieldList...)
}
return err
}, "UpdateOrderFields orderID:%s failed with error:%v", order.VendorOrderID, err)
return err
}