diff --git a/business/jxcallback/orderman/order.go b/business/jxcallback/orderman/order.go index 38d34e093..696dbc0e2 100644 --- a/business/jxcallback/orderman/order.go +++ b/business/jxcallback/orderman/order.go @@ -325,6 +325,7 @@ func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao. if len(vendorSkuIDs) > 0 { l, err := dao.GetStoreSkuPriceAndWeight(db, order.VendorStoreID, order.VendorID, vendorSkuIDs) if err != nil { + globals.SugarLogger.Warnf("updateOrderSkuOtherInfo orderID:%s failed with err:%v", order.VendorOrderID, err) return err } skumapper := storeSkuPriceAndWeight2Map(l) @@ -808,3 +809,55 @@ func AddUpdateOrdersSupplement(ctx *jxcontext.Context, ordersSupplement *model.O dao.Commit(db) return num, err } + +func RefreshOrdersPriceInfo(ctx *jxcontext.Context, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) { + if utils.IsTimeZero(fromTime) { + return "", fmt.Errorf("必须指定起始时间") + } + if utils.IsTimeZero(toTime) { + toTime = fromTime + } + + db := dao.GetDB() + orderList, err := dao.QueryOrders(db, "", 0, nil, 0, fromTime, toTime) + if err == nil && len(orderList) > 0 { + task := tasksch.NewParallelTask("RefreshOrdersPriceInfo", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, + func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + curOrder := batchItemList[0].(*model.GoodsOrder) + newOrder, err := FixedOrderManager.LoadOrder(curOrder.VendorOrderID, curOrder.VendorID) + if err == nil { + db := dao.GetDB() + if err = FixedOrderManager.updateOrderOtherInfo(newOrder, db); err == nil { + dao.Begin(db) + defer func() { + if r := recover(); r != nil { + dao.Rollback(db) + panic(r) + } + }() + if _, err = dao.UpdateEntity(db, newOrder); err != nil { + dao.Rollback(db) + return nil, err + } + + for _, sku := range newOrder.Skus { + if _, err = dao.UpdateEntity(db, sku); err != nil { + dao.Rollback(db) + return nil, err + } + } + dao.Commit(db) + } + } + return retVal, err + }, orderList) + tasksch.HandleTask(task, nil, true).Run() + if isAsync { + hint = task.GetID() + } else { + _, err = task.GetResult(0) + hint = "1" + } + } + return hint, err +} diff --git a/business/jxcallback/orderman/order_afs.go b/business/jxcallback/orderman/order_afs.go index e020bbac0..166057e0c 100644 --- a/business/jxcallback/orderman/order_afs.go +++ b/business/jxcallback/orderman/order_afs.go @@ -250,6 +250,7 @@ func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.Af if len(vendorSkuIDs) > 0 { l, err := dao.GetStoreSkuPriceAndWeight(db, order.VendorStoreID, order.VendorID, vendorSkuIDs) if err != nil { + globals.SugarLogger.Warnf("updateAfsOrderSkuOtherInfo orderID:%s failed with err:%v", order.VendorOrderID, err) return err } skumapper := storeSkuPriceAndWeight2Map(l) diff --git a/business/jxutils/jxutils_cms.go b/business/jxutils/jxutils_cms.go index e7d20815a..a7d04b834 100644 --- a/business/jxutils/jxutils_cms.go +++ b/business/jxutils/jxutils_cms.go @@ -487,6 +487,7 @@ func CaculateSkuEarningPrice(shopPrice, salePrice int64, storePayPercentage int) if salePrice == 0 || shopPrice > 0 && shopPrice < earningPrice { earningPrice = shopPrice } + storePayPercentage = ConstrainPayPercentage(storePayPercentage) if storePayPercentage <= 0 { storePayPercentage = model.DefaultEarningPricePercentage } diff --git a/business/model/dao/dao_order.go b/business/model/dao/dao_order.go index 0bfe9f5a3..321ca7d9a 100644 --- a/business/model/dao/dao_order.go +++ b/business/model/dao/dao_order.go @@ -105,7 +105,7 @@ func QueryOrders(db *DaoDB, vendorOrderID string, actID int, vendorIDs []int, st sqlParams = append(sqlParams, storeID) } if !utils.IsTimeZero(fromDate) && !utils.IsTimeZero(toDate) { - sql += " AND a.order_created_at BETWEEN ? and ?" + sql += " AND a.order_created_at BETWEEN ? AND ?" sqlParams = append(sqlParams, fromDate, toDate) } err = GetRows(db, &orderNewList, sql, sqlParams...) diff --git a/business/model/dao/sku.go b/business/model/dao/sku.go index fb83053aa..49eac5761 100644 --- a/business/model/dao/sku.go +++ b/business/model/dao/sku.go @@ -1,11 +1,8 @@ package dao import ( - "fmt" - "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/model" - "git.rosy.net.cn/jx-callback/globals" ) type SkuCategoryWithVendor struct { @@ -154,31 +151,6 @@ func GetSkuByCats(db *DaoDB, catIDs []int) (skuList []*model.Sku, err error) { return skuList, err } -func SetSkuSyncStatus(db *DaoDB, vendorID int, skuIDs []int, syncStatus int) (num int64, err error) { - globals.SugarLogger.Debugf("SetSkuSyncStatus, vendorID:%d", vendorID) - - fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID]) - sql := fmt.Sprintf(` - UPDATE sku t1 - SET t1.%s_sync_status = IF(t1.deleted_at = ?, t1.%s_sync_status | ?, 0) - `, fieldPrefix, fieldPrefix) - sqlParams := []interface{}{ - utils.DefaultTimeValue, - syncStatus, - } - if (syncStatus & model.SyncFlagNewMask) != 0 { - sql += fmt.Sprintf(`, - t1.%s_id = 0 - `, fieldPrefix) - } - sql += " WHERE 1 = 1" - if len(skuIDs) > 0 { - sql += " AND t1.id IN (" + GenQuestionMarks(len(skuIDs)) + ")" - sqlParams = append(sqlParams, skuIDs) - } - return ExecuteSQL(db, sql, sqlParams...) -} - // todo, GetSkuCategoryWithVendor与GetSkusWithVendor, // 如果mustDirty为true,应该是要thing_map为基表,LEFT JOIN原始实体表,否则当原始实体记录在未同步前被物理删除后,无法真正同步 diff --git a/business/model/dao/store_sku.go b/business/model/dao/store_sku.go index 8af4e0d87..55d7956ee 100644 --- a/business/model/dao/store_sku.go +++ b/business/model/dao/store_sku.go @@ -646,7 +646,7 @@ func GetStoreSkuPriceAndWeight(db *DaoDB, vendorStoreID string, vendorID int, ve vendorSkuIDField = "t1.id" } else if model.MultiStoresVendorMap[vendorID] != 0 { sqlThingMap = ` - LEFT JOIN thing_map t4 ON t4.thing_type = ? AND t4.thing_id = t1.id AND t4.deleted_at = ? AND t4.vendor_id = t3.vendor_id AND t4.vendor_org_code = t3.vendor_org_code` + JOIN thing_map t4 ON t4.thing_type = ? AND t4.thing_id = t1.id AND t4.deleted_at = ? AND t4.vendor_id = t3.vendor_id AND t4.vendor_org_code = t3.vendor_org_code` thingMapParams = []interface{}{ model.ThingTypeSku, utils.DefaultTimeValue, } @@ -657,8 +657,8 @@ func GetStoreSkuPriceAndWeight(db *DaoDB, vendorStoreID string, vendorID int, ve sql := fmt.Sprintf(` SELECT %s vendor_sku_id, t1.id sku_id, t2.price, t1.weight FROM sku t1 - LEFT JOIN store_sku_bind t2 ON t2.sku_id = t1.id AND t2.deleted_at = ? - LEFT JOIN store_map t3 ON t3.store_id = t2.store_id AND t3.vendor_id = ? AND t3.vendor_store_id = ? AND t2.deleted_at = ? + JOIN store_sku_bind t2 ON t2.sku_id = t1.id AND t2.deleted_at = ? + JOIN store_map t3 ON t3.store_id = t2.store_id AND t3.vendor_id = ? AND t3.vendor_store_id = ? AND t2.deleted_at = ? %s WHERE %s IN (`+GenQuestionMarks(len(vendorSkuIDs))+`)`, vendorSkuIDField, sqlThingMap, vendorSkuIDField) sqlParams := []interface{}{ diff --git a/business/model/dao/thing_map.go b/business/model/dao/thing_map.go index 5a84f8e2e..015ef17b2 100644 --- a/business/model/dao/thing_map.go +++ b/business/model/dao/thing_map.go @@ -1,10 +1,12 @@ package dao -import "git.rosy.net.cn/jx-callback/business/model" +import ( + "fmt" -import "git.rosy.net.cn/baseapi/utils" - -import "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" +) func GetThingMapList(db *DaoDB, thingType int, vendorIDs, thingIDs []int) (cats []*model.ThingMap, err error) { sql := ` @@ -86,3 +88,33 @@ func SetSkuNameSyncStatus(db *DaoDB, vendorIDs []int, vendorOrgCodes []string, n } return num, err } + +func SetSkuSyncStatus(db *DaoDB, vendorID int, skuIDs []int, syncStatus int8) (num int64, err error) { + globals.SugarLogger.Debugf("SetSkuSyncStatus, vendorID:%d", vendorID) + + if globals.IsUseThingMap { + num, err = SetThingMapSyncStatus(db, []int{vendorID}, nil, model.ThingTypeSku, skuIDs, syncStatus) + } else { + fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID]) + sql := fmt.Sprintf(` + UPDATE sku t1 + SET t1.%s_sync_status = IF(t1.deleted_at = ?, t1.%s_sync_status | ?, 0) + `, fieldPrefix, fieldPrefix) + sqlParams := []interface{}{ + utils.DefaultTimeValue, + syncStatus, + } + if (syncStatus & model.SyncFlagNewMask) != 0 { + sql += fmt.Sprintf(`, + t1.%s_id = 0 + `, fieldPrefix) + } + sql += " WHERE 1 = 1" + if len(skuIDs) > 0 { + sql += " AND t1.id IN (" + GenQuestionMarks(len(skuIDs)) + ")" + sqlParams = append(sqlParams, skuIDs) + } + num, err = ExecuteSQL(db, sql, sqlParams...) + } + return num, err +} diff --git a/business/partner/purchase/jd/act.go b/business/partner/purchase/jd/act.go index 450f469e6..28ec7333e 100644 --- a/business/partner/purchase/jd/act.go +++ b/business/partner/purchase/jd/act.go @@ -13,6 +13,7 @@ import ( "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/baseapi/utils/errlist" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/model" @@ -39,6 +40,11 @@ var ( actMap jxutils.SyncMapWithTimeout ) +// 是否按单一门店商品维度创建活动 +func isCreateTypeSingle() bool { + return !globals.IsProductEnv() +} + func splitPromotionSku(skus []*jdapi.PromotionSku, maxCount int) (skusList [][]*jdapi.PromotionSku) { for { skusLen := len(skus) @@ -213,18 +219,18 @@ func createSkuAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model. return vendorActID, err } -func cancelSkuActSkus(ctx *jxcontext.Context, vendorOrgCode string, actType int, vendorActID string, actStoreSku []*model.ActStoreSku2) (err error) { +func cancelSkuActSkus(ctx *jxcontext.Context, act *model.Act2, vendorActID string, actStoreSku []*model.ActStoreSku2) (err error) { if vendorActID != "" { if skuList := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(skuList) > 0 { - err = CancelPromotionSku(vendorOrgCode, actType, utils.Str2Int64(vendorActID), "", skuList, ctx.GetTrackInfo()) + err = CancelPromotionSku(act.VendorOrgCode, act.Type, utils.Str2Int64(vendorActID), "", skuList, ctx.GetTrackInfo()) } } return err } -func cancelSkuAct(ctx *jxcontext.Context, vendorOrgCode string, actType int, vendorActID string) (err error) { +func cancelSkuAct(ctx *jxcontext.Context, act *model.Act2, vendorActID string) (err error) { if vendorActID != "" { - err = CancelPromotion(vendorOrgCode, actType, utils.Str2Int64(vendorActID), "", ctx.GetTrackInfo()) + err = CancelPromotion(act.VendorOrgCode, act.Type, utils.Str2Int64(vendorActID), "", ctx.GetTrackInfo()) } return err } @@ -237,67 +243,80 @@ func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITa var updateItems []*dao.KVUpdateItem actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList) + actSkuCount := 0 + toDelActSkuCount := 0 for storeID := range actStoreSkuMap { for _, actStoreSku := range actStoreSkuMap[storeID] { - vendorActInfoMap[actStoreSku.VendorActID] = append(vendorActInfoMap[actStoreSku.VendorActID], actStoreSku) + vendorActID := actStoreSku.VendorActID + if vendorActID == "" { + vendorActID = act.VendorActID + } + actSkuCount++ + vendorActInfoMap[vendorActID] = append(vendorActInfoMap[vendorActID], actStoreSku) if model.IsSyncStatusDelete(actStoreSku.SyncStatus) { - vendorActID := actStoreSku.VendorActID - if vendorActID == "" { - vendorActID = act.VendorActID - } + toDelActSkuCount++ deleteActInfoMap[vendorActID] = append(deleteActInfoMap[vendorActID], actStoreSku) } else if model.IsSyncStatusNew(actStoreSku.SyncStatus) { actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku) } } } + // 如果是全删,直接添加删除(即取消)标志 + if actSkuCount == toDelActSkuCount { + act.SyncStatus |= model.SyncFlagDeletedMask + } db := dao.GetDB() err = func() (err error) { if model.IsSyncStatusDelete(act.SyncStatus) { + errList := errlist.New() for vendorActID := range vendorActInfoMap { if vendorActID != "" { - if err = cancelSkuAct(ctx, act.VendorOrgCode, act.Type, vendorActID); err != nil { - return err + if err = cancelSkuAct(ctx, act, vendorActID); err == nil { + updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, vendorActInfoMap[vendorActID], model.SyncFlagModifiedMask)...) + } else { + errList.AddErr(err) } } } - for _, actStoreSkuList := range vendorActInfoMap { - updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList, model.SyncFlagModifiedMask)...) + if err = errList.GetErrListAsOne(); err == nil { + updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask)) } - updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask)) } else if model.IsSyncStatusNew(act.SyncStatus) { - if act.VendorActID, err = createSkuAct(ctx, act, actStoreSkuList4Create); err != nil { + if act.VendorActID, err = createSkuAct(ctx, act, actStoreSkuList4Create); err == nil { + updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...) + updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask)) + } else { if act.VendorActID != "" { actMap := partner.Act2ActMap(act) - dao.UpdateEntity(db, actMap, "VendorActID") + dao.UpdateEntity(db, actMap, model.FieldVendorActID) } - return err } - updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...) - updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask)) } else if model.IsSyncStatusUpdate(act.SyncStatus) { - // globals.SugarLogger.Debug(utils.Format4Output(updateItems, false)) + errList := errlist.New() if len(actStoreSkuList4Create) > 0 { - if _, err = createSkuAct(ctx, act, actStoreSkuList4Create); err != nil { - return err + if _, err = createSkuAct(ctx, act, actStoreSkuList4Create); err == nil { + updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...) + } else { + errList.AddErr(err) } - updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...) } for vendorActID := range deleteActInfoMap { if vendorActID != "" { if len(vendorActInfoMap[vendorActID]) == len(deleteActInfoMap[vendorActID]) { - // todo 如果这个取消导致了整活动被取消的话,怎么设置京西活动的状态 - err = cancelSkuAct(ctx, act.VendorOrgCode, act.Type, vendorActID) + err = cancelSkuAct(ctx, act, vendorActID) } else { - err = cancelSkuActSkus(ctx, act.VendorOrgCode, act.Type, vendorActID, deleteActInfoMap[vendorActID]) + err = cancelSkuActSkus(ctx, act, vendorActID, deleteActInfoMap[vendorActID]) } - if err != nil { - return err + if err == nil { + updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...) + } else { + errList.AddErr(err) } + } else { + updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...) } - updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...) } - if err == nil { + if err = errList.GetErrListAsOne(); err == nil { updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask)) } } diff --git a/controllers/jx_order.go b/controllers/jx_order.go index 56cee5353..e9372bfab 100644 --- a/controllers/jx_order.go +++ b/controllers/jx_order.go @@ -968,3 +968,23 @@ func (c *OrderController) AddUpdateOrdersSupplement() { return retVal, "", err }) } + +// @Title 重新计算订单结算信息 +// @Description 重新计算订单结算信息 +// @Param token header string true "认证token" +// @Param fromTime formData string true "订单起始时间" +// @Param toTime formData string false "订单结束时间" +// @Param isAsync formData bool false "是否异步操作" +// @Param isContinueWhenError formData bool false "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /RefreshOrdersPriceInfo [post] +func (c *OrderController) RefreshOrdersPriceInfo() { + c.callRefreshOrdersPriceInfo(func(params *tOrderRefreshOrdersPriceInfoParams) (retVal interface{}, errCode string, err error) { + timeList, err := jxutils.BatchStr2Time(params.FromTime, params.ToTime) + if err == nil { + retVal, err = orderman.RefreshOrdersPriceInfo(params.Ctx, timeList[0], timeList[1], params.IsAsync, params.IsContinueWhenError) + } + return retVal, "", err + }) +} diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index d0ccd09bd..579cfa30e 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -1053,6 +1053,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], + beego.ControllerComments{ + Method: "RefreshOrdersPriceInfo", + Router: `/RefreshOrdersPriceInfo`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:OrderController"], beego.ControllerComments{ Method: "RefreshOrdersWithoutJxStoreID",