ajustes sobre verifactu y el banco
This commit is contained in:
parent
62bc070115
commit
e0ab16f82d
|
|
@ -0,0 +1,90 @@
|
|||
using System.Text.Json;
|
||||
using DoliMiddlewareApi.Dtos.VeriFactu;
|
||||
using DoliMiddlewareApi.Services.VeriFactu;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DoliMiddlewareApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class VeriFactuController(VeriFactuApiClient verifactuApiClient) : ControllerBase
|
||||
{
|
||||
[HttpGet("health")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Health()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await verifactuApiClient.GetHealthAsync();
|
||||
return Content(result.Content ?? "{\"status\":\"ok\"}", result.ContentType ?? "application/json");
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
status = "down",
|
||||
error = $"Connection refused ({verifactuApiClient.BaseUrl})",
|
||||
upstream = verifactuApiClient.BaseUrl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("public-key")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> PublicKey()
|
||||
{
|
||||
return await Proxy(verifactuApiClient.GetPublicKeyAsync());
|
||||
}
|
||||
|
||||
[HttpGet("formats")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Formats()
|
||||
{
|
||||
return await Proxy(verifactuApiClient.GetFormatsAsync());
|
||||
}
|
||||
|
||||
[HttpPost("certificates/register")]
|
||||
public async Task<IActionResult> RegisterCertificate([FromBody] RegisterCertificateDto dto)
|
||||
{
|
||||
var logger = HttpContext.RequestServices.GetRequiredService<ILogger<VeriFactuController>>();
|
||||
logger.LogInformation("[VeriFactuController] RegisterCertificate called. CertName={CertName}, CertFile length={CertFileLen}, Password length={PasswordLen}",
|
||||
dto.CertName, dto.CertFile?.Length ?? 0, dto.Password?.Length ?? 0);
|
||||
return await Proxy(verifactuApiClient.RegisterCertificateAsync(dto));
|
||||
}
|
||||
|
||||
[HttpPost("facturas")]
|
||||
public async Task<IActionResult> SendInvoice([FromBody] JsonElement payload)
|
||||
{
|
||||
return await Proxy(verifactuApiClient.SendInvoiceAsync(payload));
|
||||
}
|
||||
|
||||
[HttpPost("facturas/anular")]
|
||||
public async Task<IActionResult> CancelInvoice([FromBody] JsonElement payload)
|
||||
{
|
||||
return await Proxy(verifactuApiClient.CancelInvoiceAsync(payload));
|
||||
}
|
||||
|
||||
private async Task<IActionResult> Proxy(Task<ProxyResponse> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await task;
|
||||
return new ContentResult
|
||||
{
|
||||
StatusCode = result.StatusCode,
|
||||
Content = result.Content,
|
||||
ContentType = result.ContentType
|
||||
};
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
return StatusCode(StatusCodes.Status503ServiceUnavailable, new
|
||||
{
|
||||
title = "VeriFactu unavailable",
|
||||
status = 503,
|
||||
detail = $"No se puede conectar con VeriFactu en {verifactuApiClient.BaseUrl}"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
namespace DoliMiddlewareApi.Dtos.VeriFactu;
|
||||
|
||||
public record ProxyResponse(int StatusCode, string? Content, string? ContentType);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DoliMiddlewareApi.Dtos.VeriFactu;
|
||||
|
||||
public class RegisterCertificateDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(100)]
|
||||
[JsonPropertyName("cert_name")]
|
||||
public string CertName { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[JsonPropertyName("cert_file")]
|
||||
public string CertFile { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[StringLength(1024)]
|
||||
[JsonPropertyName("password")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ public class InvoiceDetailDto
|
|||
public DateTime? Date { get; set; }
|
||||
public DateTime? ExpireDate { get; set; }
|
||||
public int ClientId { get; set; }
|
||||
public string? ClientName { get; set; }
|
||||
public decimal? TotalHt { get; set; }
|
||||
public decimal? TotalTax { get; set; }
|
||||
public decimal? Total { get; set; }
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using DoliMiddlewareApi.Services;
|
|||
using DoliMiddlewareApi.Services.Auth;
|
||||
using DoliMiddlewareApi.Services.Clients;
|
||||
using DoliMiddlewareApi.Services.Notifications;
|
||||
using DoliMiddlewareApi.Services.VeriFactu;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Diagnostics;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
|
@ -136,12 +137,21 @@ builder.Services.AddHttpClient("Dolibarr", client =>
|
|||
client.BaseAddress = new Uri(baseUrl);
|
||||
});
|
||||
|
||||
builder.Services.AddHttpClient("VeriFactu", client =>
|
||||
{
|
||||
var baseUrl = builder.Configuration["VeriFactu:ApiUrl"] ?? "http://localhost:6789/";
|
||||
if (!baseUrl.EndsWith('/')) baseUrl += '/';
|
||||
client.BaseAddress = new Uri(baseUrl);
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<IDolibarrApiClient>(sp =>
|
||||
{
|
||||
var factory = sp.GetRequiredService<IHttpClientFactory>();
|
||||
var client = factory.CreateClient("Dolibarr");
|
||||
var tokenCacheService = sp.GetRequiredService<DolibarrTokenCacheService>();
|
||||
return new DolibarrApiClient(client, tokenCacheService);
|
||||
var config = sp.GetRequiredService<IConfiguration>();
|
||||
return new DolibarrApiClient(client, tokenCacheService, config);
|
||||
});
|
||||
|
||||
// =========================================
|
||||
|
|
@ -163,6 +173,13 @@ builder.Services.AddScoped<DocumentService>();
|
|||
// Servicio de negocio (setup/diccionarios)
|
||||
builder.Services.AddScoped<SetupService>();
|
||||
|
||||
// Cliente de VeriFactu MidAPI
|
||||
builder.Services.AddScoped<VeriFactuApiClient>(sp =>
|
||||
{
|
||||
var factory = sp.GetRequiredService<IHttpClientFactory>();
|
||||
return new VeriFactuApiClient(factory.CreateClient("VeriFactu"));
|
||||
});
|
||||
|
||||
// Servicio de negocio (banco)
|
||||
builder.Services.AddScoped<BankService>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using System.Net;
|
||||
using DoliMiddlewareApi.Exceptions;
|
||||
using DoliMiddlewareApi.Services.Auth;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace DoliMiddlewareApi.Services.Clients;
|
||||
|
||||
public class DolibarrApiClient(HttpClient httpClient, DolibarrTokenCacheService tokenCacheService)
|
||||
public class DolibarrApiClient(HttpClient httpClient, DolibarrTokenCacheService tokenCacheService, IConfiguration configuration)
|
||||
: IDolibarrApiClient
|
||||
{
|
||||
public async Task<T> GetResourceAsync<T>(string endpoint) where T : class
|
||||
|
|
@ -76,11 +77,10 @@ public class DolibarrApiClient(HttpClient httpClient, DolibarrTokenCacheService
|
|||
|
||||
private void AddDolibarrTokenHeader(HttpRequestMessage request)
|
||||
{
|
||||
var dolibarrToken = tokenCacheService.GetDolibarrToken();
|
||||
if (!string.IsNullOrEmpty(dolibarrToken))
|
||||
{
|
||||
request.Headers.Add("DOLAPIKEY", dolibarrToken);
|
||||
}
|
||||
var sharedKey = configuration["Dolibarr:ApiKey"];
|
||||
var token = !string.IsNullOrEmpty(sharedKey) ? sharedKey : tokenCacheService.GetDolibarrToken();
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
request.Headers.Add("DOLAPIKEY", token);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,19 @@ public class InvoiceService(IDolibarrApiClient apiClient, INotificationService n
|
|||
public async Task<InvoiceDetailDto> GetInvoiceAsync(int id)
|
||||
{
|
||||
var data = await apiClient.GetResourceAsync<InvoiceDetailResponse>($"invoices/{id}");
|
||||
return InvoiceMapper.MapToInvoiceDetailDto(data);
|
||||
var dto = InvoiceMapper.MapToInvoiceDetailDto(data);
|
||||
|
||||
if (dto.ClientId > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = await apiClient.GetResourceAsync<ClientResponse>($"thirdparties/{dto.ClientId}");
|
||||
dto.ClientName = client?.name;
|
||||
}
|
||||
catch { /* best-effort */ }
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<List<InvoiceDto>> GetInvoicesAsync(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using DoliMiddlewareApi.Dtos.VeriFactu;
|
||||
|
||||
namespace DoliMiddlewareApi.Services.VeriFactu;
|
||||
|
||||
public class VeriFactuApiClient(HttpClient httpClient)
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
||||
|
||||
public string BaseUrl => httpClient.BaseAddress?.ToString() ?? "http://host.docker.internal:6789/";
|
||||
|
||||
public Task<ProxyResponse> GetHealthAsync() => SendAsync(HttpMethod.Get, "api/v1/health");
|
||||
|
||||
public Task<ProxyResponse> GetPublicKeyAsync() => SendAsync(HttpMethod.Get, "api/v1/auth/public-key");
|
||||
|
||||
public Task<ProxyResponse> GetFormatsAsync() => SendAsync(HttpMethod.Get, "api/v1/formats");
|
||||
|
||||
public async Task<ProxyResponse> RegisterCertificateAsync(RegisterCertificateDto dto)
|
||||
{
|
||||
var payload = new
|
||||
{
|
||||
cert_name = dto.CertName,
|
||||
cert_file = dto.CertFile,
|
||||
password_encrypted = dto.Password
|
||||
};
|
||||
|
||||
return await SendAsync(HttpMethod.Post, "api/v1/auth/register", payload);
|
||||
}
|
||||
|
||||
public Task<ProxyResponse> SendInvoiceAsync(JsonElement payload)
|
||||
=> SendAsync(HttpMethod.Post, "api/v1/facturas", payload);
|
||||
|
||||
public Task<ProxyResponse> CancelInvoiceAsync(JsonElement payload)
|
||||
=> SendAsync(HttpMethod.Post, "api/v1/facturas/anular", payload);
|
||||
|
||||
private async Task<ProxyResponse> SendAsync(HttpMethod method, string path, object? payload = null)
|
||||
{
|
||||
using var request = new HttpRequestMessage(method, path);
|
||||
|
||||
if (payload is not null)
|
||||
{
|
||||
request.Content = JsonContent.Create(payload, options: JsonOptions);
|
||||
}
|
||||
|
||||
using var response = await httpClient.SendAsync(request);
|
||||
var content = response.Content is null ? string.Empty : await response.Content.ReadAsStringAsync();
|
||||
var contentType = response.Content?.Headers.ContentType?.ToString() ?? "application/json";
|
||||
|
||||
return new ProxyResponse((int)response.StatusCode, content, contentType);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,14 @@
|
|||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None"
|
||||
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None",
|
||||
"System.Net.Http.HttpClient.VeriFactu": "None"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Dolibarr": {
|
||||
"ApiUrl": "http://localhost/api/index.php",
|
||||
"ApiKey": ""
|
||||
"ApiKey": "847ad838254caa863c2da3dc949a5028e2317be9"
|
||||
},
|
||||
"Jwt": {
|
||||
"Secret": "",
|
||||
|
|
@ -18,5 +19,8 @@
|
|||
},
|
||||
"Notifications": {
|
||||
"WebhookUrl": ""
|
||||
},
|
||||
"VeriFactu": {
|
||||
"ApiUrl": "http://localhost:6789/"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue