From 7428eb3f8d67c27a0ee28a9befa29d1b7e611738 Mon Sep 17 00:00:00 2001 From: javiermengual Date: Mon, 29 Dec 2025 16:37:46 +0100 Subject: [PATCH] feat: implementar cliente API de Dolibarr --- .../Services/DolibarrApiClient.cs | 96 +++++++++++++++++++ DoliMiddlewareApi/Services/InvoiceResponse.cs | 15 +++ 2 files changed, 111 insertions(+) create mode 100644 DoliMiddlewareApi/Services/DolibarrApiClient.cs create mode 100644 DoliMiddlewareApi/Services/InvoiceResponse.cs diff --git a/DoliMiddlewareApi/Services/DolibarrApiClient.cs b/DoliMiddlewareApi/Services/DolibarrApiClient.cs new file mode 100644 index 0000000..7440ca8 --- /dev/null +++ b/DoliMiddlewareApi/Services/DolibarrApiClient.cs @@ -0,0 +1,96 @@ +using System.Globalization; +using System.Net; +using System.Net.Http.Json; +using DoliMiddlewareApi.Dtos; +using DoliMiddlewareApi.Dtos.Enums; +using DoliMiddlewareApi.Exceptions; + +namespace DoliMiddlewareApi.Services; + +public class DolibarrApiClient +{ + private readonly HttpClient _httpClient; + + public DolibarrApiClient(HttpClient httpClient) + { + _httpClient = httpClient; + } + + // ===== FACTURAS ===== + public async Task GetInvoiceAsync(int id) + { + var data = await GetAsync($"invoices/{id}"); + return MapToInvoiceDto(data); + } + + public async Task> GetInvoicesAsync() + { + var dataList = await GetListAsync("invoices"); + return dataList.Select(MapToInvoiceDto).ToList(); + } + + // ===== MAPPER ===== + private InvoiceDto MapToInvoiceDto(InvoiceResponse invoiceResponse) + { + return new InvoiceDto + { + Id = int.TryParse(invoiceResponse.id, out int id) ? id : 0, + Number = invoiceResponse.@ref ?? "SIN-REF", + + Date = invoiceResponse.date.HasValue + ? DateTimeOffset.FromUnixTimeSeconds(invoiceResponse.date.Value).DateTime + : null, + + ExpireDate = invoiceResponse.date_lim_reglement.HasValue + ? DateTimeOffset.FromUnixTimeSeconds(invoiceResponse.date_lim_reglement.Value).DateTime + : null, + + ClientId = int.TryParse(invoiceResponse.socid, out int clientId) ? clientId : 0, + + Total = decimal.TryParse(invoiceResponse.total_ttc, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal total) + ? Math.Round(total, 2) + : null, + RemainToPay = decimal.TryParse(invoiceResponse.remaintopay, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal remain) + ? Math.Round(remain, 2) + : null, + + Status = InvoiceStatusMapper.FromDolibarrStatus(invoiceResponse.statut ?? "0") + }; + } + + + // ===== MÉTODOS GENÉRICOS ===== + private async Task GetAsync(string endpoint) where T : class + { + var response = await _httpClient.GetAsync(endpoint); + await HandleErrorsAsync(response, endpoint); + + return await response.Content.ReadFromJsonAsync() + ?? throw new BadRequestException("Failed to deserialize response"); + } + + private async Task> GetListAsync(string endpoint) where T : class + { + var response = await _httpClient.GetAsync(endpoint); + await HandleErrorsAsync(response, endpoint); + + return await response.Content.ReadFromJsonAsync>() ?? new List(); + } + + private async Task HandleErrorsAsync(HttpResponseMessage response, string endpoint) + { + if (response.IsSuccessStatusCode) return; + + var errorContent = await response.Content.ReadAsStringAsync(); + + throw response.StatusCode switch + { + HttpStatusCode.NotFound => new NotFoundException($"Resource not found: {endpoint}"), + HttpStatusCode.Unauthorized => new UnauthorizedException("Invalid API credentials"), + HttpStatusCode.Forbidden => new ForbiddenException("Access to this resource is forbidden"), + HttpStatusCode.BadRequest => new BadRequestException($"Bad request: {errorContent}"), + HttpStatusCode.InternalServerError => new ApiException($"Server error: {errorContent}"), + _ => new ApiException($"Unexpected error ({response.StatusCode}): {errorContent}") + }; + } +} \ No newline at end of file diff --git a/DoliMiddlewareApi/Services/InvoiceResponse.cs b/DoliMiddlewareApi/Services/InvoiceResponse.cs new file mode 100644 index 0000000..f2b8628 --- /dev/null +++ b/DoliMiddlewareApi/Services/InvoiceResponse.cs @@ -0,0 +1,15 @@ +namespace DoliMiddlewareApi.Services; + +public class InvoiceResponse +{ + public string? id { get; set; } + public string? @ref { get; set; } + public long? date { get; set; } + + public long? date_lim_reglement { get; set; } + + public string? socid { get; set; } + public string? total_ttc { get; set; } + public string? remaintopay { get; set; } + public string? statut { get; set; } +} \ No newline at end of file