From 0b098376c58b44535fce0e6402b59a8d25464a88 Mon Sep 17 00:00:00 2001 From: javiermengual Date: Fri, 6 Feb 2026 15:24:47 +0100 Subject: [PATCH] feat : Agrego endpoint Post para Payments --- .../Controllers/InvoicesController.cs | 21 +++++++--- .../Dtos/command/CreateInvoicePaymentDto.cs | 28 +++++++++++++ DoliMiddlewareApi/Services/InvoiceService.cs | 41 +++++++++++++++++++ 3 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 DoliMiddlewareApi/Dtos/command/CreateInvoicePaymentDto.cs diff --git a/DoliMiddlewareApi/Controllers/InvoicesController.cs b/DoliMiddlewareApi/Controllers/InvoicesController.cs index 0eefa3d..2cc5d1a 100644 --- a/DoliMiddlewareApi/Controllers/InvoicesController.cs +++ b/DoliMiddlewareApi/Controllers/InvoicesController.cs @@ -16,9 +16,9 @@ public class InvoicesController(InvoiceService invoiceService) : ControllerBase [HttpGet] public async Task>> GetInvoices( [FromQuery] int limit = 50, - [FromQuery][Range(1, int.MaxValue)] int page = 1, + [FromQuery] [Range(1, int.MaxValue)] int page = 1, [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); return Ok(invoices); @@ -39,14 +39,16 @@ public class InvoicesController(InvoiceService invoiceService) : ControllerBase } [HttpPut("{id:int}")] - public async Task UpdateInvoice([Range(1, int.MaxValue)] int id, [FromBody] UpdateInvoiceDto updateInvoiceDto) + public async Task UpdateInvoice([Range(1, int.MaxValue)] int id, + [FromBody] UpdateInvoiceDto updateInvoiceDto) { await invoiceService.UpdateInvoiceAsync(id, updateInvoiceDto); return NoContent(); } [HttpPost("{id:int}/lines")] - public async Task> AddInvoiceLine([Range(1, int.MaxValue)] int id, [FromBody] CreateInvoiceLineDto lineDto) + public async Task> AddInvoiceLine([Range(1, int.MaxValue)] int id, + [FromBody] CreateInvoiceLineDto lineDto) { var result = await invoiceService.AddInvoiceLineAsync(id, lineDto); return CreatedAtAction(nameof(GetInvoice), new { id }, result); @@ -90,4 +92,13 @@ public class InvoicesController(InvoiceService invoiceService) : ControllerBase var payments = await invoiceService.GetInvoicePaymentsAsync(id); return Ok(payments); } -} + + [HttpPost("{id:int}/payments")] + public async Task> AddPayment( + [Range(1, int.MaxValue)] int id, + [FromBody] CreateInvoicePaymentDto dto) + { + var paymentId = await invoiceService.AddInvoicePaymentAsync(id, dto); + return Ok(paymentId); + } +} \ No newline at end of file diff --git a/DoliMiddlewareApi/Dtos/command/CreateInvoicePaymentDto.cs b/DoliMiddlewareApi/Dtos/command/CreateInvoicePaymentDto.cs new file mode 100644 index 0000000..52250c6 --- /dev/null +++ b/DoliMiddlewareApi/Dtos/command/CreateInvoicePaymentDto.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace DoliMiddlewareApi.Dtos.command; + +public class CreateInvoicePaymentDto +{ + // Si se especifica, es un pago parcial. Si es null, paga todo lo pendiente. + [Range(0.01, double.MaxValue, ErrorMessage = "Amount must be greater than 0")] + public decimal? Amount { get; set; } + + [Required] public DateTime PaymentDate { get; set; } + + // Acepta ambos nombres: paymentMethodId (del frontend) o paymentModeId (fallback) + [JsonPropertyName("paymentMethodId")] + public int? PaymentMethodId { get; set; } + + [JsonPropertyName("paymentModeId")] + public int PaymentModeId { get; set; } + + [Required] [RegularExpression("yes|no", ErrorMessage = "Must be 'yes' or 'no'")] + public string ClosePaidInvoices { get; set; } = "yes"; + + public int AccountId { get; set; } = 1; + + [JsonPropertyName("numPayment")] + public string? PaymentNumber { get; set; } +} \ No newline at end of file diff --git a/DoliMiddlewareApi/Services/InvoiceService.cs b/DoliMiddlewareApi/Services/InvoiceService.cs index f74b738..ef6c443 100644 --- a/DoliMiddlewareApi/Services/InvoiceService.cs +++ b/DoliMiddlewareApi/Services/InvoiceService.cs @@ -171,4 +171,45 @@ public class InvoiceService(IDolibarrApiClient apiClient) return payments; } + public async Task AddInvoicePaymentAsync(int invoiceId, CreateInvoicePaymentDto dto) + { + // Usar paymentMethodId si viene, si no usar paymentModeId + var paymentModeId = dto.PaymentMethodId ?? dto.PaymentModeId; + + if (dto.Amount.HasValue) + { + // Pago parcial: usar /invoices/paymentsdistributed + var requestBody = new + { + arrayofamounts = new Dictionary + { + { + invoiceId.ToString(), + new { amount = dto.Amount.Value.ToString(CultureInfo.InvariantCulture) } + } + }, + datepaye = dto.PaymentDate.ToString("yyyy-MM-dd"), + paymentid = paymentModeId, + closepaidinvoices = dto.ClosePaidInvoices, + accountid = dto.AccountId, + num_payment = dto.PaymentNumber, + }; + var responseBody = await apiClient.PostAsync("invoices/paymentsdistributed", requestBody); + return int.Parse(responseBody); + } + else + { + // Pagar completa pendiente: usar /invoices/{id}/payments + var requestBody = new + { + datepaye = dto.PaymentDate.ToString("yyyy-MM-dd"), + paymentid = paymentModeId, + closepaidinvoices = dto.ClosePaidInvoices, + accountid = dto.AccountId, + num_payment = dto.PaymentNumber, + }; + var responseBody = await apiClient.PostAsync($"invoices/{invoiceId}/payments", requestBody); + return int.Parse(responseBody); + } + } }