phronCare/phronCare.API/Controllers/Stock/ExpeditionController.cs
Leandro Hernan Rojas 0361d4c978
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 6m2s
Add Export QUOTES & refactoring
2025-09-11 22:41:46 -03:00

154 lines
6.0 KiB
C#

using Core.Interfaces.Stock;
using Documents.Interfaces;
using Documents.Models;
using Domain.Dtos.Stock;
using Domain.Entities;
using Domain.Generics;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace phronCare.API.Controllers.Stock
{
[Route("api/[controller]")]
[ApiController]
public class ExpeditionController : ControllerBase
{
private readonly IExpeditionDom _expeditionService; // ← este es _expeditionService
private readonly IDocumentTemplateService _documentTemplateService;
public ExpeditionController(
IDocumentTemplateService documentTemplateService,
IExpeditionDom expeditionService)
{
_documentTemplateService = documentTemplateService
?? throw new ArgumentNullException(nameof(documentTemplateService));
_expeditionService = expeditionService
?? throw new ArgumentNullException(nameof(expeditionService));
}
/// <summary>
/// Busca expediciones con filtros y paginación.
/// Filtros: número, estado, fechas de emisión, ubicación (opcional).
/// </summary>
[HttpGet("search")]
public async Task<ActionResult<PagedResult<ExpeditionDto>>> Search(
[FromQuery] string? expeditionNumber,
[FromQuery] string? status,
[FromQuery] DateTime? issueDateFrom,
[FromQuery] DateTime? issueDateTo,
[FromQuery] int? locationId,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50)
{
try
{
var result = await _expeditionService.SearchAsync(
expeditionNumber,
status,
issueDateFrom,
issueDateTo,
locationId,
page,
pageSize
);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
// GET /api/expedition/{id}
[HttpGet("{id:int}")]
[ProducesResponseType(typeof(ExpeditionDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<ExpeditionDto>> GetById(int id)
{
var dto = await _expeditionService.GetDtoByIdAsync(id);
if (dto is null) return NotFound($"Expedición con ID {id} no encontrada.");
return Ok(dto);
}
// (opcional) GET /api/expedition/summary/{expeditionNumber}
[HttpGet("summary/{expeditionNumber}")]
[ProducesResponseType(typeof(ExpeditionDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<ExpeditionDto>> GetByNumber(string expeditionNumber)
{
var dto = await _expeditionService.GetDtoByExpeditionNumberAsync(expeditionNumber);
if (dto is null) return NotFound($"No se encontró expedición {expeditionNumber}.");
return Ok(dto);
}
#region Endpoint de emision de expedicion (encabezado + detalles)
[HttpPost("createfull")]
public async Task<IActionResult> CreateFullExpedition([FromBody] CreateFullExpeditionRequest request)
{
try
{
if (request == null || request.Expedition == null)
return BadRequest("El payload no puede contener elementos nulos.");
// Delegamos al service, que ahora arma el grafo y llama al repo atómico
var (id, number) = await _expeditionService.CreateAndIssueAsync(
request.Expedition,
request.Expedition.PhLsmExpeditionDetails, // detalles vienen dentro, igual que en Quotes
request.FormSeriesId);
// <<< Simetría absoluta con QuoteController: objeto anónimo >>>
return Ok(new { Success = true, Id = id, ExpeditionNumber = number });
}
catch (InvalidOperationException ex)
{
return BadRequest($"Error de negocio: {ex.Message}");
}
catch (Exception ex)
{
return StatusCode(500, $"Ocurrió un error interno: {ex.Message}");
}
}
#endregion
/// <summary>
/// Genera y devuelve un archivo PDF correspondiente al presupuesto especificado por su ID.
/// </summary>
[HttpGet("{id}/pdf")]
public async Task<IActionResult> GetQuotePdf(int id)
{
var expedition = await _expeditionService.GetDtoByIdAsync(id);
if (expedition == null)
return NotFound($"Expedicion con ID {id} no encontrado.");
var pdfBytes = await _documentTemplateService.GenerateDocumentAsync(new DocumentGenerationRequest
{
Model = expedition,
DocumentType = DocumentType.Expedition
});
return File(pdfBytes, "application/pdf", $"Expedicion_{expedition.Expeditionnumber}.pdf");
}
[HttpPost("exportfiltered")]
public async Task<IActionResult> ExportFiltered([FromBody] ExpeditionSearchParams searchParams)
{
try
{
var file = await _expeditionService.ExportFilteredToExcelAsync(searchParams);
return File(file,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Expediciones.xlsx");
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
public class CreateFullExpeditionRequest
{
public ELSExpeditionHeader Expedition { get; set; } = default!;
public int FormSeriesId { get; set; }
}
}