package misc import ( "fmt" "strings" "sync" "time" "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx" "git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/business/jxstore/event" "git.rosy.net.cn/jx-callback/business/jxstore/report" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils/errlist" "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch" "git.rosy.net.cn/jx-callback/business/jxstore/act" "git.rosy.net.cn/jx-callback/business/jxstore/cms" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/jxutils/netprinter" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/netspider" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego" ) const ( SpecialTaskID = "Running" TaskNameSyncStoreSku = "SyncStoreSku" ) var ( dailyHeartbeat = []string{ "09:00:00", } dailyWorkTimeList = []string{ "22:00:00", } priceReferTimeList = []string{ "01:00:00", } checkCookieList = []string{ "08:00:00", "12:00:00", "18:00:00", } createStorePriceTimeList = []string{ "02:00:00", } refreshPageActTimeList = []string{ "7:00:00", "8:00:00", "9:00:00", "10:00:00", "11:00:00", "12:00:00", "13:00:00", "14:00:00", "15:00:00", "16:00:00", "17:00:00", "18:00:00", "19:00:00", "22:00:00", } ChangeStoreSkuSaleStatusList = []string{ "7:00:00", "8:00:00", "9:00:00", "10:00:00", "11:00:00", "12:00:00", "13:00:00", "14:00:00", "15:00:00", "16:00:00", "17:00:00", "18:00:00", "19:00:00", "20:00:00", } openRemoteStoreTimeList = []string{ "04:30:00", "23:30:00", } updateActStatusTimeList = []string{ "00:01:00", } sendSecKillWarnList = []string{ "9:00:00", } autoPayForPopluarManList = []string{ "10:30:00", } autoSaleStoreSkuTimeList = []string{ cms.AutoSaleAtStr, } backUpStoreSkuBindList = []string{ "23:30:00", } exSyncList = []string{ "11:30:00", } importantTaskMap = &sync.Map{} cancelPayTimeOutOrderList = localjx.GetHalfHoursList() ebaiStorePageCookieExdTOKEN string ebaiStorePageCookieWMUSS2 string ebaiStorePageCookieWMSTOKEN2 string ebaiStorePageCookieWMUSS string ebaiStorePageCookieWMSTOKEN string mtwmCookieStr string mtpsStoreToken string jd2StorePageCookie string JdStorePageCookie string yinbaoCookie string feiePageCookie string jdStorePageEarning string jdsCookie string ) func GetImportantTaskID(taskName string) string { if value, ok := importantTaskMap.Load(taskName); ok { return value.(string) } return "" } func SaveImportantTaskID(taskName, taskID string) { importantTaskMap.Store(taskName, taskID) } func IsImportantTaskRunning(taskName string) bool { taskID := GetImportantTaskID(taskName) if taskID == "" { return false } else if taskID == SpecialTaskID { return true } return tasksch.IsTaskRunning(taskID) } func Init() { if globals.IsProductEnv() { ScheduleTimerFunc("doDailyWork", doDailyWork, dailyWorkTimeList) ScheduleTimerFuncByInterval(func() { RefreshRealMobile(jxcontext.AdminCtx, model.VendorIDEBAI, time.Now().Add(-24*time.Hour), utils.DefaultTimeValue, false, true) }, 5*time.Second, 1*time.Hour) ScheduleTimerFuncByInterval(func() { defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true) }, 5*time.Second, 10*time.Minute) ScheduleTimerFunc("auto enable remote store", func() { cms.EnableHaveRestStores(jxcontext.AdminCtx, false, true) cms.OpenRemoteStoreByJxStatus(jxcontext.AdminCtx, nil, nil, false, false, true) }, openRemoteStoreTimeList) ScheduleTimerFunc("SaveAndSendAlarmVendorSnapshot", func() { cms.SaveAndSendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, nil, false) }, cms.WatchVendorStoreTimeList) ScheduleTimerFunc("RefreshPageActs", func() { act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false) }, refreshPageActTimeList) ScheduleTimerFunc("UpdateActStatusByTime", func() { dao.UpdateActStatusByTime(dao.GetDB(), time.Now()) }, updateActStatusTimeList) ScheduleScoreStore() ScheduleCheckStoreAlert() ScheduleTimerFunc("ChangeStoreSkuSaleStatus", func() { cms.CurVendorSync.ChangeStoreSkuSaleStatus(jxcontext.AdminCtx, 0, true, true) }, ChangeStoreSkuSaleStatusList) ScheduleTimerFunc("BeginSavePriceRefer", func() { report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil, true, true) }, priceReferTimeList) ScheduleTimerFunc("CreateStorePriceScore", func() { cms.CreateStorePriceScore(jxcontext.AdminCtx) }, createStorePriceTimeList) ScheduleTimerFunc("AutoFocusStoreSkusForTopSkus", func() { cms.AutoFocusStoreSkusForTopSkus(jxcontext.AdminCtx, true, true) }, createStorePriceTimeList) ScheduleTimerFunc("GetCheckVendorCookie", func() { event.GetCheckVendorCookie(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM, model.VendorIDMTPS}, true) }, checkCookieList) ScheduleTimerFunc("SendSeckillSkusCountMsg", func() { cms.SendSeckillSkusCountMsg(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM}, false, true) }, sendSecKillWarnList) ScheduleTimerFunc("每日报警心跳", func() { globals.SugarLogger.Warnf("每日报警心跳,这不是报警。启动时间:%s", cms.GetServiceInfo(jxcontext.AdminCtx)["startupTime"]) }, dailyHeartbeat) ScheduleTimerFunc("AutoPayForPopluarMan", func() { localjx.AutoPayForPopluarMan(jxcontext.AdminCtx) }, autoPayForPopluarManList) ScheduleTimerFunc("CancelPayTimeOutOrder", func() { localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx) }, cancelPayTimeOutOrderList) ScheduleTimerFunc("BackUpStoreSkuBind", func() { cms.BackUpStoreSkuBind(jxcontext.AdminCtx, true, true) }, backUpStoreSkuBindList) ScheduleTimerFunc("SendNoCatSkusToOperater", func() { cms.SendNoCatSkusToOperater(jxcontext.AdminCtx) }, autoPayForPopluarManList) ScheduleTimerFunc("CleanStoreIsBoughtMatter", func() { cms.CleanStoreIsBoughtMatter(jxcontext.AdminCtx) }, priceReferTimeList) ScheduleTimerFunc("exSync", func() { var ( db = dao.GetDB() storeList []int exSyncStoreIDList string syncFlag = 0 ) syncFlag = model.SyncFlagPriceMask if (time.Now().Unix()/24*3600)%10 == 0 { syncFlag |= model.SyncFlagSaleMask } if configs, err := dao.QueryConfigs(dao.GetDB(), "exSyncStoreIDList", model.ConfigTypeSys, ""); err == nil { exSyncStoreIDList = configs[0].Value } storeIDList := strings.Split(exSyncStoreIDList, ",") for _, v := range storeIDList { storeList = append(storeList, int(utils.Str2Int64(v))) } cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetMultiStoreVendorIDs(), storeList, false, nil, []int{27379}, syncFlag, true, true) }, exSyncList) } ScheduleTimerFunc("AutoSaleStoreSku", func() { cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, false) }, autoSaleStoreSkuTimeList) if beego.BConfig.RunMode == "jxgy" { ScheduleTimerFunc("SyncMatterC4ToGy", func() { cms.SyncMatterC4ToGy(jxcontext.AdminCtx, true, true) }, dailyWorkTimeList) } if beego.BConfig.RunMode == "beta" { ScheduleTimerFunc("CancelPayTimeOutOrder", func() { localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx) }, cancelPayTimeOutOrderList) ScheduleTimerFunc("GetAndStoreCitiesShops", func() { netspider.GetAndStoreCitiesShops(jxcontext.AdminCtx, nil, nil, 0, 0, false, false) }, []string{ "04:05:06", }) } if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieExdTOKEN", model.ConfigTypeCookie, ""); err == nil { ebaiStorePageCookieExdTOKEN = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMUSS2", model.ConfigTypeCookie, ""); err == nil { ebaiStorePageCookieWMUSS2 = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMSTOKEN2", model.ConfigTypeCookie, ""); err == nil { ebaiStorePageCookieWMSTOKEN2 = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMUSS", model.ConfigTypeCookie, ""); err == nil { ebaiStorePageCookieWMUSS = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMSTOKEN", model.ConfigTypeCookie, ""); err == nil { ebaiStorePageCookieWMSTOKEN = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil { mtwmCookieStr = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "mtpsStoreToken", model.ConfigTypeCookie, ""); err == nil { mtpsStoreToken = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageCookie", model.ConfigTypeCookie, ""); err == nil { JdStorePageCookie = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageEarning", model.ConfigTypeCookie, ""); err == nil { jdStorePageEarning = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "jd2StorePageCookie", model.ConfigTypeCookie, ""); err == nil { jd2StorePageCookie = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "feiePageCookie", model.ConfigTypeCookie, ""); err == nil { feiePageCookie = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "jdsCookie", model.ConfigTypeCookie, ""); err == nil { jdsCookie = configs[0].Value } if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil { yinbaoCookie := configs[0].Value api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie) } if globals.Jd2OrgCode != "" { api.Jd2API.SetJdCookie(jd2StorePageCookie) } api.EbaiAPI.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN) api.EbaiAPI.SetCookie("WMUSS", ebaiStorePageCookieWMUSS) api.EbaiAPI.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN) api.Ebai2API.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN) api.Ebai2API.SetCookie("WMUSS", ebaiStorePageCookieWMUSS2) api.Ebai2API.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN2) api.MtwmAPI.SetCookieWithStr(mtwmCookieStr) api.MtpsAPI.SetCookie("token", mtpsStoreToken) api.JdAPI.SetJdCookie(JdStorePageCookie) api.JdAPI.SetCookie("user", jdStorePageEarning) api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName, JdStorePageCookie) api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName2, JdStorePageCookie) api.FeieAPI.SetCookieWithStr(feiePageCookie) api.JdShopAPI.SetCookieWithStr(jdsCookie) } func syncStoreSku() { syncFlag := 0 // syncFlag := model.SyncFlagPriceMask // if (time.Now().Unix()/24*3600)%10 == 0 { // syncFlag |= model.SyncFlagSaleMask // } task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) errList := errlist.New() db := dao.GetDB() switch step { case 0: errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db)) errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs())) _, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo) _, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, vendorInfo.VendorID, vendorInfo.OrgCode, false, true) return retVal, err }) errList.AddErr(err) _, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetMultiStoreVendorIDs(), nil, false, nil, []int{27379}, syncFlag, true, true) // _, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true) errList.AddErr(err) case 1: //TODO 暂时不同步银豹(可能要从银豹到京西),2020-04-27 errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, []int{1, 3})) // errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs())) _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, []int{1, 3}, nil, false, true, cms.AmendPruneAll, false) // _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false) errList.AddErr(err) SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID) taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{1, 3}, nil, false, nil, nil, syncFlag, true, true) // taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true) errList.AddErr(err2) SaveImportantTaskID(TaskNameSyncStoreSku, taskID) } err = errList.GetErrListAsOne() return retVal, err }, []int{0, 1}) tasksch.HandleTask(task, nil, true).Run() } func doDailyWork() { globals.SugarLogger.Debug("doDailyWork") dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus) cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), nil, nil, true, true) syncStoreSku() InitEx() cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true) netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true) // 每天补全前一天与当天的订单 curDate := utils.Time2Date(time.Now()) orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, nil, 0, curDate.Add(-72*time.Hour), curDate, true, true) //订单门店归属补漏 //fromDate, toDate都不传默认刷新当前天5天以前的订单,只传fromDate默认刷新fromDate到当天的订单 //只传toDate默认刷新toDate到5天以前的订单 orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true) //刷新京东门店的等级 cms.RefreshJdLevel(jxcontext.AdminCtx) //删除操作日志 event.DeleteOperateEventAndDetail(jxcontext.AdminCtx, time.Now().AddDate(0, -3, 0)) //禁用没有绑定的门店 cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true) //刷新物料订单状态 localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx) //同步银豹到京西 cms.CurVendorSync.SyncStoreSkusFromYb(jxcontext.AdminCtx, nil, true, true) //刷新京东商城订单结算价 orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, time.Now().AddDate(0, 0, -3).Format("20060102"), time.Now().Format("20060102")) } func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) { globals.SugarLogger.Debug("RefreshRealMobile") handler := partner.GetPurchasePlatformFromVendorID(vendorID) if handler == nil { return "", fmt.Errorf("不合法的vendorID:%d", vendorID) } sql := ` SELECT * FROM goods_order WHERE vendor_id = ? AND consignee_mobile2 = '' ` sqlParams := []interface{}{ vendorID, } if !utils.IsTimeZero(fromTime) { sql += " AND order_created_at >= ?" sqlParams = append(sqlParams, fromTime) } if !utils.IsTimeZero(toTime) { sql += " AND order_created_at <= ?" sqlParams = append(sqlParams, toTime) } var orderList []*model.GoodsOrder db := dao.GetDB() if err = dao.GetRows(db, &orderList, sql, sqlParams...); err == nil && len(orderList) > 0 { task := tasksch.NewParallelTask("misc RefreshRealMobile", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { order := batchItemList[0].(*model.GoodsOrder) mobile, err2 := handler.GetOrderRealMobile(ctx, order) if err = err2; err == nil { mobile = jxutils.FormalizeMobile(mobile) if jxutils.IsStringLikeMobile(mobile) && strings.Index(order.ConsigneeMobile, mobile) == -1 { order.ConsigneeMobile2 = mobile _, err = dao.UpdateEntity(db, order, "ConsigneeMobile2") } } else { globals.SugarLogger.Infof("RefreshRealMobile orderID:%s failed with error:%v", order.VendorOrderID, err) } return nil, err }, orderList) tasksch.HandleTask(task, nil, true).Run() hint = task.ID if !isAsync { _, err = task.GetResult(0) } } return hint, err } // 按时间序列循环 func ScheduleTimerFunc(name string, handler func(), timeList []string) { now := time.Now() nextTime := jxutils.GetNextTimeFromList(now, timeList) duration := nextTime.Sub(now) + 1*time.Second globals.SugarLogger.Debugf("ScheduleTimerFunc, func:%s, duration:%v", name, duration) utils.AfterFuncWithRecover(duration, func() { globals.SugarLogger.Debugf("ScheduleTimerFunc func:%s", name) handler() ScheduleTimerFunc(name, handler, timeList) }) } // 按时间调度一次 func ScheduleTimerFuncOnce(name string, handler func(interface{}), timeStr string, param interface{}) { now := time.Now() nextTime := jxutils.GetNextTimeFromList(now, []string{timeStr}) duration := nextTime.Sub(now) + 1*time.Second globals.SugarLogger.Debugf("ScheduleTimerFuncOnce, func:%s, duration:%v", name, duration) utils.AfterFuncWithRecover(duration, func() { globals.SugarLogger.Debugf("ScheduleTimerFuncOnce func:%s", name) handler(param) }) } func ScheduleTimerFuncByInterval(handler func(), delay, inerval time.Duration) { globals.SugarLogger.Debugf("ScheduleTimerFuncByInterval, delay:%v, inerval:%v", delay, inerval) utils.AfterFuncWithRecover(delay, func() { beginTime := time.Now() handler() delay = inerval - time.Now().Sub(beginTime) if delay < time.Second { delay = time.Second } ScheduleTimerFuncByInterval(handler, delay, inerval) }) }