834 lines
32 KiB
Go
834 lines
32 KiB
Go
package orderman
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"math"
|
||
"strings"
|
||
"time"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
|
||
"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/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
"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() {
|
||
}
|
||
|
||
// 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.IsStringLikeMobile(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
|
||
}
|
||
|
||
var isDuplicated bool
|
||
if order.Status == model.OrderStatusNew && order.VendorID == model.VendorIDJX && !model.IsOrderJXTemp(order) {
|
||
isDuplicated, _, err = c.addOrderStatus(orderStatus, db)
|
||
} else {
|
||
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) {
|
||
globals.SugarLogger.Debugf("OnOrderAdjust orderID:%s, status:%d", order.VendorOrderID, order.Status)
|
||
if order.ConsigneeMobile2 == "" && jxutils.IsStringLikeMobile(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
|
||
}
|
||
adjustCount := int8(0)
|
||
previousOrder := &model.GoodsOrder{
|
||
VendorOrderID: order.VendorOrderID,
|
||
VendorID: order.VendorID,
|
||
}
|
||
if err = dao.GetEntity(db, previousOrder, model.FieldVendorOrderID, model.FieldVendorID); err != nil && !dao.IsNoRowsError(err) {
|
||
globals.SugarLogger.Warnf("OnOrderAdjust, order:%s GetEntity failed with error:%v", order.VendorOrderID, err)
|
||
return err
|
||
}
|
||
if err == nil {
|
||
adjustCount = previousOrder.AdjustCount
|
||
if _, err = dao.DeleteEntity(db, previousOrder); err != nil {
|
||
return err
|
||
}
|
||
order.VendorWaybillID = previousOrder.VendorWaybillID
|
||
order.WaybillVendorID = previousOrder.WaybillVendorID
|
||
} else {
|
||
globals.SugarLogger.Warnf("OnOrderAdjust, but previous order:%s doesn't exist", order.VendorOrderID)
|
||
}
|
||
// 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)
|
||
order.AdjustCount = adjustCount + 1
|
||
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(vendorOrgCode string, orderStatus *model.OrderStatus) (err error) {
|
||
// 有些平台(比如美团外卖),在新订单事件没有成功返回,但在重发订单消息前,订单状态转换,则不会再重发新订单事件,特殊处理一下
|
||
if orderStatus.Status == model.OrderStatusAccepted {
|
||
if _, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == ErrCanNotFindOrder {
|
||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderStatus.VendorID); handler != nil {
|
||
if order, err2 := handler.GetOrder(vendorOrgCode, orderStatus.VendorOrderID); err2 == nil {
|
||
c.OnOrderNew(order, orderStatus)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
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 orderStatus.Status == model.OrderStatusWaybillTipChanged {
|
||
if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil {
|
||
if handler := partner.GetWaybillTipUpdater(orderStatus.RefVendorID); handler != nil {
|
||
tipFee, err2 := handler.GetWaybillTip(jxcontext.AdminCtx, vendorOrgCode, order.VendorStoreID, orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, "")
|
||
if err2 == nil {
|
||
order.WaybillTipMoney = tipFee
|
||
c.UpdateOrderFields(order, []string{"WaybillTipMoney"})
|
||
}
|
||
}
|
||
}
|
||
} else if orderStatus.Status == model.OrderStatusFinished {
|
||
if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil {
|
||
// 当前只针对三方运单更新配送费信息
|
||
if order.WaybillVendorID >= 0 && order.VendorWaybillID != "" && order.WaybillVendorID != order.VendorID {
|
||
if waybill, err2 := c.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID); err2 == nil {
|
||
if handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID); handler != nil {
|
||
tipFee, err2 := handler.GetWaybillTip(jxcontext.AdminCtx, waybill.VendorOrgCode, "", order.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2)
|
||
if err2 == nil && waybill.TipFee != tipFee {
|
||
waybill.ActualFee += tipFee - waybill.TipFee
|
||
waybill.TipFee = tipFee
|
||
dao.UpdateEntity(db, waybill, "TipFee", "ActualFee")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if !isDuplicated {
|
||
if order != nil {
|
||
order.Skus = c.loadOrderSku(db, order.VendorOrderID, order.VendorID)
|
||
_ = 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 setFakeOrderFlag(db *dao.DaoDB, order *model.GoodsOrder) {
|
||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||
if realMobile := jxutils.GetRealMobile4Order(order); realMobile != "" {
|
||
if configList, err := dao.QueryConfigs(db, model.ConfigSysFakeOrderMobiles, model.ConfigTypeSys, ""); err == nil && len(configList) > 0 {
|
||
isMatch := false
|
||
mobileList := strings.Split(configList[0].Value, ",")
|
||
for _, v := range mobileList {
|
||
if jxutils.TrimDecorationChar(v) == realMobile {
|
||
isMatch = true
|
||
break
|
||
}
|
||
}
|
||
if isMatch {
|
||
order.Flag |= model.OrderFlagMaskFake
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||
globals.SugarLogger.Debugf("SaveOrder orderID:%s, VendorStoreID:%s, status:%d", order.VendorOrderID, order.VendorStoreID, order.Status)
|
||
// 忽略查找JX信息错误
|
||
c.updateOrderOtherInfo(order, db)
|
||
order.ID = 0
|
||
order.WaybillVendorID = model.VendorIDUnknown
|
||
order.OrderFinishedAt = utils.DefaultTimeValue
|
||
|
||
setFakeOrderFlag(db, order)
|
||
// cms.HandleOrder4Consignee(order)
|
||
|
||
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 = ? AND status > 0
|
||
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)
|
||
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, changePriceType 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) < 1*time.Hour && order.VendorID != model.VendorIDJD {
|
||
opNumStr = "2"
|
||
} else {
|
||
opNumStr = "2"
|
||
}
|
||
|
||
if jxStoreID == 0 {
|
||
return nil
|
||
}
|
||
orderSkus := order.Skus
|
||
|
||
vendorSkuIDs := make([]int64, 0)
|
||
for _, v := range orderSkus {
|
||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||
if intVendorSkuID != 0 {
|
||
vendorSkuIDs = append(vendorSkuIDs, intVendorSkuID)
|
||
}
|
||
}
|
||
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)
|
||
if order.VendorID == model.VendorIDJX {
|
||
sql = `
|
||
SELECT t1.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 t1.id IN (-1, ` + dao.GenQuestionMarks(len(vendorSkuIDs)) + ")"
|
||
}
|
||
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
|
||
}
|
||
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
// 直营店始终按比例结算,不考虑活动与结算表
|
||
salePrice := v.SalePrice
|
||
if changePriceType == model.StoreChangePriceTypeManagedStore && v.ShopPrice != 0 {
|
||
salePrice = 0
|
||
}
|
||
v.EarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, salePrice, storePayPercentage)
|
||
}
|
||
// 直营店始终按比例结算,不考虑活动与结算表
|
||
if changePriceType != model.StoreChangePriceTypeManagedStore {
|
||
updateSingleOrderEarningPrice(order, db)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func updateSingleOrderEarningPrice(order *model.GoodsOrder, db *dao.DaoDB) {
|
||
jxStoreID := jxutils.GetShowStoreIDFromOrder(order)
|
||
skuIDMap := make(map[int]int)
|
||
for _, v := range order.Skus {
|
||
skuIDMap[v.SkuID] = 1
|
||
}
|
||
if len(skuIDMap) > 0 {
|
||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []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)
|
||
}
|
||
if actStoreSkuMap := jxutils.NewActStoreSkuMap(actStoreSkuList, false); actStoreSkuMap != nil {
|
||
for _, v := range order.Skus {
|
||
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
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
changePriceType := model.StoreChangePriceTypeDirect
|
||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, order.VendorID)
|
||
if err != nil {
|
||
if !dao.IsNoRowsError(err) {
|
||
globals.SugarLogger.Warnf("updateOrderOtherInfo GetStoreDetailByVendorStoreID orderID:%s, VendorStoreID:%s, error:%v", order.VendorOrderID, order.VendorStoreID, err)
|
||
return err
|
||
}
|
||
if time.Now().Sub(order.OrderCreatedAt) < 1*time.Hour {
|
||
globals.SugarLogger.Infof("updateOrderOtherInfo [运营]订单在京西与平台都找不到京西门店信息,订单:%s,平台门店ID:%s,平台:%s", order.VendorOrderID, order.VendorStoreID, model.VendorChineseNames[order.VendorID])
|
||
}
|
||
err = nil
|
||
} else {
|
||
order.JxStoreID = storeDetail.Store.ID
|
||
payPercentage = storeDetail.PayPercentage
|
||
changePriceType = int(storeDetail.ChangePriceType)
|
||
}
|
||
if err = c.updateOrderSkuOtherInfo(order, db, payPercentage, changePriceType); 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 {
|
||
// todo 美团在订单完成后,还可能收到订单取消(应该当成售后单处理才合适),强制忽略这种情况,比如订单:80662201436073600
|
||
// 后来又发现有订单(81710104014426376)在完成后,直接再被取消的情况,不能生成售后单,还是再允许完成后取消。。。
|
||
// if orderStatus.VendorID == model.VendorIDMTWM && model.IsOrderFinalStatus(order.Status) {
|
||
// return false, order, 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",
|
||
"UpdatedAt",
|
||
}
|
||
if model.IsOrderMainStatus(orderStatus.Status) {
|
||
order.Status = orderStatus.Status
|
||
order.StatusTime = orderStatus.StatusTime
|
||
updateFields = append(updateFields, "Status", "StatusTime")
|
||
if model.IsOrderFinalStatus(orderStatus.Status) {
|
||
order.OrderFinishedAt = orderStatus.StatusTime
|
||
updateFields = append(updateFields, "OrderFinishedAt")
|
||
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.IsOrderLockStatus(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")
|
||
}
|
||
}
|
||
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 {
|
||
order = nil
|
||
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) loadOrderSku(db *dao.DaoDB, vendorOrderID string, vendorID int) (orderSkus []*model.OrderSku) {
|
||
utils.CallFuncLogError(func() (err error) {
|
||
_, err = db.Db.QueryTable("order_sku").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).All(&orderSkus)
|
||
return err
|
||
}, "loadOrderSku orderID:%s", vendorOrderID)
|
||
return orderSkus
|
||
}
|
||
|
||
func (c *OrderManager) loadOrder(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) {
|
||
db1 := dao.GetDB()
|
||
db := db1.Db
|
||
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
|
||
order.Skus = c.loadOrderSku(db1, vendorOrderID, vendorID)
|
||
}
|
||
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
|
||
} else if dao.IsNoRowsError(err) {
|
||
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
|
||
}
|
||
|
||
func (c *OrderManager) RefreshHistoryOrdersEarningPrice(ctx *jxcontext.Context, vendorOrderID string, actID int, vendorIDs []int, storeID int, fromDate, toDate string, isAsync, isContinueWhenError bool) (hint string, errCode string, err error) {
|
||
var (
|
||
orderList []*model.GoodsOrder
|
||
fromDateParam time.Time
|
||
toDateParam time.Time
|
||
beginAt time.Time
|
||
endAt time.Time
|
||
)
|
||
db := dao.GetDB()
|
||
if actID > 0 {
|
||
if fromDate != "" && toDate != "" {
|
||
fromDateParam = utils.Str2Time(fromDate)
|
||
toDateParam = utils.Str2Time(toDate)
|
||
actList, _ := dao.QueryActs(db, actID, 0, math.MaxInt32, 0, "", -1, nil, nil, nil, 0, 0, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue)
|
||
if len(actList.Data) > 0 {
|
||
actBeginAt := actList.Data[0].BeginAt
|
||
actEndAt := actList.Data[0].EndAt
|
||
if fromDateParam.Sub(actBeginAt) > 0 && fromDateParam.Sub(actEndAt) > 0 {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 :[%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam))
|
||
}
|
||
if actBeginAt.Sub(toDateParam) > 0 && actEndAt.Sub(toDateParam) > 0 {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 :[%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam))
|
||
}
|
||
if fromDateParam.Sub(actBeginAt) > 0 {
|
||
beginAt = fromDateParam
|
||
if toDateParam.Sub(actEndAt) > 0 {
|
||
endAt = actEndAt
|
||
} else {
|
||
endAt = toDateParam
|
||
}
|
||
} else {
|
||
beginAt = actBeginAt
|
||
if toDateParam.Sub(actEndAt) > 0 {
|
||
endAt = actEndAt
|
||
} else {
|
||
endAt = toDateParam
|
||
}
|
||
}
|
||
orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, beginAt, endAt)
|
||
} else {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关结算活动,活动ID:[%d]", actID))
|
||
}
|
||
} else if fromDate == "" && toDate == "" {
|
||
actList, _ := dao.QueryActs(db, actID, 0, math.MaxInt32, 0, "", -1, nil, nil, nil, 0, 0, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue)
|
||
if len(actList.Data) > 0 {
|
||
orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, actList.Data[0].BeginAt, actList.Data[0].EndAt)
|
||
} else {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关结算活动,活动ID:[%d]", actID))
|
||
}
|
||
} else {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||
}
|
||
} else {
|
||
if fromDate != "" && toDate != "" {
|
||
fromDateParam = utils.Str2Time(fromDate)
|
||
toDateParam = utils.Str2Time(toDate)
|
||
//若未传入活动ID,且时间间隔大于10天则不允许查询
|
||
if math.Ceil(toDateParam.Sub(fromDateParam).Hours()/24) > 10 {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("查询间隔时间不允许大于10天!时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||
}
|
||
orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, fromDateParam, toDateParam)
|
||
} else {
|
||
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("若不按活动查询则间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||
}
|
||
}
|
||
if len(orderList) <= 0 {
|
||
return "", model.ErrCodePoint, errors.New(fmt.Sprintf("所选活动没有要更新结算价的订单!,vendorOrderID : %s, actID : %d, 时间范围:[%v] 至 [%v]", vendorOrderID, actID, fromDate, toDate))
|
||
}
|
||
task := tasksch.NewParallelTask("刷新历史订单结算价", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
order := batchItemList[0].(*model.GoodsOrder)
|
||
db := dao.GetDB()
|
||
updateSingleOrderEarningPrice(order, db)
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
for _, value := range order.Skus {
|
||
if _, err = dao.UpdateEntity(db, value, "EarningPrice", "StoreSubID"); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
jxutils.RefreshOrderSkuRelated(order)
|
||
num, err := dao.UpdateEntity(db, order, "EarningPrice")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
dao.Commit(db)
|
||
retVal = []string{utils.Int64ToStr(num)}
|
||
return retVal, err
|
||
}, orderList)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if !isAsync {
|
||
resultNum, err2 := task.GetResult(0)
|
||
if err = err2; err == nil {
|
||
hint = resultNum[0].(string)
|
||
}
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
return hint, model.ErrCodeSuccess, err
|
||
}
|
||
|
||
func RefreshOrdersWithoutJxStoreID(ctx *jxcontext.Context, fromDate, toDate string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
var (
|
||
fromDateParam time.Time
|
||
toDateParam time.Time
|
||
)
|
||
if fromDate != "" {
|
||
fromDateParam = utils.Str2Time(fromDate)
|
||
}
|
||
if toDate != "" {
|
||
toDateParam = utils.Str2Time(toDate)
|
||
}
|
||
db := dao.GetDB()
|
||
task := tasksch.NewParallelTask("订单门店归属补漏", tasksch.NewParallelConfig().SetParallelCount(1), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
_, err = dao.UpdateOrdersWithoutJxStoreID(db, fromDateParam, toDateParam)
|
||
return retVal, err
|
||
}, []int{0})
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if !isAsync {
|
||
_, err = task.GetResult(0)
|
||
hint = "1"
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func GetOrdersSupplement(ctx *jxcontext.Context, storIDs, vendorIDs []int, vendorOrderID, fromTime, toTime string, status, stype, IsReverse, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
fromTimeP time.Time
|
||
toTimeP time.Time
|
||
)
|
||
if fromTime != "" {
|
||
fromTimeP = utils.Str2Time(fromTime)
|
||
}
|
||
if toTime != "" {
|
||
toTimeP = utils.Str2Time(toTime)
|
||
}
|
||
if fromTimeP.After(toTimeP) {
|
||
return nil, fmt.Errorf("时间范围不合法!开始时间:[%v],结束时间:[%v]", fromTimeP, toTimeP)
|
||
}
|
||
result, totalCount, err := dao.GetOrdersSupplement(db, storIDs, vendorIDs, vendorOrderID, fromTimeP, toTimeP, status, stype, IsReverse, offset, pageSize)
|
||
pageInfo = &model.PagedInfo{
|
||
Data: result,
|
||
TotalCount: totalCount,
|
||
}
|
||
return pageInfo, err
|
||
}
|
||
|
||
func AddUpdateOrdersSupplement(ctx *jxcontext.Context, ordersSupplement *model.OrderSupplementFee) (num int64, err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
id = ordersSupplement.ID
|
||
)
|
||
now := time.Now()
|
||
ordersSupplement.SupplementTime = &now
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
if id > 0 {
|
||
if ordersSupplement.Status == 1 {
|
||
return 0, fmt.Errorf("已结账的扣款信息不允许修改!门店ID:[%v],订单号:[%v]", ordersSupplement.StoreID, ordersSupplement.VendorOrderID)
|
||
}
|
||
ordersSupplement.UpdatedAt = time.Now()
|
||
ordersSupplement.LastOperator = ctx.GetUserName()
|
||
if ordersSupplement.Status == -1 {
|
||
ordersSupplement.DeletedAt = time.Now()
|
||
} else {
|
||
ordersSupplement.DeletedAt = utils.DefaultTimeValue
|
||
}
|
||
num, err = dao.UpdateEntity(db, ordersSupplement)
|
||
} else {
|
||
dao.WrapAddIDCULDEntity(ordersSupplement, ctx.GetUserName())
|
||
err = dao.CreateEntity(db, ordersSupplement)
|
||
}
|
||
dao.Commit(db)
|
||
return num, err
|
||
}
|