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() { } 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.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) { 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(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(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 !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", order.VendorOrderID, order.VendorStoreID) // 忽略查找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 = ? 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) } } } v.EarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, v.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}, []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 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", } 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 { 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, 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 "", errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 :[%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam)) } if actBeginAt.Sub(toDateParam) > 0 && actEndAt.Sub(toDateParam) > 0 { return "", 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 "", 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 "", errors.New(fmt.Sprintf("未查询到相关结算活动,活动ID:[%d]", actID)) } } else { return "", 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 "", errors.New(fmt.Sprintf("查询间隔时间不允许大于10天!时间范围:[%v] 至 [%v]", fromDate, toDate)) } orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, fromDateParam, toDateParam) } else { return "", errors.New(fmt.Sprintf("若不按活动查询则间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate)) } } if len(orderList) <= 0 { return "", 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 "", err } } jxutils.RefreshOrderSkuRelated(order) if _, err = dao.UpdateEntity(db, order, "EarningPrice"); err != nil { return "", err } dao.Commit(db) return retVal, err }, orderList) tasksch.HandleTask(task, nil, true).Run() if !isAsync { _, err = task.GetResult(0) hint = "1" } else { hint = task.GetID() } return hint, err }