From dc5293bdf7c05177b202da3846ce56b050f2c922db61eed19d1ad6e2ae420756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= <93217193+Daniel-Garmig@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:27:17 +0200 Subject: [PATCH] feat StayExport - Added service SpainCodigoMunicipio - This service gets the "municipio" code of INE using Catastro API services. --- src/Somnia.GuestLog/Program.cs | 2 + .../ISpainCodigoMunicipioService.cs | 6 + .../SpainCodigoMunicipioCatastroService.cs | 106 ++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 src/Somnia.GuestLog/Services/SpainCodigoMunicipio/ISpainCodigoMunicipioService.cs create mode 100644 src/Somnia.GuestLog/Services/SpainCodigoMunicipio/SpainCodigoMunicipioCatastroService.cs diff --git a/src/Somnia.GuestLog/Program.cs b/src/Somnia.GuestLog/Program.cs index 384639a..134890f 100644 --- a/src/Somnia.GuestLog/Program.cs +++ b/src/Somnia.GuestLog/Program.cs @@ -10,6 +10,7 @@ using Somnia.GuestLog.Models.DTOs; using Somnia.GuestLog.Services; using Somnia.GuestLog.Services.AddressQuery; using Somnia.GuestLog.Services.Entity; +using Somnia.GuestLog.Services.SpainCodigoMunicipio; using Somnia.GuestLog.Services.StayExport; using Somnia.GuestLog.Utils; using Somnia.GuestLog.Validators; @@ -67,6 +68,7 @@ builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); // Add Factories (and it's services) builder.Services.AddFactoryDI(); diff --git a/src/Somnia.GuestLog/Services/SpainCodigoMunicipio/ISpainCodigoMunicipioService.cs b/src/Somnia.GuestLog/Services/SpainCodigoMunicipio/ISpainCodigoMunicipioService.cs new file mode 100644 index 0000000..0d8a2fe --- /dev/null +++ b/src/Somnia.GuestLog/Services/SpainCodigoMunicipio/ISpainCodigoMunicipioService.cs @@ -0,0 +1,6 @@ +namespace Somnia.GuestLog.Services.SpainCodigoMunicipio; + +public interface ISpainCodigoMunicipioService +{ + public Task GetCodigoMunicipioAsync(string municipio, string province); +} \ No newline at end of file diff --git a/src/Somnia.GuestLog/Services/SpainCodigoMunicipio/SpainCodigoMunicipioCatastroService.cs b/src/Somnia.GuestLog/Services/SpainCodigoMunicipio/SpainCodigoMunicipioCatastroService.cs new file mode 100644 index 0000000..6058a5e --- /dev/null +++ b/src/Somnia.GuestLog/Services/SpainCodigoMunicipio/SpainCodigoMunicipioCatastroService.cs @@ -0,0 +1,106 @@ +using System.Xml.Serialization; +using Microsoft.AspNetCore.WebUtilities; + +namespace Somnia.GuestLog.Services.SpainCodigoMunicipio; + +public class SpainCodigoMunicipioCatastroService( + ILogger logger, + IHttpClientFactory httpFactory +) : ISpainCodigoMunicipioService +{ + private const string Api_Host = "https://ovc.catastro.meh.es"; + private const string Api_Address = "OVCServWeb/OVCWcfCallejero/COVCCallejero.svc/rest/ObtenerMunicipios"; + private const string Api_Param_Provincia = "Provincia"; + private const string Api_Param_Municipio = "Municipio"; + + public async Task GetCodigoMunicipioAsync(string municipio, string province) + { + try + { + string uri = GetRequestUri(municipio, province); + logger.LogInformation("SpainCodigoMunicipioCatastroService - Getting municipios with query: '{addr}'", uri); + + var httpClient = httpFactory.CreateClient(); + using var rsStream = await httpClient.GetStreamAsync(uri); + + XmlSerializer serializer = new(typeof(CatastroApiResult)); + + if (serializer.Deserialize(rsStream) is not CatastroApiResult rs) + { + logger.LogError("SpainCodigoMunicipioCatastroService - Result can't be deserialized!"); + return null; + } + + if (rs.municipios.Count == 0) + { + logger.LogWarning("SpainCodigoMunicipioCatastroService - No municipios found for query: '{addr}'", uri); + return null; + } + + if (rs.municipios.Count > 1) + { + logger.LogWarning("SpainCodigoMunicipioCatastroService - More than 1 municipio was returned. First one will be used!"); + } + + CatastroApiResultCodigoIne? codIne = rs.municipios.First().codigoIne; + if (codIne == null || codIne.codigoMunicipio == null || codIne.codigoProvincia == null) + { + logger.LogWarning("SpainCodigoMunicipioCatastroService - Returned Municipio without data!"); + return null; + } + + return $"{codIne.codigoProvincia}{codIne.codigoMunicipio}"; + } + catch (Exception ex) + { + logger.LogError(ex, "SpainCodigoMunicipioCatastroService - Error getting codigo municipio from catastro API!"); + return null; + } + } + + + #region Internal Methods + + private static string GetRequestUri(string municipio, string province) + { + string baseAddress = $"{Api_Host}/{Api_Address}"; + + return QueryHelpers.AddQueryString(baseAddress, [ + new KeyValuePair(Api_Param_Provincia, province), + new KeyValuePair(Api_Param_Municipio, municipio), + ]); + } + + #endregion + + #region API Model + + [XmlRoot(ElementName = "consulta_municipiero", Namespace = "http://www.catastro.meh.es/")] + public class CatastroApiResult() + { + [XmlArray(ElementName = "municipiero")] + [XmlArrayItem(ElementName = "muni")] + public required List municipios; + } + + public class CatastroApiResultMunicipio() + { + [XmlElement(ElementName = "nm")] + public string? municipio; + + [XmlElement(ElementName = "loine")] + public CatastroApiResultCodigoIne? codigoIne; + + } + + public class CatastroApiResultCodigoIne + { + [XmlElement(ElementName = "cp")] + public string? codigoProvincia; + + [XmlElement(ElementName = "cm")] + public string? codigoMunicipio; + } + + #endregion +} \ No newline at end of file