package cms import ( "bytes" "encoding/base64" "encoding/json" "errors" "fmt" "io" "math" "mime/multipart" "sort" "strconv" "strings" "time" "git.rosy.net.cn/baseapi/platformapi/sfps2" "git.rosy.net.cn/baseapi/platformapi/tao_vegetable" "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm" warehouse_getFences_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/warehouse_getFences/response" doudian_sdk "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/core" "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api" "git.rosy.net.cn/jx-callback/business/jxstore/common" "git.rosy.net.cn/jx-callback/business/jxstore/event" "git.rosy.net.cn/jx-callback/business/partner/purchase/tiktok_store" "git.rosy.net.cn/jx-callback/business/auth2" "git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin" "git.rosy.net.cn/jx-callback/business/jxstore/permission" "git.rosy.net.cn/jx-callback/business/authz" "git.rosy.net.cn/baseapi/platformapi/mtwmapi" "git.rosy.net.cn/baseapi/platformapi/yinbaoapi" "git.rosy.net.cn/jx-callback/globals/api/apimanager" "git.rosy.net.cn/jx-callback/globals/refutil" "github.com/360EntSecGroup-Skylar/excelize" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/jx-callback/business/authz/autils" "git.rosy.net.cn/jx-callback/business/jxcallback/orderman" "git.rosy.net.cn/baseapi/platformapi/autonavi" "git.rosy.net.cn/baseapi/platformapi/baidunavi" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "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" "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" "git.rosy.net.cn/jx-callback/business/jxutils/excel" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/jxutils/msg" "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/model/legacymodel" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai" "git.rosy.net.cn/jx-callback/business/partner/purchase/jd" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" ) const ( GET_BAD_COMMENTS_TYPE = 0 //获取差评的标志 GET_ALL_COMMENTS_TYPE = 1 //获取所有评论的标志 GET_FIXED_COMMENTS_TYPE = 2 //获取已解决评论的标志 ) type StoreExt struct { model.Store MarketManName string `orm:"size(8)" json:"marketManName"` // 市场负责人姓名 OperatorName string `orm:"size(8)" json:"operatorName"` // 京东运营人姓名 OperatorName2 string `orm:"size(8)" json:"operatorName2"` // 美团运营人姓名 OperatorName3 string `orm:"size(8)" json:"operatorName3"` // 饿百运营人姓名 FloatLng float64 `json:"lng"` FloatLat float64 `json:"lat"` ProvinceCode int `json:"provinceCode"` ProvinceName string `json:"provinceName"` CityName string `json:"cityName"` DistrictName string `json:"districtName"` StoreMapStr string `json:"-"` CourierMapStr string `json:"-"` PayeeBankName string `json:"payeeBankName"` // 开户行名称 LinkStoreCount int `json:"linkStoreCount"` BrandName string `json:"brandName"` BrandLogo string `json:"brandLogo"` // StoreMaps []map[string]interface{} `orm:"-"` // CourierMaps []map[string]interface{} `orm:"-"` StoreMaps []*model.StoreMap `json:"StoreMaps"` CourierMaps []*model.StoreCourierMap `json:"CourierMaps"` BussinessStatus int `json:"bussinessStatus"` //上下线状态,-1下线,1上线 OrderCount int `json:"orderCount"` } type StoresInfo struct { TotalCount int `json:"totalCount"` MapCenterLng float64 `json:"mapCenterLng"` MapCenterLat float64 `json:"mapCenterLat"` Stores []*StoreExt `json:"stores"` } type JxBadCommentsExt struct { legacymodel.JxBadComments StoreName string `json:"storeName"` CityName string `json:"cityName"` VendorOrderID2 string `orm:"column(vendor_order_id2);size(48);index" json:"vendorOrderID2"` } type VendorStoreExcel struct { StoreID int `json:"门店ID"` VendorStoreName string `json:"门店名"` Status string `json:"营业状态"` Tel1 string `json:"电话1"` Tel2 string `json:"电话2"` CityName string `json:"城市名"` Address string `json:"地址"` MarketManName string `json:"市场负责人"` OperatorName string `json:"运营负责人"` OperatorName2 string `json:"运营负责人2"` OperatorName3 string `json:"运营负责人3"` } //门店信息 type StoreInfo struct { StoreID int `json:"storeID"` //门店ID StoreName string `json:"storeName"` //门店名字 OpenTime1 int16 `json:"openTime1"` // 930就表示9点半,用两个的原因是为了支持中午休息,1与2的时间段不能交叉,为0表示没有 CloseTime1 int16 `json:"closeTime1"` // 营业时间 1 OpenTime2 int16 `json:"openTime2"` // 营业时间2 CloseTime2 int16 `json:"closeTime2"` Status int `json:"status"` //门店是否营业 Distance int `json:"distance"` //店铺与定位 直线距离 Address string `json:"address"` //门店地址 BrandID int `orm:"column(brand_id)" json:"brandID"` //品牌ID BrandName string `json:"brandName"` //品牌名字 BrandLogo string `json:"brandLogo"` //品牌logo StoreWeeklyScore int `json:"storeWeeklyScore"` //店铺每周评分 } //门店减免策略 type StoreDeductionInfo struct { StoreID int `json:"storeID"` //门店ID DeliveryFeeDeductionSill int `json:"deliveryFeeDeductionSill"` //订单满减金额 DeliveryFeeDeductionFee int `json:"deliveryFeeDeductionFee"` //订单减免金额 } //门店热销商品 type StoreSkuInfo struct { StoreID int `json:"storeID"` //门店ID SkuID int `json:"skuID"` //商品ID SkuName string `json:"skuName"` //商品名字 SkuStatus int `json:"skuStatus"` //商品是否可售状态 1可售 0不可售 BestSeller int `json:"bestSeller"` //畅销品 0不是 1是 Img string `json:"img"` //商品第一张图片 Price int `json:"price"` // 单位为分,标准价,不为份的就为实际标准价,为份的为每市斤价,实际还要乘质量 Unit string `json:"unit"` //商品售卖单位 份/kg等 } //首页展示信息 type HomePageInfos struct { StoreInfo StoreInfo `json:"storeInfo"` StoreDeductionInfo []StoreDeductionInfo `json:"StoreDeductionInfo"` StoreSkuInfo []StoreSkuInfo `json:"StoreSkuInfo"` } type JdStoreLevelExt struct { Level string `json:"level` PageNo int `json:"pageNo"` } var ( ErrMissingInput = errors.New("没有有效的输入参数") ErrCanNotFindVendor = errors.New("vendorID参数不合法") ) var ( storeKeyPropertyMap = map[string]int{ "name": 1, "cityCode": 1, "districtCode": 1, "address": 1, "tel1": 1, "tel2": 1, "openTime1": 1, "closeTime1": 1, "openTime2": 1, "closeTime2": 1, "lng": 1, "lat": 1, "deliveryRangeType": 1, "deliveryRange": 1, "status": 1, "promoteInfo": 1, "vendorStoreName": 1, } storeMapKeyPropertyMap = map[string]int{ "status": 1, "freightDeductionPack": 1, "vendorStoreName": 1, "boxFee": 1, } WatchVendorStoreTimeList = []string{ "9:00:00", "10:00:00", "11:00:00", "15:00:00", "20:00:00", } titleListStore = []string{ "门店ID", "门店名", "营业状态", "电话1", "电话2", "城市名", "地址", "市场负责人", "运营负责人", "运营负责人2", } earningInfoMap = map[string]string{ "payeeName": "收款人姓名", "payeeAccountNo": "收款账号", "payeeBankBranchName": "开户支行", "payeeBankCode": "开户行代码", } marketInfoMap = map[string]string{ "marketManPhone": "市场负责人电话", "marketManRole": "市场负责人组(角色,单人)", "jxBrandFeeFactor": "京西品牌费因子", "marketAddFeeFactor": "市场附加费因子", "payPercentage": "结算比例", } ) func getStoresSql(ctx *jxcontext.Context, keyword string, params map[string]interface{}, orderTimeFrom, orderTimeTo time.Time) (sql string, sqlParams []interface{}, sqlFrom string, sqlFromParams []interface{}, err error) { sqlFrom = ` FROM store t1 LEFT JOIN new_config bank ON bank.deleted_at = ? AND bank.type = ? AND bank.key = t1.payee_bank_code LEFT JOIN place city ON t1.city_code = city.code AND city.level = 2 LEFT JOIN place province ON province.code = city.parent_code AND province.level = 1 LEFT JOIN place district ON t1.district_code = district.code AND district.level = 3 /* LEFT JOIN store_map m1 ON t1.id = m1.store_id AND m1.deleted_at = ? LEFT JOIN store_courier_map m2 ON t1.id = m2.store_id AND m2.deleted_at = ? */ LEFT JOIN user mm ON mm.mobile <> '' AND mm.mobile = t1.market_man_phone AND mm.deleted_at = ? LEFT JOIN user om ON om.mobile <> '' AND om.mobile = t1.operator_phone AND om.deleted_at = ? LEFT JOIN user om2 ON om2.mobile <> '' AND om2.mobile = t1.operator_phone2 AND om2.deleted_at = ? LEFT JOIN user om3 ON om3.mobile <> '' AND om3.mobile = t1.operator_phone3 AND om3.deleted_at = ? LEFT JOIN brand br ON br.id = t1.brand_id ` sqlFromParams = []interface{}{ utils.DefaultTimeValue, model.ConfigTypeBank, // utils.DefaultTimeValue, // utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, } sqlWhere := ` WHERE t1.deleted_at = ? ` sqlWhereParams := []interface{}{ utils.DefaultTimeValue, } tableAliasMap := make(map[string]*struct{}) for mapCondKey, tableName := range map[string]string{ "vendorStoreCond": "store_map", "courierStoreCond": "store_courier_map", } { if mapCond := strings.ToUpper(utils.Interface2String(params[mapCondKey])); mapCond == "AND" || mapCond == "OR" { mapCondsStr := utils.Interface2String(params[mapCondKey+"s"]) if mapCondsStr != "" { var vendorStoreConds map[string]interface{} if err = utils.UnmarshalUseNumber([]byte(mapCondsStr), &vendorStoreConds); err != nil { return "", nil, "", nil, err } sqlVendorStoreCond := "" for vendor, cond2 := range vendorStoreConds { var cond string if condStr, ok := cond2.(string); !ok { cond = utils.Int64ToStr(utils.ForceInterface2Int64(cond2)) } else { cond = condStr } tableAlias := tableName + vendor if cond != "0" && cond != "" { if sqlVendorStoreCond == "" { if mapCond == "AND" { sqlVendorStoreCond += " AND ( 1 = 1" } else { sqlVendorStoreCond += " AND ( 1 = 0" } } sqlFrom += "\nLEFT JOIN " + tableName + " " + tableAlias + " ON " + tableAlias + ".vendor_id = ? AND " + tableAlias + ".store_id = t1.id AND " + tableAlias + ".deleted_at = ?" // AND " // +tableAlias + ".is_sync <> 0 " sqlFromParams = append(sqlFromParams, vendor, utils.DefaultTimeValue) if cond == "1" { sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NOT NULL" } else if cond == "-1" { sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NULL" } else { sqlFrom += " AND " + tableAlias + ".vendor_org_code = ?" sqlFromParams = append(sqlFromParams, cond) sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NOT NULL" } tableAliasMap[tableAlias] = &struct{}{} } } if sqlVendorStoreCond != "" { sqlWhere += sqlVendorStoreCond + ")" } } } } if keyword != "" { keywordLike := "%" + keyword + "%" sqlWhere += ` AND (t1.name LIKE ? OR t1.tel1 LIKE ? OR t1.tel2 LIKE ? OR t1.operator_phone LIKE ? OR t1.operator_phone2 LIKE ? OR t1.operator_phone3 LIKE ? OR t1.market_man_phone LIKE ? OR t1.last_operator LIKE ? OR city.name LIKE ? OR t1.address LIKE ? OR t1.printer_sn LIKE ? OR t1.licence_code LIKE ? OR t1.id_code LIKE ? OR t1.comment LIKE ?` sqlWhereParams = append(sqlWhereParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike) if len(tableAliasMap) > 0 { for k, _ := range tableAliasMap { sqlWhere += ` OR ` + k + ".vendor_store_name LIKE ?" sqlWhereParams = append(sqlWhereParams, keywordLike) } } if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil { if true { // jxutils.IsLegalMobileNumber(keywordInt64) { sqlWhere += ` OR ( SELECT COUNT(*) FROM casbin_rule t11 JOIN user t12 ON t12.user_id = t11.v0 AND t12.mobile LIKE ? WHERE t11.v1 <> '' AND (t11.v1 = CONCAT(?, t1.id) OR t11.v1 = CONCAT(?, t1.market_man_role) OR t11.v1 = CONCAT(?, t1.operator_role) OR t11.v1 = CONCAT(?, t1.operator_role2) OR t11.v1 = CONCAT(?, t1.operator_role3)) ) > 0` prefix := autils.NewRole("", 0).GetFullName() sqlWhereParams = append(sqlWhereParams, keyword+"%", autils.NewStoreBossRole(-1).GetFullName(), prefix, prefix, prefix, prefix) // 必须要前缀,不然不能用过些会很慢 } sqlWhere += " OR t1.id = ? OR t1.city_code = ? OR t1.district_code = ? OR t1.link_store_id = ?" sqlWhereParams = append(sqlWhereParams, keywordInt64, keywordInt64, keywordInt64, keywordInt64) if jxutils.GuessVendorIDFromVendorStoreID(keywordInt64) != model.VendorIDUnknown { sqlWhere += ` OR (SELECT COUNT(*) FROM store_map tsm WHERE t1.id = tsm.store_id AND tsm.deleted_at = ? AND tsm.vendor_store_id = ?) > 0 OR (SELECT COUNT(*) FROM store_courier_map tsm WHERE t1.id = tsm.store_id AND tsm.deleted_at = ? AND tsm.vendor_store_id = ?) > 0 ` sqlWhereParams = append(sqlWhereParams, utils.DefaultTimeValue, keyword, utils.DefaultTimeValue, keyword) } } sqlWhere += ")" } if params["storeID"] != nil || params["storeIDs"] != nil { var storeIDs []int if params["storeIDs"] != nil { if err = jxutils.Strings2Objs(utils.Interface2String(params["storeIDs"]), &storeIDs); err != nil { return "", nil, "", nil, err } } if params["storeID"] != nil { storeIDs = append(storeIDs, params["storeID"].(int)) } if len(storeIDs) > 0 { sqlWhere += " AND t1.id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")" sqlWhereParams = append(sqlWhereParams, storeIDs) } } if params["startStoreID"] != nil { sqlWhere += " AND t1.id >= ?" sqlWhereParams = append(sqlWhereParams, params["startStoreID"]) } if params["brandID"] != nil { if utils.MustInterface2Int64(params["brandID"]) != 0 { sqlWhere += " AND t1.brand_id = ?" sqlWhereParams = append(sqlWhereParams, params["brandID"]) } } if params["name"] != nil { sqlWhere += " AND t1.name LIKE ?" sqlWhereParams = append(sqlWhereParams, "%"+params["name"].(string)+"%") } if params["placeID"] != nil { level := 2 if params["placeLevel"] != nil { level = params["placeLevel"].(int) } if level == 2 { sqlWhere += " AND t1.city_code = ?" } else { sqlWhere += " AND t1.district_code = ?" } sqlWhereParams = append(sqlWhereParams, params["placeID"].(int)) } if params["address"] != nil { sqlWhere += " AND t1.address LIKE ?" sqlWhereParams = append(sqlWhereParams, "%"+params["address"].(string)+"%") } if params["marketManPhone"] != nil { sqlWhere += " AND t1.market_man_phone = ?" sqlWhereParams = append(sqlWhereParams, params["marketManPhone"].(string)) } if params["jdPhone"] != nil { jdPhone := params["jdPhone"].(string) sqlWhere += " AND t1.operator_phone = ?" if jdPhone == "0" { jdPhone = "" } sqlWhereParams = append(sqlWhereParams, jdPhone) } if params["mtPhone"] != nil { mtPhone := params["mtPhone"].(string) if mtPhone == "0" { mtPhone = "" } sqlWhere += " AND t1.operator_phone2 = ?" sqlWhereParams = append(sqlWhereParams, mtPhone) } if params["ebaiPhone"] != nil { ebaiPhone := params["ebaiPhone"].(string) if ebaiPhone == "0" { ebaiPhone = "" } sqlWhere += " AND t1.operator_phone3 = ?" sqlWhereParams = append(sqlWhereParams, ebaiPhone) } if params["tel"] != nil { sqlWhere += " AND (t1.tel1 LIKE ? OR t1.tel2 LIKE ?)" sqlWhereParams = append(sqlWhereParams, "%"+params["tel"].(string)+"%") sqlWhereParams = append(sqlWhereParams, "%"+params["tel"].(string)+"%") } if params["earningType"] != nil { if params["earningType"].(int) != 0 { if params["earningType"].(int) == 1 { sqlWhere += " AND t1.pay_percentage >= 50" } else { sqlWhere += " AND t1.pay_percentage < 50" } } } if params["statuss"] != nil { var statuss []int if err = utils.UnmarshalUseNumber([]byte(params["statuss"].(string)), &statuss); err != nil { return "", nil, "", nil, err } if len(statuss) > 0 { sqlWhere += " AND t1.status IN (" + dao.GenQuestionMarks(len(statuss)) + ")" sqlWhereParams = append(sqlWhereParams, statuss) } } if params["marketManPhones"] != nil { var phones []string if err = utils.UnmarshalUseNumber([]byte(params["marketManPhones"].(string)), &phones); err != nil { return "", nil, "", nil, err } if len(phones) > 0 { sqlWhere += " AND t1.market_man_phone IN (" + dao.GenQuestionMarks(len(phones)) + ")" sqlWhereParams = append(sqlWhereParams, phones) } } if params["storeLevels"] != nil { var storeLevels []string if err = jxutils.Strings2Objs(utils.Interface2String(params["storeLevels"]), &storeLevels); err != nil { return "", nil, "", nil, err } if len(storeLevels) > 0 { sqlWhere += " AND t1.store_level IN (" + dao.GenQuestionMarks(len(storeLevels)) + ")" sqlWhereParams = append(sqlWhereParams, storeLevels) } } if params["mapLongitude"] != nil && params["mapLatitude"] != nil && params["mapRadius"] != nil { mapLongitude := utils.Str2Float64(params["mapLongitude"].(string)) mapLatitude := utils.Str2Float64(params["mapLatitude"].(string)) mapRadius := params["mapRadius"].(int) sqlWhere += " AND getDistance(?, ?, CAST(t1.lng AS DECIMAL(15,6))/1000000, CAST(t1.lat AS DECIMAL(15,6))/1000000) * 1000 <= ?" sqlWhereParams = append(sqlWhereParams, mapLongitude, mapLatitude, mapRadius) } sql = sqlFrom + sqlWhere sqlParams = append(sqlParams, sqlFromParams...) sqlParams = append(sqlParams, sqlWhereParams...) return sql, sqlParams, sqlFrom, sqlFromParams, nil } func setStoreMapInfo(ctx *jxcontext.Context, db *dao.DaoDB, storesInfo *StoresInfo, storeIDs []int, briefLevel int, isBussinessStatus interface{}) (err error) { storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") if err != nil { return err } storeCourierList, err := dao.GetStoreCourierList(db, storeIDs, nil, model.StoreStatusAll, model.StoreAuditStatusAll) if err != nil { return err } //isStoreVendorStatus := false //if isBussinessStatus != nil { // if isBussinessStatus.(bool) { // isStoreVendorStatus = true // } //} storeMapMap := dao.StoreMapList2Map(storeMapList) storeCourierMap := dao.StoreCourierList2Map(storeCourierList) for _, v := range storesInfo.Stores { if briefLevel > 0 { v.DeliveryRange = "" v.IDCardFront = "" v.IDCardBack = "" v.IDCardHand = "" v.IDCardHandBack = "" v.Licence = "" v.Licence2Image = "" } for _, v2 := range storeMapMap[v.ID] { v.StoreMaps = append(v.StoreMaps, v2) } for _, v2 := range storeCourierMap[v.ID] { v.CourierMaps = append(v.CourierMaps, v2) } } //task := tasksch.NewParallelTask("上下线状态", tasksch.NewParallelConfig().SetParallelCount(4), ctx, // func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { // store := batchItemList[0].(*StoreExt) // for _, v2 := range store.StoreMaps { // if isStoreVendorStatus { // if handler := CurVendorSync.GetStoreHandler(v2.VendorID); handler != nil { // if store, err := handler.ReadStore(ctx, v2.VendorOrgCode, v2.VendorStoreID); err == nil && store != nil { // if store.Status != model.StoreStatusDisabled { // v2.BussinessStatus = 1 // } else { // v2.BussinessStatus = -1 // } // } // } // } // } // return retVal, err // }, storesInfo.Stores) //task.Run() //task.GetResult(0) return nil } // todo 门店绑定信息可以考虑以数组形式返回,而不是现在这样 func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interface{}, offset, pageSize int, orderTimeFrom, orderTimeTo time.Time, orderCountFrom, orderCountTo int) (retVal *StoresInfo, err error) { briefLevel := int(utils.ForceInterface2Int64(params["briefLevel"])) //权限 if permission.IsRoled(ctx) { if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil { var storeIDs2 []int if params["storeIDs"] != nil { var storeIDs []int if err = utils.UnmarshalUseNumber([]byte(params["storeIDs"].(string)), &storeIDs); err == nil { for _, v := range storeIDs { if storeIDsMap[v] != 0 { storeIDs2 = append(storeIDs2, v) } } } if len(storeIDs2) == 0 { storeIDs2 = append(storeIDs2, -1) } } else { if params["storeID"] != nil && len(storeIDsMap) > 0 { if storeIDsMap[int(utils.Interface2Int64WithDefault(params["storeID"], 0))] == 0 { params["storeID"] = nil } } else { if len(storeIDsMap) > 0 { for k, _ := range storeIDsMap { storeIDs2 = append(storeIDs2, k) } } else { //storeIDs2 = append(storeIDs2, -1)l // 商家小程序用户切换门店,如果角色storeIDsMap没有数据则查询传入数据 storeIDs2 = append(storeIDs2, int(utils.Interface2Int64WithDefault(params["storeID"], 0))) } } } if data, err := json.Marshal(storeIDs2); err == nil { params["storeIDs"] = string(data) } } } sql, sqlParams, _, _, err := getStoresSql(ctx, keyword, params, orderTimeFrom, orderTimeTo) if err != nil { return nil, err } sql = ` SELECT SQL_CALC_FOUND_ROWS DISTINCT t1.*, CAST(t1.lng AS DECIMAL(15,6))/1000000 float_lng, CAST(t1.lat AS DECIMAL(15,6))/1000000 float_lat, IF(mm.name <> '', mm.name, mm.user_id2) market_man_name, bank.value payee_bank_name, IF(om.name <> '', om.name, om.user_id2) operator_name, IF(om2.name <> '', om2.name, om2.user_id2) operator_name2, IF(om3.name <> '', om3.name, om3.user_id2) operator_name3, province.code province_code, province.name province_name, city.name city_name, district.name district_name, br.name brand_name, br.logo brand_logo, (SELECT COUNT(*) FROM store t11 WHERE t11.link_store_id = t1.id) link_store_count ` + sql + ` ORDER BY t1.id DESC LIMIT ? OFFSET ? ` db := dao.GetDB() retVal = &StoresInfo{} var storeIDs []int var storeList []*StoreExt offset = jxutils.FormalizePageOffset(offset) pageSize = jxutils.FormalizePageSize(pageSize) sqlParams = append(sqlParams, pageSize, offset) //mapLimit := false txDB, _ := dao.Begin(db) if err = dao.GetRowsTx(txDB, &storeList, sql, sqlParams...); err == nil { retVal.Stores = storeList retVal.TotalCount = dao.GetLastTotalRowCount2(db, txDB) // 地图区域限制过滤 //if mapLongitude2, ok := params["mapLongitude"].(string); ok { // var ( // mapLatitude, mapLongitude float64 // mapRadius int // ) // mapLimit = true // mapLongitude = utils.Str2Float64(mapLongitude2) // mapLatitude = utils.Str2Float64(params["mapLatitude"].(string)) // mapRadius = params["mapRadius"].(int) // for _, v := range storeList { // valid := !mapLimit // if mapLimit { // valid = jxutils.EarthDistance(mapLongitude, mapLatitude, v.FloatLng, v.FloatLat)*1000 <= float64(mapRadius) // } // if valid { // retVal.Stores = append(retVal.Stores, v) // } // } //} else { // retVal.Stores = storeList //} // 订单情况过滤 //storeList, err = filterStoreByOrderInfo(db, retVal.Stores, orderTimeFrom, orderTimeTo, orderCountFrom, orderCountTo) //if err != nil { // return nil, err //} // 分页 //retVal.TotalCount = len(storeList) //retVal.Stores = nil //for i := offset; i < offset+pageSize && i < len(storeList); i++ { // storeIDs = append(storeIDs, storeList[i].ID) // retVal.Stores = append(retVal.Stores, storeList[i]) //} //if len(storeIDs) == 0 { // return retVal, nil //} // 导出门店地图标信息时,可能会需要转换门店坐标 needConver2Baidu := int(utils.Interface2Int64WithDefault(params["coordinateType"], 0)) == model.CoordinateTypeBaiDu if needConver2Baidu { task := tasksch.NewParallelTask("坐标转换", tasksch.NewParallelConfig().SetParallelCount(4).SetBatchSize(autonavi.MaxConvertCount), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { var coords []*baidunavi.Coordinate for _, v := range batchItemList { store := v.(*StoreExt) coords = append(coords, &baidunavi.Coordinate{ Lng: store.FloatLng, Lat: store.FloatLat, }) } coords, err = api.BaiDuNaviAPI.BatchCoordinateConvert(coords, baidunavi.CoordSysGCJ02, baidunavi.CoordSysBaiDu) if err == nil { for k, v := range batchItemList { store := v.(*StoreExt) coord := coords[k] store.FloatLng = coord.Lng store.FloatLat = coord.Lat } } return retVal, err }, retVal.Stores) task.Run() task.GetResult(0) } } dao.Commit(db, txDB) if len(retVal.Stores) > 0 { setStoreMapInfo(ctx, db, retVal, storeIDs, briefLevel, params["isBussinessStatus"]) retVal.MapCenterLng, retVal.MapCenterLat = getMapCenter(retVal.Stores) } return retVal, err } func filterStoreByOrderInfo(db *dao.DaoDB, inStores []*StoreExt, orderTimeFrom, orderTimeTo time.Time, orderCountFrom, orderCountTo int) (outStores []*StoreExt, err error) { if len(inStores) > 0 && !utils.IsTimeZero(orderTimeFrom) { storeIDs := make([]int, len(inStores)) for k, v := range inStores { storeIDs[k] = v.ID } orderSaleList, err2 := dao.GetStoresOrderSaleInfo(dao.GetDB(), storeIDs, orderTimeFrom, orderTimeTo, []int{model.OrderStatusFinished}) if err = err2; err != nil { return nil, err } storeOrderCountMap := make(map[int]int) for _, v := range orderSaleList { storeOrderCountMap[v.StoreID] += v.Count } for _, v := range inStores { orderCount := storeOrderCountMap[v.ID] if orderCount >= orderCountFrom && orderCount <= orderCountTo { v.OrderCount = orderCount outStores = append(outStores, v) } } } else { outStores = inStores } return outStores, err } func getMapCenter(storeList []*StoreExt) (lng, lat float64) { if len(storeList) == 0 { return 0, 0 } lngAvg := float64(0) latAvg := float64(0) storeListLenFloat := float64(len(storeList)) for _, store := range storeList { lngAvg += store.FloatLng latAvg += store.FloatLat } lngAvg = lngAvg / storeListLenFloat latAvg = latAvg / storeListLenFloat distAvg := float64(0) for _, store := range storeList { distAvg += math.Sqrt((store.FloatLng-lngAvg)*(store.FloatLng-lngAvg) + (store.FloatLat-latAvg)*(store.FloatLat-latAvg)) } distAvg = (distAvg / storeListLenFloat) maxDist := distAvg * 5 newStoreList := []*StoreExt{} for _, store := range storeList { dist := math.Sqrt((store.FloatLng-lngAvg)*(store.FloatLng-lngAvg) + (store.FloatLat-latAvg)*(store.FloatLat-latAvg)) if dist <= maxDist { lng += store.FloatLng lat += store.FloatLat newStoreList = append(newStoreList, store) } } if len(newStoreList) == len(storeList) { lng = lng / float64(len(newStoreList)) lat = lat / float64(len(newStoreList)) // for _, store := range storeList { // globals.SugarLogger.Debugf("store:%s, lng:%, lat:%f", store.Name, store.FloatLng, store.FloatLat) // } return lng, lat } return getMapCenter(newStoreList) } func GetVendorStore(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorStoreID string) (retVal *StoreExt, err error) { if vendorID == model.VendorIDJDShop && vendorStoreID == model.JdShopMainVendorStoreID { return nil, err } //绑定顺丰专送门店校验 if vendorID == model.VendorIDSFPS { flag := false if store, err := dao.GetStoreDetail(dao.GetDB(), utils.Str2Int(vendorStoreID), 0, ""); err == nil { for k, _ := range sfps2.SFCityStoreIDs { if strings.Contains(store.CityName, k) || store.CityName == k { flag = true } } } if !flag { return nil, errors.New("此门店暂时不在顺丰派送范围,无法绑定") } } if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil { result, err2 := handler.ReadStore(ctx, vendorOrgCode, vendorStoreID, "") if err = err2; err == nil { retVal = &StoreExt{ Store: result.Store, FloatLng: jxutils.IntCoordinate2Standard(result.Lng), FloatLat: jxutils.IntCoordinate2Standard(result.Lat), } db := dao.GetDB() if city, err2 := dao.GetPlaceByCode(db, result.CityCode); err2 == nil { retVal.CityName = city.Name } if district, err2 := dao.GetPlaceByCode(db, result.DistrictCode); err2 == nil { retVal.DistrictName = district.Name } if !jxutils.IsLegalStoreID(retVal.ID) { retVal.ID = 0 } retVal.BussinessStatus = result.Status // -2 下线,禁用 ,-1 休息 ,1 营业 //if result.Status <= model.StoreStatusHaveRest { // retVal.BussinessStatus = -1 //} else { // retVal.BussinessStatus = 1 //} return retVal, nil } return nil, err } else { handler := partner.GetDeliveryPlatformFromVendorID(vendorID).Handler if store, err := handler.GetStore(ctx, 0, vendorStoreID); err == nil { retVal = &StoreExt{ Store: store.Store, //暂时添加上 //FloatLng: jxutils.IntCoordinate2Standard(store.Lng), //FloatLat: jxutils.IntCoordinate2Standard(store.Lat), } retVal.Name = store.Name retVal.BussinessStatus = store.CourierStatus //if retVal.Status == model.StoreStatusDisabled { // retVal.BussinessStatus = -1 //} else { // retVal.BussinessStatus = 1 //} return retVal, err } } return nil, err } func isUpdateStoreNeedSync(valid map[string]interface{}) bool { for k := range valid { if storeKeyPropertyMap[k] == 1 { return true } } return false } func checkBankBranch(payeeBankBranchName string) (err error) { if payeeBankBranchName != "" { if strings.Index(payeeBankBranchName, "支行") == -1 && strings.Index(payeeBankBranchName, "分行") == -1 { err = fmt.Errorf("支行信息异常,你可能没有在使用最新的版本,请强制刷新浏览器或联系开发") } } return err } func checkCreateStore(store *model.Store) (err error) { if store.Lng == 0 || store.Lat == 0 || store.Address == "" { err = fmt.Errorf("必须设置地址信息") } return err } func checkStoreDeliveryRange(deliveryRange string) (err error) { if deliveryRange != "" { points := jxutils.CoordinateStr2Points(deliveryRange) for _, point := range points { for _, coord := range point { if coord == 0 || math.IsNaN(coord) { return fmt.Errorf("坐标点数据非法:%s", deliveryRange) } } } } return err } func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interface{}, userName string) (num int64, err error) { if err = checkBankBranch(utils.Interface2String(payload["payeeBankBranchName"])); err != nil { return 0, err } db := dao.GetDB() store := &model.Store{} store.ID = storeID if err = dao.GetEntity(db, store); err != nil { return 0, err } var outStore *model.Store var beforStore = *store if payload["autoEnableAt"] != nil { payload["autoEnableAt"] = utils.Time2Date(utils.Str2Time(utils.Interface2String(payload["autoEnableAt"]))) } valid := dao.StrictMakeMapByStructObject2(payload, store, &outStore, userName) if err = checkStoreDeliveryRange(utils.Interface2String(valid["deliveryRange"])); err != nil { return 0, err } if globals.EnableWXAuth2 { if err = dao.ValidateRoles(db, utils.Interface2String(valid["marketManRole"]), utils.Interface2String(valid["operatorRole"]), utils.Interface2String(valid["operatorRole2"])); err != nil { return 0, err } } if payload["lng"] != nil || payload["lat"] != nil { intLng := jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["lng"], 0.0)) intLat := jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["lat"], 0.0)) if intLng != 0 && intLng != store.Lng { valid["lng"] = intLng } if intLat != 0 && intLat != store.Lng { valid["lat"] = intLat } } if payload["packageSetting"] != nil { valid["packageSetting"], _ = payload["packageSetting"].(json.Number).Int64() } if payload["packageSwitch"] != nil { valid["packageSwitch"], _ = payload["packageSwitch"].(json.Number).Int64() } if payload["freightMarkup"] != nil { valid["freightMarkup"], _ = payload["freightMarkup"].(json.Number).Int64() } if valid["originalName"] != nil { delete(valid, "originalName") } if valid["printerBindInfo"] != nil { delete(valid, "printerBindInfo") } syncStatus := model.SyncFlagModifiedMask if valid["name"] != nil { valid["name"] = jxutils.FormalizeName(valid["name"].(string)) store.Name = valid["name"].(string) syncStatus |= model.SyncFlagStoreName courierList, _ := dao.GetStoreCourierList2(db, []int{storeID}, nil, 0, nil) for _, v := range courierList { v.VendorStoreName = store.Name dao.UpdateEntity(db, v, "VendorStoreName") } } printerVendorID := int(utils.Interface2Int64WithDefault(valid["printerVendorID"], 0)) if printerVendorID == 0 { printerVendorID = store.PrinterVendorID } if printerVendorID == model.VendorIDXiaoWM { delete(valid, "printerKey") } // 网络打印机处理 if valid["printerVendorID"] != nil || valid["printerSN"] != nil || valid["printerKey"] != nil { if valid["printerVendorID"] == nil { valid["printerVendorID"] = store.PrinterVendorID } if printerVendorID := int(utils.Interface2Int64WithDefault(valid["printerVendorID"], 0)); printerVendorID > 0 { handler := partner.GetPrinterPlatformFromVendorID(printerVendorID) if handler == nil { return 0, fmt.Errorf("不支持的打印机厂商ID:%d", printerVendorID) } if valid["printerSN"] == nil { valid["printerSN"] = store.PrinterSN } if valid["printerKey"] == nil { valid["printerKey"] = store.PrinterKey } newID1, newID2, err2 := handler.RegisterPrinter(ctx, valid["printerSN"].(string), valid["printerKey"].(string), store.Name, int64(store.ID)) if err = err2; err != nil { return 0, err } handler.EmptyPrintList(ctx, newID1, newID2) if newID1 != "" { valid["printerSN"] = newID1 } if newID2 != "" { valid["printerKey"] = newID2 } } else { valid["printerVendorID"] = 0 valid["printerSN"] = "" valid["printerKey"] = "" } valid["printerBindInfo"] = "" if handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); handler != nil { handler.UnregisterPrinter(ctx, store.PrinterSN, utils.Int2Str(store.ID)) } } if valid["soundPercentage"] != nil && valid["printerSN"] != nil { handler := partner.GetPrinterPlatformFromVendorID(printerVendorID) if handler == nil { return 0, fmt.Errorf("不支持的打印机厂商ID:%d", printerVendorID) } err = handler.SetSound(ctx, store.PrinterSN, store.PrinterKey, jxutils.TranslateSoundSize(printerVendorID, int(utils.Interface2Int64WithDefault(valid["soundPercentage"], 50)))) if err != nil { return 0, err } } if valid["linkStoreID"] != nil { linkStoreID := int(utils.Interface2Int64WithDefault(valid["linkStoreID"], 0)) linkStoreID, err = dao.GetRealLinkStoreID(db, linkStoreID) if err != nil { return 0, err } if err = checkStoreHaveLinkedStore(storeID, linkStoreID); err != nil { return 0, err } valid["linkStoreID"] = linkStoreID } // globals.SugarLogger.Debug(utils.Format4Output(valid, false)) for _, v := range []string{ "lng", "lat", "cityCode", "address", "deliveryRange", } { if valid[v] != nil { syncStatus |= model.SyncFlagStoreAddress break } } status := 0 if valid["status"] != nil || valid["autoEnableAt"] != nil { if valid["status"] != nil { syncStatus |= model.SyncFlagStoreStatus status = int(utils.Interface2Int64WithDefault(valid["status"], 0)) if status == model.StoreStatusDisabled { valid["deliveryRangeType"] = model.DeliveryRangeTypeRadius valid["deliveryRange"] = "1" } } else { status = store.Status } if status != model.StoreStatusClosed && status != model.StoreStatusHaveRest { valid["autoEnableAt"] = nil } else { if valid["autoEnableAt"] != nil { status = model.StoreStatusHaveRest } else { status = model.StoreStatusClosed valid["autoEnableAt"] = nil } valid["status"] = status } } if valid["deliveryRange"] != nil { valid["deliveryRange"] = strings.Trim(valid["deliveryRange"].(string), ";") } //时间校验 if outStore != nil { if outStore.OpenTime1 != 0 && outStore.CloseTime1 != 0 { if err := ValidateStructPartial(outStore, "OpenTime1", "CloseTime1"); err != nil { return 0, errors.New(fmt.Sprintf("门店营业时间1设置不合法!时间范围1 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1)) } } if (outStore.OpenTime1 == 0 && outStore.CloseTime1 != 0) || (outStore.OpenTime1 != 0 && outStore.CloseTime1 == 0) { return 0, errors.New(fmt.Sprintf("门店营业时间1设置不合法!时间范围1 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1)) } if outStore.OpenTime2 != 0 && outStore.CloseTime2 != 0 { if err := ValidateStructPartial(outStore, "OpenTime2", "CloseTime2"); err != nil { return 0, errors.New(fmt.Sprintf("门店营业时间2设置不合法!时间范围2 :[%v] 至 [%v]", outStore.OpenTime2, outStore.CloseTime2)) } } if (outStore.OpenTime2 == 0 && outStore.CloseTime2 != 0) || (outStore.OpenTime2 != 0 && outStore.CloseTime2 == 0) { return 0, errors.New(fmt.Sprintf("门店营业时间2设置不合法!时间范围2 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1)) } if outStore.OpenTime1 != 0 && outStore.CloseTime1 != 0 && outStore.OpenTime2 != 0 && outStore.CloseTime2 != 0 { if outStore.OpenTime2 < outStore.CloseTime1 { return 0, errors.New(fmt.Sprintf("门店营业时间设置不合法!第二段营业时间应该在第一段营业时间之后!")) } } if beginAt, endAt := GetTimeMixByInt(outStore.OpenTime1, outStore.CloseTime1, outStore.OpenTime2, outStore.CloseTime2); beginAt != 0 && endAt != 0 { return 0, errors.New(fmt.Sprintf("两段门店营业时间不可交叉!时间范围1 :[%v] 至 [%v], 时间范围2 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1, outStore.OpenTime2, outStore.CloseTime2)) } } if valid["promoteInfo"] != nil { valid["promoteInfo"] = strings.ReplaceAll(valid["promoteInfo"].(string), "{phone}", store.Tel1) } for k, _ := range valid { if earningInfoMap[k] != "" || marketInfoMap[k] != "" { //增加权限校验 userRole, err := dao.GetUserRole(dao.GetDB(), []string{ctx.GetUserID()}, []int{model.RoleUpdateSettle}) if err != nil || len(userRole) == 0 { return 0, errors.New(fmt.Sprintf("当前用户 [%v] 无权限修改此字段!", ctx.GetUserName())) } else { menus, _ := dao.GetMenuWithUser(dao.GetDB(), "结算权限", 0, 1, ctx.GetUserID()) if len(menus) == 0 { if marketInfoMap[k] != "" { menus2, _ := dao.GetMenuWithUser(dao.GetDB(), "市场信息", 0, 1, ctx.GetUserID()) if len(menus2) == 0 { return 0, errors.New(fmt.Sprintf("当前用户 [%v] 无权限修改此字段!", ctx.GetUserName())) } } else { return 0, errors.New(fmt.Sprintf("当前用户 [%v] 无权限修改此字段!", ctx.GetUserName())) } } } } } if len(valid) > 0 { if globals.IsAddEvent { mapBefore := refutil.FindMapAndStructMixed(valid, beforStore) err = AddEventDetail(db, ctx, model.OperateUpdate, storeID, model.ThingTypeStore, storeID, BuildDiffData(mapBefore), BuildDiffData(valid)) } txDB, _ := dao.Begin(db) defer func() { dao.Rollback(db, txDB) }() num, err = dao.UpdateEntityLogically(db, store, valid, userName, nil) if err == nil && num == 1 { if isUpdateStoreNeedSync(valid) { dummy := &model.StoreMap{} kv := make(map[string]interface{}) if valid["status"] != nil { //if syncStatus&model.SyncFlagStoreStatus != 0 && status == model.StoreStatusOpened { kv[model.FieldStatus] = status //} } _, err2 := dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, dummy, kv, userName, map[string]interface{}{ model.FieldStoreID: store.ID, }, model.FieldSyncStatus, syncStatus) if err = err2; err == nil { dao.Commit(db, txDB) _, err = CurVendorSync.SyncStore(ctx, db, -1, store.ID, false, userName) if valid["tel1"] != nil || valid["tel2"] != nil { TryAddStoreBossRole4StoreByMobile(ctx, store.ID, []string{utils.Interface2String(valid["tel1"]), utils.Interface2String(valid["tel2"])}) } if syncStatus&model.SyncFlagStoreAddress != 0 || valid["tel1"] != nil || valid["payeeName"] != nil { // 修改门店信息(第三方配送平台同步) updateCourierStores(ctx, storeID) } } } else { dao.Commit(db, txDB) } notifyStoreOperatorChanged(ctx, store.ID, "京东运营", store.OperatorPhone, valid["operatorPhone"]) notifyStoreOperatorChanged(ctx, store.ID, "美团运营", store.OperatorPhone2, valid["operatorPhone2"]) notifyStoreOperatorChanged(ctx, store.ID, "饿百运营", store.OperatorPhone3, valid["operatorPhone3"]) notifyStoreOperatorChanged(ctx, store.ID, "市场", store.MarketManPhone, valid["marketManPhone"]) if err == nil { if valid["openTime1"] != 0 || valid["closeTime1"] != 0 || valid["openTime2"] != 0 || valid["closeTime2"] != 0 { err = CurVendorSync.ChangeStoreSkuSaleStatus(ctx, storeID, true, true) } } } } else { globals.SugarLogger.Debugf("UpdateStore track:%s, store:%s", ctx.GetTrackInfo(), utils.Format4Output(store, true)) } if status == -2 { } return num, err } //// updateVendorStoreStatusAndDeliveryStatus 当门店被禁用时,将三方平台和三方配送全部关闭 //func updateVendorStoreStatusAndDeliveryStatus(ctx *jxcontext.Context, storeId int) error { // var ( // db = dao.GetDB() // ) // // 获取门店绑定三方平台列表 // storeMap, err := dao.GetStoresMapList(db, nil, []int{storeId}, nil, 0, 0, "", "", "") // if err != nil { // return err // } // // 获取门店绑定的配送凭条 // storeCouriers, err := dao.GetOpenedStoreCouriersByStoreID(db, storeId, -1) // if err != nil { // return err // } // // work := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { // var errList []error // step := batchItemList[0].(int) // switch step { // case 0: // 同步修改门店营业撞他 // // 京东关店,本地店铺状态修改 // // 美团关店,本地店铺状态修改 // // 饿百关店,本地店铺状态修改 // // 抖音关店,本地店铺状态修改 // case 1: // 同步修改门店配送状态 // // 美团跑腿配送(没有门店状态修改,直接修改本店) // // 蜂鸟配送,关闭(有) // // 达达配送,关闭(有) // // uu跑腿,关闭(不涉及门店概念,直接本地取消绑定信息) // } // return errList, nil // } // tasksch.NewParallelTask( // "禁用门店,修改平台门店状态", // tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(false), // ctx, // work, // []int{0, 1}, // ) // //} func notifyStoreOperatorChanged(ctx *jxcontext.Context, storeID int, operatorRoleName, phone string, newPhone interface{}) { if phone != "" && newPhone != nil { db := dao.GetDB() if user, err := dao.GetUserByID(db, "mobile", phone); err == nil { curUserName := "" if newOperator := utils.Interface2String(newPhone); newOperator != "" { if curUser, err := dao.GetUserByID(db, "mobile", newOperator); err == nil { curUserName = curUser.GetName() } } ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), fmt.Sprintf("门店%s变更", operatorRoleName), fmt.Sprintf("门店:%d,原%s:%s,变更为:%s,操作人:%s", storeID, operatorRoleName, user.GetName(), curUserName, ctx.GetFullUser().GetName())) } } } func SetStoreStatus(ctx *jxcontext.Context, storeID, status int) (err error) { payload := map[string]interface{}{ "status": status, } _, err = UpdateStore(ctx, storeID, payload, ctx.GetUserName()) return err } func EnableHaveRestStores(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) { storeInfo, err := GetStores(ctx, "", map[string]interface{}{ "statuss": string(utils.MustMarshal([]int{model.StoreStatusHaveRest})), }, 0, model.UnlimitedPageSize, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0) if err != nil { return "", err } if len(storeInfo.Stores) == 0 { return "0", nil } task := tasksch.NewParallelTask("EnableHaveRestStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { store := batchItemList[0].(*StoreExt) var autoEnableAt time.Time if store.AutoEnableAt != nil { autoEnableAt = *store.AutoEnableAt } else { autoEnableAt = utils.Time2Date(time.Now().Add(12 * time.Hour)) // 临时休息,但没有设置恢复营业时间,缺省是第二天 } if time.Now().Sub(autoEnableAt) >= -2*time.Hour { err = SetStoreStatus(ctx, store.ID, model.StoreStatusOpened) } return nil, err }, storeInfo.Stores) tasksch.ManageTask(task).Run() if !isAsync { if _, err = task.GetResult(0); err == nil { hint = utils.Int2Str(len(storeInfo.Stores)) } } else { hint = task.GetID() } return hint, err } func checkStoreHaveLinkedStore(storeID, linkStoreID int) (err error) { if linkStoreID != 0 { if storeID == linkStoreID { err = fmt.Errorf("不能自我关联") } else { storeList, err2 := dao.GetStoreLinkStores(dao.GetDB(), storeID) if err = err2; err == nil { if len(storeList) > 0 { var storeInfo []string for _, v := range storeList { storeInfo = append(storeInfo, utils.Int2Str(v.ID)) } err = fmt.Errorf("门店%d已经被其它门店(%s)关联,不能再关联至其它门店", storeID, strings.Join(storeInfo, ",")) } } } } return err } // 创建京西门店,同时生成专送门店。 func CreateStore(ctx *jxcontext.Context, storeExt *StoreExt, userName string) (id int, err error) { if err = checkBankBranch(storeExt.PayeeBankBranchName); err != nil { return 0, err } store := &storeExt.Store if store.ID != 0 && !jxutils.IsLegalStoreID(store.ID) { return 0, fmt.Errorf("ID:%d不是合法的京西门店编号", store.ID) } db := dao.GetDB() if globals.EnableWXAuth2 { if err = dao.ValidateRoles(db, store.MarketManRole, store.OperatorRole, store.OperatorRole2, store.OperatorRole3); err != nil { return 0, err } } realLinkStoreID, err := dao.GetRealLinkStoreID(db, storeExt.LinkStoreID) if err != nil { return 0, err } if err = checkStoreHaveLinkedStore(storeExt.ID, realLinkStoreID); err != nil { return 0, err } storeExt.LinkStoreID = realLinkStoreID if storeExt.MarketManName == "" { storeExt.MarketManName = ctx.GetUserName() } if storeExt.MarketManPhone == "" { storeExt.MarketManPhone, _ = ctx.GetMobileAndUserID() } existingID := store.ID store.Lng = jxutils.StandardCoordinate2Int(storeExt.FloatLng) store.Lat = jxutils.StandardCoordinate2Int(storeExt.FloatLat) if err = checkCreateStore(&storeExt.Store); err != nil { return 0, err } store.Name = jxutils.FormalizeName(store.Name) store.DeliveryRange = strings.Trim(store.DeliveryRange, ";") if store.PrinterSN != "" { handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID) if handler == nil { return 0, fmt.Errorf("不支持的打印机厂商ID:%d", store.PrinterVendorID) } newID1, newID2, err2 := handler.RegisterPrinter(ctx, store.PrinterSN, store.PrinterKey, store.Name, int64(store.ID)) if err = err2; err != nil { return 0, err } handler.EmptyPrintList(ctx, newID1, newID2) if newID1 != "" { store.PrinterSN = newID1 } if newID2 != "" { store.PrinterKey = newID2 } } if store.StoreLevel == "" { store.StoreLevel = "C" } dao.WrapAddIDCULDEntity(store, userName) store.ID = existingID if err = dao.CreateEntity(db, store); err == nil { if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateAdd, store.ID, model.ThingTypeStore, store.ID, "", "") } // 同步门店信息 UpdateOrCreateCourierStores(ctx, store.ID, false, false, false) TryAddStoreBossRole4StoreByMobile(ctx, storeExt.ID, []string{storeExt.Tel1, storeExt.Tel2}) // InsertStoreCategories(ctx, db, store.ID) AddStoreVendorMap(ctx, db, model.VendorIDJX, "", store.ID, &model.StoreMap{ VendorStoreID: utils.Int2Str(store.ID), AutoPickup: 1, DeliveryCompetition: 1, PricePercentage: 100, IsSync: 1, Status: model.StoreStatusOpened, PricePercentagePack: "无", VendorID: model.VendorIDJX, }, false) //尝试把平台负责人加到他自己的权限里 if store.MarketManPhone != "" { user, _ := dao.GetUserByID(db, "mobile", store.MarketManPhone) if roles, _ := dao.GetRole(db, user.Name, ""); len(roles) > 0 { role := roles[0] if role.StoreIDs != "" { role.StoreIDs = role.StoreIDs + "," + utils.Int2Str(store.ID) } else { role.StoreIDs = utils.Int2Str(store.ID) } dao.UpdateEntity(db, role, "StoreIDs") } else { if roles, _ := dao.GetRole(db, user.Name+"城市", ""); len(roles) > 0 { role := roles[0] if role.StoreIDs != "" { role.StoreIDs = role.StoreIDs + "," + utils.Int2Str(store.ID) } else { role.StoreIDs = utils.Int2Str(store.ID) } dao.UpdateEntity(db, role, "StoreIDs") } } } return store.ID, err } return 0, err } // 创建京西门店,不在生成专送门店! func CreateStore2JX(ctx *jxcontext.Context, storeExt *StoreExt, userName string) (id int, err error) { if err = checkBankBranch(storeExt.PayeeBankBranchName); err != nil { return 0, err } store := &storeExt.Store if store.ID != 0 && !jxutils.IsLegalStoreID(store.ID) { return 0, fmt.Errorf("ID:%d不是合法的京西门店编号", store.ID) } db := dao.GetDB() if globals.EnableWXAuth2 { if err = dao.ValidateRoles(db, store.MarketManRole, store.OperatorRole, store.OperatorRole2, store.OperatorRole3); err != nil { return 0, err } } realLinkStoreID, err := dao.GetRealLinkStoreID(db, storeExt.LinkStoreID) if err != nil { return 0, err } if err = checkStoreHaveLinkedStore(storeExt.ID, realLinkStoreID); err != nil { return 0, err } storeExt.LinkStoreID = realLinkStoreID if storeExt.MarketManName == "" { storeExt.MarketManName = ctx.GetUserName() } if storeExt.MarketManPhone == "" { storeExt.MarketManPhone, _ = ctx.GetMobileAndUserID() } existingID := store.ID store.Lng = jxutils.StandardCoordinate2Int(storeExt.FloatLng) store.Lat = jxutils.StandardCoordinate2Int(storeExt.FloatLat) if err = checkCreateStore(&storeExt.Store); err != nil { return 0, err } store.Name = jxutils.FormalizeName(store.Name) store.DeliveryRange = strings.Trim(store.DeliveryRange, ";") if store.PrinterSN != "" { handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID) if handler == nil { return 0, fmt.Errorf("不支持的打印机厂商ID:%d", store.PrinterVendorID) } newID1, newID2, err2 := handler.RegisterPrinter(ctx, store.PrinterSN, store.PrinterKey, store.Name, int64(store.ID)) if err = err2; err != nil { return 0, err } handler.EmptyPrintList(ctx, newID1, newID2) if newID1 != "" { store.PrinterSN = newID1 } if newID2 != "" { store.PrinterKey = newID2 } } if store.StoreLevel == "" { store.StoreLevel = "C" } if store.Tel1 == "" { store.Tel1 = model.DefaultPhone } if store.IDName == "" { store.IDName = model.DefaultName } if store.IDCode == "" { store.IDCode = model.DefaultIdCard } // 默认无品牌 store.BrandID = 9 dao.WrapAddIDCULDEntity(store, userName) store.ID = existingID if err = dao.CreateEntity(db, store); err == nil { if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateAdd, store.ID, model.ThingTypeStore, store.ID, "", "") } // 同步门店信息 //UpdateOrCreateCourierStores(ctx, store.ID, false, false, false) TryAddStoreBossRole4StoreByMobile(ctx, storeExt.ID, []string{storeExt.Tel1, storeExt.Tel2}) // InsertStoreCategories(ctx, db, store.ID) AddStoreVendorMap(ctx, db, model.VendorIDJX, "", store.ID, &model.StoreMap{ VendorStoreID: utils.Int2Str(store.ID), AutoPickup: 1, DeliveryCompetition: 1, PricePercentage: 100, IsSync: 0, Status: model.StoreStatusOpened, PricePercentagePack: "无", CreateDeliveryType: model.YES, // 菜市门店默认门店发单 VendorID: model.VendorIDJX, }, false) //尝试把平台负责人加到他自己的权限里 if store.MarketManPhone != "" { user, _ := dao.GetUserByID(db, "mobile", store.MarketManPhone) if roles, _ := dao.GetRole(db, user.Name, ""); len(roles) > 0 { role := roles[0] if role.StoreIDs != "" { role.StoreIDs = role.StoreIDs + "," + utils.Int2Str(store.ID) } else { role.StoreIDs = utils.Int2Str(store.ID) } dao.UpdateEntity(db, role, "StoreIDs") } else { if roles, _ := dao.GetRole(db, user.Name+"城市", ""); len(roles) > 0 { role := roles[0] if role.StoreIDs != "" { role.StoreIDs = role.StoreIDs + "," + utils.Int2Str(store.ID) } else { role.StoreIDs = utils.Int2Str(store.ID) } dao.UpdateEntity(db, role, "StoreIDs") } } } return store.ID, err } return 0, err } func CreateStoreByUser(ctx *jxcontext.Context, mobile string) (id int, err error) { store := &model.Store{} db := dao.GetDB() store.Lng = jxutils.StandardCoordinate2Int(104.3975) store.Lat = jxutils.StandardCoordinate2Int(30.504679) store.Address = "成都市简阳市简阳市" store.Name = "无名称" + utils.Int64ToStr(time.Now().Unix()) store.DeliveryRangeType = model.DeliveryRangeTypeRadius store.DeliveryRange = "3000" store.PayPercentage = 100 store.Status = model.StoreStatusClosed store.OpenTime1 = 700 store.CloseTime1 = 1900 store.Tel1 = mobile store.CityCode = 510100 store.DistrictCode = 510185 store.BrandID = 9 if store.StoreLevel == "" { store.StoreLevel = "C" } store.MarketManPhone = "18048531223" dao.WrapAddIDCULDEntity(store, ctx.GetUserName()) storeList, _ := dao.GetStoreList(db, nil, nil, nil, nil, []string{mobile}, "") if len(storeList) > 0 { return 0, fmt.Errorf("此电话已有门店了![%v]", mobile) } if err = dao.CreateEntity(db, store); err == nil { if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateAdd, store.ID, model.ThingTypeStore, store.ID, "", "") } TryAddStoreBossRole4StoreByMobile(ctx, store.ID, []string{mobile}) return store.ID, err } return 0, err } func GetStoreVendorMaps(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, vendorID int) (storeMaps []*model.StoreMap, err error) { cond := map[string]interface{}{ model.FieldStoreID: storeID, } if vendorID != -1 { cond[model.FieldVendorID] = vendorID } if vendorID == model.VendorIDDD { if err1 := dao.GetEntitiesByKV(db, &storeMaps, cond, false); err1 == nil && len(storeMaps) > 0 { _ = tiktok_store.GetRemoteStoreSth(storeMaps[0].VendorOrgCode, storeMaps[0].VendorStoreID, storeID) } } return storeMaps, dao.GetEntitiesByKV(db, &storeMaps, cond, false) } // todo 需要对字段做有效性检查 func AddStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, vendorID int, vendorOrgCode string, storeID int, storeMap *model.StoreMap, isAdd bool) (outStoreMap *model.StoreMap, err error) { errList := errlist.ErrList{} if storeID == 0 { return nil, fmt.Errorf("storeID不能为0") } if vendorID != model.VendorIDJD && (storeMap.AutoPickup == 0) { return nil, fmt.Errorf("非京东平台要求必须自动拣货") } userName := ctx.GetUserName() storeMap.StoreID = storeID storeMap.VendorID = vendorID storeMap.VendorOrgCode = vendorOrgCode storeMap.Status = model.StoreStatusOpened storeMap.DeliveryType = model.StoreDeliveryTypeByStore storeMap.SyncStatus = 0 if vendorID != model.VendorIDJX && vendorID != model.VendorIDYB && vendorID != model.VendorIDJDShop { if storeMap.VendorOrgCode == "" { return nil, fmt.Errorf("必须指定平台分账号信息") } if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil { if vendorOrgCode != globals.Mtwm2Code { store, err2 := handler.ReadStore(ctx, vendorOrgCode, storeMap.VendorStoreID, storeMap.VendorStoreName) if err = err2; err == nil || storeMap.IsSync == 0 { if store != nil { storeMap.DeliveryType = store.DeliveryType storeMap.Status = store.Status storeMap.VendorStoreName = store.Name } err = nil } } else { //美团商超获取token mtapi := apimanager.CurAPIManager.GetAPI(model.VendorIDMTWM, storeMap.VendorOrgCode).(*mtwmapi.API) if token, err := mtapi.GetAccessToken2(storeMap.VendorStoreID); err == nil && token != nil { storeMap.MtwmToken = token.AccessToken storeMap.MtwmRefreshToken = token.RefreshToken } } storeMap.SyncStatus = model.SyncFlagModifiedMask | model.SyncFlagStoreName | model.SyncFlagStoreAddress // 新增绑定门店是修改的概念 } else { err = ErrCanNotFindVendor } storeDetail, _ := dao.GetStoreDetailByVendorStoreID(db, storeMap.VendorStoreID, storeMap.VendorID, "") if storeDetail != nil { return nil, fmt.Errorf("此平台门店ID已在京西有绑定,请先解除绑定,平台门店ID :[%v]", storeMap.VendorStoreID) } if vendorID == model.VendorIDDD { //抖店绑定店铺时 检查并补充创建 if err2 := tiktok_store.CreateOrUpdateAll(vendorOrgCode, int64(storeMap.StoreID), utils.Str2Int64(storeMap.VendorStoreID), int64(storeMap.DeliveryFeeDeductionFee), int64(storeMap.DeliveryFeeDeductionSill), utils.Str2Int64(storeMap.YbStorePrefix), storeMap.YbAppID); err2 != nil { errList.AddErr(err2) } } } else if vendorID == model.VendorIDJX { ReCalculateJxPriceLight(db, ctx, storeID) //} else if vendorID == model.VendorIDYB { // err = checkYbParams(db, storeMap, storeID) // if err != nil { // return nil, err // } } else if vendorID == model.VendorIDJDShop { if storeMap.VendorStoreID == "" { storeMap.SyncStatus = model.SyncFlagNewMask //京东商城要去建店 } else { if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil { store, err2 := handler.ReadStore(ctx, vendorOrgCode, storeMap.VendorStoreID, storeMap.VendorStoreName) if err = err2; err == nil || storeMap.IsSync == 0 { if store != nil { storeMap.Status = store.Status } err = nil storeMap.SyncStatus = model.SyncFlagModifiedMask | model.SyncFlagStoreName | model.SyncFlagStoreAddress } else { return nil, err } } else { err = ErrCanNotFindVendor } } } storeMapList, err := dao.GetStoresMapList2(db, []int{vendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "", true) if len(storeMapList) > 0 { _, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeID, false, userName) } else { if err == nil { dao.WrapAddIDCULDEntity(storeMap, userName) if db == nil { db = dao.GetDB() } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if err = dao.CreateEntity(db, storeMap); err == nil { dao.Commit(db, txDB) outStoreMap = storeMap } else { dao.Rollback(db, txDB) } } } if err != nil { return outStoreMap, err } if vendorID == model.VendorIDJDShop { //绑定京东商城后,需要对绑定的门店现有的和模板店相同且可售的商品设置京东商城的门店库存 //TODO SyncFlagSaleMask对京东商城来说,修改门店商品状态就是修改库存 if _, err = SetStoreSkuSyncStatus2(db, []int{storeID}, []int{model.VendorIDJDShop}, findSkusBetweenJdsMainStore(db, storeID), model.SyncFlagSaleMask); err == nil { // CurVendorSync.SyncStoresSkus(ctx, nil, 0, db, nil, []int{storeID}, nil, false, true, true) } } if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateAdd, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`) } _, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeID, false, userName) _, err = CurVendorSync.FullSyncStoresSkus(ctx, db, []int{vendorID}, []int{storeID}, true, nil, true, true, isAdd) if utils.IsNil(errList) && err == nil { return outStoreMap, nil } else { return outStoreMap, errors.New(fmt.Sprintf("errList=%s,err=%v", utils.Format4Output(errList, true), err)) } } func DeleteStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, userName string) (num int64, err error) { if db == nil { db = dao.GetDB() } storeMap := &model.StoreMap{ StoreID: storeID, VendorID: vendorID, } storeMap.DeletedAt = utils.DefaultTimeValue if err = dao.GetEntity(db, storeMap, model.FieldStoreID, model.FieldVendorID, model.FieldDeletedAt); err == nil { if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil { handler.UpdateStoreCustomID(ctx, storeMap.VendorOrgCode, storeMap.VendorStoreID, utils.Str2Int64WithDefault(storeMap.VendorStoreID, 0)) } storeMap.FakeOpenStart = 0 storeMap.FakeOpenStop = 0 num, err = dao.DeleteEntityLogically(db, storeMap, map[string]interface{}{ model.FieldStatus: model.StoreStatusDisabled, }, userName, nil) if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateDelete, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`) } } //删除抖店映射 //if vendorID == model.VendorIDDD { if _, err1 := dao.ExecuteSQL(db, "DELETE FROM freight_template WHERE freight_template.store_id = ? ", storeID); err1 != nil { err = fmt.Errorf("%v,%v", err, err1) } //} return num, err } func isStoreMapNeedSync(vendorID int, valid map[string]interface{}) bool { if vendorID != model.VendorIDJX { for k := range valid { if storeMapKeyPropertyMap[k] == 1 { return true } } } return false } func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, payload map[string]interface{}, userName string) (num int64, err error) { if vendorID != model.VendorIDJD { if autoPickup, ok := payload["autoPickup"]; ok && autoPickup == 0 { return 0, fmt.Errorf("非京东平台要求必须自动拣货") } } var storeHandler partner.IPurchasePlatformHandler if vendorID != model.VendorIDJX { storeHandler = CurVendorSync.GetStoreHandler(vendorID) if storeHandler == nil { return 0, ErrCanNotFindVendor } } // 暂时不开放isSync if isSync, ok := payload["isSync"].(int); ok && isSync == 0 { delete(payload, "isSync") } delete(payload, "bussinessStatus") //var vendorOrgCode = "" //if payload["vendorOrgCode"].(string) == "" { // return 0, fmt.Errorf("平台账号不能为空") //} else { // vendorOrgCode = payload["vendorOrgCode"].(string) //} if db == nil { db = dao.GetDB() } storeMap := &model.StoreMap{ StoreID: storeID, VendorID: vendorID, //VendorOrgCode: vendorOrgCode, } storeMap.DeletedAt = utils.DefaultTimeValue if err = dao.GetEntity(db, storeMap, model.FieldStoreID, model.FieldVendorID, model.FieldDeletedAt); err != nil { return 0, err } var beforeStoreMap = *storeMap syncStatus := model.SyncFlagModifiedMask valid := dao.StrictMakeMapByStructObject(payload, storeMap, userName) if valid["status"] != nil { syncStatus |= model.SyncFlagStoreStatus } //修改分类开关需要打同步标志 if valid["isSysCat"] != nil { SetStoreCategorySyncStatus2(db, []int{storeID}, nil, model.SyncFlagModifiedMask) } if _, ok := valid["vendorStoreName"]; ok { // if utf8.RuneCountInString(vendorStoreName) > jdapi.MaxStoreNameLen && vendorID == model.VendorIDJD { // return 0, fmt.Errorf("门店名称不允许超过13位!") // } syncStatus |= model.SyncFlagStoreName } //增加同步到抖店厂商的同步标志 DDFlag := false errList := errlist.ErrList{} //deliveryFeeDeductionSill-包邮模板 满x包邮金额 deliveryFeeDeductionFee-打包费 ybStorePrefix-起送价 ybAppID-自动运力设置 if (valid["deliveryFeeDeductionSill"] != nil || valid["deliveryFeeDeductionFee"] != nil || valid["ybStorePrefix"] != nil || valid["ybAppID"] != nil) && vendorID == model.VendorIDDD { DDFlag = true } //特殊处理抖店运费模板、打包费 if DDFlag { if err := tiktok_store.SpecialTreat(storeMap.VendorOrgCode, utils.Str2Int64(storeMap.VendorStoreID), int64(storeMap.StoreID), int64(storeMap.DeliveryFeeDeductionFee), int64(storeMap.DeliveryFeeDeductionSill), utils.Str2Int64(storeMap.YbStorePrefix), storeMap.YbAppID); err != nil { errList.AddErr(fmt.Errorf("抖店运费模板、起送价、打包费、自动运力设置相关处理错误:%v", err)) } } for _, v := range [][]string{ []string{ "pricePercentagePack", model.ConfigTypePricePack, }, []string{ "freightDeductionPack", model.ConfigTypeFreightPack, }, } { if valid[v[0]] != nil { if value := utils.Interface2String(valid[v[0]]); value != "" { _, err2 := dao.QueryConfigs(db, value, v[1], "") if err = err2; err != nil { return 0, err } } } } if vendorID != model.VendorIDJX && vendorID != model.VendorIDYB { if vendorStoreID := utils.Interface2String(valid["vendorStoreID"]); vendorStoreID != "" { vendorStoreInfo, err2 := storeHandler.ReadStore(ctx, storeMap.VendorOrgCode, vendorStoreID, storeMap.VendorStoreName) if err = err2; err == nil { valid["deliveryType"] = vendorStoreInfo.DeliveryType } err = nil // todo 忽略读不到DeliveryType的错误 } } // 增加门店地址修改同步 storeDetail, err := dao.GetStoreBaseByVendorStoreID(storeMap.VendorStoreID, storeMap.VendorID) address := "" if err != nil || storeDetail == nil { return 0, fmt.Errorf("基础门店信息异常,请联系管理员") } if storeDetail != nil && payload["address"] != nil && payload["address"].(string) != storeDetail.Address { // // 修改门店地址 // storeDetail.Address = payload["address"].(string) // dao.UpdateEntity(db, storeDetail, "Address") // // 添加同步 valid["address"] = payload["address"].(string) syncStatus |= model.SyncFlagStoreName address = payload["address"].(string) // 这个字段暂存美团门店地址 storeMap.YbStorePrefix = address dao.UpdateEntity(db, storeMap, "YbStorePrefix") } if err == nil { if len(valid) > 0 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() // 这里面包含address时会报错,所以删除 if address != "" { delete(valid, "address") } // storeMap 不包含address参数 if isStoreMapNeedSync(vendorID, valid) { // 对于store vendor map,只有Status改变才需要同步到厂商 num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeMap, valid, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, //"VendorOrgCode": vendorOrgCode, }, model.FieldSyncStatus, syncStatus) } else { num, err = dao.UpdateEntityLogically(db, storeMap, valid, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, //"VendorOrgCode": vendorOrgCode, }) } if err != nil { dao.Rollback(db, txDB) return 0, err } isSyncStoreMapSku := false if num > 0 { if globals.IsAddEvent { mapBefore := refutil.FindMapAndStructMixed(valid, beforeStoreMap) err = AddEventDetail(db, ctx, model.OperateUpdate, vendorID, model.ThingTypeStore, storeID, BuildDiffData(mapBefore), BuildDiffData(valid)) } if vendorID != model.VendorIDJX { if valid["pricePercentage"] != nil || valid["pricePercentagePack"] != nil { storeSkuBind := &model.StoreSkuBind{} if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeSkuBind, nil, userName, map[string]interface{}{ model.FieldStoreID: storeID, }, dao.GetSyncStatusStructField(model.VendorNames[vendorID]), model.SyncFlagPriceMask); err != nil { dao.Rollback(db, txDB) return 0, err } isSyncStoreMapSku = true } } else { if valid["pricePercentage"] != nil || valid["pricePercentagePack"] != nil { ReCalculateJxPriceLight(db, ctx, storeID) } } } dao.Commit(db, txDB) if address != "" { valid["address"] = address } if isUpdateStoreNeedSync(valid) { // 同步修改门店已经配送门店 _, err = CurVendorSync.SyncStore(ctx, db, vendorID, storeID, false, userName) // address原来的userName 因为storeMap无法保存address,所以美团暂时使用该参数代替 //updateCourierStores(ctx, storeID) } // 更新商品 if isSyncStoreMapSku { singleStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) task := tasksch.NewParallelTask("修改门店调价包的时候,同时同步门店商品", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) switch step { case 1: if singleStoreHandler != nil { // 直接同步商品 err = syncStoreSkuNew(ctx, task, 0, true, vendorID, storeID, "", nil, nil, nil, false, true) } } return retVal, err }, []int{1}) tasksch.HandleTask(task, nil, true).Run() _, err = task.GetResult(0) return 0, err } } } errList.AddErr(err) endErr := errList.GetErrListAsOne() return num, endErr } func DeleteStore(ctx *jxcontext.Context, storeID int) (num int64, err error) { db := dao.GetDB() store := &model.Store{} store.ID = storeID if err = dao.GetEntity(db, store); err != nil { return 0, err } if store.Status == model.StoreStatusOpened { return 0, fmt.Errorf("删除京西门店前必须将所有门店解绑且门店处于关店状态") } sql := ` SELECT (SELECT COUNT(*) FROM store_map t1 WHERE t1.store_id = ? AND t1.deleted_at = ?) + (SELECT COUNT(*) FROM store_courier_map t1 WHERE t1.store_id = ? AND t1.deleted_at = ?) ct ` ct := 0 if err = dao.GetRow(db, &ct, sql, storeID, utils.DefaultTimeValue, storeID, utils.DefaultTimeValue); err != nil { return 0, err } if ct > 0 { return 0, fmt.Errorf("删除京西门店前必须将所有门店解绑且门店处于关店状态") } txDB, _ := dao.Begin(db) defer dao.Rollback(db, txDB) now := time.Now() for _, tableName := range []string{"store_sku_bind", "store_sku_category_map", "store_op_request"} { sql = fmt.Sprintf(` UPDATE %s t1 SET t1.deleted_at = ?, t1.updated_at = ?, t1.last_operator = ? WHERE t1.store_id = ? AND t1.deleted_at = ? `, tableName) if _, err = dao.ExecuteSQL(db, sql, now, now, ctx.GetUserName(), storeID, utils.DefaultTimeValue); err != nil { return 0, err } } if num, err = dao.DeleteEntityLogically(db, store, nil, ctx.GetUserName(), nil); err != nil { return 0, err } if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateDelete, storeID, model.ThingTypeStore, storeID, "", "") } DeleteStoreCategroies(ctx, db, storeID) dao.Commit(db, txDB) return num, err // return 0, errors.New("暂不支持删除京西门店") } // 状态是未解决,且初始是2星以下 func TmpGetJxBadCommentsNo(ctx *jxcontext.Context, storeID int) (count int, err error) { db := dao.GetDB() var ctInfo struct { Ct int } if err = dao.GetRow(db, &ctInfo, ` SELECT COUNT(*) ct FROM jx_bad_comments WHERE status = ? AND jxstoreid = ? AND score <= ? `, orderman.COMMENT_NOT_RESOLVED, utils.Int2Str(storeID), orderman.JX_BAD_COMMENTS_MAX_LEVEL); err == nil { count = ctInfo.Ct } return count, err } func TmpGetJxBadCommentsByStoreId(ctx *jxcontext.Context, keyword string, storeIDs []int, offset, pageSize, commentType int, fromTime, toTime time.Time) (retVal map[string]interface{}, err error) { db := dao.GetDB() //权限 if permission.IsRoled(ctx) { if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil { var storeIDs2 []int if len(storeIDs) > 0 { for _, v := range storeIDs { if storeIDsMap[v] != 0 { storeIDs2 = append(storeIDs2, v) } } if len(storeIDs2) == 0 { storeIDs2 = append(storeIDs2, -1) } } else { for k, _ := range storeIDsMap { storeIDs2 = append(storeIDs2, k) } } storeIDs = nil storeIDs = storeIDs2 } } sql := ` SELECT SQL_CALC_FOUND_ROWS t1.*, t2.name store_name, t3.name city_name, t4.vendor_order_id2 FROM jx_bad_comments t1 LEFT JOIN store t2 ON t2.id = t1.jxstoreid LEFT JOIN place t3 ON t3.code = t2.city_code LEFT JOIN goods_order t4 ON t4.vendor_order_id = t1.order_id AND t4.vendor_id = t1.order_flag WHERE 1 = 1 ` sqlParams := []interface{}{} if keyword != "" { keywordLike := "%" + keyword + "%" sql += ` AND (t1.order_id LIKE ? OR t1.jxstoreid LIKE ? OR t1.userphone LIKE ? OR t1.scorecontent LIKE ? OR t1.vendertags LIKE ? OR t1.updated_scorecontent LIKE ? OR t1.updated_vendertags LIKE ? OR t2.name LIKE ?)` sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike) } if len(storeIDs) > 0 { sql += " AND t1.jxstoreid IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")" sqlParams = append(sqlParams, storeIDs) } if commentType != GET_ALL_COMMENTS_TYPE { sql += " AND t1.status = ?" if commentType == GET_BAD_COMMENTS_TYPE { sql += " AND t1.score <= ?" sqlParams = append(sqlParams, orderman.COMMENT_NOT_RESOLVED, orderman.JX_BAD_COMMENTS_MAX_LEVEL) } else { sqlParams = append(sqlParams, orderman.COMMENT_RESOLVED) } } if !utils.IsTimeZero(fromTime) { sql += " AND t1.createtime >= ?" sqlParams = append(sqlParams, fromTime) } if !utils.IsTimeZero(toTime) { sql += " AND t1.createtime < ?" sqlParams = append(sqlParams, toTime) } sql += " ORDER BY t1.createtime DESC" pageSize = jxutils.FormalizePageSize(pageSize) offset = jxutils.FormalizePageOffset(offset) sql += " LIMIT ? OFFSET ?" sqlParams = append(sqlParams, pageSize, offset) var commentList []*JxBadCommentsExt txDB, _ := dao.Begin(db) defer func() { dao.Rollback(db, txDB) }() if err = dao.GetRowsTx(txDB, &commentList, sql, sqlParams...); err == nil { retVal = map[string]interface{}{ "total": dao.GetLastTotalRowCount2(db, txDB), "list": commentList, } dao.Commit(db, txDB) } return retVal, err } type GetStoreCourierMapsResult struct { storeCourierMaps *model.StoreCourierMap CourierAddress string `json:"courierAddress"` CourierPhone string `json:"courierPhone"` } func GetStoreCourierMaps(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, vendorID int) (storeCourierMaps []*model.StoreCourierMap, err error) { cond := map[string]interface{}{ model.FieldStoreID: storeID, } if vendorID != -1 { cond[model.FieldVendorID] = vendorID } err = dao.GetEntitiesByKV(db, &storeCourierMaps, cond, false) if len(storeCourierMaps) != 0 { //同步美团配送与否状态及美团门店是否存在 for _, v := range storeCourierMaps { if v.VendorID != model.VendorIDMTPS { continue } else { SetMTPSStatus(jxcontext.AdminCtx, v.StoreID, v.Status) break } } } handler := partner.GetDeliveryPlatformFromVendorID(vendorID).Handler storeDetail, _ := handler.GetStore(ctx, storeID, utils.Int2Str(storeID)) for _, v := range storeCourierMaps { if v != nil { if v.VendorStoreName == "" { if storeDetail != nil { v.VendorStoreName = storeDetail.Name } } } } return storeCourierMaps, err } func AddStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, storeCourierMap *model.StoreCourierMap) (outStoreCourierMap *model.StoreCourierMap, err error) { return addStoreCourierMap(ctx, db, storeID, vendorID, storeCourierMap, true) } func addStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, storeCourierMap *model.StoreCourierMap, isNeedUpdateRemote bool) (outStoreCourierMap *model.StoreCourierMap, err error) { storeCourierMap.StoreID = storeID storeCourierMap.VendorID = vendorID storeCourierMap.VendorStatus = storeCourierMap.Status if handler := partner.GetDeliveryPlatformFromVendorID(vendorID); handler != nil { if db == nil { db = dao.GetDB() } if isNeedUpdateRemote { storeDetail, err2 := dao.GetStoreDetail2(db, storeID, "", vendorID) if err = err2; err != nil { return nil, err } if storeDetail.VendorStoreID != "" { return nil, fmt.Errorf("门店已经绑定了%s, ID:%s, 如需重新绑定, 请先解绑", model.VendorChineseNames[vendorID], storeDetail.VendorStoreID) } storeDetail.VendorID = vendorID storeDetail.VendorStoreID = storeCourierMap.VendorStoreID if err = updateCourierStore(ctx, storeDetail); err != nil { if vendorID != model.VendorIDMTPS { return nil, err } // 如果是美团配送,强制忽略更新错 globals.SugarLogger.Infof("addStoreCourierMap storeID:%d, vendorID:%d failed with err:%v", storeID, vendorID, err) err = nil } } dao.WrapAddIDCULDEntity(storeCourierMap, ctx.GetUserName()) if err = dao.CreateEntity(db, storeCourierMap); err != nil { return nil, err } if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateAdd, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`) } outStoreCourierMap = storeCourierMap } else { err = ErrCanNotFindVendor } //同步美团配送与否状态及美团门店是否存在 if outStoreCourierMap.VendorID == model.VendorIDMTPS { //SetMTPSStatus(jxcontext.AdminCtx, outStoreCourierMap.StoreID, outStoreCourierMap.Status) SetMTPSStatus2(outStoreCourierMap.StoreID) } return outStoreCourierMap, err } func DeleteStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, userName string) (num int64, err error) { if db == nil { db = dao.GetDB() } storeCourierMap := &model.StoreCourierMap{} num, err = dao.DeleteEntityLogically(db, storeCourierMap, map[string]interface{}{ model.FieldStatus: model.StoreStatusDisabled, model.FieldVendorStatus: model.StoreStatusDisabled, }, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, }) if globals.IsAddEvent { err = AddEventDetail(db, ctx, model.OperateDelete, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`) } return num, err } func UpdateStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, payload map[string]interface{}, userName string) (num int64, err error) { if db == nil { db = dao.GetDB() } storeCourier := &model.StoreCourierMap{ StoreID: storeID, VendorID: vendorID, } storeCourier.DeletedAt = utils.DefaultTimeValue if err = dao.GetEntity(db, storeCourier, model.FieldStoreID, model.FieldVendorID, model.FieldDeletedAt); err != nil { return 0, err } var beforeStoreCourier = *storeCourier delete(payload, "auditStatus") // 不允许直接修改auditStatus的值 valid := dao.NormalMakeMapByStructObject(payload, storeCourier, userName) if len(valid) > 0 { if storeCourier.AuditStatus != model.StoreAuditStatusOnline { if status := utils.Interface2Int64WithDefault(valid["status"], 0); status == model.StoreStatusOpened { // 没有通过审核的禁止改状态为正常 //return 0, fmt.Errorf("此快递门店还没有通过审核,不启用") } } num, err = dao.UpdateEntityLogically(db, storeCourier, valid, userName, nil) if globals.IsAddEvent { mapBefore := refutil.FindMapAndStructMixed(valid, beforeStoreCourier) err = AddEventDetail(db, ctx, model.OperateUpdate, vendorID, model.ThingTypeStore, storeID, BuildDiffData(mapBefore), BuildDiffData(valid)) } } return num, err } func updateCourierStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (err error) { if handlerInfo := partner.GetDeliveryPlatformFromVendorID(storeDetail.VendorID); handlerInfo != nil && handlerInfo.Use4CreateWaybill { if updateHandler, ok := handlerInfo.Handler.(partner.IDeliveryUpdateStoreHandler); ok { err = updateHandler.UpdateStore(ctx, formalizeStore4Courier(storeDetail)) } } else { err = fmt.Errorf("配送平台:%s不被支持", model.VendorChineseNames[storeDetail.VendorID]) } return err } // 更新门店信息 //VendorIDDada = 101 // 达达配送 //VendorIDMTPS = 102 // 美团配送 //VendorIDFengNiao = 103 // 蜂鸟配送 func updateCourierStores(ctx *jxcontext.Context, storeID int) (err error) { db := dao.GetDB() errList := errlist.New() for k, v := range partner.DeliveryPlatformHandlers { if v.Use4CreateWaybill { if _, ok := v.Handler.(partner.IDeliveryUpdateStoreHandler); ok { storeDetail, err2 := dao.GetStoreDetail2(db, storeID, "", k) if err = err2; err2 == nil { if storeDetail.VendorStoreID != "" && storeDetail.AuditStatus == model.StoreAuditStatusOnline { // 同步更新门店信息 err = updateCourierStore(ctx, storeDetail) if err == nil { //美团配送修改门店信息后要待审核 if k == model.VendorIDMTPS { if couriers, err := dao.GetStoreCourierList(db, []int{storeID}, []int{model.VendorIDMTPS}, model.StoreStatusAll, model.StoreAuditStatusAll); len(couriers) > 0 && err == nil { couriers[0].AuditStatus = model.StoreAuditStatusUpdated dao.UpdateEntity(db, couriers[0], "AuditStatus") } } } } } errList.AddErr(err) } } } return errList.GetErrListAsOne() } func UpdateStoreName() error { var ( db = dao.GetDB() context = jxcontext.AdminCtx ) sql := ` SELECT * FROM store_courier_map WHERE vendor_id IN (?,?,?,?) AND deleted_at = ?` courierList := make([]*model.StoreCourierMap, 0, 0) if err := dao.GetRows(db, &courierList, sql, []interface{}{model.VendorIDMTPS, model.VendorIDFengNiao, model.VendorIDDada, model.VendorIDUUPT, utils.DefaultTimeValue}...); err != nil { return err } for i := 0; i < len(courierList); i++ { storeDetail, _ := dao.GetStoreDetail2(db, courierList[i].StoreID, courierList[i].VendorStoreID, courierList[i].VendorID) formalizeStore4Courier(storeDetail) if handlerInfo := partner.GetDeliveryPlatformFromVendorID(storeDetail.VendorID); handlerInfo != nil { if updateHandler, _ := handlerInfo.Handler.(partner.IDeliveryUpdateStoreHandler); updateHandler != nil { if err := updateHandler.UpdateStore(context, storeDetail); err != nil { globals.SugarLogger.Debugf("err := %v,storeID : %s,storeName :%s , vendorId : %d", err, storeDetail.VendorStoreID, storeDetail.Name, storeDetail.VendorID) } } } } return nil } // ====================================第三方店铺创建============================= func updateOrCreateCourierStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (isCreated bool, err error) { if handlerInfo := partner.GetDeliveryPlatformFromVendorID(storeDetail.VendorID); handlerInfo != nil && handlerInfo.Use4CreateWaybill { if storeDetail.DistrictName == "" { return false, fmt.Errorf("门店的区码有问题,请检查") } if storeDetail.CityName == "" { return false, fmt.Errorf("门店的城市码有问题,请检查") } formalizeStore4Courier(storeDetail) needUpdate := false remoteStoreDetail, err2 := handlerInfo.Handler.GetStore(ctx, 0, storeDetail.VendorStoreID) if err = err2; err != nil { if handlerInfo.Handler.IsErrStoreNotExist(err) { // 本地门店同步第三方平台 storeDetail.VendorStoreID, storeDetail.AuditStatus, err = handlerInfo.Handler.CreateStore(ctx, storeDetail) if err == nil { isCreated = true } else if handlerInfo.Handler.IsErrStoreExist(err) { storeDetail.AuditStatus = model.StoreAuditStatusCreated err = nil } } } else { storeDetail.CourierStatus = remoteStoreDetail.CourierStatus storeDetail.AuditStatus = remoteStoreDetail.AuditStatus if storeDetail.VendorID == model.VendorIDFengNiao { storeDetail.VendorStoreID = remoteStoreDetail.VendorStoreID } needUpdate = true } if err == nil && needUpdate { if updateHandler, _ := handlerInfo.Handler.(partner.IDeliveryUpdateStoreHandler); updateHandler != nil { err = updateHandler.UpdateStore(ctx, storeDetail) } else { // err = fmt.Errorf("快递平台%s不支持更新门店信息,请手动处理", model.VendorChineseNames[storeDetail.VendorID]) } } if err != nil { err = fmt.Errorf("门店ID:%d,门店名:%s,错误描述:%s", storeDetail.Store.ID, storeDetail.Name, err.Error()) } } return isCreated, err } func UpdateOrCreateCourierStores(ctx *jxcontext.Context, storeID int, isForceUpdate, isAsync, isContinueWhenError bool) (hint string, err error) { var storeIDs []int if storeID != 0 { storeIDs = []int{storeID} } else { storesInfo, err2 := GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0) if err = err2; err != nil { return "", err } for _, v := range storesInfo.Stores { storeIDs = append(storeIDs, v.ID) } } // 定时任务更新或者创建时修改东西 task := tasksch.NewParallelTask("UpdateOrCreateCourierStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { var resultList []interface{} storeID := batchItemList[0].(int) errList := errlist.New() db := dao.GetDB() for vendorID, v := range partner.DeliveryPlatformHandlers { if v.Use4CreateWaybill { if _, ok := v.Handler.(partner.IDeliveryUpdateStoreHandler); ok { storeDetail, err2 := dao.GetStoreDetail2(db, storeID, "", vendorID) if err = err2; err2 == nil { isNeedAdd := storeDetail.VendorStoreID == "" if isForceUpdate || isNeedAdd { if isNeedAdd { storeDetail.VendorID = vendorID storeDetail.VendorStoreID = utils.Int2Str(storeDetail.ID) } if _, err = updateOrCreateCourierStore(ctx, storeDetail); err == nil && isNeedAdd { storeCourier := &model.StoreCourierMap{ VendorStoreID: storeDetail.VendorStoreID, Status: model.StoreStatusOpened, AuditStatus: storeDetail.AuditStatus, VendorStoreName: storeDetail.Name, } if storeDetail.AuditStatus != model.StoreAuditStatusOnline { storeCourier.Status = model.StoreStatusDisabled } if _, err = addStoreCourierMap(ctx, db, storeDetail.ID, storeDetail.VendorID, storeCourier, false); err == nil { resultList = append(resultList, 1) } } } } errList.AddErr(err) } } } return resultList, errList.GetErrListAsOne() }, storeIDs) tasksch.HandleTask(task, nil, len(storeIDs) > 1).Run() if !isAsync { resultList, err2 := task.GetResult(0) if err = err2; err == nil { hint = utils.Int2Str(len(resultList)) } } else { hint = task.ID } return hint, err } func formalizeStore4Courier(storeDetail *dao.StoreDetail2) *dao.StoreDetail2 { // 获取品牌名称 brandInfo, err := dao.GetBrands(dao.GetDB(), "", storeDetail.BrandID, "", false, "") if err != nil { return nil } storeDetail.Name = fmt.Sprintf("%s-%s-%s", strings.ReplaceAll(brandInfo[0].Name, " ", ""), strings.ReplaceAll(storeDetail.CityName, " ", ""), strings.ReplaceAll(storeDetail.Name, " ", "")) if storeDetail.PayeeName == "" { storeDetail.PayeeName = "店主" } return storeDetail } type EbaiStoreHealthy struct { RealShopID int `json:"门店ID"` MerchantID string `json:"平台门店ID"` MerchantName string `json:"平台门店名"` SkuNum string `json:"日均在架且有库存的商品数"` IsSku string `json:"商品数是否达标"` HasPhotoRate string `json:"有图率"` IsYoutu string `json:"有图率是否达标"` Hours string `json:"日均营业时长"` IsYinye string `json:"营业时长是否达标"` UnvalidOrderNum string `json:"商家原因取消订单数"` IsJiedan string `json:"取消数是否达标"` BadOrderRate string `json:"差评订单率"` IsCp string `json:"差评率是否达标"` RestaurantSubsidy string `json:"商家补贴金额(元)"` IsButie string `json:"补贴是否达标"` IsHealthy string `json:"商户是否健康"` } func ExportShopsHealthInfo(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { db := dao.GetDB() vendorID := model.VendorIDEBAI storeMapList, err := dao.GetStoresMapList(db, []int{vendorID}, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "") if err != nil { return "", err } storeMap2 := make(map[string]*model.StoreMap) for _, v := range storeMapList { storeMap2[v.VendorStoreID] = v } if len(storeMapList) > 0 { var healthInfoList []interface{} var excelBin []byte var excelURL string task := tasksch.NewSeqTask(fmt.Sprintf("ExportShopHealthInfo[%s]", model.VendorChineseNames[vendorID]), ctx, func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: subTask := tasksch.NewParallelTask(fmt.Sprintf("ExportShopHealthInfo2[%s]", model.VendorChineseNames[vendorID]), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { storeMap := batchItemList[0].(*model.StoreMap) healthInfo, err := ebai.CurPurchaseHandler.GetShopHealthInfo(storeMap.VendorStoreID) if err == nil { retVal = []map[string]interface{}{healthInfo} } return retVal, err }, storeMapList) tasksch.AddChild(task, subTask).Run() healthInfoList, err = subTask.GetResult(0) if isContinueWhenError && err != nil && len(healthInfoList) > 0 { err = nil } case 1: var healthInfoList2 []map[string]interface{} for _, v := range healthInfoList { mapInfo := v.(map[string]interface{}) mapInfo["real_shop_id"] = storeMap2[utils.Interface2String(mapInfo["merchant_id"])].StoreID healthInfoList2 = append(healthInfoList2, mapInfo) } var healthyList []*EbaiStoreHealthy for _, v := range healthInfoList2 { healthy := &EbaiStoreHealthy{ RealShopID: v["real_shop_id"].(int), MerchantID: v["merchant_id"].(string), MerchantName: v["merchant_name"].(string), SkuNum: v["sku_num"].(string), IsSku: v["is_sku"].(string), HasPhotoRate: v["has_photo_rate"].(string), IsYoutu: v["is_youtu"].(string), Hours: v["hours"].(string), IsYinye: v["is_yinye"].(string), UnvalidOrderNum: v["unvalid_order_num"].(string), IsJiedan: v["is_jiedan"].(string), BadOrderRate: v["bad_order_rate"].(string), IsCp: v["is_cp"].(string), RestaurantSubsidy: v["restaurant_subsidy"].(string), IsButie: v["is_butie"].(string), IsHealthy: v["is_healthy"].(string), } healthyList = append(healthyList, healthy) } excelConf := &excel.Obj2ExcelSheetConfig{ Title: "饿百门店情况导出", Data: healthyList, CaptionList: []string{ "门店ID", "平台门店ID", "平台门店名", "日均在架且有库存的商品数", "商品数是否达标", "有图率", "有图率是否达标", "日均营业时长", "营业时长是否达标", "商家原因取消订单数", "取消数是否达标", "差评订单率", "差评率是否达标", "商家补贴金额(元)", "补贴是否达标", "商户是否健康", }, } excelBin = excel.Obj2Excel([]*excel.Obj2ExcelSheetConfig{excelConf}) case 2: keyPart := []string{ ctx.GetUserName(), "饿百门店情况", } keyPart = append(keyPart, time.Now().Format("20060102T150405")+".xlsx") key := "export/" + strings.Join(keyPart, "_") excelURL, err = jxutils.UploadExportContent(excelBin, key) if err == nil { task.SetNoticeMsg(excelURL) } globals.SugarLogger.Debugf("导出饿百门店情况excelURL:%s, err:%v", excelURL, err) } return nil, err }, 3) tasksch.HandleTask(task, nil, true).Run() if !isAsync { _, err = task.GetResult(0) if err == nil { hint = excelURL } } else { hint = task.GetID() } } return hint, err } func GetCorporationInfo(ctx *jxcontext.Context, licenceCode, licenceImg string) (corporationInfo *jdapi.GetOrderDetailByLicenseImg, err error) { // 门店ID随便一个合法的京东门店ID就可以 jdImg, err := api.JdAPI.StoreUploadImgByURL(licenceImg) if err != nil { return nil, err } corporationInfo, err = api.JdAPI.GetCorporationInfo2(jdImg) // 下面的方法无法使用,找不到出处 // corporationInfo, err = api.JdAPI.GetCorporationInfo("11734851", licenceCode) return corporationInfo, err } func GetStoresVendorSnapshot(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs, storeIDs []int) (vendorStoreSnapshotList []*model.VendorStoreSnapshot, err error) { db := dao.GetDB() storeMapList, err := dao.GetStoresMapList(db, vendorIDs, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") if err != nil { return nil, err } task := tasksch.NewParallelTask("GetStoresVendorSnapshot", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { storeMap := batchItemList[0].(*model.StoreMap) if model.IsVendorRemote(storeMap.VendorID) { if handler := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID); handler != nil { store, err2 := handler.ReadStore(ctx, storeMap.VendorOrgCode, storeMap.VendorStoreID, storeMap.VendorStoreName) if err = err2; err == nil { retVal = []interface{}{&model.VendorStoreSnapshot{ StoreID: storeMap.StoreID, VendorID: storeMap.VendorID, VendorStoreID: storeMap.VendorStoreID, Status: store.Status, OpenTime1: store.OpenTime1, CloseTime1: store.CloseTime1, OpenTime2: store.OpenTime2, CloseTime2: store.CloseTime2, DeliveryType: store.DeliveryType, StoreName: store.OriginalName, IsAutoOrder: store.IsAutoOrder, }} } } } return retVal, err }, storeMapList) tasksch.HandleTask(task, parentTask, true).Run() resultList, err := task.GetResult(0) if len(resultList) > 0 { for _, v := range resultList { dao.WrapAddIDCULDEntity(v, ctx.GetUserName()) vendorStoreSnapshotList = append(vendorStoreSnapshotList, v.(*model.VendorStoreSnapshot)) } } return vendorStoreSnapshotList, err } func getCurrentSnapshotAt(now time.Time) (snapshotAt time.Time) { return jxutils.GetLastTimeFromList(now, WatchVendorStoreTimeList) } func updateVendorStoreStatusBySnapshot(db *dao.DaoDB, curSnapshotList []*model.VendorStoreSnapshot) (err error) { storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") if err != nil { return err } snapshotMap := make(map[int64]*model.VendorStoreSnapshot) for _, v := range curSnapshotList { snapshotMap[jxutils.Combine2Int(v.StoreID, v.VendorID)] = v } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) if r != nil { panic(r) } } }() for _, v := range storeMapList { if snapshot := snapshotMap[jxutils.Combine2Int(v.StoreID, v.VendorID)]; snapshot != nil && (v.Status != snapshot.Status || v.DeliveryType != snapshot.DeliveryType || v.StoreName != snapshot.StoreName) { v.Status = snapshot.Status v.DeliveryType = snapshot.DeliveryType v.StoreName = snapshot.StoreName if _, err = dao.UpdateEntity(db, v, model.FieldStatus, "DeliveryType", "StoreName"); err != nil { return err } } } dao.Commit(db, txDB) utils.CallFuncAsync(func() { for _, v := range storeMapList { if snapshot := snapshotMap[jxutils.Combine2Int(v.StoreID, v.VendorID)]; snapshot != nil { if snapshot.IsAutoOrder == 1 { if handler, ok := partner.GetPurchasePlatformFromVendorID(snapshot.VendorID).(partner.IStoreHandler); ok { handler.EnableAutoAcceptOrder(jxcontext.AdminCtx, v.VendorOrgCode, v.StoreID, v.VendorStoreID, false) } } } } }) return err } func SaveStoresVendorSnapshot(db *dao.DaoDB, snapshotAt time.Time, curSnapshotList []*model.VendorStoreSnapshot) (err error) { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) if r != nil { panic(r) } } }() if err = dao.DeleteVendorStoreSnapshot(db, snapshotAt.Add(-48*time.Hour)); err != nil { return err } for _, v := range curSnapshotList { v.SnapshotAt = snapshotAt dao.DeleteEntity(db, v, "VendorStoreID", "VendorID", "SnapshotAt") if err = dao.CreateEntity(db, v); err != nil { return err } } dao.Commit(db, txDB) return err } func isVendorStoresStatusNotOk(storeMapList []*model.VendorStoreSnapshot) bool { statusMap := make(map[int]int) maxStatus := model.StoreStatusClosed for _, v := range storeMapList { statusMap[v.Status] = 1 if v.Status > maxStatus { maxStatus = v.Status } } return len(statusMap) > 1 && maxStatus == model.StoreStatusOpened } func getAllUsers4Store(ctx *jxcontext.Context, db *dao.DaoDB, store *model.Store) (userList []*model.User) { storeID := store.ID var userIDs []string userMap := make(map[string]int) // 门店老板 if roleUserIDList, err := GetRoleUserList(ctx, autils.NewStoreBossRole(storeID)); err == nil && len(roleUserIDList) > 0 { userIDs = append(userIDs, roleUserIDList...) } // 全局相关角色(市场或运营) for _, v := range []string{store.MarketManRole, store.OperatorRole, store.OperatorRole2, store.OperatorRole3} { if v != "" { if roleUserIDList, err := GetRoleUserList(ctx, autils.NewRole(v, 0)); err == nil && len(roleUserIDList) > 0 { userIDs = append(userIDs, roleUserIDList...) } } } if len(userIDs) > 0 { userList, _, _ = dao.GetUsers(db, 0, "", userIDs, nil, nil, 0, -1) for _, v := range userList { userMap[v.GetID()] = 1 } } // 直接电话信息相关人员 for _, mobile := range []string{store.Tel1, store.Tel2, store.MarketManPhone, store.OperatorPhone, store.OperatorPhone2, store.OperatorPhone3} { if mobile != "" { if user, err2 := dao.GetUserByID(db, "mobile", mobile); err2 == nil { if userMap[user.GetID()] == 0 { userMap[user.GetID()] = 1 userList = append(userList, user) } } } } return userList } type tStoreIDList struct { StoreIDList []int StoreMap map[int]*model.Store } func (l *tStoreIDList) Len() int { return len(l.StoreIDList) } func (l *tStoreIDList) Less(i, j int) bool { storei := l.StoreMap[l.StoreIDList[i]] storej := l.StoreMap[l.StoreIDList[j]] if storei.CityCode == storej.CityCode { return storei.ID < storej.ID } return storei.CityCode < storej.CityCode } func (l *tStoreIDList) Swap(i, j int) { l.StoreIDList[i], l.StoreIDList[j] = l.StoreIDList[j], l.StoreIDList[i] } func SendAlarmVendorSnapshot(ctx *jxcontext.Context, parentTask tasksch.ITask, prevSnapshotList, curSnapshotList []*model.VendorStoreSnapshot) (err error) { if len(prevSnapshotList) == 0 { return nil } prevSnapshotMap := make(map[string]*model.VendorStoreSnapshot) prevSnapshotMap2 := make(map[int]map[int]*model.VendorStoreSnapshot) for _, v := range prevSnapshotList { prevSnapshotMap[v.GenMapKey()] = v if prevSnapshotMap2[v.StoreID] == nil { prevSnapshotMap2[v.StoreID] = make(map[int]*model.VendorStoreSnapshot) } prevSnapshotMap2[v.StoreID][v.VendorID] = v } curSnapshotMap := make(map[string]*model.VendorStoreSnapshot) curSnapshotMap2 := make(map[int]map[int]*model.VendorStoreSnapshot) curSnapshotGroupMap := make(map[int][]*model.VendorStoreSnapshot) alarmSnapshotMap := make(map[int][]*model.VendorStoreSnapshot) txtAlarmSnapshotMap := make(map[int][]*model.VendorStoreSnapshot) // 之前是开店当前是关店的,或营业时间缩短的 for _, v := range curSnapshotList { curSnapshotGroupMap[v.StoreID] = append(curSnapshotGroupMap[v.StoreID], v) if curSnapshotMap2[v.StoreID] == nil { curSnapshotMap2[v.StoreID] = make(map[int]*model.VendorStoreSnapshot) } curSnapshotMap2[v.StoreID][v.VendorID] = v curSnapshotMap[v.GenMapKey()] = v prevSnapshot := prevSnapshotMap[v.GenMapKey()] if prevSnapshot != nil { if (prevSnapshot.Status == model.StoreStatusOpened && v.Status != model.StoreStatusOpened) || v.CompareOperationTime(prevSnapshot) < 0 { alarmSnapshotMap[v.StoreID] = append(alarmSnapshotMap[v.StoreID], v) txtAlarmSnapshotMap[prevSnapshot.StoreID] = append(txtAlarmSnapshotMap[prevSnapshot.StoreID], prevSnapshot) } } } //当前门店,不同平台门店状态不一致的 for storeID, list := range curSnapshotGroupMap { if isVendorStoresStatusNotOk(list) { alarmSnapshotMap[storeID] = list } } // 之前有店(且是开店状态),当前无店的 for _, v := range prevSnapshotList { if v.Status == model.StoreStatusOpened && curSnapshotMap[v.GenMapKey()] == nil { alarmSnapshotMap[v.StoreID] = append(alarmSnapshotMap[v.StoreID], v) txtAlarmSnapshotMap[v.StoreID] = append(txtAlarmSnapshotMap[v.StoreID], v) } } db := dao.GetDB() storeDetailMap := make(map[int]*dao.StoreDetail) userMap2 := make(map[string]*model.User) userMap := make(map[string]map[int]int) userMapTxt := make(map[string][]*model.VendorStoreSnapshot) for storeID, list := range alarmSnapshotMap { storeDetail, _ := dao.GetStoreDetail(db, storeID, list[0].VendorID, "") if storeDetail != nil { storeDetailMap[storeID] = storeDetail userList := getAllUsers4Store(ctx, db, &storeDetail.Store) for _, user := range userList { userID := user.GetID() if userMap[userID] == nil { userMap[userID] = make(map[int]int) userMap2[userID] = user } userMap[userID][storeID] = 1 if txtAlarmSnapshotMap[storeID] != nil { userMapTxt[userID] = append(userMapTxt[userID], txtAlarmSnapshotMap[storeID]...) } } } } var userList []*model.User for _, user := range userMap2 { userList = append(userList, user) } if len(userList) > 0 { allStores, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "") if err != nil { return err } allStoreMap := make(map[int]*model.Store) for _, v := range allStores { allStoreMap[v.ID] = v } const fixTitle = "门店状态变化" title := fmt.Sprintf("%s:%s-->%s", fixTitle, utils.Time2Str(prevSnapshotList[0].SnapshotAt), utils.Time2Str(curSnapshotList[0].SnapshotAt)) task := tasksch.NewParallelTask("SendAlarmVendorSnapshot", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { user := batchItemList[0].(*model.User) var excelURL string if user.Type&model.UserTypeOperator != 0 { var dataList []map[string]interface{} captionList := []string{"京西门店ID", "门店名", "城市"} isFirstRow := true storeIDList := &tStoreIDList{ StoreMap: allStoreMap, } for storeID := range userMap[user.GetID()] { storeIDList.StoreIDList = append(storeIDList.StoreIDList, storeID) } sort.Sort(storeIDList) for _, storeID := range storeIDList.StoreIDList { prevAlarmMap := prevSnapshotMap2[storeID] curAlarmMap := curSnapshotMap2[storeID] data := map[string]interface{}{ "京西门店ID": storeID, "门店名": storeDetailMap[storeID].Store.Name, "城市": storeDetailMap[storeID].CityName, } for _, vendorID := range []int{model.VendorIDJD, model.VendorIDEBAI, model.VendorIDMTWM} { if isFirstRow { captionList = append(captionList, model.VendorChineseNames[vendorID]+"ID", model.VendorChineseNames[vendorID]+"之前状态", model.VendorChineseNames[vendorID]+"当前状态", model.VendorChineseNames[vendorID]+"之前营业时间", model.VendorChineseNames[vendorID]+"当前营业时间") } if prevAlarmMap != nil { data[model.VendorChineseNames[vendorID]+"当前状态"] = "" data[model.VendorChineseNames[vendorID]+"当前营业时间"] = "" if prevSnapshot := prevAlarmMap[vendorID]; prevSnapshot != nil { data[model.VendorChineseNames[vendorID]+"ID"] = prevSnapshot.VendorStoreID data[model.VendorChineseNames[vendorID]+"之前状态"] = model.StoreStatusName[prevSnapshot.Status] data[model.VendorChineseNames[vendorID]+"之前营业时间"] = jxutils.OperationTimeStr4VendorStore(prevSnapshot) if snapshot := curSnapshotMap[prevSnapshot.GenMapKey()]; snapshot != nil { data[model.VendorChineseNames[vendorID]+"当前状态"] = model.StoreStatusName[snapshot.Status] data[model.VendorChineseNames[vendorID]+"当前营业时间"] = jxutils.OperationTimeStr4VendorStore(snapshot) } } else { data[model.VendorChineseNames[vendorID]+"ID"] = "" data[model.VendorChineseNames[vendorID]+"之前状态"] = "" data[model.VendorChineseNames[vendorID]+"之前营业时间"] = "" } } else if curAlarmMap != nil { data[model.VendorChineseNames[vendorID]+"之前状态"] = "" data[model.VendorChineseNames[vendorID]+"之前营业时间"] = "" if curSnapshot := curAlarmMap[vendorID]; curSnapshot != nil { data[model.VendorChineseNames[vendorID]+"ID"] = curSnapshot.VendorStoreID data[model.VendorChineseNames[vendorID]+"当前状态"] = model.StoreStatusName[curSnapshot.Status] data[model.VendorChineseNames[vendorID]+"当前营业时间"] = jxutils.OperationTimeStr4VendorStore(curSnapshot) } else { data[model.VendorChineseNames[vendorID]+"ID"] = "" data[model.VendorChineseNames[vendorID]+"当前状态"] = "" data[model.VendorChineseNames[vendorID]+"当前营业时间"] = "" } } } dataList = append(dataList, data) isFirstRow = false } excelConf := &excel.Obj2ExcelSheetConfig{ Title: fixTitle, Data: dataList, CaptionList: captionList, } excelBin := excel.Obj2Excel([]*excel.Obj2ExcelSheetConfig{excelConf}) keyPart := []string{ "store_status", user.GetMobile(), time.Now().Format("20060102T150405") + ".xlsx", } key := "export/" + strings.Join(keyPart, "_") excelURL, err = jxutils.UploadExportContent(excelBin, key) if err != nil { globals.SugarLogger.Warnf("SendAlarmVendorSnapshot, %s upload %s failed with error:%v", user.GetName(), key, err) } var txtAlarm []string for _, v := range userMapTxt[user.GetID()] { curSnapshot := curSnapshotMap[v.GenMapKey()] storeDetail := storeDetailMap[v.StoreID] curStoreStatus := "无店" curOpTimeStr := "无店" if curSnapshot != nil { curStoreStatus = model.StoreStatusName[curSnapshot.Status] curOpTimeStr = jxutils.OperationTimeStr4VendorStore(curSnapshot) } txtAlarm = append(txtAlarm, fmt.Sprintf(`## 门店: %s(%d) - 城市: %s - 平台: %s - 平台ID: %s - 之前状态: %s - 当前状态: %s - 之前营业时间: %s - 当前营业时间: %s `, storeDetail.Store.Name, v.StoreID, storeDetail.CityName, model.VendorChineseNames[v.VendorID], v.VendorStoreID, model.StoreStatusName[v.Status], curStoreStatus, jxutils.OperationTimeStr4VendorStore(v), curOpTimeStr)) } alarmTextStr := "# " + title + " \n" + fmt.Sprintf("[详情点我](%s/billshow/?normal=true&path=%s) \n", globals.BackstageHost, excelURL) + strings.Join(txtAlarm, " \n") sendStoreStatusInfo2Mobile(user, dingdingapi.MsgTypeMarkdown, title, alarmTextStr) } else if len(userMapTxt[user.GetID()]) > 0 { var txtAlarm []string for _, v := range userMapTxt[user.GetID()] { curSnapshot := curSnapshotMap[v.GenMapKey()] // storeDetail := storeDetailMap[v.StoreID] curStoreStatus := "下线" if curSnapshot != nil { curStoreStatus = model.StoreStatusName[curSnapshot.Status] } txtAlarm = append(txtAlarm, fmt.Sprintf("您的门店:%s,平台:%s,%s了", v.StoreName, model.VendorChineseNames[v.VendorID], curStoreStatus)) } alarmTextStr := strings.Join(txtAlarm, ",\n") sendStoreStatusInfo2Mobile(user, dingdingapi.MsgTyeText, title, alarmTextStr) } return nil, nil }, userList) tasksch.HandleTask(task, parentTask, true).Run() _, err = task.GetResult(0) } return err } func sendStoreStatusInfo2Mobile(user *model.User, msgType, title, txtAlarm string) { msg.SendUserMessage(msgType, user, title, txtAlarm) } func SaveAndSendAlarmVendorSnapshot(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isAsync bool) (err error) { curSnapshotAt := getCurrentSnapshotAt(time.Now()) prevSnapshotAt := getCurrentSnapshotAt(curSnapshotAt.Add(-1 * time.Second)) db := dao.GetDB() var curSnapshotList, prevSnapshotList []*model.VendorStoreSnapshot task := tasksch.NewParallelTask("SaveAndSendAlarmVendorSnapshot", tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetParallelCount(1), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) switch step { case 0: curSnapshotList, err = GetStoresVendorSnapshot(ctx, task, vendorIDs, storeIDs) if len(curSnapshotList) == 0 { task.Cancel() } else { updateVendorStoreStatusBySnapshot(db, curSnapshotList) } case 1: err = SaveStoresVendorSnapshot(db, curSnapshotAt, curSnapshotList) case 2: prevSnapshotList, err = dao.GetVendorStoreSnapshot(db, prevSnapshotAt) case 3: err = SendAlarmVendorSnapshot(ctx, task, prevSnapshotList, curSnapshotList) } return nil, err }, []int{0, 1, 2, 3}) tasksch.ManageTask(task).Run() if !isAsync { _, err = task.GetResult(0) } return err } func SyncStoresCourierInfo(ctx *jxcontext.Context, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { db := dao.GetDB() storeList2, err := dao.GetStoreList(db, storeIDs, nil, nil, nil, nil, "") var storeList []*model.Store for _, v := range storeList2 { if v.Status != model.StoreStatusDisabled { storeList = append(storeList, v) } } if err == nil && len(storeList) > 0 { task := tasksch.NewParallelTask(fmt.Sprintf("同步门店快递信息1:%v", storeIDs), tasksch.NewParallelConfig().SetParallelCount(2).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { store := batchItemList[0].(*model.Store) subTask := tasksch.NewParallelTask(fmt.Sprintf("同步门店快递信息2:%d", store.ID), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { vendorID := batchItemList[0].(int) storeDetail2, err := dao.GetStoreDetail2(db, store.ID, "", vendorID) if err == nil && storeDetail2.VendorStoreID != "" /*&& storeDetail2.CourierStatus != model.StoreStatusDisabled*/ { if handler := partner.GetDeliveryPlatformFromVendorID(vendorID); handler != nil { if updateHandler, ok := handler.Handler.(partner.IDeliveryUpdateStoreHandler); ok { updateHandler.UpdateStore(ctx, storeDetail2) } storeCourier, err2 := handler.Handler.GetStore(ctx, store.ID, storeDetail2.VendorStoreID) if err = err2; err == nil { if storeDetail2.AuditStatus == model.StoreAuditStatusCreated { // 如果已经通过审核,更新本地状态 partner.CurStoreManager.OnCourierStoreStatusChanged(ctx, storeCourier.VendorStoreID, vendorID, storeCourier.AuditStatus, storeCourier.Comment) } distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat), jxutils.IntCoordinate2Standard(storeCourier.Lng), jxutils.IntCoordinate2Standard(storeCourier.Lat)) params := map[string]interface{}{ "Lng": storeCourier.Lng, "Lat": storeCourier.Lat, "Remark": fmt.Sprintf("%d", int(distance*1000)), } _, err = dao.UpdateEntityLogically(dao.GetDB(), &model.StoreCourierMap{}, params, ctx.GetUserName(), map[string]interface{}{ "StoreID": store.ID, "VendorID": vendorID, }) if distance > 0.2 { retVal = [][]interface{}{ []interface{}{ store, storeDetail2, }, } } } else if handler.Handler.IsErrStoreNotExist(err) { if storeDetail2.AuditStatus == model.StoreAuditStatusCreated { err = nil } else { globals.SugarLogger.Infof("SyncStoresCourierInfo [运营2]门店:%s-%d的%s配送门店%s获取出错:%v", store.Name, store.ID, model.VendorChineseNames[vendorID], storeDetail2.VendorStoreID, err) } } } } else if dao.IsNoRowsError(err) { err = nil } return retVal, err }, partner.UseableDeliveryVendorIDs) tasksch.HandleTask(subTask, task, true).Run() retVal, err = subTask.GetResult(0) return retVal, err }, storeList) tasksch.HandleTask(task, nil, true).Run() if isAsync { hint = task.GetID() } else { resultList, err2 := task.GetResult(0) if err = err2; err == nil { hint = utils.Int2Str(len(resultList)) } } } return hint, err } func SyncStoresQualify(ctx *jxcontext.Context, storeIDs []int, vendorID int, isAsync, isContinueWhenError bool) (hint string, err error) { if len(storeIDs) > 0 { db := dao.GetDB() task := tasksch.NewParallelTask(fmt.Sprintf("上传门店资质:%v", storeIDs), tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { if handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreSyncQualifyHandler); handler != nil { storeID := batchItemList[0].(int) storeDetail, err2 := dao.GetStoreDetail(db, storeID, vendorID, "") if err = err2; err == nil { if err = handler.SyncQualify(ctx, storeDetail); err == nil { retVal = []int{1} } } } else { err = fmt.Errorf("平台%s不支持此操作", model.VendorChineseNames[vendorID]) } return retVal, err }, storeIDs) tasksch.HandleTask(task, nil, true).Run() if isAsync { hint = task.GetID() } else { resultList, err2 := task.GetResult(0) if err = err2; err == nil { hint = utils.Int2Str(len(resultList)) } } } return hint, err } func JdStoreInfoCoordinateRecover(ctx *jxcontext.Context, vendorOrgCode string, files []*multipart.FileHeader) (err error) { if len(files) == 0 { return errors.New("没有文件上传!") } fileHeader := files[0] file1, err := fileHeader.Open() defer file1.Close() db := dao.GetDB() storeList, err := dao.GetStoresMapList(db, []int{model.VendorIDJD}, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "") if err == nil { var validStoreList []*dao.StoreDetail for _, v := range storeList { if v.Status != model.StoreStatusDisabled && v.CreatedAt.Sub(utils.Str2Time("2019-10-01")) > 0 { storeInfo, err := jd.GetAPI(vendorOrgCode).GetStoreInfoByStationNo2(v.VendorStoreID) if err == nil && storeInfo.CreateTime.GoTime().Sub(utils.Str2Time("2019-10-25")) > 0 { if storeDetail, err := dao.GetStoreDetail(db, v.StoreID, v.VendorID, ""); err == nil { validStoreList = append(validStoreList, storeDetail) } } } } getStoreList := func(lng, lat, lng2, lat2 int) (vendorStoreIDs []string) { for _, v := range validStoreList { if v.Lng >= lng && v.Lng <= lng2 && v.Lat >= lat && v.Lat <= lat2 { vendorStoreIDs = append(vendorStoreIDs, v.VendorStoreID) } } return vendorStoreIDs } sheetName := "老格明细" file, err2 := excelize.OpenReader(file1) if err = err2; err == nil { rows, err2 := file.GetRows(sheetName) if err = err2; err == nil { str2Coords := func(str string) (lng, lat int) { list := strings.Split(str, ",") if len(list) >= 2 { lng, lat = jxutils.StandardCoordinate2Int(utils.Str2Float64WithDefault(list[1], 0)), jxutils.StandardCoordinate2Int(utils.Str2Float64WithDefault(list[0], 0)) } return lng, lat } for i := 1; i < len(rows); i++ { lng, lat := str2Coords(rows[i][8]) lng2, lat2 := str2Coords(rows[i][7]) vendorStoreIDs := getStoreList(lng, lat, lng2, lat2) countInfo := fmt.Sprintf("京西已拓%d", len(vendorStoreIDs)) axis, _ := excelize.CoordinatesToCellName(5, i+1) file.SetCellStr(sheetName, axis, countInfo) axis2, _ := excelize.CoordinatesToCellName(6, i+1) file.SetCellStr(sheetName, axis2, strings.Join(vendorStoreIDs, ",")) } filename := ExecuteFileName(fileHeader.Filename) buf := bytes.NewBuffer(nil) if _, err = io.Copy(buf, file1); err != nil { return err } baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", filename) downloadURL, err := jxutils.UploadExportContent(buf.Bytes(), filename) if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s, failed error:%v", filename, err) } else { if authInfo, err := ctx.GetV2AuthInfo(); err == nil { noticeMsg := fmt.Sprintf("path=%s\n", downloadURL) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, authInfo.UserID, "导出老格恢复拓店进度成功", noticeMsg) } baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", filename, downloadURL) } } } } return err } func ExecuteFileName(filename string) (name string) { filePrefix := filename[strings.LastIndex(filename, "."):len(filename)] fileRealName := filename[0:strings.LastIndex(filename, ".")] name = fileRealName + utils.Int64ToStr(time.Now().Unix()) + filePrefix return name } func GetVendorStoreInfo(ctx *jxcontext.Context, vendorIDList []int, isAsync, isContinueWhenError bool) (hint string, err error) { var ( storeListJD []VendorStoreExcel storeListMT []VendorStoreExcel storeListEB []VendorStoreExcel storeIDs []string ) taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: for _, vendorID := range vendorIDList { iStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler) if vendorID == model.VendorIDEBAI { storeIDs, err = ebai.CurPurchaseHandler.GetShopIDsByPage() } else { storeIDs, err = iStoreHandler.GetAllStoresVendorID(ctx, "") } if err != nil { return "", err } taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { var storeDetail *dao.StoreDetail storeID := batchItemList[0].(string) if partner.IsMultiStore(vendorID) { multiHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler) storeDetail, err = multiHandler.ReadStore(ctx, "", storeID, "") if err != nil { return retVal, err } } else { singleHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreHandler) storeDetail, err = singleHandler.ReadStore(ctx, "", storeID, "") if err != nil { return retVal, err } } db := dao.GetDB() storeDetail2, err := dao.GetStoreDetailByVendorStoreID(db, storeDetail.VendorStoreID, vendorID, "") if err != nil { return "", err } if storeDetail.Status != model.StoreStatusOpened { if storeDetail2 != nil { var storeExcel = VendorStoreExcel{ StoreID: storeDetail2.ID, VendorStoreName: storeDetail.Name, Tel1: storeDetail.Tel1, Tel2: storeDetail.Tel2, Address: storeDetail.Address, Status: StoreStatus2Chinese(storeDetail.Status), CityName: storeDetail.CityName, MarketManName: storeDetail2.MarketManName, OperatorName: storeDetail2.OperatorName, OperatorName2: storeDetail2.OperatorName2, OperatorName3: storeDetail2.OperatorName3, } retVal = []VendorStoreExcel{storeExcel} } } return retVal, err } taskParallel := tasksch.NewParallelTask("获取各平台未营业门店", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeIDs) tasksch.HandleTask(taskParallel, task, true).Run() storeList, _ := taskParallel.GetResult(0) for _, v := range storeList { if vendorID == model.VendorIDJD { storeListJD = append(storeListJD, v.(VendorStoreExcel)) } if vendorID == model.VendorIDEBAI { storeListEB = append(storeListEB, v.(VendorStoreExcel)) } if vendorID == model.VendorIDMTWM { storeListMT = append(storeListMT, v.(VendorStoreExcel)) } } } case 1: WriteToExcelStore(task, storeListJD, storeListMT, storeListEB) } return result, err } taskSeq := tasksch.NewSeqTask2("导出各平台未营业门店-序列任务", ctx, isContinueWhenError, taskSeqFunc, 2) tasksch.HandleTask(taskSeq, nil, true).Run() if !isAsync { _, err = taskSeq.GetResult(0) hint = "1" } else { hint = taskSeq.GetID() } return hint, err } func WriteToExcelStore(task *tasksch.SeqTask, storeListJD, storeListMT, storeListEB []VendorStoreExcel) (err error) { var sheetList []*excel.Obj2ExcelSheetConfig var downloadURL, fileName string if len(storeListJD) > 0 { excelConf := &excel.Obj2ExcelSheetConfig{ Title: "京东平台", Data: storeListJD, CaptionList: titleListStore, } sheetList = append(sheetList, excelConf) } if len(storeListMT) > 0 { excelConf := &excel.Obj2ExcelSheetConfig{ Title: "美团平台", Data: storeListMT, CaptionList: titleListStore, } sheetList = append(sheetList, excelConf) } if len(storeListEB) > 0 { excelConf := &excel.Obj2ExcelSheetConfig{ Title: "饿百平台", Data: storeListEB, CaptionList: titleListStore, } sheetList = append(sheetList, excelConf) } if len(sheetList) == 0 { return errors.New("所选平台没有未营业的门店!") } else { downloadURL, fileName, err = jxutils.UploadExeclAndPushMsg(sheetList, "各平台未营业门店统计") if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s failed error:%v", fileName, err) } else { noticeMsg := fmt.Sprintf("[详情点我]path=%s \n", downloadURL) task.SetNoticeMsg(noticeMsg) baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", fileName, downloadURL) } } return err } func StoreStatus2Chinese(status int) (str string) { if status == model.StoreStatusOpened { return "正常营业" } else if status == model.StoreStatusDisabled { return "暂停营业" } else if status == model.StoreStatusClosed { return "休息中" } else { return "未知的营业状态" } } func GetStorePriceScore(ctx *jxcontext.Context, storeIDs, vendorIDs []int, fromScore, toScore, sort int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) { var snapDateParam time.Time db := dao.GetDB() //权限 if permission.IsRoled(ctx) { if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil { var storeIDs2 []int if len(storeIDs) > 0 { for _, v := range storeIDs { if storeIDsMap[v] != 0 { storeIDs2 = append(storeIDs2, v) } } if len(storeIDs2) == 0 { storeIDs2 = append(storeIDs2, -1) } } else { for k, _ := range storeIDsMap { storeIDs2 = append(storeIDs2, k) } } storeIDs = nil storeIDs = storeIDs2 } } if snapDate != "" { snapDateParam = utils.Str2Time(snapDate) } storePriceScore, totalCount, err := dao.GetStorePriceScore(db, storeIDs, vendorIDs, fromScore, toScore, sort, snapDateParam, offset, pageSize) pagedInfo = &model.PagedInfo{ Data: storePriceScore, TotalCount: totalCount, } return pagedInfo, err } func CreateStorePriceScore(ctx *jxcontext.Context) (err error) { db := dao.GetDB() var snapshotAt time.Time snapshotAt = utils.Time2Date(time.Now().AddDate(0, 0, -1)) storePriceScoreSnapshot, err := dao.GetStorePriceScoreSnapshot(db, snapshotAt) if len(storePriceScoreSnapshot) > 0 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) if r != nil { panic(r) } } }() priceReferSnapshotDeleteHis := &model.StorePriceScoreSnapshot{SnapshotAt: snapshotAt.AddDate(0, 0, -7)} priceReferSnapshotDelete := &model.StorePriceScoreSnapshot{SnapshotAt: snapshotAt} dao.DeleteEntity(db, priceReferSnapshotDeleteHis, "SnapshotAt") dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt") for _, v := range storePriceScoreSnapshot { dao.WrapAddIDCULDEntity(v, ctx.GetUserName()) v.SnapshotAt = snapshotAt if err = dao.CreateEntity(db, v); err != nil { return err } } dao.Commit(db, txDB) } return err } func RefreshJdLevel(ctx *jxcontext.Context) (err error) { db := dao.GetDB() storeMapList, err := dao.GetStoresMapList(db, []int{model.VendorIDJD}, nil, nil, model.StoreStatusOpened, -1, "", "", "") if len(storeMapList) > 0 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil || err != nil { dao.Rollback(db, txDB) if r != nil { panic(r) } } }() task := tasksch.NewParallelTask("更新京东门店等级", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { v := batchItemList[0].(*model.StoreMap) var ( pageLimit = 5 pageNo = 1 level string ) for ; pageNo < pageLimit+1; pageNo++ { level, err = jd.GetAPI(v.VendorOrgCode).GetJdStoreLevel(v.VendorOrgCode, v.VendorStoreID, pageNo) if err != nil { return retVal, err } if level != "" { break } if pageNo == pageLimit { level = "" } } v.JdStoreLevel = level _, err = dao.UpdateEntity(db, v, "JdStoreLevel") return retVal, err }, storeMapList) tasksch.HandleTask(task, nil, true).Run() _, err = task.GetResult(0) dao.Commit(db, txDB) } return err } type tJdStoreInfo struct { model.Store VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空 FreightDeductionPack string `orm:"size(32)" json:"freightDeductionPack"` // JdCityCode int JdDistrictCode int JdStoreStatus int VendorStoreID string `orm:"column(vendor_store_id)"` RealLastOperator string SyncStatus int VendorStoreName string } func UpdateJdStoreNameAll(ctx *jxcontext.Context) (err error) { storeMap := map[int]int{ 100345: 100345, 100347: 100347, 100852: 100852, 101689: 101689, 102654: 102654, 102381: 102381, 102500: 102500, 102810: 102810, } db := dao.GetDB() userName := ctx.GetUserName() for _, v := range storeMap { var stores []*tJdStoreInfo sql := ` SELECT t1.*, city.jd_code jd_city_code, district.jd_code jd_district_code, t2.status jd_store_status, t2.vendor_store_id, IF(t1.updated_at > t2.updated_at, t1.last_operator, t2.last_operator) real_last_operator, t2.sync_status, t2.freight_deduction_pack, t2.vendor_org_code, t2.vendor_store_name FROM store t1 JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? LEFT JOIN place city ON t1.city_code = city.code LEFT JOIN place district ON t1.district_code = district.code WHERE t1.id = ? ORDER BY t2.updated_at ` if err = dao.GetRows(db, &stores, sql, model.VendorIDJD, v); err == nil { for _, store := range stores { if store.Status == model.StoreStatusDisabled { continue } a := jd.GetAPI(store.VendorOrgCode) storeParams := &jdapi.OpStoreParams{ StationNo: store.VendorStoreID, Operator: userName, Phone: store.Tel1, Mobile: store.Tel2, } if store.SyncStatus&model.SyncFlagDeletedMask == 0 { storeParams.OutSystemID = utils.Int2Str(int(store.ID)) } else { storeParams.OutSystemID = store.VendorStoreID } if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 { if store.VendorStoreName != "" { storeParams.StationName = store.VendorStoreName } else { storeParams.StationName = jxutils.ComposeStoreName(store.Name, model.VendorIDJD) } storeParams.StationName = utils.LimitUTF8StringLen(storeParams.StationName, jdapi.MaxStoreNameLen) } if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 { storeParams.StationAddress = store.Address storeParams.CoordinateType = jdapi.CoordinateTypeAutonavi // 一直用高德 storeParams.Lng = jxutils.IntCoordinate2Standard(store.Lng) storeParams.Lat = jxutils.IntCoordinate2Standard(store.Lat) if store.JdCityCode != 0 { storeParams.City = store.JdCityCode } if store.JdDistrictCode != 0 { storeParams.County = store.JdDistrictCode } } // if specialDistrictMap[storeParams.County] != 0 { // storeParams.City = storeParams.County // storeParams.County = specialDistrictMap[storeParams.County] // } storeParams.StoreNotice = store.PromoteInfo modifyCloseStatus := false if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagDeletedMask|model.SyncFlagStoreStatus) != 0 { modifyCloseStatus = true _, storeParams.CloseStatus = jd.JxStoreStatus2JdStatus(jxutils.MergeStoreStatus(store.Status, store.JdStoreStatus)) } // fillOpTimeParams(storeParams, store.GetOpTimeList()) errList := errlist.New() if globals.EnableJdStoreWrite { errList.AddErr(a.UpdateStoreInfo4Open2(storeParams, modifyCloseStatus)) } err = errList.GetErrListAsOne() } } } return err } func DeletePrinterSeq(ctx *jxcontext.Context, storeIDs []int) (err error) { db := dao.GetDB() for _, v := range storeIDs { stores, err := dao.GetStoreList(db, []int{v}, nil, nil, nil, nil, "") if err != nil || len(stores) == 0 { return err } vendorID := stores[0].PrinterVendorID if vendorID == model.NO { return fmt.Errorf("该门店没有绑定打印机,ID:[%v],名字:[%v]", stores[0].ID, stores[0].Name) } if vendorID == model.VendorIDXiaoWM { return fmt.Errorf("暂不支持该打印机品牌清空打印队列,[%v]", model.VendorChineseNames[model.VendorIDXiaoWM]) } handler := partner.GetPrinterPlatformFromVendorID(vendorID) err = handler.EmptyPrintList(ctx, stores[0].PrinterSN, stores[0].PrinterKey) } return err } func checkYbParams(db *dao.DaoDB, storeMap *model.StoreMap, storeID int) (err error) { var ( appID = storeMap.YbAppID appKey = storeMap.YbAppKey yinbaoCookie string storeMap2 *model.StoreMap ) if appID == "" { return fmt.Errorf("绑定银豹平台必须输入appID!") } if appKey == "" { return fmt.Errorf("绑定银豹平台必须输入appKey!") } api.YinBaoAPI = yinbaoapi.New(appKey, appID) _, err = api.YinBaoAPI.QueryProductByBarcode("") if err != nil { if errCode, ok := err.(*utils.ErrorWithCode); ok { if errCode.Code() == yinbaoapi.AppIDErrCode { return fmt.Errorf("请输入正确的银豹appID!,[%v]", appID) } if errCode.Code() == yinbaoapi.AppKeyErrCode { return fmt.Errorf("请输入正确的银豹appKey!,[%v]", appKey) } } } storeMaps, err := dao.GetStoresMapList2(db, []int{model.VendorIDYB}, nil, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "", false) if len(storeMaps) > 0 { for _, v := range storeMaps { if v.YbAppID == appID { return fmt.Errorf("appID和已有店铺重复![%v]", v.StoreID) } if v.YbAppKey == appKey { return fmt.Errorf("appKey和已有店铺重复![%v]", v.StoreID) } } } stores, err := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "") if len(stores) > 0 { if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil { yinbaoCookie = configs[0].Value } api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie) result, err := loadSubStoresByUserIdDDLJson() if err != nil { return err } flag := false for _, v := range result { if v.Company == stores[0].Name { storeMap.VendorStoreID = utils.Int2Str(v.ID) flag = true break } } if !flag { return fmt.Errorf("未在平台上找到该门店,请确保京西门店名和银豹门店名相同!") } } sql := "SELECT * FROM store_map WHERE vendor_id = ? and deleted_at = ? ORDER BY yb_store_prefix DESC LIMIT 1" sqlParams := []interface{}{model.VendorIDYB, utils.DefaultTimeValue} err = dao.GetRow(db, &storeMap2, sql, sqlParams) if err == nil { prefix := utils.Int64ToStr(utils.Str2Int64(storeMap2.YbStorePrefix) + 1) realPrefix := prefix for i := 0; i < 3-len(prefix); i++ { realPrefix = "0" + realPrefix } storeMap.YbStorePrefix = realPrefix } return err } func loadSubStoresByUserIdDDLJson() (result []*yinbaoapi.LoadSubStoresByUserIdDDLJsonResult, err error) { for { result, err = api.YinBaoAPI.LoadSubStoresByUserIdDDLJson() if err == nil { break } else { if yinbaoapi.IsErrCookie(err) { err = ChangeYbCookie() if err != nil { break } result, err = loadSubStoresByUserIdDDLJson() } else { break } } } return result, err } func ChangeYbCookie() (err error) { cookie, err := api.YinBaoAPI.TryGetCookie() if err != nil { return err } api.YinBaoAPI.SetCookie(".POSPALAUTH30220", cookie) UpdateConfig(jxcontext.AdminCtx, "yinbaoCookie", model.ConfigTypeCookie, cookie) return err } func GetStoreCategoryMap(ctx *jxcontext.Context, parentID, level int, storeID int) (storeCatMaps []*model.StoreCategoryMap, err error) { db := dao.GetDB() storeCatMaps, err = dao.GetStoreCategoryMap(db, parentID, level, storeID, 0) if err != nil { return nil, err } //if ctx.GetLoginType() != auth2.AuthTypePassword && ctx.GetLoginType() != weixin.AuthTypeMP && ctx.GetLoginType() != weixin.AuthTypeMini && ctx.GetLoginType() != weixin.AuthTypeWxApp && ctx.GetLoginType() != weixin.AuthTypeWxAppCaishi && ctx.GetLoginType() != auth2.AuthTypeMobile { // return storeCatMaps, err //} //表示没有门店分类 if len(storeCatMaps) == 0 { storeCatMaps, err = dao.GetCategoriesForStore(db, parentID, 0, nil) } return storeCatMaps, err } func GetStoreCategoryMapNoDefault(ctx *jxcontext.Context, parentID, level int, storeID int) (storeCatMaps []*model.StoreCategoryMap, err error) { db := dao.GetDB() storeCatMaps, err = dao.GetStoreCategoryMap(db, parentID, level, storeID, 0) if err != nil { return nil, err } if ctx.GetLoginType() != weixin.AuthTypeMP && ctx.GetLoginType() != weixin.AuthTypeMini && ctx.GetLoginType() != weixin.AuthTypeWxApp && ctx.GetLoginType() != weixin.AuthTypeWxAppCaishi && ctx.GetLoginType() != auth2.AuthTypeMobile { return storeCatMaps, err } return storeCatMaps, err } func AddStoreCategoryMap(ctx *jxcontext.Context, storeCategoryMap *model.StoreCategoryMap) (result *model.StoreCategoryMap, err error) { var ( db = dao.GetDB() ) if storeCategoryMap.Level == 1 { storeCatMaps, _ := dao.GetStoreCategoryMap(db, -1, 0, storeCategoryMap.StoreID, storeCategoryMap.CategoryID) if len(storeCatMaps) > 0 { for _, v := range storeCatMaps { if storeCategoryMap.StoreCategoryName == v.StoreCategoryName { return nil, fmt.Errorf("已存在绑定的京西分类,分类名:[%v]", storeCatMaps[0].StoreCategoryName) } } } } storeCategoryMap.StoreCategoryName = strings.Trim(storeCategoryMap.StoreCategoryName, " ") dao.WrapAddIDCULDEntity(storeCategoryMap, ctx.GetUserName()) txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if err = dao.CreateEntity(db, storeCategoryMap); err != nil { dao.Rollback(db, txDB) return nil, err } dao.Commit(db, txDB) result = storeCategoryMap if storeCategoryMap.CategoryID != 0 { SetStoreCategorySyncStatus2(db, []int{storeCategoryMap.StoreID}, []int{storeCategoryMap.CategoryID}, model.SyncFlagModifiedMask) } // _, err = CurVendorSync.SyncCategory(ctx, nil, cat.ID, false, userName) return result, err } func UpdateStoreCategoryMap(ctx *jxcontext.Context, ID int, storeCategoryMap *model.StoreCategoryMap, isDelete bool) (num int64, err error) { var ( db = dao.GetDB() valid = make(map[string]interface{}) storeCategoryMap2 = &model.StoreCategoryMap{} ) storeCategoryMap2.ID = ID if err = dao.GetEntity(db, storeCategoryMap2); err != nil { return 0, err } if storeCategoryMap.StoreCategoryName != "" { valid["storeCategoryName"] = storeCategoryMap.StoreCategoryName } if storeCategoryMap.IsHidden < 2 { valid["isHidden"] = storeCategoryMap.IsHidden } if storeCategoryMap.CategoryID != 0 { valid["categoryID"] = storeCategoryMap.CategoryID if !isDelete { storeCatMaps, _ := dao.GetStoreCategoryMap(db, -1, 0, storeCategoryMap2.StoreID, storeCategoryMap.CategoryID) if len(storeCatMaps) > 0 { for _, v := range storeCatMaps { if v.ID != ID { return 0, fmt.Errorf("已存在绑定的京西分类,分类名:[%v]", storeCatMaps[0].StoreCategoryName) } } } } } if storeCategoryMap.Level != 0 { valid["level"] = storeCategoryMap.Level if storeCategoryMap.Level == 2 { cat2, _ := dao.GetCategories(db, -1, 0, []int{storeCategoryMap.CategoryID}, false) if len(cat2) > 0 { if cat2[0].ParentID != storeCategoryMap.ParentID && cat2[0].ParentID != model.NO { return 0, fmt.Errorf("此二级分类只能绑定到对应一级分类下!") } } } } if isDelete { valid["deletedAt"] = time.Now() valid["updatedAt"] = time.Now() valid["lastOperator"] = ctx.GetUserName() //如果是1级分类则删除下面的子分类 var catIDs []int if storeCategoryMap2.Level == 1 { storeCatMaps, _ := dao.GetStoreCategoryMap(db, storeCategoryMap2.CategoryID, 2, storeCategoryMap2.StoreID, 0) if len(storeCatMaps) > 0 { for _, v := range storeCatMaps { catIDs = append(catIDs, v.CategoryID) v.DeletedAt = time.Now() v.LastOperator = ctx.GetUserName() dao.UpdateEntity(db, v, "DeletedAt", "LastOperator") } } } var storeSkus []*model.StoreSkuBind sql := ` SELECT a.* FROM store_sku_bind a JOIN sku b ON a.sku_id = b.id JOIN sku_name c ON c.id = b.name_id WHERE a.deleted_at = ? AND b.deleted_at = ? AND c.deleted_at = ? AND c.category_id = ? AND a.store_id = ? UNION ALL SELECT a.* FROM store_sku_bind a JOIN sku b ON a.sku_id = b.id JOIN sku_name c ON c.id = b.name_id JOIN sku_category d ON d.id = c.category_id JOIN sku_category e ON e.id = d.parent_id WHERE a.deleted_at = ? AND b.deleted_at = ? AND c.deleted_at = ? AND e.id = ? AND a.store_id = ? ` sqlParams := []interface{}{ utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, storeCategoryMap2.CategoryID, storeCategoryMap2.StoreID, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, storeCategoryMap2.CategoryID, storeCategoryMap2.StoreID, } if err = dao.GetRows(db, &storeSkus, sql, sqlParams); err != nil { return 0, err } if len(storeSkus) > 0 { return 0, fmt.Errorf("该分类下或该分类的子分类下有关注的商品,不可删除!分类名:[%v]", storeCategoryMap2.StoreCategoryName) } catIDs = append(catIDs, storeCategoryMap.CategoryID) SetStoreCategorySyncStatus2(db, []int{storeCategoryMap2.StoreID}, catIDs, model.SyncFlagModifiedMask) } else { SetStoreCategorySyncStatus2(db, []int{storeCategoryMap2.StoreID}, []int{storeCategoryMap.CategoryID, storeCategoryMap2.CategoryID}, model.SyncFlagModifiedMask) } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if num, err = dao.UpdateEntityLogically(db, storeCategoryMap2, valid, ctx.GetUserName(), nil); err != nil { dao.Rollback(db, txDB) return 0, err } dao.Commit(db, txDB) return num, err } func ReorderStoreCategories(ctx *jxcontext.Context, parentID, storeID int, categoryIDs []int) (err error) { var ( storeCatsMap []*model.StoreCategoryMap ) db := dao.GetDB() storeCatsMap, err = dao.GetStoreCategoryMap(db, parentID, 0, storeID, 0) catsLen := len(storeCatsMap) if catsLen != len(categoryIDs) { return ErrInputCatsDoesntMatch } catsMap := make(map[int]*model.StoreCategoryMap, catsLen) for _, cat := range storeCatsMap { catsMap[cat.CategoryID] = cat } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() for k, v := range categoryIDs { if catsMap[v] == nil { dao.Rollback(db, txDB) return fmt.Errorf("分类:%d不在%d分类下", v, parentID) } catsMap[v].StoreCategorySeq = k catsMap[v].LastOperator = ctx.GetUserName() if _, err = dao.UpdateEntity(db, catsMap[v]); err != nil { dao.Rollback(db, txDB) return err } } dao.Commit(db, txDB) SetStoreCategorySyncStatus2(db, nil, categoryIDs, model.SyncFlagModifiedMask) if err == nil { CurVendorSync.SyncStoresCategory(ctx, db, nil, nil, false, true, true) } return err } func CopyStoreCategories(ctx *jxcontext.Context, fromStoreID int, toStoreIDs, categoryIDs []int, isContinueWhenError, isAsync bool) (hint string, err error) { var ( db = dao.GetDB() ) //权限 if permission.IsRoled(ctx) { if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil { if storeIDsMap[fromStoreID] == 0 { return "", fmt.Errorf("抱歉,您无权更改他人店铺分类 [%v]", fromStoreID) } for _, v := range toStoreIDs { if storeIDsMap[v] == 0 { return "", fmt.Errorf("抱歉,您无权更改他人店铺分类 [%v]", v) } } } } storeCatList, err := dao.GetStoreCategoryMap(db, -1, 0, fromStoreID, 0) if err != nil { return "", err } if len(storeCatList) == 0 { return "", fmt.Errorf("原门店无分类信息!storeID: %v", fromStoreID) } task := tasksch.NewParallelTask("CopyStoreCategories", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { storeID := batchItemList[0].(int) //证明是要全复制 if len(categoryIDs) == 0 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() sql := ` DELETE FROM store_category_map WHERE store_id = ? ` sqlParams := []interface{}{storeID} if _, err = dao.ExecuteSQL(db, sql, sqlParams); err != nil { return retVal, err } sql2 := ` INSERT INTO store_category_map(created_at,updated_at,last_operator,deleted_at,store_id,category_id,store_category_name,store_category_seq,level,parent_id,is_hidden) SELECT ?, ?, ?, ?, ?, category_id, store_category_name, store_category_seq, level, parent_id,is_hidden FROM store_category_map WHERE store_id = ? AND deleted_at = ? ` sqlParams2 := []interface{}{ time.Now(), time.Now(), ctx.GetUserName(), utils.DefaultTimeValue, storeID, fromStoreID, utils.DefaultTimeValue, } if _, err = dao.ExecuteSQL(db, sql2, sqlParams2); err != nil { return retVal, err } dao.Commit(db, txDB) } else { for _, v := range categoryIDs { list, err := dao.GetStoreCategoryMap(db, -1, 0, storeID, v) if err != nil { return retVal, err } if len(list) > 0 { return retVal, fmt.Errorf("该门店已有重复绑定的京西分类!storeID: %v,categroyID: %v", storeID, v) } else { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() sql2 := ` INSERT INTO store_category_map(created_at,updated_at,last_operator,deleted_at,store_id,category_id,store_category_name,store_category_seq,level,parent_id,is_hidden) SELECT ?, ?, ?, ?, ?, category_id, store_category_name, store_category_seq, level, parent_id,is_hidden FROM store_category_map WHERE store_id = ? AND deleted_at = ? AND category_id = ? ` sqlParams2 := []interface{}{ time.Now(), time.Now(), ctx.GetUserName(), utils.DefaultTimeValue, storeID, fromStoreID, utils.DefaultTimeValue, v, } if _, err = dao.ExecuteSQL(db, sql2, sqlParams2); err != nil { return retVal, err } dao.Commit(db, txDB) } } } return retVal, err }, toStoreIDs) tasksch.HandleTask(task, nil, true).Run() if isAsync { hint = task.GetID() } else { _, err = task.GetResult(0) hint = "1" } return hint, err } func DisabledStoreWithoutVendor(ctx *jxcontext.Context, isContinueWhenError, isAsync bool) (hint string, err error) { var ( db = dao.GetDB() ) stores, err := dao.GetStoreList(db, nil, nil, []int{model.StoreStatusClosed, model.StoreStatusHaveRest, model.StoreStatusOpened}, nil, nil, "") task := tasksch.NewParallelTask("DisabledStoreWithoutVendor", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { store := batchItemList[0].(*model.Store) storeMaps, err := dao.GetStoresMapList(db, []int{model.VendorIDYB, model.VendorIDJD, model.VendorIDJX, model.VendorIDEBAI, model.VendorIDMTWM, model.VendorIDJDShop}, []int{store.ID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") if len(storeMaps) == 0 { store.Status = model.StoreStatusDisabled dao.UpdateEntity(db, store, "Status") } return retVal, err }, stores) tasksch.HandleTask(task, nil, true).Run() if isAsync { hint = task.GetID() } else { _, err = task.GetResult(0) hint = "1" } return hint, err } func CleanStoreIsBoughtMatter(ctx *jxcontext.Context) (err error) { //每周一凌晨1点清空 if int(time.Now().Weekday()) != 1 { return err } db := dao.GetDB() sql := ` UPDATE store SET is_bought_matter = ? ` sqlParam := []interface{}{model.NO} _, err = dao.ExecuteSQL(db, sql, sqlParam) return err } func InsertStoreCategories(ctx *jxcontext.Context, db *dao.DaoDB, storeID int) (err error) { if db == nil { db = dao.GetDB() } if err = dao.DeleteStoreCategroies2(db, storeID); err == nil { err = dao.InsertStoreCategories(db, ctx.GetUserName(), storeID) } return err } func DeleteStoreCategroies(ctx *jxcontext.Context, db *dao.DaoDB, storeID int) (err error) { err = dao.DeleteStoreCategroies(db, ctx.GetUserName(), storeID) return err } func findSkusBetweenJdsMainStore(db *dao.DaoDB, storeID int) (skus []int) { var skuMap = make(map[int]int) storeSkus1, _ := dao.GetStoresSkusInfo(db, []int{model.JdShopMainStoreID}, nil) storeSkus2, _ := dao.GetStoresSkusInfo(db, []int{storeID}, nil) for _, v := range storeSkus1 { if v.Status == model.SkuStatusNormal { skuMap[v.SkuID] = 1 } } for _, v := range storeSkus2 { if v.Status == model.SkuStatusNormal && skuMap[v.SkuID] != 0 { skus = append(skus, v.SkuID) } } return skus } func UpdateStorePricePack(ctx *jxcontext.Context, storeID, vendorID int, pricePack, value string) (err error) { if err = checkConfig(model.SyncFlagModifiedMask, model.ConfigTypePricePack, pricePack, value); err != nil { return err } db := dao.GetDB() storeDetail, _ := dao.GetStoreDetail(db, storeID, vendorID, "") if storeDetail.PayPercentage > 50 { return fmt.Errorf("目前只允许扣点的门店修改调价包!") } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() //证明是门店自己的调价包 if strings.Contains(pricePack, utils.Int2Str(storeID)) { obj := dao.PricePercentagePack2Obj(value) realValue, _ := json.Marshal(obj) // _, err = UpdateConfig(ctx, pricePack, model.ConfigTypePricePack, string(realValue)) configList, err := dao.QueryConfigs(db, pricePack, model.ConfigTypePricePack, "") if err != nil { dao.Rollback(db, txDB) return err } if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{ "Value": string(realValue), }, ctx.GetUserName(), nil); err != nil { dao.Rollback(db, txDB) return err } } else { //表示门店要改他原有的调价包 //1、调价包名字要加上门店编号门店名等 //2、添加config //3、更新storeVendorMap //4、同步相关 pricePack = pricePack + "_" + utils.Int2Str(storeID) + "_" + storeDetail.Name if err = AddConfig(ctx, pricePack, model.ConfigTypePricePack, value); err != nil { dao.Rollback(db, txDB) return err } storeMapList, err := dao.GetStoresMapList(db, []int{vendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") if err != nil { dao.Rollback(db, txDB) return err } if len(storeMapList) > 0 { storeMapList[0].PricePercentagePack = pricePack dao.UpdateEntity(db, storeMapList[0], "PricePercentagePack") } } dao.Commit(db, txDB) storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, pricePack, "", "") if err != nil { dao.Rollback(db, txDB) return err } vendorStoreMap := make(map[int][]int) for _, v := range storeMapList { vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID) } for vendorID, storeIDs := range vendorStoreMap { dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask) } return err } func GetJdDeliveryArea(ctx *jxcontext.Context, storeIDs []int) (err error) { type tmp struct { JdID string `json:"jdID"` S int `json:"s"` } type SpecialtyStoreSkus struct { StoreID int `json:"门店ID"` StoreName string `json:"门店名"` City string `json:"城市"` Area int `json:"面积"` } var ( ss []*tmp excelTitle = []string{ "门店ID", "门店名", "城市", "面积", } sheetList []*excel.Obj2ExcelSheetConfig specialtyStoreSkus []*SpecialtyStoreSkus downloadURL, fileName string ) storeMaps, _ := dao.GetStoresMapList(dao.GetDB(), []int{model.VendorIDJD}, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") for _, v := range storeMaps { time.Sleep(time.Second / 3) station, err := jd.GetAPI("320406").GetDeliveryRangeByStationNo2(v.VendorStoreID) if err != nil { continue } if station.DeliveryRangeType == 2 { strs := strings.Split(station.DeliveryRange, ";") ss = append(ss, &tmp{ JdID: v.VendorStoreID, S: utils.Float64TwoInt(math.Ceil((jxutils.ComputeSignedArea(strs[:len(strs)-1])))), }) } } for i := 0; i < len(ss)-1; i++ { for j := 0; j < len(ss)-1-i; j++ { if ss[j].S > ss[j+1].S { temp := ss[j] ss[j] = ss[j+1] ss[j+1] = temp } } } for _, v := range ss { storeDetail, _ := dao.GetStoreDetailByVendorStoreID(dao.GetDB(), v.JdID, model.VendorIDJD, "") place, _ := dao.GetPlaceByCode(dao.GetDB(), storeDetail.CityCode) specialtyStoreSku := &SpecialtyStoreSkus{ StoreID: storeDetail.ID, StoreName: storeDetail.Name, City: place.Name, Area: v.S, } specialtyStoreSkus = append(specialtyStoreSkus, specialtyStoreSku) } excelConf := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: specialtyStoreSkus, CaptionList: excelTitle, } sheetList = append(sheetList, excelConf) if excelConf != nil { downloadURL, fileName, err = jxutils.UploadExeclAndPushMsg(sheetList, "面积") } else { baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!") } if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName, err) } else { noticeMsg := fmt.Sprintf("[详情点我]%s/billshow/?normal=true&path=%s \n", globals.BackstageHost, downloadURL) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, ctx.GetUserID(), "异步任务完成", noticeMsg) baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess downloadURL: [%v]", downloadURL) } return err } func UpdateStorePushClient(ctx *jxcontext.Context, storeID int, cID string) (err error) { var ( db = dao.GetDB() ) storePushClients, err := dao.GetStorePushClient(db, storeID, cID) if err != nil { return err } if len(storePushClients) == 0 { storePushClient := &model.StorePushClient{ StoreID: storeID, ClientID: cID, } dao.WrapAddIDCULDEntity(storePushClient, ctx.GetUserName()) dao.CreateEntity(db, storePushClient) } return err } func CreateStoreAudit(ctx *jxcontext.Context, storeAudit *model.StoreAudit) (err error) { var ( db = dao.GetDB() ) storeAudits, err := dao.GetStoreAudit(db, []int{model.StoreAuditStatusOnline}, storeAudit.UserID, "") if len(storeAudits) > 0 { return fmt.Errorf("您已申请过入驻,请不要重复申请!") } if storeAudit.Address == "" { return fmt.Errorf("门店地址必填!") } if storeAudit.Lng == 0 || storeAudit.Lat == 0 { lng, lat, _ := api.AutonaviAPI.GetCoordinateFromAddress(storeAudit.Address, "") if lng != 0 && lat != 0 { storeAudit.Lng = jxutils.StandardCoordinate2Int(lng) storeAudit.Lat = jxutils.StandardCoordinate2Int(lat) } else { return fmt.Errorf("请填写正确的门店地址!") } } if storeAudit.UserID == "" { storeAudit.UserID = ctx.GetUserID() } dao.WrapAddIDCULDEntity(storeAudit, ctx.GetUserName()) dao.CreateEntity(db, storeAudit) return err } func GetStoreAudit(ctx *jxcontext.Context, statuss []int, keyword, applyTimeStart, applyTimeEnd, auditTimeStart, auditTimeEnd string, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) { var ( applyTimeStartp, applyTimeEndp, auditTimeStartp, auditTimeEndp time.Time db = dao.GetDB() ) if applyTimeStart != "" { applyTimeStartp = utils.Str2Time(applyTimeStart) } if applyTimeEnd != "" { applyTimeEndp = utils.Str2Time(applyTimeEnd) } if auditTimeStart != "" { auditTimeStartp = utils.Str2Time(auditTimeStart) } if auditTimeEnd != "" { auditTimeEndp = utils.Str2Time(auditTimeEnd) } pagedInfo, err = dao.GetStoreAuditPage(db, statuss, keyword, applyTimeStartp, applyTimeEndp, auditTimeStartp, auditTimeEndp, pageSize, offset) return pagedInfo, err } func StoreAudit(ctx *jxcontext.Context, storeAudits []*model.StoreAudit, status int) (hint string, err error) { db := dao.GetDB() if status != model.StoreAuditStatusCreated && status != model.StoreAuditStatusRejected { return "", fmt.Errorf("审核标志不正确!") } task := tasksch.NewParallelTask("StoreAudit", tasksch.NewParallelConfig().SetParallelCount(5).SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { storeAudit := batchItemList[0].(*model.StoreAudit) storeAudits, err := dao.GetStoreAudit(db, []int{model.StoreAuditStatusOnline}, storeAudit.UserID, "") if len(storeAudits) == 0 || err != nil { return retVal, fmt.Errorf("未查询到待审核信息!") } if len(storeAudits) > 1 { return retVal, fmt.Errorf("查询到该用户的待审核信息大于1条!userID: [%s]", storeAudit.UserID) } //审核通过 if status == model.StoreAuditStatusCreated { storeAudits[0].AuditStatus = model.StoreAuditStatusCreated //添加门店 storeExt := &StoreExt{} if data, err := json.Marshal(&storeAudits[0]); err == nil { utils.UnmarshalUseNumber(data, &storeExt) } storeExt.ID = 0 storeExt.Store.StoreLevel = "C" storeExt.FloatLng = jxutils.IntCoordinate2Standard(utils.Float64TwoInt(storeExt.FloatLng)) storeExt.FloatLat = jxutils.IntCoordinate2Standard(utils.Float64TwoInt(storeExt.FloatLat)) storeExt.Status = model.StoreStatusDisabled storeExt.MarketManName = ctx.GetUserName() storeExt.MarketManPhone, _ = ctx.GetMobileAndUserID() storeID, err := CreateStore2JX(ctx, storeExt, ctx.GetUserName()) if err != nil { return retVal, fmt.Errorf(err.Error()) } err = AddUsers4Role(ctx, autils.NewRole(authz.StoreRoleBoss, storeID), []string{storeAudit.UserID}) if err != nil { return retVal, fmt.Errorf(err.Error()) } } else if status == model.StoreAuditStatusRejected { storeAudits[0].AuditStatus = model.StoreAuditStatusRejected } else { return retVal, fmt.Errorf("审核标志不正确!") } storeAudits[0].LastOperator = ctx.GetUserName() storeAudits[0].Remark = storeAudit.Remark _, err = dao.UpdateEntity(db, storeAudits[0], "LastOperator", "AuditStatus", "Remark") //是否推送app消息 if err == nil { } return retVal, err }, storeAudits) tasksch.HandleTask(task, nil, true).Run() hint = task.GetID() return hint, err } func GetDiffJxStoreAndMTWMStoreInfo(ctx *jxcontext.Context, storeIDs []int) (err error) { type TmpDiffStore struct { StoreID int `json:"门店ID"` StoreName string `json:"门店名"` City string `json:"城市"` Coordinate string `json:"坐标"` Address string `json:"地址"` Phone string `json:"电话"` CoordinateMT string `json:"坐标(美团)"` AddressMT string `json:"地址(美团)"` PhoneMT string `json:"电话(美团)"` Comment string `json:"对比情况"` } var ( excelTitle = []string{ "门店ID", "门店名", "城市", "坐标", "地址", "电话", "坐标(美团)", "地址(美团)", "电话(美团)", "对比情况", } sheetList []*excel.Obj2ExcelSheetConfig tmpDiffStoreList []*TmpDiffStore downloadURL, fileName string db = dao.GetDB() ) courierStoreList, _ := dao.GetStoreCourierList(db, storeIDs, []int{model.VendorIDMTPS}, model.StoreStatusAll, model.StoreAuditStatusAll) for _, v := range courierStoreList { comment := "" tmpDiffStore := &TmpDiffStore{ StoreID: v.StoreID, } stores, err := dao.GetStoreList(db, []int{v.StoreID}, nil, nil, nil, nil, "") store := stores[0] place, _ := dao.GetPlaceByCode(db, store.CityCode) tmpDiffStore.City = place.Name tmpDiffStore.StoreName = store.Name tmpDiffStore.Coordinate = utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lng)) + "," + utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lat)) tmpDiffStore.Address = store.Address tmpDiffStore.Phone = store.Tel1 shopInfo, err := api.MtpsAPI.ShopQuery(v.VendorStoreID) if err != nil { tmpDiffStore.Comment += err.Error() tmpDiffStoreList = append(tmpDiffStoreList, tmpDiffStore) continue } tmpDiffStore.CoordinateMT = utils.Float64ToStr(jxutils.IntCoordinate2Standard(shopInfo.ShopLng)) + "," + utils.Float64ToStr(jxutils.IntCoordinate2Standard(shopInfo.ShopLat)) tmpDiffStore.AddressMT = shopInfo.ShopAddress tmpDiffStore.PhoneMT = shopInfo.ContactPhone if tmpDiffStore.Coordinate != tmpDiffStore.CoordinateMT { comment += "坐标不同;" } if tmpDiffStore.Address != tmpDiffStore.AddressMT { comment += "地址不同;" } if tmpDiffStore.Phone != tmpDiffStore.PhoneMT { comment += "电话不同;" } tmpDiffStore.Comment = comment if comment != "" { tmpDiffStoreList = append(tmpDiffStoreList, tmpDiffStore) } } excelConf := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: tmpDiffStoreList, CaptionList: excelTitle, } sheetList = append(sheetList, excelConf) if excelConf != nil { downloadURL, fileName, err = jxutils.UploadExeclAndPushMsg(sheetList, "美团配送信息对比") } else { baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!") } if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName, err) } else { noticeMsg := fmt.Sprintf("[详情点我]%s/billshow/?normal=true&path=%s \n", globals.BackstageHost, downloadURL) ddmsg.SendUserMessage(dingdingapi.MsgTyeText, ctx.GetUserID(), "异步任务完成", noticeMsg) baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess downloadURL: [%v]", downloadURL) } return err } type GetBrandsResult struct { *model.Brand Balance int `json:"balance"` } func GetBrands(ctx *jxcontext.Context, name string, brandID int, isManage bool) (getBrandsResult []*GetBrandsResult, err error) { brands, _ := dao.GetBrands(dao.GetDB(), name, brandID, "", isManage, ctx.GetUserID()) for _, v := range brands { balance, _ := partner.CurStoreAcctManager.GetBrandBalance(v.ID) result := &GetBrandsResult{ Brand: v, Balance: balance, } getBrandsResult = append(getBrandsResult, result) } return getBrandsResult, err } func AddBrand(ctx *jxcontext.Context, brand *model.Brand) (err error) { var ( db = dao.GetDB() ) if brand.Name == "" { return fmt.Errorf("请输入品牌名!") } brand.Name = utils.TrimBlankChar(brand.Name) dao.WrapAddIDCULDEntity(brand, ctx.GetUserName()) err = dao.CreateEntity(db, brand) return err } func UpdateBrand(ctx *jxcontext.Context, payload map[string]interface{}, isDel bool) (err error) { var ( db = dao.GetDB() brand = &model.Brand{} ) brand.ID = int(utils.MustInterface2Int64(payload["id"])) dao.GetEntity(db, brand) if isDel { brand.DeletedAt = time.Now() brand.LastOperator = ctx.GetUserName() dao.UpdateEntity(db, brand, "DeletedAt", "LastOperator") //品牌下的用户也删了 if brandUsers, _ := dao.GetBrandUser(db, brand.ID, ""); len(brandUsers) > 0 { for _, v := range brandUsers { UpdateBrandUser(ctx, v.BrandID, v.UserID, true) } } } else { valid := dao.StrictMakeMapByStructObject(payload, brand, ctx.GetUserName()) if len(valid) > 0 { txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } if _, err = dao.UpdateEntityLogically(db, brand, valid, ctx.GetUserName(), nil); err != nil { dao.Rollback(db, txDB) return } dao.Commit(db, txDB) }() } } return err } func CreateVendorStore(ctx *jxcontext.Context, storeID, vendorID int, payload map[string]interface{}) (err error) { var ( db = dao.GetDB() storeDetail *dao.StoreDetail ) if storeDetail, err = dao.GetStoreDetail(db, storeID, vendorID, ""); err != nil { return fmt.Errorf("获取门店信息失败,请联系技术部!") } if payload["vendorOrgCode"] == nil { return fmt.Errorf("请选择平台账号!") } if vendorID == model.VendorIDMTWM { if brands, err := dao.GetBrands(db, "", storeDetail.BrandID, "", false, ""); err == nil { if len(brands) > 0 { if strings.Contains(brands[0].Name, "无品牌") { return fmt.Errorf("无品牌店铺不允许创建美团门店!") } } } } if payload["vendorStoreName"] == nil { return fmt.Errorf("请输入平台名!") } handler := partner.GetPurchasePlatformFromVendorID(vendorID) vendorStoreID, err := handler.CreateStore2(db, storeID, ctx.GetUserName(), payload, storeDetail) if err != nil { return err } if vendorStoreID != "" && vendorStoreID != "0" && vendorID != model.VendorIDDD { //抖店单独处理 //AddStoreVendorMap 太复杂了并不满足,还是手动加吧 storeMap := &model.StoreMap{ VendorStoreID: vendorStoreID, StoreID: storeID, VendorID: vendorID, VendorOrgCode: payload["vendorOrgCode"].(string), Status: 0, //平台还未审核等 DeliveryType: model.StoreDeliveryTypeByStore, PricePercentage: int16(utils.MustInterface2Int64(payload["pricePercentage"])), AutoPickup: 1, DeliveryCompetition: 1, IsSync: 1, PricePercentagePack: payload["pricePercentagePack"].(string), } dao.WrapAddIDCULDEntity(storeMap, ctx.GetUserName()) err = dao.CreateEntity(db, storeMap) } return err } func GetBrandStore(ctx *jxcontext.Context, name string) (brands []*model.BrandStore, err error) { var ( db = dao.GetDB() ) sql := ` SELECT * FROM brand_store WHERE deleted_at = ? ` sqlParams := []interface{}{utils.DefaultTimeValue} if name != "" { sql += " AND name LIKE ?" sqlParams = append(sqlParams, "%"+name+"%") } err = dao.GetRows(db, &brands, sql, sqlParams) return brands, err } // RefreshMTWMToken 刷新美团外卖门token func RefreshMTWMToken(ctx *jxcontext.Context) (err error) { var ( db = dao.GetDB() ) if time.Now().YearDay()%10 != 0 { return } //token是1个月过期,每10天刷一次吧 storeMaps, _ := dao.GetStoresMapList(db, []int{model.VendorIDMTWM}, nil, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", globals.Mtwm2Code) for _, v := range storeMaps { if v.MtwmRefreshToken != "" { if result, err := api.Mtwm2API.RefreshAccessToken(v.MtwmRefreshToken); err == nil { v.MtwmToken = result.AccessToken v.MtwmRefreshToken = result.RefreshToken dao.UpdateEntity(db, v, "MtwmToken", "MtwmRefreshToken") } } } return err } // RefreshTiktokShopToken 属性抖店门店tokne func RefreshTiktokShopToken(ctx *jxcontext.Context) (err error) { var ( db = dao.GetDB() ) codes, _ := dao.GetVendorOrgCode(db, model.VendorIDDD, "", "platform") api := api.TiktokStore for _, v := range codes { if v.Token != "" { var access *doudian_sdk.AccessToken if err := json.Unmarshal([]byte(v.Token), &access); err != nil { globals.SugarLogger.Debugf("定时任务更新抖店店铺token错误:%s,%s", utils.Format4Output(v, false), err.Error()) continue } if access.ExpiresIn-time.Now().Unix() > 60*60 { continue } api.SetToken(access.AccessToken) api.SetRefreshToken(access.RefreshToken) api.SetExpiresIn(access.ExpiresIn) api.SetAcctokenObj(access) if result, err := api.RefreshToken(); err == nil { token, _ := json.Marshal(result) v.Token = string(token) v.UpdatedAt = time.Now() v.StoreBrandName = "定时任务更新" dao.UpdateEntity(db, v, "Token", "UpdatedAt", "StoreBrandName") tiktok_store.HttpToGuoYuan(utils.Struct2MapByJson(v), tiktok_store.CaiShiPushGyTagToken) } } } return err } func StoreConfirmAct(ctx *jxcontext.Context, status, msgStatusID int) (err error) { msgStatus := &model.MessageStatus{} msgStatus.ID = msgStatusID db := dao.GetDB() if err = dao.GetEntity(db, msgStatus); err != nil { return err } if status == model.YES { msg := &model.Message{} msg.ID = msgStatus.MessageID if err = dao.GetEntity(db, msg); err != nil { return err } actMap := &model.MessageActInfo{} err = json.Unmarshal([]byte(msg.ActInfo), &actMap) if time.Now().Sub(utils.Str2Time(actMap.BeginAt)) > 0 { msgStatus.ConfirmStatus = -1 dao.WrapUpdateULEntity(msgStatus, ctx.GetUserName()) _, err = dao.UpdateEntity(db, msgStatus, "ConfirmStatus") return fmt.Errorf("参与活动时间已过期!") } } msgStatus.ConfirmStatus = status dao.WrapUpdateULEntity(msgStatus, ctx.GetUserName()) _, err = dao.UpdateEntity(db, msgStatus, "ConfirmStatus") return err } func GetStoreAcctBalance(ctx *jxcontext.Context, storeID int) (storeAcct *model.StoreAcct, err error) { var ( db = dao.GetDB() ) totalIncome, err := dao.GetStoreAcctIncomeTotal(db, storeID, nil, "", utils.ZeroTimeValue, utils.ZeroTimeValue) if err != nil { return nil, err } totalExpend, err := dao.GetStoreAcctExpendTotal(db, storeID, nil, "", utils.ZeroTimeValue, utils.ZeroTimeValue) if err != nil { return nil, err } return &model.StoreAcct{ StoreID: storeID, AccountBalance: totalIncome - totalExpend, }, err } func RefreshStoreBind(ctx *jxcontext.Context) (err error) { var ( db = dao.GetDB() ) stores, err := dao.GetStoreList(db, nil, nil, []int{model.StoreStatusClosed, model.StoreStatusHaveRest, model.StoreStatusOpened}, nil, nil, "") task := tasksch.NewParallelTask("RefreshStoreBind", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { store := batchItemList[0].(*model.Store) var ( userIDmap1 = make(map[string]string) userIDmap2 = make(map[string]string) mobileList, userIDsAdd, userIDsDel []string ) // userList := getAllUsers4Store(ctx, db, store) // if store.Tel1 != "" { // mobileList = append(mobileList, store.Tel1) // } // if store.Tel2 != "" { // mobileList = append(mobileList, store.Tel2) // } if store.MarketManPhone != "" { mobileList = append(mobileList, store.MarketManPhone) } if store.OperatorPhone != "" { mobileList = append(mobileList, store.OperatorPhone) } if store.OperatorPhone2 != "" { mobileList = append(mobileList, store.OperatorPhone2) } if store.OperatorPhone3 != "" { mobileList = append(mobileList, store.OperatorPhone3) } mobileList = append(mobileList, "18160030913", "15520595380", "18048531223", "18080188338") for _, v := range mobileList { if user, err := dao.GetUserByID(db, "mobile", v); err == nil && user != nil { userIDmap1[user.UserID] = user.UserID } } nowUserIDs, _ := GetRoleUserList(ctx, autils.NewRole(authz.StoreRoleBoss, store.ID)) for _, v := range nowUserIDs { userIDmap2[v] = v if userIDmap1[v] == "" { userIDsDel = append(userIDsDel, v) } } for _, v := range userIDmap1 { if userIDmap2[v] == "" { userIDsAdd = append(userIDsAdd, v) } } AddUsers4Role(ctx, autils.NewRole(authz.StoreRoleBoss, store.ID), userIDsAdd) // DeleteUsers4Role(ctx, autils.NewRole(authz.StoreRoleBoss, store.ID), userIDsDel) return retVal, err }, stores) tasksch.HandleTask(task, nil, true).Run() task.GetID() return err } func UpdateVendorStoreBussinessStatus(ctx *jxcontext.Context, storeID int, vendorID []int, status int) (err error) { var ( db = dao.GetDB() errList = errlist.New() ) for _, v := range vendorID { storeDetail, err := dao.GetStoreDetail(db, storeID, v, "") if err != nil { return err } handler := partner.GetPurchasePlatformFromVendorID(v) if err = handler.UpdateStoreLineStatus(ctx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID, status); err == nil { if storeMaps, _ := dao.GetStoresMapList(db, []int{v}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", ""); len(storeMaps) > 0 { storeMaps[0].IsOnline = status storeMaps[0].Status = status dao.UpdateEntity(db, storeMaps[0], "IsOnline", "Status") } } else { errList.AddErr(fmt.Errorf("平台[%d],门店id[%d],错误:%s", v, storeID, err)) } } if errList.GetErrListAsOne() != nil { return errList.GetErrListAsOne() } return nil } type JdPage struct { ID int `orm:"column(id)" json:"id"` Name string `json:"name"` MonthSalesTip string `json:"month_sales_tip"` ShippingTime string `json:"shipping_time"` Address string `json:"address"` Phone string `json:"phone"` Pj string `json:"pj"` Orgcode string `json:"orgcode"` Wmpoiid string `json:"wmpoiid"` ThirdCategory string `json:"third_category"` Set string `json:"set"` Settime string `json:"settime"` Latr string `json:"latr"` Longr string `json:"longr"` Rek string `json:"rek"` BakInfo string `json:"bak_info"` GoodsNumber int `json:"goods_number"` Lat string `json:"lat"` Lng string `json:"lng"` DistrictName string `json:"district_name"` BrandName string `json:"brand_name"` } type MtPage struct { ID int `orm:"column(id)" json:"id"` Name string `json:"name"` MonthSalesTip string `json:"month_sales_tip"` ShippingTime string `json:"shipping_time"` Address string `json:"address"` Phone string `json:"phone"` Pj string `json:"pj"` Wmpoiid string `json:"wmpoiid"` ThirdCategory string `json:"third_category"` Set string `json:"set"` Settime string `json:"settime"` Latr string `json:"latr"` Longr string `json:"longr"` Rek string `json:"rek"` CityName string `json:"city_name"` GoodsNumber int `json:"goods_number"` Lat string `json:"lat"` Lng string `json:"lng"` DistrictName string `json:"district_name"` BrandName string `json:"brand_name"` } type EbaiPage struct { LibraryName string `json:"library_name"` EleID string `orm:"column(ele_id)" json:"ele_id"` MonthSales string `json:"month_sales"` FirstOpenTime string `json:"first_open_time"` Wid string `json:"wid"` ShopScore string `json:"shop_score"` StoreID string `orm:"column(store_id)" json:"store_id"` Phone string `json:"phone"` Classif string `json:"classif"` ClassifyParameter string `json:"classify_parameter"` Address string `json:"address"` Settime string `json:"settime"` Remark string `json:"remark"` State int `json:"state"` Lat string `json:"lat"` Lng string `json:"lng"` DistrictName string `json:"district_name"` BrandName string `json:"brand_name"` } func RefreshPageStore() { var ( db = dao.GetDB() jds []*JdPage mts []*MtPage ebais []*EbaiPage ) //刷京东门店表的坐标和区名 sql := ` SELECT * FROM jingdong_showd WHERE (lng IS NULL AND lat IS NULL) OR (lng = 0 AND lat = 0) ` dao.GetRows(db, &jds, sql, nil) for _, v := range jds { var ( lng, lat float64 dis string ) if (v.Lat == "" && v.Lng == "") || (v.Lat == "0" && v.Lng == "0") { if v.Address != "" { if v.BakInfo != "" { //result, _ := api.AutonaviAPI.GetCoordinateFromAddressAll(v.Address, v.Remark) //lng, lat, dis := utils.Float64ToStr(result.Lng), utils.Float64ToStr(result.Lat), result.AdName place, _ := dao.GetPlaceByName(db, v.BakInfo, 2, 0) if result1, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, place.Code); result1 != nil { if result1.Lng == 0 || result1.Lat == 0 { result2, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, 0) lng, lat, dis = result2.Lng, result2.Lat, result2.AdName } else { lng, lat, dis = result1.Lng, result1.Lat, result1.AdName } } sql := ` UPDATE jingdong_showd SET lng = ?, lat = ?, district_name = ? WHERE id = ? ` sqlparams := []interface{}{ lng, lat, dis, v.ID, } dao.ExecuteSQL(db, sql, sqlparams) } else { result1, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, 0) lng, lat, dis = result1.Lng, result1.Lat, result1.AdName sql := ` UPDATE jingdong_showd SET lng = ?, lat = ?, district_name = ? WHERE id = ? ` sqlparams := []interface{}{ lng, lat, dis, v.ID, } dao.ExecuteSQL(db, sql, sqlparams) } } } } //刷美团门店表的坐标和区名 sql2 := ` SELECT * FROM meituan_showd WHERE (lng IS NULL AND lat IS NULL) OR (lng = 0 AND lat = 0) ` dao.GetRows(db, &mts, sql2, nil) for _, v := range mts { var ( lng, lat float64 dis string ) if (v.Lat == "" && v.Lng == "") || (v.Lat == "0" && v.Lng == "0") { if v.Address != "" { if v.CityName != "" { //result, _ := api.AutonaviAPI.GetCoordinateFromAddressAll(v.Address, v.Remark) //lng, lat, dis := utils.Float64ToStr(result.Lng), utils.Float64ToStr(result.Lat), result.AdName place, _ := dao.GetPlaceByName(db, v.CityName, 2, 0) if result1, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, place.Code); result1 != nil { if result1.Lng == 0 || result1.Lat == 0 { result2, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, 0) lng, lat, dis = result2.Lng, result2.Lat, result2.AdName } else { lng, lat, dis = result1.Lng, result1.Lat, result1.AdName } } sql := ` UPDATE meituan_showd SET lng = ?, lat = ?, district_name = ? WHERE id = ? ` sqlparams := []interface{}{ lng, lat, dis, v.ID, } dao.ExecuteSQL(db, sql, sqlparams) } else { result1, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, 0) lng, lat, dis = result1.Lng, result1.Lat, result1.AdName sql := ` UPDATE meituan_showd SET lng = ?, lat = ?, district_name = ? WHERE id = ? ` sqlparams := []interface{}{ lng, lat, dis, v.ID, } dao.ExecuteSQL(db, sql, sqlparams) } } } } //刷饿百门店表的坐标和区名 sqlebai := ` SELECT * FROM elm_showd WHERE (lng IS NULL AND lat IS NULL) OR (lng = 0 AND lat = 0) OR (lng = '' AND lat = '') ` dao.GetRows(db, &ebais, sqlebai, nil) for _, v := range ebais { var ( lng, lat float64 dis string ) if (v.Lat == "" && v.Lng == "") || (v.Lat == "0" && v.Lng == "0") { if v.Address != "" { if v.Remark != "" { //result, _ := api.AutonaviAPI.GetCoordinateFromAddressAll(v.Address, v.Remark) //lng, lat, dis := utils.Float64ToStr(result.Lng), utils.Float64ToStr(result.Lat), result.AdName place, _ := dao.GetPlaceByName(db, v.Remark, 2, 0) if result1, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, place.Code); result1 != nil { if result1.Lng == 0 || result1.Lat == 0 { result2, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, 0) lng, lat, dis = result2.Lng, result2.Lat, result2.AdName } else { lng, lat, dis = result1.Lng, result1.Lat, result1.AdName } } sql := ` UPDATE elm_showd SET lng = ?, lat = ?, district_name = ? WHERE store_id = ? ` sqlparams := []interface{}{ lng, lat, dis, v.StoreID, } dao.ExecuteSQL(db, sql, sqlparams) } else { result1, _ := api.AutonaviAPI.GetCoordinateFromAddressByPageAll(v.Address, 0) lng, lat, dis = result1.Lng, result1.Lat, result1.AdName sql := ` UPDATE elm_showd SET lng = ?, lat = ?, district_name = ? WHERE store_id = ? ` sqlparams := []interface{}{ lng, lat, dis, v.StoreID, } dao.ExecuteSQL(db, sql, sqlparams) } } } } ////商品表合并 //sql3 := ` TRUNCATE page_sku` //dao.ExecuteSQL(db, sql3) //sql4 := ` // INSERT INTO page_sku (created_at,updated_at,last_operator,vendor_id,vendor_store_id,vendor_sku_id,vendor_sku_name,month_saled,act_price,sale_price,unit) // SELECT NOW(),NOW(),'jxadmin',t1.* FROM ( // ( // SELECT 0, a.wmpoiid, a.Base, a.name, a.month_saled, ISNULL(a.min_price) *100, a.basic_price*100, '' // FROM jingdong_foodlist a // ) // UNION ALL // ( // SELECT 1, a.wmpoiid, '', a.name, a.month_saled, 0, a.min_price*100, a.unit // FROM meituan_foodlist a // ) // )t1 //` //dao.ExecuteSQL(db, sql4) ////门店表合并 //sql5 := ` TRUNCATE page_store` //dao.ExecuteSQL(db, sql5) //sql6 := ` // INSERT INTO page_store (created_at,updated_at,last_operator,vendor_id,vendor_store_id,vendor_store_name,address,city_name,org_code,lng,lat) // SELECT NOW(),NOW(),'jxadmin',t1.* FROM ( // ( // SELECT 0, a.wmpoiid, a.name, a.address, a.bak_info, a.orgcode, a.lng, a.lat // FROM jingdong_showd a // ) // UNION ALL // ( // SELECT 1, a.wmpoiid, a.name, a.address, a.city_name, '', a.lng, a.lat // FROM meituan_showd a // ) // )t1 //` //dao.ExecuteSQL(db, sql6) var ( jds2 []*JdPage mts2 []*MtPage splitStr1 = []string{ "-", "(", "(", "•", "【", } splitStr2 = []string{ "-", "(", "(", "•", " ", "【", } ebai2 []*EbaiPage ) trySplitBrand := func(splitStr []string, name string) (brandName string) { for _, v := range splitStr { if strings.Index(name, v) != -1 { return name[:strings.Index(name, v)] } else { continue } } return "无" } sql7 := ` SELECT * FROM jingdong_showd WHERE brand_name = '' OR brand_name IS NULL OR brand_name = '无' OR brand_name = '0' ` dao.GetRows(db, &jds2, sql7) if len(jds2) > 0 { for _, v := range jds2 { sql := ` UPDATE jingdong_showd SET brand_name = ? WHERE id = ? ` sqlparams := []interface{}{ trySplitBrand(splitStr1, v.Name), v.ID, } dao.ExecuteSQL(db, sql, sqlparams) } } sql8 := ` SELECT * FROM meituan_showd WHERE brand_name = '' OR brand_name IS NULL OR brand_name = '无' OR brand_name = '0' ` dao.GetRows(db, &mts2, sql8) if len(mts2) > 0 { for _, v := range mts2 { sql := ` UPDATE meituan_showd SET brand_name = ? WHERE id = ? ` sqlparams := []interface{}{ trySplitBrand(splitStr2, v.Name), v.ID, } dao.ExecuteSQL(db, sql, sqlparams) } } sqle := ` SELECT * FROM elm_showd WHERE brand_name = '' OR brand_name IS NULL OR brand_name = '无' OR brand_name = '0' ` dao.GetRows(db, &ebai2, sqle) if len(ebai2) > 0 { for _, v := range ebai2 { brandName := trySplitBrand(splitStr2, v.LibraryName) if brandName == "无" { var count = struct { Count int }{} sql := ` SELECT COUNT(library_name) count,library_name FROM elm_showd WHERE library_name = ? GROUP BY 2 ` sqlParams := []interface{}{v.LibraryName} dao.GetRow(db, &count, sql, sqlParams) if count.Count > 1 { brandName = v.LibraryName } } sql := ` UPDATE elm_showd SET brand_name = ? WHERE store_id = ? ` sqlparams := []interface{}{ brandName, v.StoreID, } dao.ExecuteSQL(db, sql, sqlparams) } } sql9 := ` TRUNCATE page_brand` dao.ExecuteSQL(db, sql9) sql10 := ` INSERT INTO page_brand (created_at,updated_at,last_operator,brand_name) SELECT NOW(),NOW(),'jxadmin', t1.* FROM ( ( SELECT DISTINCT a.brand_name FROM jingdong_showd a ) UNION ( SELECT DISTINCT a.brand_name FROM meituan_showd a ) UNION ( SELECT DISTINCT a.brand_name FROM elm_showd a ) )t1 ` dao.ExecuteSQL(db, sql10) } func QueryPageStores2(db *dao.DaoDB, pageSize, offset int, keyword, vendorStoreID, brandName string, vendorID, cityCode, districtCode int, tel string, minShopScore float32, minRecentOrderNum, minSkuCount int, lng1, lat1, lng2, lat2 float64, cat string) (pagedInfo *model.PagedInfo, err error) { // db.Db = orm.NewOrmUsingDB("c4beta") sqlJD := ` SELECT name, 0 vendor_id, wmpoiid vendor_store_id, orgcode org_code, 1 vendor_status, address, phone tel1, pj shop_score, month_sales_tip recent_order_num, bak_info city_name, goods_number sku_count, lat, lng, district_name, brand_name, third_category category, shipping_time FROM jingdong_showd ` sqlEbai := ` SELECT library_name name, 3 vendor_id, store_id vendor_store_id, '' org_code, 1 vendor_status, address, phone tel1, shop_score, month_sales recent_order_num, remark city_name, 0 sku_count, lat, lng, district_name, brand_name, classify_parameter category, first_open_time shipping_time FROM elm_showd ` sqlMT := ` SELECT name, 1 vendor_id, wmpoiid vendor_store_id, '' org_code, 1 vendor_status, address, phone tel1, pj shop_score, REPLACE(REPLACE(month_sales_tip,'月售',''),'+','') recent_order_num, city_name, goods_number sku_count, lat, lng, district_name, brand_name, IF(rek = '买菜', '菜市', rek) category, shipping_time FROM meituan_showd ` sqlGD := ` SELECT name, 10 vendor_id, wmpoiid vendor_store_id, '' org_code, 1 vendor_status, address, phone tel1, pj shop_score, month_sales_tip recent_order_num, city_name, goods_number sku_count, lat, lng, district_name, brand_name, third_category category, shipping_time FROM gaode_showd ` //lat, lng, //sqlCLB := ` // SELECT name ,20 vendor_id, wmpoiid vendor_store_id,'' org_code,1 vendor_status,address, phone tel1,pj shop_score,month_sales_tip recent_order_num, // city_name,goods_number sku_count,lat, lng, district_name, brand_name, third_category category , shipping_time // FROM clb_showd //` sql := ` SELECT SQL_CALC_FOUND_ROWS t1.*, t2.code city_code FROM ( ` if vendorID == -1 { sql += sqlJD + ` UNION` sql += sqlMT + ` UNION` sql += sqlEbai + ` UNION` sql += sqlGD } else { switch vendorID { case model.VendorIDJD: sql += sqlJD case model.VendorIDMTWM: sql += sqlMT case model.VendorIDEBAI: sql += sqlEbai case model.VendorIDGD: sql += sqlGD } } sql += ` )t1 LEFT JOIN place t2 ON t2.name = t1.city_name AND t2.level = 2 WHERE 1 = 1 ` sqlParams := []interface{}{} if vendorStoreID != "" { sql += " AND t1.vendor_store_id = ?" sqlParams = append(sqlParams, vendorStoreID) } if cityCode != 0 { sql += " AND t2.code = ?" sqlParams = append(sqlParams, cityCode) } if tel != "" { sql += " AND t1.tel1 = ?" sqlParams = append(sqlParams, tel) } if brandName != "" { sql += " AND t1.brand_name = ?" sqlParams = append(sqlParams, brandName) } if minShopScore > 0 { sql += " AND t1.shop_score >= ?" sqlParams = append(sqlParams, minShopScore) } if minRecentOrderNum > 0 { sql += " AND t1.recent_order_num >= ?" sqlParams = append(sqlParams, minRecentOrderNum) } if minSkuCount > 0 { sql += " AND t1.sku_count >= ?" sqlParams = append(sqlParams, minSkuCount) } if keyword != "" { keywordLike := "%" + keyword + "%" sql += " AND (t1.name LIKE ? OR t1.tel1 LIKE ? OR t1.org_code LIKE ? OR t1.address LIKE ? OR t2.name LIKE ? " sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike) sql += ")" } if lng1 > 0 { sql += " AND t1.lng >= ? AND t1.lat >= ? AND t1.lng <= ? AND t1.lat <= ?" sqlParams = append(sqlParams, lng1, lat1, lng2, lat2) } if cat != "" { sql += " AND t1.category = ?" sqlParams = append(sqlParams, cat) } sql += ` LIMIT ? OFFSET ? ` pageSize = jxutils.FormalizePageSize(pageSize) offset = jxutils.FormalizePageOffset(offset) sqlParams = append(sqlParams, pageSize, offset) var shopList []*dao.PageShopWithPlaceName txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if err = dao.GetRowsTx(txDB, &shopList, sql, sqlParams...); err == nil { pagedInfo = &model.PagedInfo{ TotalCount: dao.GetLastTotalRowCount2(db, txDB), Data: shopList, } dao.Commit(db, txDB) //var newShopList []*dao.PageShopWithPlaceName //task := tasksch.NewParallelTask("", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx, // func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { // v := batchItemList[0].(*dao.PageShopWithPlaceName) // if v.Address != "" && v.CityName != "" { // result, _ := api.AutonaviAPI.GetCoordinateFromAddressAll(v.Address, v.CityName) // lng, lat := result.Lng, result.Lat // v.DistrictName = result.AdName // v.Lng, v.Lat = lng, lat // if lng1 > 0 { // if !(lng >= lng1 && lat >= lat1 && lng <= lng2 && lat <= lat2) { // retVal = []*dao.PageShopWithPlaceName{v} // } // } else { // retVal = []*dao.PageShopWithPlaceName{v} // } // retVal = []*dao.PageShopWithPlaceName{v} // } else { // retVal = []*dao.PageShopWithPlaceName{v} // } // return retVal, err // }, shopList) //tasksch.HandleTask(task, nil, true).Run() //result, _ := task.GetResult(0) //for _, v := range result { // newShopList = append(newShopList, v.(*dao.PageShopWithPlaceName)) //} //pagedInfo.Data = newShopList } return pagedInfo, err } type QueryPageSkusResult struct { OrgCode string `json:"orgCode"` //商家ID StoreId string `orm:"column(store_id)" json:"storeId"` //门店ID StoreName string `json:"storeName"` //门店名 SkuId string `orm:"column(sku_id)" json:"skuId"` //skuID SkuName string `json:"skuName"` //商品名 Parameter string `json:"parameter"` //规格 MonthSales string `json:"monthSales"` //月销量 RealTimePrice string `json:"realTimePrice"` //促销价 BasicPrice string `json:"basicPrice"` // 原价 VendorID int `orm:"column(vendor_id)" json:"vendorID"` Address string `json:"address"` CityName string `json:"cityName"` CityCode int `json:"cityCode"` } func QueryPageSkus(ctx *jxcontext.Context, vendorID int, vendorStoreIDs []string, keyword string, cityCode int, lng, lat, lng1, lat1, lng2, lat2 float64, radius, sortType, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) { var ( db = dao.GetDB() results []*QueryPageSkusResult ) //db.Db = orm.NewOrmUsingDB("c4beta") sqlParams := []interface{}{} sqlJD := ` SELECT 0 vendor_id, b.orgcode org_code, a.wmpoiid store_id, b.name store_name, a.Base sku_id, a.name sku_name, a.month_saled month_sales, a.basic_price, b.address, '' parameter, b.bak_info city_name, b.lng, b.lat, getDistance(?, ?, b.lng, b.lat) distance FROM jingdong_foodlist a LEFT JOIN jingdong_showd b ON a.wmpoiid = b.wmpoiid LEFT JOIN place c ON c.name = b.bak_info WHERE 1 = 1 ` sqlEbai := ` ` sqlMT := ` SELECT 1 vendor_id, '' org_code, a.wmpoiid store_id, b.name store_name, '' sku_id, a.name sku_name, a.month_saled month_sales, a.min_price basic_price, b.address, a.unit parameter, b.city_name, b.lng, b.lat, getDistance(?, ?, b.lng, b.lat) distance FROM meituan_foodlist a LEFT JOIN meituan_showd b ON a.wmpoiid = b.wmpoiid LEFT JOIN place c ON c.name = b.city_name WHERE 1 = 1 ` sql := ` SELECT SQL_CALC_FOUND_ROWS t1.* FROM ( ` if vendorID == -1 { //sql += sqlEbai + ` UNION` //jd sqlParams = append(sqlParams, lng, lat) if cityCode > 0 { sqlJD += " AND c.code = ?" sqlParams = append(sqlParams, cityCode) } if lng1 > 0 { sqlJD += " AND b.lng >= ? AND b.lat >= ? AND b.lng <= ? AND b.lat <= ?" sqlParams = append(sqlParams, lng1, lat1, lng2, lat2) } //mt sqlParams = append(sqlParams, lng, lat) if cityCode > 0 { sqlMT += " AND c.code = ?" sqlParams = append(sqlParams, cityCode) } if lng1 > 0 { sqlMT += " AND b.lng >= ? AND b.lat >= ? AND b.lng <= ? AND b.lat <= ?" sqlParams = append(sqlParams, lng1, lat1, lng2, lat2) } sql += sqlJD + ` UNION ALL` sql += sqlMT } else { switch vendorID { case model.VendorIDJD: sqlParams = append(sqlParams, lng, lat) if cityCode > 0 { sqlJD += " AND c.code = ?" sqlParams = append(sqlParams, cityCode) } if lng1 > 0 { sqlJD += " AND b.lng >= ? AND b.lat >= ? AND b.lng <= ? AND b.lat <= ?" sqlParams = append(sqlParams, lng1, lat1, lng2, lat2) } sql += sqlJD case model.VendorIDMTWM: sqlParams = append(sqlParams, lng, lat) if cityCode > 0 { sqlMT += " AND c.code = ?" sqlParams = append(sqlParams, cityCode) } if lng1 > 0 { sqlMT += " AND b.lng >= ? AND b.lat >= ? AND b.lng <= ? AND b.lat <= ?" sqlParams = append(sqlParams, lng1, lat1, lng2, lat2) } sql += sqlMT case model.VendorIDEBAI: sql += sqlEbai } } sql += ` )t1 WHERE 1 = 1 ` if keyword != "" { keywordLike := "%" + keyword + "%" sql += " AND t1.sku_name LIKE ?" sqlParams = append(sqlParams, keywordLike) } if len(vendorStoreIDs) > 0 { sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(vendorStoreIDs)) + ")" sqlParams = append(sqlParams, vendorStoreIDs) } //if radius > 0 { // sql += " AND ROUND(t1.distance * 1000) < ?" // sqlParams = append(sqlParams, radius) //} if sortType != 0 { switch math.Abs(float64(sortType)) { case 1: if sortType < 0 { sql += " ORDER BY t1.month_sales DESC" } else { sql += " ORDER BY t1.month_sales" } case 2: if sortType < 0 { sql += " ORDER BY t1.distance DESC" } else { sql += " ORDER BY t1.distance" } } } sql += ` LIMIT ? OFFSET ? ` sqlParams = append(sqlParams, pageSize, offset) txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if err = dao.GetRowsTx(txDB, &results, sql, sqlParams...); err == nil { pagedInfo = &model.PagedInfo{ TotalCount: dao.GetLastTotalRowCount2(db, txDB), Data: results, } dao.Commit(db, txDB) //if radius > 0 { // var newShopList []*QueryPageSkusResult // task := tasksch.NewParallelTask("", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx, // func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { // v := batchItemList[0].(*QueryPageSkusResult) // if radius > 0 { // result, _ := api.AutonaviAPI.GetCoordinateFromAddressAll(v.Address, v.CityName) // distance := jxutils.EarthDistance(lng, lat, result.Lng, result.Lat) // if utils.Float64TwoInt(math.Round(distance*1000)) < radius { // retVal = []*QueryPageSkusResult{v} // } // } else { // retVal = []*QueryPageSkusResult{v} // } // return retVal, err // }, results) // tasksch.HandleTask(task, nil, true).Run() // result, _ := task.GetResult(0) // for _, v := range result { // newShopList = append(newShopList, v.(*QueryPageSkusResult)) // } // pagedInfo.Data = newShopList //} else { // pagedInfo.Data = results //} } else { dao.Rollback(db, txDB) } return pagedInfo, err } func GetPageBrands(ctx *jxcontext.Context) (brands []*model.PageBrand, err error) { var ( db = dao.GetDB() ) //db.Db = orm.NewOrmUsingDB("c4beta") sql := ` SELECT * FROM page_brand ` dao.GetRows(db, &brands, sql) return brands, err } func AddStoreMapAudit(ctx *jxcontext.Context, storeID, vendorID int, vendorOrgCode, vendorStoreID, vendorStoreName, vendorAccount, vendorPasswaord string) (err error) { var ( db = dao.GetDB() storeMapAudit = &model.StoreMapAudit{ StoreID: storeID, VendorID: vendorID, VendorOrgCode: vendorOrgCode, VendorStoreID: vendorStoreID, VendorStoreName: vendorStoreName, VendorAccount: vendorAccount, } ) if vendorPasswaord != "" { if configList, err := dao.QueryConfigs(db, "jxKeyIV", model.ConfigTypeSys, ""); err == nil && len(configList) > 0 { aesKey, iv := configList[0].Value, configList[0].Value if data, err2 := utils.AESCBCEncpryt([]byte(vendorPasswaord), []byte(aesKey), []byte(iv)); err2 == nil { vendorPasswaord = base64.StdEncoding.EncodeToString(data) } } storeMapAudit.VendorPasswaord = vendorPasswaord } dao.WrapAddIDCULDEntity(storeMapAudit, ctx.GetUserName()) if err = dao.CreateEntity(db, storeMapAudit); err == nil { //发消息 var ( userIDMap = make(map[string]string) ) store, _ := dao.GetStoreDetail(db, storeID, vendorID, "") operatorRoleList := []string{store.OperatorRole, store.OperatorRole2, store.OperatorRole3} for _, vv := range operatorRoleList { var ( roleList []*authz.RoleInfo ) if vv != "" { roleList = append(roleList, autils.NewRole(vv, 0)) if userIDMap2, err := GetRolesUserList(jxcontext.AdminCtx, roleList); err == nil { for _, w := range userIDMap2 { for _, ww := range w { userIDMap[ww] = ww } } } } noticeMsg := fmt.Sprintf("您有负责的商家申请授权,请尽快审核!门店ID :[%d],门店名:[%s],申请平台:[%v]", store.ID, store.Name, model.VendorChineseNames[vendorID]) user2, err := dao.GetUserByID(db, "mobile", store.MarketManPhone) if err == nil { userIDMap[user2.UserID] = user2.UserID for _, v := range userIDMap { if api.DingDingAPI.GetToken() != "" { ddmsg.SendUserMessage(dingdingapi.MsgTyeText, v, "您有商家申请授权!", noticeMsg) } } } } } return err } func AuditStoreMap(ctx *jxcontext.Context, ID int, vendorOrgCode, vendorStoreID string, auditStatus int, comment string) (err error) { var ( db = dao.GetDB() storeMapAudit = &model.StoreMapAudit{} ) storeMapAudit.ID = ID err = dao.GetEntity(db, storeMapAudit) if err != nil { return err } retVal, err := GetVendorStore(ctx, storeMapAudit.VendorID, vendorOrgCode, vendorStoreID) if err != nil { return err } if retVal == nil { return fmt.Errorf("未在平台上查询到此门店,请确认平台账号和平台门店ID!") } if auditStatus == model.StoreMapAuditStatusPass { if storeMapAudit.VendorOrgCode == "" && vendorOrgCode == "" { return fmt.Errorf("请选择平台账号进行绑定!") } if vendorStoreID == "" { return fmt.Errorf("请输入绑定的平台门店ID!") } storeMap := &model.StoreMap{ VendorStoreID: vendorStoreID, IsSync: 0, AutoPickup: 1, DeliveryCompetition: 1, PricePercentage: 100, } _, err = AddStoreVendorMap(ctx, db, storeMapAudit.VendorID, vendorOrgCode, storeMapAudit.StoreID, storeMap, false) } else { if comment == "" { fmt.Errorf("审核不通过请输入原因!") } } storeMapAudit.AuditStatus = auditStatus storeMapAudit.AuditAt = time.Now() storeMapAudit.AuditOperator = ctx.GetUserName() dao.UpdateEntity(db, storeMapAudit, "AuditStatus", "AuditAt", "AuditOperator") return err } func GetStoreMapAudit(ctx *jxcontext.Context, storeIDs, vendorIDs, auditStatuss []int, fromTime, toTime string, offset, pageSize int) (page *model.PagedInfo, err error) { return dao.GetStoreMapAudit(dao.GetDB(), storeIDs, vendorIDs, auditStatuss, utils.Str2Time(fromTime), utils.Str2Time(toTime), offset, pageSize) } func GetBrandUser(ctx *jxcontext.Context, brandID int) (brandUsers []*dao.GetBrandUserResult, err error) { return dao.GetBrandUser(dao.GetDB(), brandID, "") } func UpdateBrandUser(ctx *jxcontext.Context, brandID int, userID string, isDel bool) (err error) { var ( db = dao.GetDB() ) brandUsers, err := dao.GetBrandUser(db, brandID, userID) if err != nil { return err } if !isDel { if len(brandUsers) > 0 { return fmt.Errorf("此用户已经绑定了该品牌!") } brandUser := &model.BrandUser{ BrandID: brandID, UserID: userID, } dao.WrapAddIDCULDEntity(brandUser, ctx.GetUserName()) dao.CreateEntity(db, brandUser) } else { if len(brandUsers) == 0 { return fmt.Errorf("此用户没有绑定该品牌!") } brandUser := brandUsers[0].BrandUser brandUser.DeletedAt = time.Now() dao.UpdateEntity(db, &brandUser, "DeletedAt") } return err } func UpdateOrCreateCourierStoresByBrand(ctx *jxcontext.Context, brandID, vendorID int) (hint string, err error) { var ( db = dao.GetDB() ) stores, _ := dao.GetStoreList(db, nil, nil, nil, []int{brandID}, nil, "") task := tasksch.NewParallelTask("UpdateOrCreateCourierStoresByBrand", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { var resultList []interface{} store := batchItemList[0].(*model.Store) errList := errlist.New() v := partner.GetDeliveryPlatformFromVendorID(vendorID) if v.Use4CreateWaybill { if _, ok := v.Handler.(partner.IDeliveryUpdateStoreHandler); ok { storeDetail, err2 := dao.GetStoreDetail2(db, store.ID, "", vendorID) if err = err2; err2 == nil { isNeedAdd := storeDetail.VendorStoreID == "" if isNeedAdd { storeDetail.VendorID = vendorID storeDetail.VendorStoreID = utils.Int2Str(storeDetail.ID) } if _, err = updateOrCreateCourierStore(ctx, storeDetail); err == nil && isNeedAdd { storeCourier := &model.StoreCourierMap{ VendorStoreID: storeDetail.VendorStoreID, Status: model.StoreStatusOpened, AuditStatus: storeDetail.AuditStatus, VendorStoreName: storeDetail.Name, } if storeDetail.AuditStatus != model.StoreAuditStatusOnline { storeCourier.Status = model.StoreStatusDisabled } if _, err = addStoreCourierMap(ctx, db, storeDetail.ID, storeDetail.VendorID, storeCourier, false); err == nil { resultList = append(resultList, 1) } } errList.AddErr(err) } } } return resultList, errList.GetErrListAsOne() }, stores) tasksch.HandleTask(task, nil, true).Run() hint = task.ID return hint, err } //StoreStatusDisabled = -2 //StoreStatusClosed = -1 //StoreStatusHaveRest = 0 //StoreStatusOpened = 1 // 定时任务更新门店信息,添加storeStatuss参数,只查询和同步营业的门店 1营业0临时休息-1休息-2禁用 func RefreshStoreIsOnline(ctx *jxcontext.Context) (err error) { var ( db = dao.GetDB() ) stores, _ := dao.GetStoresMapList(db, []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, []int{model.StoreStatusOpened, model.StoreStatusHaveRest}, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") task := tasksch.NewParallelTask("RefreshStoreBind", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { storeMap := batchItemList[0].(*model.StoreMap) if handler := CurVendorSync.GetStoreHandler(storeMap.VendorID); handler != nil { if store, err := handler.ReadStore(ctx, storeMap.VendorOrgCode, storeMap.VendorStoreID, ""); err == nil && store != nil { if store.Status != model.StoreStatusDisabled { storeMap.IsOnline = 1 } else { storeMap.IsOnline = -1 storeMap.Status = model.StoreStatusClosed } dao.UpdateEntity(db, storeMap, "IsOnline", "Status") store := fmt.Sprintf("门店id:%d,门店名称:%s,第三方门店状态:%d,本地门店修改后状态:%d,第三方平台Id(美团,饿了么...):%d", store.Store.ID, store.Store.Name, store.Store.Status, storeMap.IsOnline, storeMap.VendorID) event.AddOperateEvent(ctx, ctx.GetTrackInfo(), store, "", "", 10, "UpdateStore") } } return retVal, err }, stores) tasksch.HandleTask(task, nil, true).Run() task.GetID() return err } func GetBrandCategoryMap(ctx *jxcontext.Context, parentID, level int, brandID int) (brandCatMaps []*model.BrandCategoryMap, err error) { db := dao.GetDB() brandCatMaps, err = dao.GetBrandCategoryMap(db, parentID, level, brandID, 0) if err != nil { return nil, err } if ctx.GetLoginType() != weixin.AuthTypeMP && ctx.GetLoginType() != weixin.AuthTypeMini && ctx.GetLoginType() != weixin.AuthTypeWxApp && ctx.GetLoginType() != weixin.AuthTypeWxAppCaishi && ctx.GetLoginType() != auth2.AuthTypeMobile { return brandCatMaps, err } return brandCatMaps, err } func AddBrandCategoryMap(ctx *jxcontext.Context, brandCategoryMap *model.BrandCategoryMap) (result *model.BrandCategoryMap, err error) { var ( db = dao.GetDB() ) if brandCategoryMap.Level != 1 { brandCatMaps, _ := dao.GetBrandCategoryMap(db, -1, 0, brandCategoryMap.BrandID, brandCategoryMap.CategoryID) if len(brandCatMaps) > 0 { return nil, fmt.Errorf("已存在绑定的京西分类,分类名:[%v]", brandCatMaps[0].BrandCategoryName) } } brandCategoryMap.BrandCategoryName = strings.Trim(brandCategoryMap.BrandCategoryName, " ") dao.WrapAddIDCULDEntity(brandCategoryMap, ctx.GetUserName()) txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if err = dao.CreateEntity(db, brandCategoryMap); err != nil { dao.Rollback(db, txDB) return nil, err } dao.Commit(db, txDB) result = brandCategoryMap if brandCategoryMap.CategoryID != 0 { var storeIDList []int if stores, _ := dao.GetStoreList(db, nil, nil, nil, []int{brandCategoryMap.BrandID}, nil, ""); len(stores) > 0 { for _, v := range stores { storeIDList = append(storeIDList, v.ID) } if len(storeIDList) > 0 { SetStoreCategorySyncStatus2(db, storeIDList, []int{brandCategoryMap.CategoryID}, model.SyncFlagModifiedMask) } } } // _, err = CurVendorSync.SyncCategory(ctx, nil, cat.ID, false, userName) return result, err } func UpdateBrandCategoryMap(ctx *jxcontext.Context, ID int, brandCategoryMap *model.BrandCategoryMap, isDelete bool) (num int64, err error) { var ( db = dao.GetDB() valid = make(map[string]interface{}) brandCategoryMap2 = &model.BrandCategoryMap{} storeIDList []int ) brandCategoryMap2.ID = ID if err = dao.GetEntity(db, brandCategoryMap2); err != nil { return 0, err } if brandCategoryMap.BrandCategoryName != "" { valid["brandCategoryName"] = brandCategoryMap.BrandCategoryName } if brandCategoryMap.CategoryID != 0 { valid["categoryID"] = brandCategoryMap.CategoryID if !isDelete { brandCatMaps, _ := dao.GetBrandCategoryMap(db, -1, 0, brandCategoryMap2.BrandID, brandCategoryMap.CategoryID) if len(brandCatMaps) > 0 { for _, v := range brandCatMaps { if v.ID != ID { return 0, fmt.Errorf("已存在绑定的京西分类,分类名:[%v]", brandCatMaps[0].BrandCategoryName) } } } } } if brandCategoryMap.Level != 0 { valid["level"] = brandCategoryMap.Level if brandCategoryMap.Level == 2 { cat2, _ := dao.GetCategories(db, -1, 0, []int{brandCategoryMap.CategoryID}, false) if len(cat2) > 0 { if cat2[0].ParentID != brandCategoryMap.ParentID { return 0, fmt.Errorf("此二级分类只能绑定到对应一级分类下!") } } } } if stores, _ := dao.GetStoreList(db, nil, nil, nil, []int{brandCategoryMap.BrandID}, nil, ""); len(stores) > 0 { for _, v := range stores { storeIDList = append(storeIDList, v.ID) } } if isDelete { valid["deletedAt"] = time.Now() valid["updatedAt"] = time.Now() valid["lastOperator"] = ctx.GetUserName() //如果是1级分类则删除下面的子分类 var catIDs []int if brandCategoryMap2.Level == 1 { brandCatMaps, _ := dao.GetBrandCategoryMap(db, brandCategoryMap2.CategoryID, 2, brandCategoryMap2.BrandID, 0) if len(brandCatMaps) > 0 { for _, v := range brandCatMaps { catIDs = append(catIDs, v.CategoryID) v.DeletedAt = time.Now() v.LastOperator = ctx.GetUserName() dao.UpdateEntity(db, v, "DeletedAt", "LastOperator") } } } catIDs = append(catIDs, brandCategoryMap.CategoryID) if len(storeIDList) > 0 { SetStoreCategorySyncStatus2(db, storeIDList, catIDs, model.SyncFlagModifiedMask) } } else { if len(storeIDList) > 0 { SetStoreCategorySyncStatus2(db, storeIDList, []int{brandCategoryMap.CategoryID, brandCategoryMap2.CategoryID}, model.SyncFlagModifiedMask) } } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if num, err = dao.UpdateEntityLogically(db, brandCategoryMap2, valid, ctx.GetUserName(), nil); err != nil { dao.Rollback(db, txDB) return 0, err } dao.Commit(db, txDB) return num, err } func ReorderBrandCategories(ctx *jxcontext.Context, parentID, brandID int, categoryIDs []int) (err error) { var ( brandCatsMap []*model.BrandCategoryMap storeIDList []int ) db := dao.GetDB() brandCatsMap, err = dao.GetBrandCategoryMap(db, parentID, 0, brandID, 0) catsLen := len(brandCatsMap) if catsLen != len(categoryIDs) { return ErrInputCatsDoesntMatch } catsMap := make(map[int]*model.BrandCategoryMap, catsLen) for _, cat := range brandCatsMap { catsMap[cat.CategoryID] = cat } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() for k, v := range categoryIDs { if catsMap[v] == nil { dao.Rollback(db, txDB) return fmt.Errorf("分类:%d不在%d分类下", v, parentID) } catsMap[v].BrandCategorySeq = k catsMap[v].LastOperator = ctx.GetUserName() if _, err = dao.UpdateEntity(db, catsMap[v]); err != nil { dao.Rollback(db, txDB) return err } } dao.Commit(db, txDB) if stores, _ := dao.GetStoreList(db, nil, nil, nil, []int{brandID}, nil, ""); len(stores) > 0 { for _, v := range stores { storeIDList = append(storeIDList, v.ID) } } if len(storeIDList) > 0 { SetStoreCategorySyncStatus2(db, storeIDList, categoryIDs, model.SyncFlagModifiedMask) } if err == nil { CurVendorSync.SyncStoresCategory(ctx, db, nil, storeIDList, false, true, true) } return err } func InsertBrandCategories(ctx *jxcontext.Context, brandID int) (err error) { var ( db = dao.GetDB() ) if err = dao.DeleteBrandCategroies2(db, brandID); err == nil { err = dao.InsertBrandCategories(db, ctx.GetUserName(), brandID) } return err } func UpdateStoreTemplate(ctx *jxcontext.Context, storeID int, content, sound string) (err error) { var ( db = dao.GetDB() store = &model.Store{} ) store.ID = storeID dao.GetEntity(db, store) configs, _ := dao.QueryConfigs(db, "jxPrintTemplate", model.ConfigTypeSys, "") sysTemp := configs[0].Value if strings.EqualFold(content, sysTemp) { store.PrinterTemplate = "" } else { store.PrinterTemplate = content } if !strings.EqualFold(sound, store.PrinterSound) { store.PrinterSound = sound } _, err = dao.UpdateEntity(db, store, "PrinterTemplate", "PrinterSound") return err } //条件过滤 B2B、物料店 func FilterByB2B(locationList []*common.Store4User) (retVal []*common.Store4User, errCode string, err error) { //userAuth, err := auth2.GetTokenInfo(token) // //if err != nil { // // return nil, "", err // //} // //user, total, err := dao.GetUsers(dao.GetDB(), 1, "", []string{userAuth.UserID}, nil, nil, 0, 1) // //if err != nil { // // return nil, "", err // //} // 获取位置附近门店列表 storeIDs := make([]int, 0, len(locationList)) for _, v := range locationList { storeIDs = append(storeIDs, v.ID) } // 判断门店是不是b2b门店,如果是,用户必须为系统管理员(门店老板和运营人员) store, err := dao.GetStoreList(dao.GetDB(), storeIDs, nil, nil, nil, nil, "") if err != nil { return nil, "", err } isMatterStore := false for _, v := range storeIDs { if v == model.MatterStoreID { isMatterStore = true } } result := make([]*common.Store4User, 0, 0) for _, v := range store { for _, s := range locationList { if v.ID == s.ID { //if (v.BrandID == model.B2BNumberId || isMatterStore) && user[0].Type == model.YES { // 普通用户进入物料店和b2b店 if v.BrandID == model.B2BNumberId || isMatterStore { // 普通用户进入物料店和b2b店 continue } else { result = append(result, s) } } } } //if total != model.YES { // return result, "", errors.New("") //} //if user[0].Type != model.YES { // return locationList, "", nil //} else { return result, "", err //} } //首页信息展示 func GetHomePageByLocation(ctx *jxcontext.Context, lng, lat float64, needWalkDistance bool) (interface{}, string, error) { //获取门店信息 var ( storeID []int storeScore = 0 storeInfos []StoreInfo storeDeductionInfo StoreDeductionInfo storeDeductionInfos []StoreDeductionInfo storeSkuInfo StoreSkuInfo StoreSkuInfos []StoreSkuInfo homePages []HomePageInfos ) locationList, err := common.GetStoreListByLocation(ctx, lng, lat, 20000, needWalkDistance, false, 0) if err != nil { return nil, "经纬度获取推荐门店失败", err } //if token != "" { //权限过滤门店 //filterStore, _, err := FilterByB2B(locationList, token) filterStore, _, err := FilterByB2B(locationList) if err != nil { return nil, "权限过滤门店失败", err } for _, v := range filterStore { storeID = append(storeID, v.ID) //获取门店品牌信息 brandInfos, err := dao.GetStoreBrandInfos(v.ID) if err != nil { return nil, "获取门店品牌信息失败", err } //获取门店每周评分 if scores, err := GetWeeklyStoreScore(v.ID, 0); err == nil && len(scores) > 0 { storeScore = scores[0].TotalScore } storeInfo := StoreInfo{ StoreID: v.ID, StoreName: v.Name, OpenTime1: v.OpenTime1, CloseTime1: v.CloseTime1, OpenTime2: v.OpenTime2, CloseTime2: v.CloseTime2, Status: v.Status, Distance: v.Distance, Address: v.Address, BrandName: brandInfos.Name, BrandLogo: brandInfos.Logo, StoreWeeklyScore: storeScore, } storeInfos = append(storeInfos, storeInfo) //获取门店减免策略 storePolicy, err := GetStoreVendorMaps(ctx, dao.GetDB(), v.ID, 9) if err != nil { return nil, "获取门店减免策略失败", err } for _, k := range storePolicy { if k.StoreID == v.ID { storeDeductionInfo = StoreDeductionInfo{ StoreID: k.StoreID, DeliveryFeeDeductionSill: k.DeliveryFeeDeductionSill, DeliveryFeeDeductionFee: k.DeliveryFeeDeductionFee, } } storeDeductionInfos = append(storeDeductionInfos, storeDeductionInfo) } //} //获取热销商品 topSkusInfo, err := GetTopSkusByStoreIDs(ctx, storeID) if err != nil { return nil, "获取热销商品失败", err } for _, j := range topSkusInfo { storeSkuInfo = StoreSkuInfo{ StoreID: j.StoreID, SkuID: j.SkuID, SkuName: j.Name, SkuStatus: j.Status, BestSeller: j.BestSeller, Img: j.Img, Price: j.Price, Unit: j.Unit, } StoreSkuInfos = append(StoreSkuInfos, storeSkuInfo) } for _, i := range storeInfos { homePage := HomePageInfos{} i := i homePage.StoreInfo = i for _, j := range storeDeductionInfos { j := j if i.StoreID == j.StoreID { homePage.StoreDeductionInfo = append(homePage.StoreDeductionInfo, j) } else { continue } } for _, k := range StoreSkuInfos { k := k if i.StoreID == k.StoreID { homePage.StoreSkuInfo = append(homePage.StoreSkuInfo, k) } else { continue } } homePages = append(homePages, homePage) } } return homePages, "", nil } // 抖店定时任务 主动拉取门店审核状态信息并更新 func UpdateStorePoiStatus(ctx *jxcontext.Context) error { var ( db = dao.GetDB() ) storeList, _ := dao.GetStoresMapList(db, []int{model.VendorIDDD}, nil, []int{model.StoreStatusOpened, model.StoreStatusHaveRest}, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "") task := tasksch.NewParallelTask("UpdateDDStorePoiAuditInfo", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { storeMap := batchItemList[0].(*model.StoreMap) if handler := CurVendorSync.GetStoreHandler(storeMap.VendorID); handler != nil { if storePoiStatus, err := handler.GetStoreStatus(ctx, storeMap.VendorOrgCode, storeMap.StoreID, storeMap.VendorStoreID); err != nil { return nil, err } else { if storePoiStatus == tiktok_api.PoiAuditStateSuccessBind { storeMap.AuditStatus = model.StoreAuditStatusCreated } else if storePoiStatus == tiktok_api.PoiAuditStateReject { storeMap.AuditStatus = model.StoreAuditStatusRejected } dao.UpdateEntity(db, storeMap, "AuditStatus") store := fmt.Sprintf("门店ID:%d,门店名称:%s,抖店平台审核状态:%d,抖店平台门店ID:%s", storeMap.StoreID, storeMap.StoreName, storeMap.AuditStatus, storeMap.VendorStoreID) event.AddOperateEvent(ctx, ctx.GetTrackInfo(), store, "", "", 10, "UpdateStore") } } return retVal, err }, storeList) tasksch.HandleTask(task, nil, true).Run() task.GetID() return nil } //抖音定时任务 func UpdateStoreRelInformation(ctx *jxcontext.Context) error { var ( tempRelIDs map[int64]string db = dao.GetDB() errList = errlist.New() tempIDs map[string]map[int64]string FreightTemplate = &model.FreightTemplate{} ) if vendorOrgCodes, err := dao.GetVendorOrgCode(db, model.VendorIDDD, "", "platform"); err != nil { return fmt.Errorf("获取vendorOrgCodes失败: %v", err) } else { for _, v := range vendorOrgCodes { tempRelIDs, err = tiktok_store.GetAllVendorStoreMap(ctx, v.VendorOrgCode) //平台与京西门店映射关系 if err != nil { return err } tempIDs[v.VendorOrgCode] = tempRelIDs } for i, j := range tempIDs { for m, n := range j { //m-vendorStoreID n-storeID subTask := tasksch.NewSeqTask(fmt.Sprintf("UpdateStoreRelInformation 平台门店(%d) 本地门店(%s):同步本地相关信息", m, n), ctx, func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: //(1)仓库以及电子围栏 if bindWarehouse, err := tiktok_store.GetWarehouseByStore(i, m); err != nil { errList.AddErr(fmt.Errorf("同步任务: 获取门店(%s)绑定的仓库以及电子围栏失败:%v", n, err)) } else if len(bindWarehouse[i][0].OutFenceIds) > 0 { for _, s := range bindWarehouse[i][0].OutFenceIds { if s == n { FreightTemplate.FenceID = s } } } else { FreightTemplate.WarehouseID = bindWarehouse[i][0].WarehouseId } case 1: //(2)运费模板 if bindFreightIDs, err := tiktok_store.GetStoreFreight(i, m); err != nil { globals.SugarLogger.Debugf("同步任务: 获取门店(%s) 绑定运费模板出错:%v", n, err) errList.AddErr(fmt.Errorf("同步任务: 获取门店(%s) 绑定运费模板出错:%v", n, err)) } else { FreightTemplate.TemplateID = bindFreightIDs } case 2: //(3)限售模板 if bindTradeLimitID, err := tiktok_store.GetStoreSaleLimit(i, m); err != nil { globals.SugarLogger.Debugf("同步任务: 获取门店(%s) 限售模板出错:%v", n, err) errList.AddErr(fmt.Errorf("同步任务: 获取门店(%s) 限售模板出错:%v", n, err)) } else { FreightTemplate.TradeLimitID = bindTradeLimitID } } return nil, nil }, 4) tasksch.ManageTask(subTask).Run() //time.Sleep(2 * time.Second) FreightTemplate.VendorStoreID = utils.Int64ToStr(m) FreightTemplate.StoreID = utils.Str2Int(n) if err := dao.ReplaceInsertFreight(FreightTemplate); err != nil { if err1 := dao.InsertItemFreight(FreightTemplate); err1 != nil { globals.SugarLogger.Debug("UpdateStoreRelInformation 同步数据库错误信息:%v", err1) } } //if _, err := dao.UpdateEntity(db, FreightTemplate, "VendorStoreID", "StoreID", "TemplateID", "WarehouseID", "FenceID", "TradeLimitID"); err != nil { // if err1 := dao.CreateEntity(db, FreightTemplate); dao.IsDuplicateError(err1) || err1 != nil { // errList.AddErr(fmt.Errorf("创建操作,同步进数据库错误信息:%v", err1)) // } else { // errList.AddErr(fmt.Errorf("更新操作,同步进数据库错误信息:%v", err)) // } //} } } } lastErr := errList.GetErrListAsOne() if lastErr != nil { globals.SugarLogger.Debugf("定时任务同步抖店门店信息到本地 相关提示:%s", lastErr) //return lastErr } return nil } //获取抖店门店建议范围 (即电子围栏) func GetDDScope(ctx *jxcontext.Context, storeID int, vendorStoreID string) ([]warehouse_getFences_response.FencesItem, error) { if storeID == 0 || len(vendorStoreID) == 0 { return nil, errors.New("storeID,vendorStoreID 必填") } if storeMap, err := GetVendorOrgCode(ctx, dao.GetDB(), storeID, model.VendorIDDD, vendorStoreID); err != nil { return nil, errors.New(fmt.Sprintf("获取vendorOrgCode失败,请检查数据或重试:%v", err)) } else { if bind, err := tiktok_store.GetWarehouseByStore(storeMap[0].VendorOrgCode, utils.Str2Int64(vendorStoreID)); err != nil { return nil, errors.New(fmt.Sprintf("获取门店(%d) 仓库以及电子围栏信息失败:%v", storeID, err)) } else { if len(bind) != 0 && len(bind[vendorStoreID][0].OutFenceIds) != 0 { if resp, err := tiktok_store.GetFence(storeMap[0].VendorOrgCode, bind[vendorStoreID][0].OutFenceIds); err != nil { return nil, errors.New(fmt.Sprintf("获取门店(%d) 电子围栏失败:%v", storeID, err)) } else { return resp, nil } } } } return nil, nil } //获取 VendorOrgCode func GetVendorOrgCode(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, vendorStoreID string) (storeMap []*model.StoreMap, err error) { cond := map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorStoreID: vendorStoreID, } if vendorID != -1 { cond[model.FieldVendorID] = vendorID } return storeMap, dao.GetEntitiesByKV(db, &storeMap, cond, false) } //批量辅助创建电子围栏 func AssistCreateFence(relInfo map[string][]tiktok_store.RelInfo) (string, error) { var ( tempFenceID string tStr1 = "" tStr2 = "" endStr = "" db = dao.GetDB() errList = errlist.New() ) for k, v := range relInfo { for _, i := range v { FreightTemplate := &model.FreightTemplate{ StoreID: utils.Str2Int(i.StoreID), VendorStoreID: i.VendorStoreID, } tempStoreID := utils.Str2Int64(i.StoreID) tempVendorStoreID := utils.Str2Int64(i.VendorStoreID) //预处理门店无配送范围情况 if localStore, err := dao.GetStoreDetail(db, utils.Str2Int(i.StoreID), model.VendorIDDD, k); err == nil { if localStore.DeliveryRangeType == tiktok_store.LocalShapeCircular && utils.Str2Int(localStore.DeliveryRange) <= 0 { tStr1 += i.StoreID + "," } else if localStore.DeliveryRangeType == tiktok_store.LocalShapePolygon { tempStr := strings.Split(localStore.DeliveryRange, ";") if len(tempStr) < 3 { tStr2 += i.StoreID + "," } } endStr = tStr1 + "," + tStr2 if len(endStr) > 0 { globals.SugarLogger.Debugf("京西平台没有配送范围的门店ID=%s", endStr) } } if bindFence, err := tiktok_store.GetWarehouseByStore(k, utils.Str2Int64(i.VendorStoreID)); err == nil && (len(bindFence) > 0 && len(bindFence[i.VendorStoreID][0].OutFenceIds) > 0) { tempFenceID = bindFence[i.VendorStoreID][0].OutFenceIds[0] if err1 := tiktok_store.UpdateFenceByStore(k, tempFenceID, i.StoreID); err1 != nil { errList.AddErr(fmt.Errorf("平台门店(%s),门店(%s)更新电子围栏失败:%v", i.VendorStoreID, i.StoreID, err1)) } else { FreightTemplate.FenceID = tempFenceID } } else { if fenceID, err := tiktok_store.CreateFenceByStore(k, tempStoreID); err != nil { if strings.Contains(err.Error(), "该电子围栏已经存在,请使用修改接口") { //兜底处理 if err1 := tiktok_store.BindFenceByStore(k, tempVendorStoreID, []string{i.StoreID}); err1 == nil { if err2 := tiktok_store.UpdateFenceByStore(k, i.StoreID, i.StoreID); err2 != nil { errList.AddErr(fmt.Errorf("平台门店(%s),门店(%s)更新电子围栏失败:%v", i.VendorStoreID, i.StoreID, err1)) } else { FreightTemplate.FenceID = i.StoreID } } errList.AddErr(fmt.Errorf("平台门店(%s),门店(%s)创建电子围栏失败:%v", i.VendorStoreID, i.StoreID, err)) } } else if len(fenceID) > 0 { if err := tiktok_store.BindFenceByStore(k, tempVendorStoreID, []string{i.StoreID}); err != nil { errList.AddErr(fmt.Errorf("平台门店(%s),门店(%s)绑定电子围栏失败:%v", i.VendorStoreID, i.StoreID, err)) } else { FreightTemplate.FenceID = tempFenceID } } } if err := dao.ReplaceInsertFreight(FreightTemplate); err != nil { if err1 := dao.InsertItemFreight(FreightTemplate); err1 != nil { globals.SugarLogger.Debug("同步数据库错误信息:%v", err1) } } } //if err := dao.CreateEntity(db, FreightTemplate); dao.IsDuplicateError(err) || err != nil { // if _, err1 := dao.UpdateEntity(db, FreightTemplate, "FenceID"); err1 != nil { // globals.SugarLogger.Debugf("db update storeID,vendorStoreID defeat on :%v", err1) // //errList.AddErr(fmt.Errorf("更新操作,同步进数据库错误信息:%v", err1)) // } else { // globals.SugarLogger.Debugf("db create storeID,vendorStoreID defeat on :%v", err1) // //errList.AddErr(fmt.Errorf("创建操作,同步进数据库错误信息:%v", err)) // } //} } if errList.GetErrListAsOne() != nil { if len(endStr) > 0 { return fmt.Sprintf("批量创建电子围栏错误,请根据提示处理:%v,#门店%s的配送范围不合法,请处理后再进行创建#", errList.GetErrListAsOne(), endStr), nil } else { return fmt.Sprintf("批量创建电子围栏错误,请根据提示处理:%v", errList.GetErrListAsOne()), nil } } return "", nil } //批量创建包邮运费模板 func BatchCreateFreeShipTemplate(relInfo map[string][]tiktok_store.RelInfo, shipFee int64) (string, error) { errList := errlist.New() for k, v := range relInfo { for _, i := range v { if bindFreightID, err := tiktok_store.GetStoreFreight(k, utils.Str2Int64(i.VendorStoreID)); err != nil || bindFreightID == 0 { if err := tiktok_store.CreateBindFreeShipTemplate(k, utils.Str2Int(i.StoreID), shipFee); err != nil { errList.AddErr(err) } } else { _ = tiktok_store.ShopBindStoreFreight(k, utils.Str2Int64(i.VendorStoreID), bindFreightID) globals.SugarLogger.Debugf("进入更新包邮模板操作") if err := tiktok_store.UpdateFreeShipTemplate(k, utils.Str2Int(i.StoreID), shipFee); err != nil { errList.AddErr(err) } } } } if errList.GetErrListAsOne() != nil { return fmt.Sprintf("%v", errList.GetErrListAsOne()), nil } return "", nil } //批量配置抖音门店自动呼叫运力 func SetStoreAutoCallRider(vendorOrgCode string, openIDs, closeIDs []int64) (string, error) { var errList = errlist.New() if len(openIDs) > 0 { for _, i := range openIDs { if err := tiktok_store.SetStoreAutoCallRider(vendorOrgCode, tiktok_api.AutoCallRiderOpen, i); err != nil { errList.AddErr(fmt.Errorf("%d err:%v", i, err)) } } } if len(closeIDs) > 0 { for _, j := range closeIDs { if err := tiktok_store.SetStoreAutoCallRider(vendorOrgCode, tiktok_api.AutoCallRiderClose, j); err != nil { errList.AddErr(fmt.Errorf("%d err:%v", j, err)) } } } if errList.GetErrListAsOne() != nil { return fmt.Sprintf("部分门店配置自动运力失败:%s", utils.Format4Output(errList.GetErrListAsOne(), false)), nil } return "", nil } // CreateDDWarehouse 创建抖音门店区域仓 func CreateDDWarehouse(vendorOrgCode string, vendorStoreID, storeID int64) error { var errList errlist.ErrList bind, err := tiktok_store.GetWarehouseByStore(vendorOrgCode, vendorStoreID) globals.SugarLogger.Debugf("CreateDDWarehouse bind=%s", utils.Format4Output(bind, false)) if err == nil && bind[utils.Int64ToStr(vendorStoreID)][0].WarehouseId > 0 { return nil } warehouseID, err1 := tiktok_store.CreateWarehouse(vendorOrgCode, storeID) if err1 != nil || warehouseID == 0 { errList.AddErr(fmt.Errorf("门店(%d) 创建仓库:%v", storeID, err1)) //globals.SugarLogger.Debugf("CreateDDWarehouse hint=%v", fmt.Errorf("门店(%d) 创建仓库失败:%v", storeID, err1)) } err1 = tiktok_store.BindStoreWarehouse(vendorOrgCode, utils.Int64ToStr(storeID), vendorStoreID) if err1 != nil { //仓库绑定通过自定义外部ID errList.AddErr(fmt.Errorf("门店(%d) 绑定仓库:%v", storeID, err1)) } return errList.GetErrListAsOne() } type MtRelInfo struct { PoiCode string `json:"poi_code"` PicUrl string `json:"pic_url"` Address string `json:"address"` } //[]{PoiCode:"16594433",PicUrl:"http://p0.meituan.net/business/e23d337029fcf74f5a7bcea4e01dac98219292.jpg"} //批量获取美团门店logos func BatchGetMTStoreLogos(vendorOrgCode string, mtStoreIDs []string) (storeLogos []MtRelInfo) { for _, v := range mtStoreIDs { if storeInfos, err1 := mtwm.GetAPI(vendorOrgCode, 0, "").PoiGet(v); err1 != nil { storeLogos = append(storeLogos, MtRelInfo{ PoiCode: v, PicUrl: " ", }) } else { if len(storeInfos.PicURL) != 0 { storeLogos = append(storeLogos, MtRelInfo{ PoiCode: v, PicUrl: storeInfos.PicURL, }) } } } return storeLogos } //批量更新美团门店logos func BatchUpdateMTStoreLogos(vendorOrgCode string, relInfo []MtRelInfo) (hint string) { param := map[string]interface{}{} if len(relInfo[0].PicUrl) > 0 { param["pic_url"] = relInfo[0].PicUrl } for _, v := range relInfo { if len(v.PicUrl) == 0 && len(v.Address) == 0 { return "暂无需要更新数据" } if len(v.Address) > 0 { param["address"] = v.Address } apiObj := mtwm.GetAPI(vendorOrgCode, 0, v.PoiCode) if err := apiObj.PoiSave(v.PoiCode, param); err != nil { hint += fmt.Sprintf("%s:%v\n", v.PoiCode, err) } } if len(hint) != 0 { return hint } return "" } type TaoBindInfo struct { storeID int `json:"storeID"` VendorStoreID string `json:"vendorStoreID"` VendorStoreName string `json:"vendorStoreName"` Status string `json:"status"` //渠道营业状态 } var TaoStoreStatus = map[string]int{ tao_vegetable.StoreOnlineWord: model.StoreStatusOpened, tao_vegetable.StoreOfflineWord: model.StoreStatusClosed, } // SingleBindTaoVegetable 单独绑定淘鲜达平台三方映射 func SingleBindTaoVegetable(ctx *jxcontext.Context, bind []TaoBindInfo, vendorOrgCode string) (error, string) { var ( db *dao.DaoDB errList errlist.ErrList errIDName = make([]string, 0) storeMaps = make([]*model.StoreMap, 0) ) if len(bind) == 0 { return fmt.Errorf("绑定门店数据为空,请检查"), "" } for _, v := range bind { if len(v.VendorStoreID) == 0 || len(v.VendorStoreName) == 0 { errIDName = append(errIDName, v.VendorStoreID) } //else { // if strings.Contains(v.VendorStoreID, "X") { // temp := strings.Split(v.VendorStoreID, "X") // storeID = temp[1] // } else { // return fmt.Errorf("淘鲜达门店ID不合法"), "" // } //} storeMap := &model.StoreMap{ StoreID: v.storeID, VendorID: model.VendorIDTaoVegetable, VendorOrgCode: vendorOrgCode, Status: TaoStoreStatus[v.Status], DeliveryType: model.StoreDeliveryTypeByStore, SyncStatus: 0, VendorStoreName: v.VendorStoreName, MtwmToken: "", MtwmRefreshToken: "", VendorStoreID: v.VendorStoreID, } //跟美团同步 平台调价、调价套餐 var ( cond = map[string]interface{}{ model.FieldStoreID: v.storeID, model.FieldVendorID: model.VendorIDMTWM, } tempMaps []*model.StoreMap ) if err := dao.GetEntitiesByKV(db, &tempMaps, cond, false); err == nil && len(tempMaps) > 0 { storeMap.PricePercentage = tempMaps[0].PricePercentage storeMap.PricePercentagePack = tempMaps[0].PricePercentagePack } storeMaps = append(storeMaps, storeMap) } userName := ctx.GetUserName() for _, k := range storeMaps { dao.WrapAddIDCULDEntity(k, userName) if db == nil { db = dao.GetDB() } txDB, _ := dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db, txDB) panic(r) } }() if err := dao.CreateEntity(db, k); err == nil { errList.AddErr(fmt.Errorf("%s:%v", k.VendorStoreID, err)) dao.Commit(db, txDB) } else { dao.Rollback(db, txDB) } } if len(errIDName) > 0 { errList.AddErr(fmt.Errorf("门店%s Id/名字不合法", errIDName)) } if errList.GetErrListAsOne() != nil { return nil, fmt.Sprintf("批量绑定淘鲜达门店错误:%v", errList.GetErrListAsOne()) } return nil, "" } // ReplaceInsertFreight 操作 freight_template func ReplaceInsertFreight(storeID, templateID, warehouseID, tradeLimitID int, vendorStoreID, fenceID string) error { return dao.ReplaceInsertFreight2(storeID, templateID, warehouseID, tradeLimitID, vendorStoreID, fenceID) } //辅助函数 func String2ArrayInt64(data string) (retVal []int64) { temp := strings.Split(data, ",") for _, v := range temp { retVal = append(retVal, utils.Str2Int64(v)) } return retVal } func String2ArrayString(data string) (retVal []string) { temp := strings.Split(data, ",") for _, v := range temp { retVal = append(retVal, v) } return retVal } func GetVendorStoreBind(vendorStoreId string, vendorId int) (int, error) { return dao.GetCodeAndIDByMeiTuan(vendorStoreId, vendorId) } func BindJxPrintToStore(storeId int64, printSn, printKey string) error { return dao.BindJXPrintToStore(storeId, printSn, printKey) } var ( storeScoreFieldName = []string{ model.FieldStoreOpenTime, model.FieldSaleSkuCount, model.FieldAveragePickupTime, model.FieldBadCommentOrder, model.FieldUnfinishOrder, model.FieldAbsentGoodsOrder, model.FieldPromotionSku, model.FieldFullVendor, model.FieldStoreRange, model.FieldSaleSkuPrice, } ) func GetWeeklyStoreScore(storeID, weekIndexParam int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) { db := dao.GetDB() storeScoreList, err := dao.GetWeeklyStoreScoreList(db, storeID, 1) if err == nil && len(storeScoreList) > 0 { weeklyStoreScoreDataList := []*model.WeeklyStoreScore{} weekDataList := SplitToSingleWeekDataList(storeScoreList) for weekIndex, weekData := range weekDataList { weeklyData := &model.WeeklyStoreScore{} weeklyData.ID = weekIndex weeklyData.ItemTotalScore = 10 weeklyData.StoreID = storeID weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData) weekDataCount := len(weekData) for dayIndex, dayData := range weekData { for _, fieldName := range storeScoreFieldName { srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int) destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int) refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValue+srcFieldValue) } if weekDataCount == 1 { weeklyData.BeginTime = dayData.ScoreDate weeklyData.EndTime = dayData.ScoreDate } else { if dayIndex == 0 { weeklyData.EndTime = dayData.ScoreDate } else if dayIndex == weekDataCount-1 { weeklyData.BeginTime = dayData.ScoreDate } } weeklyData.StoreName = dayData.StoreName } for _, fieldName := range storeScoreFieldName { destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int) refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValue)/float64(weekDataCount)))) } for _, fieldName := range storeScoreFieldName { srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int) destFieldValue := refutil.GetObjFieldByName(weeklyData, model.FieldTotalScore).(int) refutil.SetObjFieldByName(weeklyData, model.FieldTotalScore, destFieldValue+srcFieldValue) } weeklyData.Level = GetStoreScoreLevel(weeklyData.TotalScore) } if weekIndexParam == -1 { outWeeklyStoreScoreDataList = weeklyStoreScoreDataList } else { //fmt.Println("testss", utils.Format4Output(weeklyStoreScoreDataList, false)) outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndexParam]} } } return outWeeklyStoreScoreDataList, err } func SplitToSingleWeekDataList(storeScoreList []*model.StoreScoreEx) (weekDataList [][]*model.StoreScoreEx) { singleWeekData := []*model.StoreScoreEx{} weekIndex := 0 for _, value := range storeScoreList { if weekIndex == 0 { weekIndex = Time2Week(value.ScoreDate) } if weekIndex == Time2Week(value.ScoreDate) { singleWeekData = append(singleWeekData, value) } else { weekDataList = append(weekDataList, singleWeekData) singleWeekData = []*model.StoreScoreEx{} weekIndex = 0 singleWeekData = append(singleWeekData, value) } } if len(singleWeekData) > 0 { weekDataList = append(weekDataList, singleWeekData) } return weekDataList } func GetStoreScoreLevel(score int) int { level := 0 if score >= 90 { level = 1 } else if score >= 80 { level = 2 } else if score >= 70 { level = 3 } return level } func Time2Week(t time.Time) int { yearDay := t.YearDay() yearFirstDay := t.AddDate(0, 0, -yearDay+1) firstDayInWeek := int(yearFirstDay.Weekday()) firstWeekDays := 1 if firstDayInWeek != 0 { firstWeekDays = 7 - firstDayInWeek + 1 } var week int if yearDay <= firstWeekDays { week = 1 } else { tempWeek := (float64(yearDay) - float64(firstWeekDays)) / float64(7) week = int(math.Ceil(tempWeek)) + 1 } return week }