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
|
#region Exportación
|
||||||
Task<byte[]> ExportFilteredQuotesToExcelAsync(QuoteSearchParams searchParams);
|
Task<byte[]> ExportFilteredQuotesToExcelAsync(QuoteSearchParams searchParams);
|
||||||
|
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -195,5 +195,69 @@ namespace PhronCare.Core.Services.Sales
|
|||||||
}
|
}
|
||||||
#endregion
|
#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.Entities;
|
||||||
using Domain.Generics;
|
using Domain.Generics;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
|
||||||
namespace Models.Interfaces
|
namespace Models.Interfaces
|
||||||
{
|
{
|
||||||
@ -40,5 +41,7 @@ namespace Models.Interfaces
|
|||||||
/// Elimina un impuesto asociado a un presupuesto a partir de su ID.
|
/// Elimina un impuesto asociado a un presupuesto a partir de su ID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task DeleteTaxAsync(int taxId);
|
Task DeleteTaxAsync(int taxId);
|
||||||
|
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
||||||
|
Task<IDbContextTransaction> BeginTransactionAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
using Domain.Generics;
|
using Domain.Generics;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
using Models.Helpers;
|
using Models.Helpers;
|
||||||
using Models.Interfaces;
|
using Models.Interfaces;
|
||||||
using Models.Models;
|
using Models.Models;
|
||||||
|
|
||||||
namespace PhronCare.Core.Data.Repositories.Sales
|
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 PhronCareOperationsHubContext _context = context;
|
||||||
|
private readonly IPhSFormSeriesRepository _formSeriesRepository = formSeriesRepository;
|
||||||
public async Task<PagedResult<EQuoteHeader>> GetAllAsync(int page = 1, int pageSize = 50)
|
public async Task<PagedResult<EQuoteHeader>> GetAllAsync(int page = 1, int pageSize = 50)
|
||||||
{
|
{
|
||||||
var query = _context.PhSQuoteHeaders
|
var query = _context.PhSQuoteHeaders
|
||||||
@ -204,5 +206,88 @@ namespace PhronCare.Core.Data.Repositories.Sales
|
|||||||
await _context.SaveChangesAsync();
|
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
|
#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": []
|
"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",
|
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
|
||||||
"Method": "Delete",
|
"Method": "Delete",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user