コード例 #1
0
ファイル: AddressManager.cs プロジェクト: Sellec/OnXap
        private Address PrepareAddressDataIntoDB(string address, DaData.Entities.AddressData result, UnitOfWork <Address, AddressSearchHistory> db)
        {
            var addresses = PrepareAddressDataIntoDBResult(result, db);

            if (addresses != null && addresses.Count > 0)
            {
                var addressesFiltered = addresses.GroupBy(x => x.KodAddress).Select(x => x.First()).ToList();
                db.Repo1.AddOrUpdate(y => y.KodAddress, addressesFiltered.ToArray());
                db.SaveChanges();

                // Возвращаем последний из найденных адресов. Для зданий это будет kladr_id с номером дома. Для остальных адресов - просто последняя часть адреса.
                return(addresses.LastOrDefault());
            }
            else
            {
                return(null);
            }
        }
コード例 #2
0
ファイル: AddressManager.cs プロジェクト: Sellec/OnXap
        ExecutionResult <Address> IManager.SearchAddress(string address)
        {
            try
            {
                using (var db = this.CreateUnitOfWork())
                {
                    var DadataClient = GetDadataClient();

                    DaData.Entities.AddressData result = null;

                    if (result == null)
                    {
                        try
                        {
                            var found = db.Repo2.Where(x => x.NameAddressSearch.Equals(address, StringComparison.InvariantCultureIgnoreCase) && x.ServiceFound == "DaData").OrderByDescending(x => x.DateSearch).FirstOrDefault();
                            if (found != null)
                            {
                                if (found.IsSuccess)
                                {
                                    result = Newtonsoft.Json.JsonConvert.DeserializeObject <DaData.Entities.AddressData>(found.ServiceAnswer);
                                }
                                else
                                {
                                    var timeoutForNewSearch = TimeSpan.FromDays(5); //Время, в течение которого мы используем старый неудачный результат поиска, чтобы не тратить деньги ЛК DaData.
                                    if (DateTime.Now - found.DateSearch < timeoutForNewSearch)
                                    {
                                        return(new ExecutionResult <Address>(false, "Указанный адрес не найден."));
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            this.RegisterEvent(Journaling.EventType.Error, "Ошибка во время поиска кешированного результата.", $"Адрес: {address}", null, ex);
                        }
                    }

                    if (result == null)
                    {
                        var results = DadataClient.Clean <DaData.Entities.AddressData>(new string[] { address });
                        if (results.IsSuccess)
                        {
                            if (results.Data != null && results.Data.Count > 0)
                            {
                                var resultPre = results.Data.First();

                                var history = new AddressSearchHistory()
                                {
                                    NameAddressSearch = address,
                                    DateSearch        = DateTime.Now,
                                    IsSuccess         = false,
                                    AddressType       = AddressType.Country,
                                    ServiceFound      = "DaData",
                                    ServiceAnswer     = Newtonsoft.Json.JsonConvert.SerializeObject(resultPre)
                                };

                                var allowed = resultPre.qc == DaData.Constants.QC.QC_OK;//Разрешаем только точные совпадения.
                                if (!allowed && resultPre.qc == DaData.Constants.QC.QC_UNSURE)
                                {
                                    int fias_level;
                                    if (int.TryParse(resultPre.fias_level, out fias_level))
                                    {
                                        if (fias_level >= 7)
                                        {
                                            allowed = true;                   //Если точность совпадения - улица, тоже разрешаем.
                                        }
                                        if (fias_level == 6 && string.IsNullOrEmpty(resultPre.city_kladr_id) && !string.IsNullOrEmpty(resultPre.settlement_kladr_id))
                                        {
                                            allowed = true;                                                                                                                          //Если точность совпадения - некрупный населенный пункт, тоже разрешаем.
                                        }
                                    }
                                }

                                if (allowed)
                                {
                                    result = resultPre;

                                    history.IsSuccess     = true;
                                    history.KodAddress    = result.kladr_id;
                                    history.ServiceAnswer = Newtonsoft.Json.JsonConvert.SerializeObject(result);
                                }

                                db.Repo2.Add(history);
                                db.SaveChanges();
                            }
                        }
                        else
                        {
                            if (results.Code == 402)
                            {
                                _cachedEvents.GetOrAddWithExpiration("account_balance_empty", (k) =>
                                {
                                    this.RegisterServiceState(ServiceStatus.CannotRunBecouseOfErrors, "Пополните баланс на счете Дадаты - не работают стандартизация и подсказки.");
                                    return(DateTime.Now);
                                }, TimeSpan.FromMinutes(5));
                                return(new ExecutionResult <Address>(false, "Поиск недоступен - недостаточно средств на счете Дадаты."));
                            }
                            else
                            {
                                this.RegisterServiceState(ServiceStatus.CannotRunBecouseOfErrors, "Необработанная ошибка в ответе сервиса.", new Exception($"Код ответа {results.Code}, текст: {results.Detail}"));
                                return(new ExecutionResult <Address>(false, "Необработанная ошибка в ответе сервиса."));
                            }
                        }
                    }

                    var prepareResult = PrepareAddressDataIntoDB(address, result, db);
                    return(new ExecutionResult <Address>(prepareResult != null, null, prepareResult));
                }
            }
            catch (Exception ex)
            {
                this.RegisterEvent(Journaling.EventType.Error, "Ошибка во время обработки результата поиска.", $"SearchAddress: {address}", null, ex);
                return(new ExecutionResult <Address>(false, "Ошибка во время обработки результата поиска."));
            }
        }
コード例 #3
0
ファイル: AddressManager.cs プロジェクト: Sellec/OnXap
        private List <Address> PrepareAddressDataIntoDBResult(DaData.Entities.AddressData result, UnitOfWork <DB.Address, DB.AddressSearchHistory> db)
        {
            if (result != null)
            {
                var addressFinal = new DB.Address();
                var addresses    = new List <DB.Address>();
                var nameFull     = new Dictionary <string, string>();

                var resultData = TypeHelper.ObjectToDictionary(result).ToDictionary(x => x.Key, x => x.Value != null ? x.Value.ToString() : "");

                // Заметки:
                // 1. Если не указан район (пустой area), то предполагаем, что это городской округ и используем город в качестве обозначения района.
                // 2. Если указан settlement, то для значения "мкр" считаем, что это часть адреса (street) и KodCity у такого адреса будет равен коду города. Другие значения считаются отдельными населенными пунктами и получают свой собственный KodCity.
                // 3. Дадата отдает данные без кода КЛАДР дома (иногда), поэтому для таких случаев генерим код КЛАДР на основе кода улицы и номера дома.
                var prefixList         = new string[] { "region", "area", "city", "settlement", "street", "house" };
                var prefixListFiltered = prefixList.Where(x => resultData.ContainsKey(x + "_kladr_id") && !string.IsNullOrEmpty(resultData[x + "_kladr_id"])).ToArray();

                // Условности. Заметки, п. 3.
                if (resultData.ContainsKey("house") && (!resultData.ContainsKey("house_kladr_id") || string.IsNullOrEmpty(resultData["house_kladr_id"])))
                {
                    resultData["house_kladr_id"] = resultData["kladr_id"] + "_" + resultData["house"];
                }

                foreach (var prefix in prefixListFiltered)
                {
                    nameFull.Add(prefix, resultData.ContainsKey(prefix + "_with_type") && !string.IsNullOrEmpty(resultData[prefix + "_with_type"]) ?
                                 resultData[prefix + "_with_type"] :
                                 ((string.IsNullOrEmpty(resultData.GetValueOrDefault(prefix + "_type", "")) ? "" : resultData.GetValueOrDefault(prefix + "_type", "") + ".").Replace("..", ".") + " " + resultData[prefix]).Trim());

                    var isRegion   = false;
                    var isDistrict = false;
                    var isCity     = false;

                    addressFinal.KodAddress = resultData[prefix + "_kladr_id"];

                    // Запись основных частей адреса - регион, район, город, улица, дом.
                    if (prefix == "region")
                    {
                        addressFinal.KodRegion = resultData[prefix + "_kladr_id"];
                        isRegion = true;
                    }

                    if (prefix == "area")
                    {
                        addressFinal.KodDistrict = resultData[prefix + "_kladr_id"];
                        isDistrict = true;
                    }

                    if (prefix == "city")
                    {
                        addressFinal.KodCity = resultData[prefix + "_kladr_id"];
                        isCity = true;
                    }

                    if (prefix == "street")
                    {
                        addressFinal.KodStreet = resultData[prefix + "_kladr_id"];
                    }

                    if (prefix == "house")
                    {
                        addressFinal.KodBuildingCommon = resultData[prefix + "_kladr_id"];
                        addressFinal.KodBuilding       = addressFinal.KodBuildingCommon;// $"{resultData[prefix + "_kladr_id"]}_{resultData["house_type"]}{resultData["house"]}";
                    }

                    // Условности. Если в качестве региона город, то это город федерального значения. Он отмечается как область, район и город.
                    if (prefix == "region" && resultData[prefix + "_type"] == "г")
                    {
                        isRegion                 = true;
                        isDistrict               = true;
                        isCity                   = true;
                        addressFinal.KodRegion   = resultData[prefix + "_kladr_id"];
                        addressFinal.KodDistrict = resultData[prefix + "_kladr_id"];
                        addressFinal.KodCity     = resultData[prefix + "_kladr_id"];
                    }

                    // Условности. Заметки, п. 1. Если работаем с городом, но при этом район не определился, то в качестве района указываем город.
                    if (prefix == "city" && string.IsNullOrEmpty(addressFinal.KodDistrict))
                    {
                        isDistrict = true;
                        addressFinal.KodDistrict = addressFinal.KodCity;
                    }

                    // Условности. Заметки, п. 2.
                    if (prefix == "settlement")
                    {
                        // Если это деревня или село, то у него будет указан settlement_kladr_id и мы можем записать адрес как отдельную единицу. Собственно, только в этом случае сюда и попадем.
                        // Для микрорайонов settlement_kladr_id не передается, поэтому сюда попадания и не должно быть, но на всякий случай добавим условие и сделаем запись в лог.
                        if (resultData[prefix + "_type"] != "мкр")
                        {
                            isCity = true;
                            addressFinal.KodCity = resultData[prefix + "_kladr_id"];
                        }
                        else
                        {
                            addressFinal.KodStreet = resultData[prefix + "_kladr_id"];
                        }
                    }
                    if (prefix == "street" || prefix == "house")
                    {
                        // Проверяем, есть ли settlement без settlement_kladr_id. Если есть, то это, скорее всего, микрорайон (тоже проверяем), а для микрорайонов не указывается id, поэтому он не фигурирует у нас в базе как отдельный адрес.
                        // В таком случае микрорайон обозначаем как часть адреса - пристыковываем к улице или номеру дома, если нет улицы.
                        if (resultData.ContainsKey("settlement_type") && resultData["settlement_type"] == "мкр" && string.IsNullOrEmpty(resultData["settlement_kladr_id"]))
                        {
                            var namepart = resultData.ContainsKey("settlement_with_type") && !string.IsNullOrEmpty(resultData["settlement_with_type"]) ?
                                           resultData["settlement_with_type"] :
                                           ((string.IsNullOrEmpty(resultData.GetValueOrDefault("settlement_type", "")) ? "" : resultData.GetValueOrDefault("settlement_type", "") + ".").Replace("..", ".") + " " + resultData[prefix]).Trim();

                            var prefix2 = nameFull.ContainsKey("street") ? "street" : "house";
                            if (prefix2 == prefix)
                            {
                                nameFull[prefix2] = string.Join(", ", new string[] { namepart, nameFull[prefix2] }.Where(x => !string.IsNullOrEmpty(x)));
                            }
                        }
                    }


                    // Работаем с определенными данными дальше.
                    var addressLevel = new DB.Address()
                    {
                        KodAddress        = resultData[prefix + "_kladr_id"],
                        NameAddress       = resultData[prefix],
                        NameAddressShort  = resultData[prefix + "_type"],
                        NameAddressFull   = string.Join(", ", nameFull.Values.GroupBy(x => x).Select(x => x.Key).Where(x => !string.IsNullOrEmpty(x))),
                        KodFias           = resultData.ContainsKey(prefix + "_fias_id") ? (Guid?)new Guid(resultData[prefix + "_fias_id"]) : null,
                        DateChange        = DateTime.Now,
                        KodRegion         = addressFinal.KodRegion,
                        KodDistrict       = addressFinal.KodDistrict,
                        KodCity           = addressFinal.KodCity,
                        KodStreet         = addressFinal.KodStreet,
                        KodBuildingCommon = addressFinal.KodBuildingCommon,
                        KodBuilding       = addressFinal.KodBuilding,
                        AddressType       = getAddressType(addressFinal.KodRegion, addressFinal.KodDistrict, addressFinal.KodCity, addressFinal.KodStreet, addressFinal.KodBuildingCommon, addressFinal.KodBuilding),
                        IsRegion          = isRegion,
                        IsDistrict        = isDistrict,
                        IsCity            = isCity,
                    };

                    // Проверяем маркер города.
                    if (isCity && resultData.ContainsKey("capital_marker"))
                    {
                        if (resultData["capital_marker"] == "1" || resultData["capital_marker"] == "3" || resultData["capital_marker"] == "3")
                        {
                            addressLevel.IsDistrictCenter = true;
                        }
                        if (resultData["capital_marker"] == "3" || resultData["capital_marker"] == "3")
                        {
                            addressLevel.IsRegionCenter = true;
                        }
                    }
                    if (isCity && isDistrict && isRegion)
                    {
                        addressLevel.IsRegionCenter   = true;
                        addressLevel.IsDistrictCenter = true;
                    }

                    //
                    addresses.Add(addressLevel);

                    // Если это дом, то сохраняем адрес дважды - первый раз просто с kladr_id, а второй - kladr_id плюс номер дома. В кладр-апи была проблема, что один kladr_api соответствовал нескольким домам.
                    if (prefix == "house")
                    {
                        var kodAddress = $"{resultData[prefix + "_kladr_id"]}_{resultData["house_type"]}{resultData["house"]}".ToLower();

                        addresses.Add(new Address()
                        {
                            KodAddress        = kodAddress,
                            NameAddress       = addressLevel.NameAddress,
                            NameAddressShort  = addressLevel.NameAddressShort,
                            NameAddressFull   = addressLevel.NameAddressFull,
                            KodFias           = addressLevel.KodFias,
                            DateChange        = addressLevel.DateChange,
                            KodRegion         = addressLevel.KodRegion,
                            KodDistrict       = addressLevel.KodDistrict,
                            KodCity           = addressLevel.KodCity,
                            KodStreet         = addressLevel.KodStreet,
                            KodBuildingCommon = addressLevel.KodBuildingCommon,
                            KodBuilding       = kodAddress,
                            AddressType       = addressLevel.AddressType,
                            IsRegion          = addressLevel.IsRegion,
                            IsDistrict        = addressLevel.IsDistrict,
                            IsCity            = addressLevel.IsCity,
                            IsDistrictCenter  = addressLevel.IsDistrictCenter,
                            IsRegionCenter    = addressLevel.IsRegionCenter,
                        });
                    }
                }

                if (addresses.Count > 0)
                {
                    var addressesToChange = addresses.Last().ToEnumerable().Union(addresses.Where(x => x.AddressType == AddressType.Building));

                    decimal?[] geo = new decimal?[] { null, null };
                    decimal    d   = 0;
                    if (resultData.ContainsKey("geo_lat") && !string.IsNullOrEmpty(resultData["geo_lat"]))
                    {
                        if (decimal.TryParse(resultData["geo_lat"], out d))
                        {
                            addressesToChange.ForEach(x => x.CoordinateX = d);
                        }
                        else if (decimal.TryParse(resultData["geo_lat"].Replace(".", ","), out d))
                        {
                            addressesToChange.ForEach(x => x.CoordinateX = d);
                        }
                    }
                    if (resultData.ContainsKey("geo_lon") && !string.IsNullOrEmpty(resultData["geo_lon"]))
                    {
                        if (decimal.TryParse(resultData["geo_lon"], out d))
                        {
                            addressesToChange.ForEach(x => x.CoordinateY = d);
                        }
                        else if (decimal.TryParse(resultData["geo_lon"].Replace(".", ","), out d))
                        {
                            addressesToChange.ForEach(x => x.CoordinateY = d);
                        }
                    }

                    if (resultData.ContainsKey("okato") && !string.IsNullOrEmpty(resultData["okato"]))
                    {
                        addressesToChange.ForEach(x => x.Okato = resultData["okato"]);
                    }
                    if (resultData.ContainsKey("postal_code") && !string.IsNullOrEmpty(resultData["postal_code"]))
                    {
                        addressesToChange.ForEach(x => x.ZipCode = resultData["postal_code"]);
                    }

                    var addressesToBase = new Dictionary <string, DB.Address>();
                    addresses.ForEach(x =>
                    {
                        if (!addressesToBase.ContainsKey(x.KodAddress))
                        {
                            addressesToBase[x.KodAddress] = x;
                        }
                    });

                    return(addressesToBase.Values.ToList());
                }
            }

            return(null);
        }
コード例 #4
0
ファイル: AddressManager.cs プロジェクト: Sellec/OnXap
        private ExecutionResult <Address> GetAddressByQuery(string addressString, Func <string, DaData.Entities.Suggestions.Suggestion <DaData.Entities.AddressData> > suggectionProvider)
        {
            try
            {
                using (var db = this.CreateUnitOfWork())
                {
                    DaData.Entities.AddressData result = null;

                    if (result == null)
                    {
                        try
                        {
                            var found = db.Repo2.Where(x => x.NameAddressSearch.Equals(addressString, StringComparison.InvariantCultureIgnoreCase) && x.ServiceFound == "DaData" && x.AddressType == AddressType.IP_Address).OrderByDescending(x => x.DateSearch).FirstOrDefault();
                            if (found != null)
                            {
                                if (found.IsSuccess)
                                {
                                    result = Newtonsoft.Json.JsonConvert.DeserializeObject <DaData.Entities.AddressData>(found.ServiceAnswer);
                                }
                                else
                                {
                                    var timeoutForNewSearch = TimeSpan.FromMinutes(5); //Время, в течение которого мы используем старый неудачный результат поиска, чтобы не тратить счетчик подсказок DaData.
                                    if (DateTime.Now - found.DateSearch < timeoutForNewSearch)
                                    {
                                        return(new ExecutionResult <Address>(false, "Указанный адрес не найден."));
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            this.RegisterEvent(Journaling.EventType.Error, "Ошибка во время поиска кешированного результата.", $"Адрес: {addressString}", null, ex);
                        }
                    }

                    AddressSearchHistory history = null;

                    if (result == null)
                    {
                        history = new AddressSearchHistory()
                        {
                            NameAddressSearch = addressString,
                            DateSearch        = DateTime.Now,
                            IsSuccess         = false,
                            AddressType       = AddressType.IP_Address,
                            ServiceFound      = "DaData"
                        };

                        var suggestion_result = suggectionProvider(addressString);
                        if (suggestion_result != null)
                        {
                            result = suggestion_result.data;

                            Debug.WriteLineNoLog("GetAddressByQuery: {0}", addressString);
                            Debug.WriteLineNoLog(Newtonsoft.Json.JsonConvert.SerializeObject(result));

                            history.IsSuccess     = true;
                            history.KodAddress    = result.kladr_id;
                            history.ServiceFound  = "DaData";
                            history.ServiceAnswer = Newtonsoft.Json.JsonConvert.SerializeObject(result);
                        }

                        db.Repo2.Add(history);
                        db.SaveChanges();
                    }

                    var prepareResult = PrepareAddressDataIntoDB(addressString, result, db);
                    if (prepareResult != null && history != null)
                    {
                        history.AddressType = prepareResult.AddressType;
                        db.SaveChanges();
                        throw new NotImplementedException("Здесь надо проверить корректность заполнения AddressType в базе после повторного вызова SaveChanges.");
                    }

                    return(new ExecutionResult <Address>(prepareResult != null, null, prepareResult));
                }
            }
            catch (NotImplementedException) { throw; }
            catch (Exception ex)
            {
                this.RegisterEvent(Journaling.EventType.Error, "Ошибка во время обработки результата поиска.", $"GetAddressByQuery: {addressString}", null, ex);
                return(new ExecutionResult <Address>(false, "Ошибка во время обработки результата поиска."));
            }
        }