Add Controller QuoteCreateFull
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 3m24s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 3m24s
This commit is contained in:
parent
b1ab76aa5a
commit
09090bef21
@ -41,6 +41,7 @@ namespace Models.Interfaces
|
||||
|
||||
#region Exportación
|
||||
Task<byte[]> ExportFilteredQuotesToExcelAsync(QuoteSearchParams searchParams);
|
||||
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@ -195,5 +195,69 @@ namespace PhronCare.Core.Services.Sales
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||
public async Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId)
|
||||
{
|
||||
using var transaction = await _quoteHeaderRepository.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
// Obtener el próximo número de presupuesto desde la serie
|
||||
var nextNumber = await _formSeriesRepository.GetNextInternalNumberAsync(formSeriesId);
|
||||
quote.Quotenumber = nextNumber.ToString();
|
||||
|
||||
// Crear encabezado principal
|
||||
var headerEntity = await _quoteHeaderRepository.AddAsync(quote);
|
||||
|
||||
// Crear detalles
|
||||
if (quote.PhSQuoteDetails?.Any() == true)
|
||||
{
|
||||
foreach (var detail in quote.PhSQuoteDetails)
|
||||
{
|
||||
detail.QuoteheaderId = headerEntity.Id;
|
||||
await _quoteDetailRepository.AddAsync(detail);
|
||||
}
|
||||
}
|
||||
|
||||
// Crear roles
|
||||
if (quote.PhSQuoteRoles?.Any() == true)
|
||||
{
|
||||
foreach (var role in quote.PhSQuoteRoles)
|
||||
{
|
||||
role.QuoteheaderId = headerEntity.Id;
|
||||
await _quoteRoleRepository.AddAsync(role);
|
||||
}
|
||||
}
|
||||
|
||||
// Crear ajustes (rebajas)
|
||||
if (quote.PhSQuoteAdjustments?.Any() == true)
|
||||
{
|
||||
foreach (var adj in quote.PhSQuoteAdjustments)
|
||||
{
|
||||
adj.QuoteheaderId = headerEntity.Id;
|
||||
await _quoteHeaderRepository.AddAdjustmentAsync(adj);
|
||||
}
|
||||
}
|
||||
|
||||
// Crear impuestos
|
||||
if (quote.PhSQuoteTaxes?.Any() == true)
|
||||
{
|
||||
foreach (var tax in quote.PhSQuoteTaxes)
|
||||
{
|
||||
tax.QuoteheaderId = headerEntity.Id;
|
||||
await _quoteHeaderRepository.AddTaxAsync(tax);
|
||||
}
|
||||
}
|
||||
|
||||
await transaction.CommitAsync();
|
||||
return headerEntity.Quotenumber;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using Domain.Entities;
|
||||
using Domain.Generics;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
|
||||
namespace Models.Interfaces
|
||||
{
|
||||
@ -40,5 +41,7 @@ namespace Models.Interfaces
|
||||
/// Elimina un impuesto asociado a un presupuesto a partir de su ID.
|
||||
/// </summary>
|
||||
Task DeleteTaxAsync(int taxId);
|
||||
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
||||
Task<IDbContextTransaction> BeginTransactionAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
using Domain.Entities;
|
||||
using Domain.Generics;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Models.Helpers;
|
||||
using Models.Interfaces;
|
||||
using Models.Models;
|
||||
|
||||
namespace PhronCare.Core.Data.Repositories.Sales
|
||||
{
|
||||
public class PhSQuoteHeaderRepository(PhronCareOperationsHubContext context) : IPhSQuoteHeaderRepository
|
||||
public class PhSQuoteHeaderRepository(PhronCareOperationsHubContext context, IPhSFormSeriesRepository formSeriesRepository) : IPhSQuoteHeaderRepository
|
||||
{
|
||||
private readonly PhronCareOperationsHubContext _context = context;
|
||||
private readonly IPhSFormSeriesRepository _formSeriesRepository = formSeriesRepository;
|
||||
public async Task<PagedResult<EQuoteHeader>> GetAllAsync(int page = 1, int pageSize = 50)
|
||||
{
|
||||
var query = _context.PhSQuoteHeaders
|
||||
@ -204,5 +206,88 @@ namespace PhronCare.Core.Data.Repositories.Sales
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||
/// <summary>
|
||||
/// Crea un nuevo presupuesto, incluyendo encabezado, detalles, roles, ajustes e impuestos asociados.
|
||||
/// Genera automáticamente el número de presupuesto en base a la serie indicada.
|
||||
/// </summary>
|
||||
/// <param name="quote">Presupuesto a registrar, incluyendo entidades relacionadas.</param>
|
||||
/// <param name="formSeriesId">Identificador de la serie de numeración a utilizar.</param>
|
||||
/// <returns>Cadena con el número generado del presupuesto.</returns>
|
||||
public async Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// Obtener el próximo número de presupuesto desde SP
|
||||
var nextNumber = await _formSeriesRepository.GetNextInternalNumberAsync(formSeriesId);
|
||||
quote.Quotenumber = nextNumber.ToString();
|
||||
|
||||
// Map y guardado de Header
|
||||
var headerEntity = EntityMapper.MapEntity<EQuoteHeader, PhSQuoteHeader>(quote);
|
||||
_context.PhSQuoteHeaders.Add(headerEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Guardado de Detalles
|
||||
if (quote.PhSQuoteDetails?.Any() == true)
|
||||
{
|
||||
foreach (var detail in quote.PhSQuoteDetails)
|
||||
{
|
||||
detail.QuoteheaderId = headerEntity.Id;
|
||||
var dbDetail = EntityMapper.MapEntity<EQuoteDetail, PhSQuoteDetail>(detail);
|
||||
_context.PhSQuoteDetails.Add(dbDetail);
|
||||
}
|
||||
}
|
||||
|
||||
// Guardado de Roles
|
||||
if (quote.PhSQuoteRoles?.Any() == true)
|
||||
{
|
||||
foreach (var role in quote.PhSQuoteRoles)
|
||||
{
|
||||
role.QuoteheaderId = headerEntity.Id;
|
||||
var dbRole = EntityMapper.MapEntity<EQuoteRole, PhSQuoteRole>(role);
|
||||
_context.PhSQuoteRoles.Add(dbRole);
|
||||
}
|
||||
}
|
||||
|
||||
// Guardado de Ajustes
|
||||
if (quote.PhSQuoteAdjustments?.Any() == true)
|
||||
{
|
||||
foreach (var adj in quote.PhSQuoteAdjustments)
|
||||
{
|
||||
adj.QuoteheaderId = headerEntity.Id;
|
||||
var dbAdj = EntityMapper.MapEntity<EQuoteAdjustment, PhSQuoteAdjustment>(adj);
|
||||
_context.PhSQuoteAdjustments.Add(dbAdj);
|
||||
}
|
||||
}
|
||||
|
||||
// Guardado de Impuestos
|
||||
if (quote.PhSQuoteTaxes?.Any() == true)
|
||||
{
|
||||
foreach (var tax in quote.PhSQuoteTaxes)
|
||||
{
|
||||
tax.QuoteheaderId = headerEntity.Id;
|
||||
var dbTax = EntityMapper.MapEntity<EQuoteTax, PhSQuoteTaxis>(tax);
|
||||
_context.PhSQuoteTaxes.Add(dbTax);
|
||||
}
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
|
||||
return headerEntity.Quotenumber;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public async Task<IDbContextTransaction> BeginTransactionAsync()
|
||||
{
|
||||
return await _context.Database.BeginTransactionAsync();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -312,5 +312,32 @@ namespace phronCare.API.Controllers.Sales
|
||||
|
||||
#endregion
|
||||
|
||||
#region Endpoint de emision de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||
[HttpPost("createfull")]
|
||||
public async Task<IActionResult> CreateFullQuote([FromBody] EQuoteHeader quote, [FromQuery] int formSeriesId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (quote == null)
|
||||
return BadRequest("El presupuesto no puede ser nulo.");
|
||||
|
||||
var quoteNumber = await _quoteService.CreateFullQuoteAsync(quote, formSeriesId);
|
||||
return Ok(new { QuoteNumber = quoteNumber });
|
||||
}
|
||||
catch (ArgumentNullException ex)
|
||||
{
|
||||
return BadRequest($"Validación fallida: {ex.Message}");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest($"Error de negocio: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1704,6 +1704,27 @@
|
||||
],
|
||||
"ReturnTypes": []
|
||||
},
|
||||
{
|
||||
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
|
||||
"Method": "CreateFullQuote",
|
||||
"RelativePath": "api/Quote/createfull",
|
||||
"HttpMethod": "POST",
|
||||
"IsController": true,
|
||||
"Order": 0,
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "quote",
|
||||
"Type": "Domain.Entities.EQuoteHeader",
|
||||
"IsRequired": true
|
||||
},
|
||||
{
|
||||
"Name": "formSeriesId",
|
||||
"Type": "System.Int32",
|
||||
"IsRequired": false
|
||||
}
|
||||
],
|
||||
"ReturnTypes": []
|
||||
},
|
||||
{
|
||||
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
|
||||
"Method": "Delete",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user