feat : Añado endpoint Get para Clients de dolibar.

This commit is contained in:
javiermengual 2026-01-30 16:34:23 +01:00
parent 161696269d
commit e729388981
11 changed files with 188 additions and 14 deletions

View File

@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
using DoliMiddlewareApi.Dtos.query;
using DoliMiddlewareApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace DoliMiddlewareApi.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class ClientsController(ClientService clientService) : ControllerBase
{
[HttpGet]
[ProducesResponseType(typeof(List<ClientDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<List<ClientDto>>> GetClientes(
[FromQuery] int limit = 50,
[FromQuery] [Range(1, int.MaxValue)] int page = 1)
{
var clients = await clientService.GetClientsAsync(limit, page);
return Ok(clients);
}
}

View File

@ -10,15 +10,8 @@ namespace DoliMiddlewareApi.Controllers;
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
[Authorize] [Authorize]
public class InvoicesController : ControllerBase public class InvoicesController(InvoiceService invoiceService) : ControllerBase
{ {
private readonly InvoiceService _invoiceService;
public InvoicesController(InvoiceService invoiceService)
{
_invoiceService = invoiceService;
}
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(List<InvoiceDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(List<InvoiceDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
@ -29,7 +22,7 @@ public class InvoicesController : ControllerBase
[FromQuery] string? status = null, [FromQuery] string? status = null,
[FromQuery] [StringLength(100)] string? search = null) [FromQuery] [StringLength(100)] string? search = null)
{ {
var invoices = await _invoiceService.GetInvoicesAsync(limit, page, status, search); var invoices = await invoiceService.GetInvoicesAsync(limit, page, status, search);
return Ok(invoices); return Ok(invoices);
} }
@ -40,7 +33,7 @@ public class InvoicesController : ControllerBase
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<InvoiceDetailDto>> GetInvoice([Range(1, int.MaxValue)] int id) public async Task<ActionResult<InvoiceDetailDto>> GetInvoice([Range(1, int.MaxValue)] int id)
{ {
var invoice = await _invoiceService.GetInvoiceAsync(id); var invoice = await invoiceService.GetInvoiceAsync(id);
return Ok(invoice); return Ok(invoice);
} }
@ -50,7 +43,7 @@ public class InvoicesController : ControllerBase
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<int>> CreateInvoice([FromBody] CreateInvoiceDto createInvoiceDto) public async Task<ActionResult<int>> CreateInvoice([FromBody] CreateInvoiceDto createInvoiceDto)
{ {
var invoiceId= await _invoiceService.CreateInvoiceAsync(createInvoiceDto); var invoiceId= await invoiceService.CreateInvoiceAsync(createInvoiceDto);
return CreatedAtAction(nameof(GetInvoice), new { id = invoiceId }, invoiceId); return CreatedAtAction(nameof(GetInvoice), new { id = invoiceId }, invoiceId);
} }
@ -62,7 +55,7 @@ public class InvoicesController : ControllerBase
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateInvoice([Range(1, int.MaxValue)] int id, [FromBody] UpdateInvoiceDto updateInvoiceDto) public async Task<IActionResult> UpdateInvoice([Range(1, int.MaxValue)] int id, [FromBody] UpdateInvoiceDto updateInvoiceDto)
{ {
await _invoiceService.UpdateInvoiceAsync(id, updateInvoiceDto); await invoiceService.UpdateInvoiceAsync(id, updateInvoiceDto);
return NoContent(); return NoContent();
} }
@ -74,7 +67,7 @@ public class InvoicesController : ControllerBase
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<string>> AddInvoiceLine([Range(1, int.MaxValue)] int id, [FromBody] CreateInvoiceLineDto lineDto) public async Task<ActionResult<string>> AddInvoiceLine([Range(1, int.MaxValue)] int id, [FromBody] CreateInvoiceLineDto lineDto)
{ {
var result = await _invoiceService.AddInvoiceLineAsync(id, lineDto); var result = await invoiceService.AddInvoiceLineAsync(id, lineDto);
return CreatedAtAction(nameof(GetInvoice), new { id }, result); return CreatedAtAction(nameof(GetInvoice), new { id }, result);
} }
} }

View File

@ -23,7 +23,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Controllers\" />
<Folder Include="Models\" /> <Folder Include="Models\" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,17 @@
namespace DoliMiddlewareApi.Dtos.Dolibarr;
public class ClientResponse
{
public string? id { get; set; }
// Nombre comercial / razón social
public string? name { get; set; }
// Código cliente (CUxxxx)
public string? code_client { get; set; }
// Contacto
public string? email { get; set; }
public string? phone { get; set; }
}

View File

@ -0,0 +1,20 @@
namespace DoliMiddlewareApi.Dtos.Dolibarr;
public class ContactResponse
{
public string? id { get; set; }
public string? lastname { get; set; }
public string? firstname { get; set; }
public string? email { get; set; }
public string? phone_pro { get; set; }
public string? phone_perso { get; set; }
public string? phone_mobile { get; set; }
public string? fk_soc { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace DoliMiddlewareApi.Dtos.query;
public class ClientDto
{
public int Id { get; set; }
public required string? Name { get; set; }
public required string? CodeClient { get; set; }
public List<ContactDto> Contacts { get; set; } = new();
}

View File

@ -0,0 +1,20 @@
namespace DoliMiddlewareApi.Dtos.query;
public class ContactDto
{
public int Id { get; set; }
public required string? Lastname { get; set; }
public required string? Firstname { get; set; }
public required string? Email { get; set; }
public required string? PhonePro { get; set; }
public required string? PhonePerso { get; set; }
public required string? PhoneMobile { get; set; }
public int ClientId { get; set; }
}

View File

@ -0,0 +1,32 @@
using DoliMiddlewareApi.Dtos.Dolibarr;
using DoliMiddlewareApi.Dtos.query;
namespace DoliMiddlewareApi.Mappers;
public class ClientMapper
{
public static ClientDto MapToClientDto(ClientResponse clientResponse, List<ContactDto> contacts)
{
var clientId = int.TryParse(clientResponse.id, out int id) ? id : 0;
return new ClientDto
{
Id = clientId,
Name = clientResponse.name,
CodeClient = clientResponse.code_client,
Contacts = contacts.Where(c => c.ClientId == clientId).ToList()
};
}
public static ClientDto MapToClientDtoWithoutContacts(ClientResponse clientResponse)
{
return new ClientDto
{
Id = int.TryParse(clientResponse.id, out int id) ? id : 0,
Name = clientResponse.name,
CodeClient = clientResponse.code_client
};
}
}

View File

@ -0,0 +1,22 @@
using DoliMiddlewareApi.Dtos.Dolibarr;
using DoliMiddlewareApi.Dtos.query;
namespace DoliMiddlewareApi.Mappers;
public class ContactMapper
{
public static ContactDto MapToContactDto(ContactResponse contactResponse)
{
return new ContactDto
{
Id = int.TryParse(contactResponse.id, out int id) ? id : 0,
Lastname = contactResponse.lastname,
Firstname = contactResponse.firstname,
Email = contactResponse.email,
PhonePro = contactResponse.phone_pro,
PhonePerso = contactResponse.phone_perso,
PhoneMobile = contactResponse.phone_mobile,
ClientId = int.TryParse(contactResponse.fk_soc, out int clientId) ? clientId : 0
};
}
}

View File

@ -100,6 +100,9 @@ builder.Services.AddScoped<IDolibarrApiClient>(sp =>
// Servicio de negocio (facturas) // Servicio de negocio (facturas)
builder.Services.AddScoped<InvoiceService>(); builder.Services.AddScoped<InvoiceService>();
// Servicio de negocio (clientes)
builder.Services.AddScoped<ClientService>();
// Servicio de aplicación (orquesta login + cache) // Servicio de aplicación (orquesta login + cache)
builder.Services.AddScoped<AuthApplicationService>(); builder.Services.AddScoped<AuthApplicationService>();

View File

@ -0,0 +1,29 @@
using DoliMiddlewareApi.Dtos.Dolibarr;
using DoliMiddlewareApi.Dtos.query;
using DoliMiddlewareApi.Mappers;
using DoliMiddlewareApi.Services.Clients;
namespace DoliMiddlewareApi.Services;
public class ClientService(IDolibarrApiClient dolibarrApiClient)
{
public async Task<List<ClientDto>> GetClientsAsync(
int limit = 50,
int page = 1)
{
var endpoint = $"thirdparties?limit={limit}&page={page - 1}";
var clients = await dolibarrApiClient.GetCollectionAsync<ClientResponse>(endpoint);
if (clients.Count == 0)
return clients.Select(ClientMapper.MapToClientDtoWithoutContacts).ToList();
var clientIds = string.Join(",", clients.Select(c => c.id).Where(id => !string.IsNullOrEmpty(id)));
var contactsEndpoint = $"contacts?thirdparty_ids={clientIds}";
var contacts = await dolibarrApiClient.GetCollectionAsync<ContactResponse>(contactsEndpoint);
var contactDtos = contacts.Select(ContactMapper.MapToContactDto).ToList();
return clients.Select(c => ClientMapper.MapToClientDto(c, contactDtos)).ToList();
}
}