Update GetByIdDTO
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 6m14s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 6m14s
This commit is contained in:
parent
510862ed60
commit
5ec19044f2
@ -19,6 +19,7 @@ namespace Models.Interfaces
|
|||||||
#endregion
|
#endregion
|
||||||
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||||
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
||||||
|
Task<QuoteDto?> GetDtoByIdAsync(int id);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@ namespace Core.Services
|
|||||||
//private readonly IPhSQuoteRepository _quoteRepository = quoteRepository;
|
//private readonly IPhSQuoteRepository _quoteRepository = quoteRepository;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Presupuestos
|
||||||
public async Task<PagedResult<QuoteDto>> SearchAsync(int? customerId, string? customerText, string? quoteNumber, int? professionalId, string? professionalText, int? institutionId, string? institutionText, int? patientId, string? patientText, DateTime? issueDateFrom, DateTime? issueDateTo, string? status, int page, int pageSize)
|
public async Task<PagedResult<QuoteDto>> SearchAsync(int? customerId, string? customerText, string? quoteNumber, int? professionalId, string? professionalText, int? institutionId, string? institutionText, int? patientId, string? patientText, DateTime? issueDateFrom, DateTime? issueDateTo, string? status, int page, int pageSize)
|
||||||
{
|
{
|
||||||
return await _quoteRepository.SearchAsync(
|
return await _quoteRepository.SearchAsync(
|
||||||
@ -31,7 +32,11 @@ namespace Core.Services
|
|||||||
page,
|
page,
|
||||||
pageSize);
|
pageSize);
|
||||||
}
|
}
|
||||||
#region Presupuestos
|
|
||||||
|
public async Task<QuoteDto?> GetDtoByIdAsync(int id)
|
||||||
|
{
|
||||||
|
return await _quoteRepository.GetDtoByIdAsync(id);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||||
|
|||||||
@ -23,9 +23,6 @@ namespace Documents.Services
|
|||||||
{
|
{
|
||||||
// 👉 Renderizar HTML usando RazorLight
|
// 👉 Renderizar HTML usando RazorLight
|
||||||
string html = await _templateRenderer.RenderAsync("Quotes/Template_v1.cshtml", request.Model);
|
string html = await _templateRenderer.RenderAsync("Quotes/Template_v1.cshtml", request.Model);
|
||||||
|
|
||||||
// 🔍 Dump HTML a archivo temporal para inspección
|
|
||||||
File.WriteAllText("/tmp/html_debug_output.html", html, Encoding.UTF8);
|
|
||||||
// 👉 Generar PDF desde el HTML
|
// 👉 Generar PDF desde el HTML
|
||||||
return await _pdfGeneratorService.GeneratePdfFromHtmlAsync(html);
|
return await _pdfGeneratorService.GeneratePdfFromHtmlAsync(html);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
@model Domain.Dtos.QuoteDto
|
@using Domain.Dtos
|
||||||
|
@using System.Globalization
|
||||||
|
@model Domain.Dtos.QuoteDto
|
||||||
|
|
||||||
@{
|
@{
|
||||||
var culture = System.Globalization.CultureInfo.GetCultureInfo("es-AR");
|
var culture = CultureInfo.GetCultureInfo("es-AR");
|
||||||
}
|
}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -10,171 +13,163 @@
|
|||||||
<title>Presupuesto @Model.Quotenumber</title>
|
<title>Presupuesto @Model.Quotenumber</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: "Liberation Sans", "DejaVu Sans", sans-serif;
|
font-family: 'Liberation Sans', Arial, sans-serif;
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
color: #222;
|
color: #000;
|
||||||
margin: 40px;
|
margin: 30px;
|
||||||
line-height: 1.5;
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.company-info {
|
h1, h2, h3 {
|
||||||
font-size: 11px;
|
margin: 0;
|
||||||
line-height: 1.4;
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 10px;
|
||||||
color: #444;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header, .footer {
|
.section {
|
||||||
text-align: center;
|
margin-top: 10px;
|
||||||
}
|
min-height: 60px;
|
||||||
|
|
||||||
.footer {
|
|
||||||
font-size: 10px;
|
|
||||||
margin-top: 40px;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 22px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
color: #004B8D;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-top: 30px;
|
|
||||||
color: #004B8D;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-top: 10px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
padding: 6px;
|
padding: 4px;
|
||||||
vertical-align: top;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.totals-table td {
|
.totales {
|
||||||
border: none;
|
margin-top: 10px;
|
||||||
|
float: right;
|
||||||
|
width: 45%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.footer {
|
||||||
text-align: right;
|
text-align: center;
|
||||||
}
|
font-size: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
.highlight {
|
color: #666;
|
||||||
background-color: #e6f7ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.observaciones {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 10px;
|
|
||||||
background: #f9f9f9;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="company-info">
|
|
||||||
<strong>BIODEC S.A.</strong><br />
|
|
||||||
CUIT: 33-70849672-9 | Ing. Brutos: 901-070604-2<br />
|
|
||||||
Inicio Actividades: 02/10/2003 | IVA: Responsable Inscripto<br />
|
|
||||||
Segurola 1885 – C.P. C1407AOK – CABA – Buenos Aires – Argentina<br />
|
|
||||||
Tel: (011) 4864-6005 | Fax: 4864-5710<br />
|
|
||||||
<a href="mailto:ventas@biodec.net">ventas@biodec.net</a> |
|
|
||||||
Web: www.biodec.net<br />
|
|
||||||
Urgencias: 15-2155-9380 / 15-5909-4987 / 15-5909-4892
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>phronCare - Presupuesto</h1>
|
<h2>Presupuesto Nº @Model.Quotenumber</h2>
|
||||||
<p><strong>Número:</strong> @Model.Quotenumber</p>
|
<p>Fecha de emisión: @Model.IssueDate.ToString("dd/MM/yyyy")</p>
|
||||||
<p><strong>Fecha de Emisión:</strong> @Model.IssueDate.ToString("dd/MM/yyyy")</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Datos del Cliente</h2>
|
<div class="section">
|
||||||
<table>
|
<h3>Datos del Cliente</h3>
|
||||||
<tr><th>Razón Social</th><td>@Model.CustomerName</td></tr>
|
<p><strong>Nombre:</strong> @Model.Customer.Name</p>
|
||||||
<tr><th>Paciente</th><td>@Model.PatientName</td></tr>
|
<p><strong>Domicilio:</strong> @Model.Customer.Address</p>
|
||||||
<tr><th>Médico</th><td>@Model.ProfessionalName</td></tr>
|
<p><strong>Condición IVA:</strong> @Model.Customer.IvaCondition</p>
|
||||||
<tr><th>Institución</th><td>@Model.InstitutionName</td></tr>
|
@if (Model.Customer.Documents != null && Model.Customer.Documents.Any())
|
||||||
<tr><th>Fecha estimada cirugía</th><td>@(Model.EstimatedDate?.ToString("dd/MM/yyyy") ?? "-")</td></tr>
|
{
|
||||||
</table>
|
<p><strong>Documentos:</strong></p>
|
||||||
|
<ul>
|
||||||
|
@foreach (var doc in Model.Customer.Documents)
|
||||||
|
{
|
||||||
|
<li>@doc.DocumentType: @doc.Number</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>— Sin documentos —</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Productos Cotizados</h2>
|
<div class="section">
|
||||||
|
<h3>Datos del Paciente y Atención</h3>
|
||||||
|
<p><strong>Paciente:</strong> @Model.PatientName</p>
|
||||||
|
<p><strong>Médico:</strong> @Model.ProfessionalName</p>
|
||||||
|
<p><strong>Institución:</strong> @Model.InstitutionName</p>
|
||||||
|
<p><strong>Fecha estimada:</strong> @(Model.EstimatedDate?.ToString("dd/MM/yyyy") ?? "—")</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h3>Productos Cotizados</h3>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Cantidad</th>
|
|
||||||
<th>Descripción</th>
|
<th>Descripción</th>
|
||||||
<th class="right">Precio Unitario (@Model.Currency)</th>
|
<th>Cantidad</th>
|
||||||
<th class="right">Total (@Model.Currency)</th>
|
<th>Precio Unitario</th>
|
||||||
|
<th>Subtotal</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var item in Model.Items)
|
@foreach (var item in Model.Items)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td>@item.Quantity</td>
|
|
||||||
<td>@item.Description</td>
|
<td>@item.Description</td>
|
||||||
<td class="right">@item.UnitPrice.ToString("C", culture)</td>
|
<td>@item.Quantity</td>
|
||||||
<td class="right">@item.Total.ToString("C", culture)</td>
|
<td>@item.UnitPrice.ToString("C", culture)</td>
|
||||||
|
<td>@item.Total.ToString("C", culture)</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Totales</h2>
|
<div class="section">
|
||||||
<table class="totals-table">
|
<h3>Totales</h3>
|
||||||
|
<table class="totales">
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="right"><strong>Subtotal:</strong></td>
|
<td><strong>Subtotal</strong></td>
|
||||||
<td class="right">@Model.Items.Sum(i => i.Subtotal).ToString("C", culture)</td>
|
<td>@Model.Items.Sum(i => i.Subtotal).ToString("C", culture)</td>
|
||||||
</tr>
|
</tr>
|
||||||
@if (Model.Taxes?.Any() == true)
|
@if (Model.Taxes?.Any() == true)
|
||||||
{
|
{
|
||||||
foreach (var tax in Model.Taxes)
|
@foreach (var tax in Model.Taxes)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="right"><strong>@tax.TaxName (@tax.TaxRate%)</strong></td>
|
<td><strong>@tax.TaxName (@tax.TaxRate%)</strong></td>
|
||||||
<td class="right">@tax.TaxAmount.ToString("C", culture)</td>
|
<td>@tax.TaxAmount.ToString("C", culture)</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@if (Model.Adjustments?.Any() == true)
|
@if (Model.Adjustments?.Any() == true)
|
||||||
{
|
{
|
||||||
foreach (var adj in Model.Adjustments)
|
@foreach (var adj in Model.Adjustments)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="right"><strong>Ajuste: @adj.Reason</strong></td>
|
<td><strong>Ajuste: @adj.Reason</strong></td>
|
||||||
<td class="right">@adj.Amount.ToString("C", culture)</td>
|
<td>@adj.Amount.ToString("C", culture)</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<tr class="highlight">
|
<tr>
|
||||||
<td class="right"><strong>Total Final:</strong></td>
|
<td><strong>Total Final</strong></td>
|
||||||
<td class="right">@Model.Total.ToString("C", culture)</td>
|
<td>@Model.Total.ToString("C", culture)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Observaciones</h2>
|
<div class="section">
|
||||||
<div class="observaciones">
|
<h3>Observaciones</h3>
|
||||||
@Model.Observations
|
<p>@(string.IsNullOrWhiteSpace(Model.Observations) ? "— Sin observaciones —" : Model.Observations)</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>Sistema de gestión y administración PhronCare © 2025</p>
|
<p>Sistema de Gestión y Administración - PhronCare © 2025</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -3,10 +3,8 @@
|
|||||||
public class QuoteCustomerDto
|
public class QuoteCustomerDto
|
||||||
{
|
{
|
||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = "";
|
||||||
public string Cuit { get; set; } = "";
|
|
||||||
public string IngresosBrutos { get; set; } = "";
|
|
||||||
public string Address { get; set; } = "";
|
public string Address { get; set; } = "";
|
||||||
public string IvaCondition { get; set; } = "";
|
public string IvaCondition { get; set; } = "";
|
||||||
|
public List<QuoteCustomerDocumentDto> Documents { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
8
Domain/Dtos/QuoteCustomerDocumentDto.cs
Normal file
8
Domain/Dtos/QuoteCustomerDocumentDto.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Domain.Dtos
|
||||||
|
{
|
||||||
|
public class QuoteCustomerDocumentDto
|
||||||
|
{
|
||||||
|
public string DocumentType { get; set; } = "";
|
||||||
|
public string Number { get; set; } = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ namespace Models.Interfaces
|
|||||||
#endregion
|
#endregion
|
||||||
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||||
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
Task<string> CreateFullQuoteAsync(EQuoteHeader quote, int formSeriesId);
|
||||||
|
Task<QuoteDto?> GetDtoByIdAsync(int id);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,6 +213,129 @@ namespace Models.Repositories
|
|||||||
PageSize = pagedEntities.PageSize
|
PageSize = pagedEntities.PageSize
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
public async Task<QuoteDto?> GetDtoByIdAsync(int id)
|
||||||
|
{
|
||||||
|
var header = await _context.PhSQuoteHeaders
|
||||||
|
.Include(q => q.PhSQuoteDetails)
|
||||||
|
.Include(q => q.PhSQuoteRoles)
|
||||||
|
.Include(q => q.PhSQuoteAdjustments)
|
||||||
|
.Include(q => q.PhSQuoteTaxes)
|
||||||
|
.FirstOrDefaultAsync(q => q.Id == id);
|
||||||
|
|
||||||
|
if (header == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Cargar Customer completo con documentos y tipos
|
||||||
|
var customer = await _context.PhSCustomers
|
||||||
|
.Include(c => c.PhSCustomerDocuments)
|
||||||
|
.ThenInclude(d => d.Documenttypes) // ✅ CORRECTO
|
||||||
|
.Include(c => c.PhSCustomerAddresses)
|
||||||
|
.Include(c => c.TaxCondition)
|
||||||
|
.FirstOrDefaultAsync(c => c.Id == header.CustomerId);
|
||||||
|
|
||||||
|
var totalTaxAmount = header.PhSQuoteTaxes.Sum(t => t.Taxamount);
|
||||||
|
var netBase = header.Netamount.GetValueOrDefault() != 0m
|
||||||
|
? header.Netamount.Value
|
||||||
|
: 1m;
|
||||||
|
|
||||||
|
var dto = new QuoteDto
|
||||||
|
{
|
||||||
|
Id = header.Id,
|
||||||
|
Quotenumber = header.Quotenumber,
|
||||||
|
IssueDate = header.Issuedate,
|
||||||
|
EstimatedDate = header.Estimateddate,
|
||||||
|
Currency = header.Currency,
|
||||||
|
Total = header.Total.GetValueOrDefault(0m),
|
||||||
|
Status = header.Status.Trim(),
|
||||||
|
Observations = header.Observations ?? "",
|
||||||
|
|
||||||
|
CustomerName = customer?.Name ?? "",
|
||||||
|
BusinessUnitName = _context.PhSBusinessUnits
|
||||||
|
.Where(b => b.Id == header.BusinessunitId)
|
||||||
|
.Select(b => b.Code)
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
|
||||||
|
ProfessionalName = header.PhSQuoteRoles
|
||||||
|
.Where(r => r.Entitytype == PhSEntityTypes.Professional)
|
||||||
|
.Select(r => _context.PhSProfessionals
|
||||||
|
.Where(p => p.Id == r.EntityId)
|
||||||
|
.Select(p => p.Fullname)
|
||||||
|
.FirstOrDefault())
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
|
||||||
|
InstitutionName = header.PhSQuoteRoles
|
||||||
|
.Where(r => r.Entitytype == PhSEntityTypes.Institution)
|
||||||
|
.Select(r => _context.PhSInstitutions
|
||||||
|
.Where(i => i.Id == r.EntityId)
|
||||||
|
.Select(i => i.Name)
|
||||||
|
.FirstOrDefault())
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
|
||||||
|
PatientName = header.PhSQuoteRoles
|
||||||
|
.Where(r => r.Entitytype == PhSEntityTypes.Patient)
|
||||||
|
.Select(r => _context.PhSPatients
|
||||||
|
.Where(pt => pt.Id == r.EntityId)
|
||||||
|
.Select(pt => (pt.Firstname + " " + pt.Lastname).Trim())
|
||||||
|
.FirstOrDefault())
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
|
||||||
|
SalespersonName = _context.PhSPeople
|
||||||
|
.Where(u => u.Id == header.PeopleId)
|
||||||
|
.Select(u => u.Name)
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
|
||||||
|
Items = header.PhSQuoteDetails.Select(d =>
|
||||||
|
{
|
||||||
|
var itemBase = d.Quantity * d.Unitprice;
|
||||||
|
var itemTax = totalTaxAmount * itemBase / netBase;
|
||||||
|
|
||||||
|
return new QuoteItemDto
|
||||||
|
{
|
||||||
|
Description = d.ProductDescription,
|
||||||
|
Quantity = d.Quantity,
|
||||||
|
UnitPrice = d.Unitprice,
|
||||||
|
Subtotal = itemBase,
|
||||||
|
TaxAmount = itemTax,
|
||||||
|
Total = itemBase + itemTax
|
||||||
|
};
|
||||||
|
}).ToList(),
|
||||||
|
|
||||||
|
Taxes = header.PhSQuoteTaxes.Select(t => new QuoteTaxDto
|
||||||
|
{
|
||||||
|
TaxName = t.Taxname,
|
||||||
|
TaxCode = t.Taxcode,
|
||||||
|
TaxableAmount = t.TaxableAmount,
|
||||||
|
TaxRate = t.Taxrate,
|
||||||
|
TaxAmount = t.Taxamount,
|
||||||
|
IsIncludedInPrice = t.IsIncludedInPrice
|
||||||
|
}).ToList(),
|
||||||
|
|
||||||
|
Adjustments = header.PhSQuoteAdjustments.Select(a => new QuoteAdjustmentDto
|
||||||
|
{
|
||||||
|
Reason = _context.PhSAdjustmentReasons
|
||||||
|
.Where(r => r.Code == a.ReasonCode)
|
||||||
|
.Select(r => r.Description)
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
Amount = a.Amount.GetValueOrDefault(0m)
|
||||||
|
}).ToList(),
|
||||||
|
|
||||||
|
Customer = new QuoteCustomerDto
|
||||||
|
{
|
||||||
|
Name = customer?.Name ?? "",
|
||||||
|
Address = customer?.PhSCustomerAddresses
|
||||||
|
.Select(a => a.Streetaddress1)
|
||||||
|
.FirstOrDefault() ?? "",
|
||||||
|
IvaCondition = customer?.TaxCondition?.Description ?? "",
|
||||||
|
Documents = customer?.PhSCustomerDocuments
|
||||||
|
.Select(d => new QuoteCustomerDocumentDto
|
||||||
|
{
|
||||||
|
DocumentType = d.Documenttypes.Name, // ✅ correcto
|
||||||
|
Number = d.DocumentNumber
|
||||||
|
}).ToList() ?? new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
#region Guardado completo de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||||
|
|||||||
22
phronCare.API/Controllers/Documents/DocumentsController.cs
Normal file
22
phronCare.API/Controllers/Documents/DocumentsController.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Documents.Interfaces;
|
||||||
|
using Documents.Models;
|
||||||
|
using Domain.Dtos;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Models.Interfaces;
|
||||||
|
|
||||||
|
namespace phronCare.API.Controllers.Documents
|
||||||
|
{
|
||||||
|
public class DocumentController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IDocumentTemplateService _documentTemplateService;
|
||||||
|
private readonly IQuoteDom _quoteService;
|
||||||
|
|
||||||
|
public DocumentController(IDocumentTemplateService documentTemplateService, IQuoteDom quoteService)
|
||||||
|
{
|
||||||
|
_documentTemplateService = documentTemplateService;
|
||||||
|
_quoteService = quoteService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,11 @@
|
|||||||
using Domain.Dtos;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Documents.Models;
|
||||||
|
using Domain.Dtos;
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
using Domain.Generics;
|
using Domain.Generics;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Models.Interfaces;
|
using Models.Interfaces;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Documents.Interfaces;
|
||||||
|
|
||||||
namespace phronCare.API.Controllers.Sales
|
namespace phronCare.API.Controllers.Sales
|
||||||
{
|
{
|
||||||
@ -11,10 +13,14 @@ namespace phronCare.API.Controllers.Sales
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class QuoteController : ControllerBase
|
public class QuoteController : ControllerBase
|
||||||
{
|
{
|
||||||
|
private readonly IDocumentTemplateService _documentTemplateService;
|
||||||
private readonly IQuoteDom _quoteService;
|
private readonly IQuoteDom _quoteService;
|
||||||
public QuoteController(IQuoteDom quoteService)
|
public QuoteController(IDocumentTemplateService documentTemplateService, IQuoteDom quoteService)
|
||||||
{
|
{
|
||||||
_quoteService = quoteService ?? throw new ArgumentNullException(nameof(quoteService));
|
_documentTemplateService = documentTemplateService ??
|
||||||
|
throw new ArgumentNullException(nameof(documentTemplateService)); ;
|
||||||
|
_quoteService = quoteService ??
|
||||||
|
throw new ArgumentNullException(nameof(quoteService));
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Obtener Presupuestos
|
#region Obtener Presupuestos
|
||||||
@ -65,143 +71,24 @@ namespace phronCare.API.Controllers.Sales
|
|||||||
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("quote/{id}/pdf")]
|
||||||
|
public async Task<IActionResult> GetQuotePdf(int id)
|
||||||
|
{
|
||||||
|
var quote = await _quoteService.GetDtoByIdAsync(id);
|
||||||
|
|
||||||
|
if (quote == null)
|
||||||
|
return NotFound($"Presupuesto con ID {id} no encontrado.");
|
||||||
|
|
||||||
|
var pdfBytes = await _documentTemplateService.GenerateDocumentAsync(new DocumentGenerationRequest
|
||||||
|
{
|
||||||
|
Model = quote
|
||||||
|
});
|
||||||
|
|
||||||
|
return File(pdfBytes, "application/pdf", $"Presupuesto_{quote.Quotenumber}.pdf");
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
//[HttpGet("all")]
|
|
||||||
//public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 50)
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var result = await _quoteService.GetAllQuotesAsync(page, pageSize);
|
|
||||||
// return Ok(result);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
|
||||||
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//[HttpGet("search")]
|
|
||||||
//public async Task<IActionResult> Search(
|
|
||||||
// [FromQuery] int? customerId,
|
|
||||||
// [FromQuery] string? customerText,
|
|
||||||
// [FromQuery] string? quoteNumber,
|
|
||||||
// [FromQuery] int? professionalId,
|
|
||||||
// [FromQuery] string? professionalText,
|
|
||||||
// [FromQuery] int? institutionId,
|
|
||||||
// [FromQuery] string? institutionText,
|
|
||||||
// [FromQuery] int? patientId,
|
|
||||||
// [FromQuery] string? patientText,
|
|
||||||
// [FromQuery] DateTime? issueDateFrom,
|
|
||||||
// [FromQuery] DateTime? issueDateTo,
|
|
||||||
// [FromQuery] string? status,
|
|
||||||
// [FromQuery] int page = 1,
|
|
||||||
// [FromQuery] int pageSize = 50)
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var result = await _quoteService.SearchAsync(
|
|
||||||
// customerId,
|
|
||||||
// customerText,
|
|
||||||
// quoteNumber,
|
|
||||||
// professionalId,
|
|
||||||
// professionalText,
|
|
||||||
// institutionId,
|
|
||||||
// institutionText,
|
|
||||||
// patientId,
|
|
||||||
// patientText,
|
|
||||||
// issueDateFrom,
|
|
||||||
// issueDateTo,
|
|
||||||
// status,
|
|
||||||
// page,
|
|
||||||
// pageSize);
|
|
||||||
|
|
||||||
// return Ok(result);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
|
||||||
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//[HttpGet("{id:int}")]
|
|
||||||
//public async Task<ActionResult<EQuoteHeader>> GetById(int id)
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var quote = await _quoteService.GetQuoteByIdAsync(id);
|
|
||||||
// if (quote == null)
|
|
||||||
// return NotFound();
|
|
||||||
|
|
||||||
// return Ok(quote);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
|
||||||
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Crear / Actualizar / Eliminar
|
|
||||||
|
|
||||||
//[HttpPut("update")]
|
|
||||||
//public async Task<IActionResult> Update([FromBody] EQuoteHeader quote)
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// if (quote == null || quote.Id <= 0)
|
|
||||||
// return BadRequest("El presupuesto es inválido o no tiene un ID válido.");
|
|
||||||
|
|
||||||
// await _quoteService.UpdateQuoteAsync(quote);
|
|
||||||
// return Ok("Presupuesto actualizado correctamente.");
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
|
||||||
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//[HttpDelete("delete/{id:int}")]
|
|
||||||
//public async Task<IActionResult> Delete(int id)
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// await _quoteService.DeleteQuoteAsync(id);
|
|
||||||
// return Ok("Presupuesto eliminado correctamente.");
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
|
||||||
// return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
//#region Exportación
|
|
||||||
|
|
||||||
//[HttpPost("exportfiltered")]
|
|
||||||
//public async Task<IActionResult> ExportFiltered([FromBody] QuoteSearchParams searchParams)
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var file = await _quoteService.ExportFilteredQuotesToExcelAsync(searchParams);
|
|
||||||
// return File(file,
|
|
||||||
// "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
||||||
// "Presupuestos.xlsx");
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// return BadRequest(ex.Message);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
#region Endpoint de emision de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
#region Endpoint de emision de presupuesto (encabezado + detalles + roles + ajustes + impuestos)
|
||||||
[HttpPost("createfull")]
|
[HttpPost("createfull")]
|
||||||
public async Task<IActionResult> CreateFullQuote([FromBody] CreateFullQuoteRequest request)
|
public async Task<IActionResult> CreateFullQuote([FromBody] CreateFullQuoteRequest request)
|
||||||
@ -243,5 +130,7 @@ namespace phronCare.API.Controllers.Sales
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1602,6 +1602,22 @@
|
|||||||
],
|
],
|
||||||
"ReturnTypes": []
|
"ReturnTypes": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
|
||||||
|
"Method": "GetQuotePdf",
|
||||||
|
"RelativePath": "api/Quote/quote/{id}/pdf",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "id",
|
||||||
|
"Type": "System.Int32",
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
|
"ContainingType": "phronCare.API.Controllers.Sales.QuoteController",
|
||||||
"Method": "Search",
|
"Method": "Search",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user