package cms import ( "errors" "fmt" "strconv" "strings" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/model/legacymodel" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" ) const ( GET_BAD_COMMENTS_TYPE = 0 //获取差评的标志 GET_ALL_COMMENTS_TYPE = 1 //获取所有评论的标志 ) type StoreExt struct { model.Store FloatLng float64 `json:"lng"` FloatLat float64 `json:"lat"` CityName string `json:"cityName"` DistrictName string `json:"districtName"` StoreMapStr string `json:"-"` CourierMapStr string `json:"-"` StoreMaps []interface{} `orm:"-"` CourierMaps []interface{} `orm:"-"` } type StoresInfo struct { TotalCount int `json:"totalCount"` Stores []*StoreExt `json:"stores"` } var ( ErrMissingInput = errors.New("没有有效的输入参数") ErrCanNotFindVendor = errors.New("vendorID参数不合法") ) // todo 门店绑定信息可以考虑以数组形式返回,而不是现在这样 func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interface{}, offset, pageSize int) (retVal *StoresInfo, err error) { sql := ` SELECT SQL_CALC_FOUND_ROWS CAST(t1.lng AS DECIMAL(15,6))/1000000 float_lng, CAST(t1.lat AS DECIMAL(15,6))/1000000 float_lat, t1.id, t1.created_at, t1.updated_at, t1.last_operator, t1.deleted_at, t1.name, t1.city_code, t1.district_code, t1.address, t1.tel1, t1.tel2, t1.open_time1, t1.close_time1, t1.open_time2, t1.close_time2, t1.delivery_range_type, t1.delivery_range, t1.status, t1.id_card_front, t1.id_card_back, t1.id_card_hand, t1.licence, t1.licence_code, city.name city_name, district.name district_name, CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"vendorStoreID":"', m1.vendor_store_id, '", "vendorID":', m1.vendor_id, ', "status":', m1.status, "}")), "]") store_map_str, CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"vendorStoreID":"', m2.vendor_store_id, '", "vendorID":', m2.vendor_id, ', "status":', m2.status, "}")), "]") courier_map_str FROM store t1 LEFT JOIN place city ON t1.city_code = city.code AND city.level = 2 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 = ? ` sqlParams := []interface{}{ utils.DefaultTimeValue, utils.DefaultTimeValue, } sqlWhere := ` WHERE t1.deleted_at = ? ` sqlWhereParams := []interface{}{ utils.DefaultTimeValue, } 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]int if err = utils.UnmarshalUseNumber([]byte(mapCondsStr), &vendorStoreConds); err != nil { return nil, err } sqlVendorStoreCond := "" for vendor, cond := range vendorStoreConds { tableAlias := tableName + vendor if cond != 0 { if sqlVendorStoreCond == "" { if mapCond == "AND" { sqlVendorStoreCond += " AND ( 1 = 1" } else { sqlVendorStoreCond += " AND ( 1 = 0" } } sql += " LEFT JOIN " + tableName + " " + tableAlias + " ON " + tableAlias + ".vendor_id = ? AND " + tableAlias + ".store_id = t1.id AND " + tableAlias + ".deleted_at = ?" sqlParams = append(sqlParams, vendor, utils.DefaultTimeValue) if cond == 1 { sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NOT NULL" } else { sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NULL" } } } if sqlVendorStoreCond != "" { sqlWhere += sqlVendorStoreCond + ")" } } } } if keyword != "" { keywordLike := "%" + keyword + "%" sqlWhere += " AND (t1.name LIKE ? OR t1.tel1 LIKE ? OR t1.tel2 LIKE ? OR t1.last_operator LIKE ? OR city.name LIKE ? OR m1.vendor_store_id LIKE ? OR m2.vendor_store_id LIKE ?" sqlWhereParams = append(sqlWhereParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike) if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil { if jxutils.IsLegalMobileNumber(keywordInt64) { sql += ` LEFT JOIN weixins wx1 ON t1.id = wx1.jxstoreid AND wx1.parentid = -1 AND wx1.tel = ? LEFT JOIN weixins wx2 ON t1.id = wx2.jxstoreid AND wx2.parentid = -1 LEFT JOIN weixins wx3 ON wx3.parentid = wx2.id AND wx3.tel = ? ` sqlParams = append(sqlParams, keywordInt64, keywordInt64) sqlWhere += " OR wx1.id IS NOT NULL OR wx3.id IS NOT NULL" } sqlWhere += " OR t1.id = ? OR t1.city_code = ? OR t1.district_code = ?" sqlWhereParams = append(sqlWhereParams, keywordInt64, keywordInt64, keywordInt64) } sqlWhere += ")" } if params["storeID"] != nil { sqlWhere += " AND t1.id = ?" sqlWhereParams = append(sqlWhereParams, params["storeID"].(int)) } 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["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["statuss"] != nil { var statuss []int if err = utils.UnmarshalUseNumber([]byte(params["statuss"].(string)), &statuss); err != nil { return nil, err } if len(statuss) > 0 { sqlWhere += " AND t1.status IN (" + dao.GenQuestionMarks(len(statuss)) + ")" sqlWhereParams = append(sqlWhereParams, statuss) } } sql += sqlWhere + ` GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 ORDER BY t1.id DESC LIMIT ? OFFSET ?` pageSize = jxutils.FormalizePageSize(pageSize) if offset < 0 { offset = 0 } sqlParams = append(sqlParams, sqlWhereParams...) sqlParams = append(sqlParams, pageSize, offset) retVal = &StoresInfo{} db := dao.GetDB() dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() // globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false)) // globals.SugarLogger.Debug(sql) if err = dao.GetRows(db, &retVal.Stores, sql, sqlParams...); err == nil { countInfo := &struct{ Ct int }{} if err = dao.GetRow(db, countInfo, "SELECT FOUND_ROWS() ct"); err == nil { retVal.TotalCount = countInfo.Ct } for _, v := range retVal.Stores { if v.StoreMapStr != "" { if err = utils.UnmarshalUseNumber([]byte(v.StoreMapStr), &v.StoreMaps); err != nil { dao.Rollback(db) return nil, err } } if v.CourierMapStr != "" { if err = utils.UnmarshalUseNumber([]byte(v.CourierMapStr), &v.CourierMaps); err != nil { dao.Rollback(db) return nil, err } } } } dao.Commit(db) return retVal, err } func GetVendorStore(ctx *jxcontext.Context, vendorStoreID string, vendorID int) (retVal *StoreExt, err error) { if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil { result, err2 := handler.ReadStore(vendorStoreID) if err = err2; err == nil { retVal = &StoreExt{ Store: *result, 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 } return retVal, nil } return nil, err } return nil, ErrCanNotFindVendor } func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interface{}, userName string) (num int64, err error) { globals.SugarLogger.Debugf("UpdateStore storeID:%d, payload:%s", storeID, utils.Format4Output(payload, false)) db := dao.GetDB() store := &model.Store{} store.ID = storeID if err = dao.GetEntity(db, store); err != nil { return 0, err } valid := dao.StrictMakeMapByStructObject(payload, store, userName) if valid["name"] != nil { valid["name"] = jxutils.FormalizeName(valid["name"].(string)) } var lng, lat float64 if payload["lng"] != nil { lng = utils.Interface2FloatWithDefault(payload["lng"], 0.0) lat = utils.Interface2FloatWithDefault(payload["lat"], 0.0) valid["lng"] = jxutils.StandardCoordinate2Int(lng) valid["lat"] = jxutils.StandardCoordinate2Int(lat) } if valid["deliveryRange"] != nil { valid["deliveryRange"] = strings.Trim(valid["deliveryRange"].(string), ";") } // districtCode := 0 // if valid["districtCode"] != nil { // districtCode = int(utils.MustInterface2Int64(valid["districtCode"])) // } // if districtCode == 0 && store.DistrictCode == 0 { // if lng == 0 { // lng = jxutils.IntCoordinate2Standard(store.Lng) // lat = jxutils.IntCoordinate2Standard(store.Lat) // } // valid["districtCode"] = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat) // } if len(valid) > 0 { dao.Begin(db) defer func() { dao.Rollback(db) }() if num, err = dao.UpdateEntityLogically(db, store, valid, userName, nil); err == nil && num == 1 { dummy := &model.StoreMap{} _, err2 := dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, dummy, nil, userName, map[string]interface{}{ model.FieldStoreID: store.ID, }, model.FieldSyncStatus) if err = err2; err == nil { dao.Commit(db) _, err = CurVendorSync.SyncStore(ctx, db, -1, store.ID, false, userName) } } } return num, err } func CreateStore(ctx *jxcontext.Context, storeExt *StoreExt, userName string) (id int, err error) { globals.SugarLogger.Debugf("CreateStore storeExt:%s", utils.Format4Output(storeExt, false)) store := &storeExt.Store if store.ID != 0 && !jxutils.IsLegalStoreID(store.ID) { return 0, fmt.Errorf("ID:%d不是合法的京西门店编号") } existingID := store.ID store.Lng = jxutils.StandardCoordinate2Int(storeExt.FloatLng) store.Lat = jxutils.StandardCoordinate2Int(storeExt.FloatLat) store.Name = jxutils.FormalizeName(store.Name) store.DeliveryRange = strings.Trim(store.DeliveryRange, ";") dao.WrapAddIDCULDEntity(store, userName) store.ID = existingID if err = dao.CreateEntity(nil, store); err == nil { 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 } return storeMaps, dao.GetEntitiesByKV(db, &storeMaps, cond, false) } func AddStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, storeMap *model.StoreMap, userName string) (outStoreMap *model.StoreMap, err error) { if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil { store, err2 := handler.ReadStore(storeMap.VendorStoreID) if err = err2; err == nil { dao.WrapAddIDCULDEntity(storeMap, userName) storeMap.StoreID = storeID storeMap.VendorID = vendorID storeMap.DeliveryType = store.DeliveryType storeMap.Status = store.Status storeMap.SyncStatus = model.SyncFlagModifiedMask // 新增绑定门店是修改的概念 if db == nil { db = dao.GetDB() } dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() if err = dao.CreateEntity(db, storeMap); err == nil { dao.Commit(db) outStoreMap = storeMap _, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeID, false, userName) } if err != nil { dao.Rollback(db) } } } else { err = ErrCanNotFindVendor } return outStoreMap, 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{} if num, err = dao.DeleteEntityLogically(db, storeMap, map[string]interface{}{ model.FieldSyncStatus: model.SyncFlagDeletedMask, model.FieldStatus: model.StoreStatusDisabled, }, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, }); err == nil && num > 0 { _, err = CurVendorSync.SyncStore(ctx, db, vendorID, storeID, false, userName) } return num, err } func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, payload map[string]interface{}, userName string) (num int64, err error) { storeHandler := CurVendorSync.GetStoreHandler(vendorID) if storeHandler == nil { return 0, ErrCanNotFindVendor } if db == nil { db = dao.GetDB() } if vendorStoreID := utils.Interface2String(payload["vendorStoreID"]); vendorStoreID != "" { vendorStoreInfo, err2 := storeHandler.ReadStore(vendorStoreID) if err = err2; err == nil { payload["deliveryType"] = vendorStoreInfo.DeliveryType } err = nil // todo 忽略读不到DeliveryType的错误 } if err == nil { 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 { return 0, err } valid := dao.StrictMakeMapByStructObject(payload, storeMap, userName) // globals.SugarLogger.Debug(utils.Format4Output(valid, false)) if len(valid) > 0 { dao.Begin(db) defer func() { dao.Rollback(db) }() if valid["status"] != nil { // 对于store vendor map,只有Status改变才需要同步到厂商 num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeMap, valid, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, }, model.FieldSyncStatus) } else { num, err = dao.UpdateEntityLogically(db, storeMap, valid, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, }) } if err == nil && num > 0 { storeSkuBind := &model.StoreSkuBind{} if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeSkuBind, nil, userName, map[string]interface{}{ model.FieldStoreID: storeID, }, dao.GetSyncStatusStructField(model.VendorNames[vendorID])); err != nil { return 0, err } dao.Commit(db) if valid["status"] != nil { _, err = CurVendorSync.SyncStore(ctx, db, vendorID, storeID, false, userName) } } } } return num, err } func DeleteStore(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, userName string) (num int64, err error) { return 0, errors.New("暂不支持删除京西门店") } 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 = 0 AND jxstoreid = ?", utils.Int2Str(storeID)); err == nil { count = ctInfo.Ct } return count, err } func TmpGetJxBadCommentsByStoreId(ctx *jxcontext.Context, storeID, page, size, commentType int) (retVal map[string]interface{}, err error) { db := dao.GetDB() sql := ` SELECT SQL_CALC_FOUND_ROWS * FROM jx_bad_comments WHERE jxstoreid = ? ` if commentType == GET_BAD_COMMENTS_TYPE { sql += " AND status = 0" } sql += " ORDER BY createtime DESC LIMIT ? OFFSET ?" var commentList []*legacymodel.JxBadComments dao.Begin(db) defer func() { dao.Rollback(db) }() globals.SugarLogger.Debug(sql) if err = dao.GetRows(db, &commentList, sql, utils.Int2Str(storeID), size, (page-1)*size); err == nil { countInfo := &struct{ Ct int }{} if err = dao.GetRow(db, countInfo, "SELECT FOUND_ROWS() ct"); err == nil { dao.Commit(db) retVal = map[string]interface{}{ "total": countInfo.Ct, "list": commentList, } } } return retVal, err } 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 } return storeCourierMaps, dao.GetEntitiesByKV(db, &storeCourierMaps, cond, false) } func AddStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, storeCourierMap *model.StoreCourierMap, userName string) (outStoreCourierMap *model.StoreCourierMap, err error) { if handler := partner.GetDeliveryPlatformFromVendorID(vendorID); handler != nil { dao.WrapAddIDCULDEntity(storeCourierMap, userName) storeCourierMap.StoreID = storeID storeCourierMap.VendorID = vendorID if db == nil { db = dao.GetDB() } dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() if err = dao.CreateEntity(db, storeCourierMap); err == nil { dao.Commit(db) outStoreCourierMap = storeCourierMap _, err = CurVendorSync.SyncStore(ctx, db, storeCourierMap.VendorID, storeID, false, userName) } if err != nil { dao.Rollback(db) } } else { err = ErrCanNotFindVendor } 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{} if num, err = dao.DeleteEntityLogically(db, storeCourierMap, map[string]interface{}{ model.FieldStatus: model.StoreStatusDisabled, }, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, }); err == nil && num > 0 { _, err = CurVendorSync.SyncStore(ctx, db, vendorID, storeID, false, userName) } 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() } dummyStoreCourierMap := &model.StoreCourierMap{} valid := dao.NormalMakeMapByStructObject(payload, dummyStoreCourierMap, userName) if len(valid) > 0 { num, err = dao.UpdateEntityLogically(db, dummyStoreCourierMap, valid, userName, map[string]interface{}{ model.FieldStoreID: storeID, model.FieldVendorID: vendorID, }) } return num, err }