Fix UI Quotes
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 6m30s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 6m30s
This commit is contained in:
parent
c2bd8247a1
commit
a462e1791c
@ -7,12 +7,14 @@
|
||||
@inject QuoteService quoteService
|
||||
@inject IToastService toastService
|
||||
|
||||
<div class="card" style="zoom:80%">
|
||||
<div class="card-header d-flex justify-content-center align-items-center">
|
||||
<h3 class="card-title m-0">Consulta de Presupuestos</h3>
|
||||
<div class="card shadow-sm mb-3" style="zoom: 0.8;">
|
||||
<div class="card-header py-2">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<h3 class="card-title m-0">Consulta de Presupuestos</h3>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BODY -->
|
||||
<div class="card-body px-4">
|
||||
<div class="card-body">
|
||||
<!-- FILTROS -->
|
||||
<div class="mb-3 row g-2 align-items-end">
|
||||
<div class="col-sm">
|
||||
@ -55,7 +57,7 @@
|
||||
<label for="dateto">Hasta</label>
|
||||
<InputDate id="dateto" @bind-Value="Filters.IssueDateTo" class="form-control form-control-sm" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="d-flex justify-content-end gap-2 mt-3">
|
||||
<button class="btn btn-primary btn-sm rounded-pill" @onclick="Search">
|
||||
<i class="fas fa-binoculars me-1"></i> Buscar
|
||||
</button>
|
||||
@ -67,228 +69,231 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm" style="zoom:0.8;">
|
||||
<div class="table-responsive">
|
||||
<!-- TABLA DE RESULTADOS -->
|
||||
@if (PagedQuotes?.Items?.Any() == true)
|
||||
{
|
||||
<table class="table table-sm table-hover" style="zoom:0.9;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Quotenumber</th>
|
||||
<th>Emisión</th>
|
||||
<th>Estimada</th>
|
||||
<th>Cliente</th>
|
||||
<th>Médico</th>
|
||||
<th>Hospital</th>
|
||||
<th>Paciente</th>
|
||||
<th>Unidad</th>
|
||||
<th>Moneda</th>
|
||||
<th>Total</th>
|
||||
<th>Estado</th>
|
||||
<th>Vendedor</th>
|
||||
<th style="width:80px;">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<table class="table table-sm align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Quotenumber</th>
|
||||
<th>Emisión</th>
|
||||
<th>Estimada</th>
|
||||
<th>Cliente</th>
|
||||
<th>Médico</th>
|
||||
<th>Hospital</th>
|
||||
<th>Paciente</th>
|
||||
<th>Unidad</th>
|
||||
<th>Moneda</th>
|
||||
<th>Total</th>
|
||||
<th>Estado</th>
|
||||
<th>Vendedor</th>
|
||||
<th style="width:80px;">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (PagedQuotes?.Items?.Any() == true)
|
||||
{
|
||||
@foreach (var quote in PagedQuotes.Items)
|
||||
{
|
||||
<tr class="text-center">
|
||||
<td>@quote.Quotenumber</td>
|
||||
<td>@quote.IssueDate.ToString("dd/MM/yyyy")</td>
|
||||
<td>@(quote.EstimatedDate.HasValue ? quote.EstimatedDate.Value.ToString("dd/MM/yyyy") : "—")</td>
|
||||
<td>@quote.CustomerName</td>
|
||||
<td>@quote.ProfessionalName</td>
|
||||
<td>@quote.InstitutionName</td>
|
||||
<td>@quote.PatientName</td>
|
||||
<td>@quote.BusinessUnitName</td>
|
||||
<td>@quote.Currency</td>
|
||||
<td>@string.Format("{0:N2}", quote.Total)</td>
|
||||
<td>
|
||||
<span class="badge @GetStatusBadge(quote.Status)">@quote.Status</span>
|
||||
</td>
|
||||
<td>@quote.SalespersonName</td>
|
||||
<td class="text-center align-middle">
|
||||
<button class="btn btn-link btn-lg p-0 text-primary ms-2" title="Ver detalle" @onclick="() => ToggleDetail(quote)"><i class="fas fa-eye"></i></button>
|
||||
<button class="btn btn-link btn-lg p-0 text-success ms-2" title="Generar PDF" @onclick="() => PrintPdf(quote.Id, quote.Quotenumber)"><i class="fas fa-print"></i></button>
|
||||
@if (quote.Status?.ToLower() == "emitido")
|
||||
{
|
||||
<button class="btn btn-link btn-lg p-0 text-info ms-2"
|
||||
title="Autorizar presupuesto"
|
||||
@onclick="() => Autorizar(quote.Id)">
|
||||
<i class="fas fa-unlock"></i>
|
||||
</button>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="text-center">
|
||||
<td>@quote.Quotenumber</td>
|
||||
<td>@quote.IssueDate.ToString("dd/MM/yyyy")</td>
|
||||
<td>@(quote.EstimatedDate.HasValue ? quote.EstimatedDate.Value.ToString("dd/MM/yyyy") : "—")</td>
|
||||
<td>@quote.CustomerName</td>
|
||||
<td>@quote.ProfessionalName</td>
|
||||
<td>@quote.InstitutionName</td>
|
||||
<td>@quote.PatientName</td>
|
||||
<td>@quote.BusinessUnitName</td>
|
||||
<td>@quote.Currency</td>
|
||||
<td>@string.Format("{0:N2}", quote.Total)</td>
|
||||
<td>
|
||||
<span class="badge @GetStatusBadge(quote.Status)">@quote.Status</span>
|
||||
</td>
|
||||
<td>@quote.SalespersonName</td>
|
||||
<td class="text-center align-middle">
|
||||
<button class="btn btn-link btn-lg p-0 text-primary ms-2" title="Ver detalle" @onclick="() => ToggleDetail(quote)"><i class="fas fa-eye"></i></button>
|
||||
<button class="btn btn-link btn-lg p-0 text-success ms-2" title="Generar PDF" @onclick="() => PrintPdf(quote.Id, quote.Quotenumber)"><i class="fas fa-print"></i></button>
|
||||
@if (quote.Status?.ToLower() == "emitido")
|
||||
{
|
||||
<button class="btn btn-link btn-lg p-0 text-info ms-2"
|
||||
title="Autorizar presupuesto"
|
||||
@onclick="() => Autorizar(quote.Id)">
|
||||
<i class="fas fa-unlock"></i>
|
||||
</button>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (SelectedQuote != null)
|
||||
{
|
||||
<!-- BACKDROP semitransparente -->
|
||||
<div class="position-fixed top-0 start-0 w-100 h-100" style="background: rgba(0,0,0,0.4);"></div>
|
||||
<!-- DRAWER LATERAL -->
|
||||
<div class="position-fixed top-0 end-0 h-100 bg-white shadow" style="width: 45%; z-index:1050;">
|
||||
<!-- CABECERA -->
|
||||
<div class="d-flex justify-content-between align-items-center border-bottom px-3 py-2">
|
||||
<h5 class="m-0">Detalle Presupuesto @SelectedQuote?.Quotenumber</h5>
|
||||
<button class="btn-close" @onclick="() => SelectedQuote = null"></button>
|
||||
</div>
|
||||
<!-- CONTENIDO -->
|
||||
<div class="p-3">
|
||||
<ul class="nav nav-tabs mb-3" role="tablist">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link @((activeTab == "Datos") ? "active bg-primary text-white" : "")"
|
||||
@onclick='() => activeTab = "Datos"'
|
||||
title="Datos generales">
|
||||
<i class="fas fa-info-circle me-1"></i> Datos
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link @((activeTab == "Items") ? "active bg-success text-white" : "")"
|
||||
@onclick='() => activeTab = "Items"'
|
||||
title="Productos e impuestos">
|
||||
<i class="fas fa-boxes-stacked me-1"></i> Items
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@if (activeTab == "Datos")
|
||||
{
|
||||
<dl class="row">
|
||||
<dt class="col-5">Cliente:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.CustomerName</dd>
|
||||
<dt class="col-5">Médico:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.ProfessionalName</dd>
|
||||
<dt class="col-5">Hospital:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.InstitutionName</dd>
|
||||
<dt class="col-5">Paciente:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.PatientName</dd>
|
||||
<dt class="col-5">Emisión:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.IssueDate.ToString("dd/MM/yyyy")</dd>
|
||||
<dt class="col-5">Estimada:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.EstimatedDate?.ToString("dd/MM/yyyy")</dd>
|
||||
<dt class="col-5">Unidad Negocio:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.BusinessUnitName</dd>
|
||||
<dt class="col-5">Moneda:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.Currency</dd>
|
||||
<dt class="col-5">Vendedor:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.SalespersonName</dd>
|
||||
<dt class="col-5">Estado:</dt>
|
||||
<dd class="col-7">
|
||||
<span class="badge @GetStatusBadge(SelectedQuote?.Status ?? "")">@SelectedQuote?.Status</span>
|
||||
</dd>
|
||||
<dt class="col-5">Observaciones:</dt>
|
||||
<dd class="col-7">SN</dd>
|
||||
</dl>
|
||||
}
|
||||
else if (activeTab == "Items")
|
||||
{
|
||||
if (SelectedQuote?.Items == null || !SelectedQuote.Items.Any())
|
||||
{
|
||||
<p>No hay productos en este presupuesto.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h6 class="mt-2"><i class="fas fa-box-open me-1"></i> Productos cotizados</h6>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Descripción</th>
|
||||
<th>Cant.</th>
|
||||
<th>Precio U.</th>
|
||||
<th>Subtotal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in SelectedQuote.Items)
|
||||
{
|
||||
<tr>
|
||||
<td>@item.Description</td>
|
||||
<td>@item.Quantity</td>
|
||||
<td>@string.Format("{0:N2}", item.UnitPrice)</td>
|
||||
<td>@string.Format("{0:N2}", item.Quantity * item.UnitPrice)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
if (SelectedQuote?.Taxes != null && SelectedQuote.Taxes.Any())
|
||||
{
|
||||
<hr class="my-3" />
|
||||
<h6 class="mt-4"><i class="fas fa-receipt me-1"></i> Impuestos aplicados</h6>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Impuesto</th>
|
||||
<th>Código</th>
|
||||
<th>Porcentaje</th>
|
||||
<th>Importe</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var tax in SelectedQuote.Taxes)
|
||||
{
|
||||
<tr>
|
||||
<td>@tax.TaxName</td>
|
||||
<td>@tax.TaxCode</td>
|
||||
<td>@string.Format("{0:N2}%", tax.TaxRate)</td>
|
||||
<td>@string.Format("{0:N2}", tax.TaxAmount)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else if (IsLoading)
|
||||
{
|
||||
<p>Cargando...</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>No hay resultados.</p>
|
||||
}
|
||||
}
|
||||
else if (IsLoading)
|
||||
{
|
||||
<tr><td colspan="13" class="text-center text-muted py-4">Cargando...</td></tr>
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr><td colspan="13" class="text-center text-muted py-4">Sin resultados</td></tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- FOOTER: PAGINACIÓN -->
|
||||
<div class="card-footer d-flex justify-content-center align-items-center" style="zoom:80%;">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<button class="btn btn-secondary btn-sm rounded-pill" @onclick="PrimeraPagina" disabled="@(Filters.Page == 1)">
|
||||
<!-- Paginación debajo -->
|
||||
<div class="d-flex justify-content-between align-items-center px-3 py-2 border-top">
|
||||
<div class="btn-group align-items-center">
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill" @onclick="PrimeraPagina" disabled="@(Filters.Page == 1)">
|
||||
<i class="fas fa-angle-double-left me-1"></i> Primera
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm rounded-pill" @onclick="AnteriorPagina" disabled="@(!PuedeRetroceder)">
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill" @onclick="AnteriorPagina" disabled="@(!PuedeRetroceder)">
|
||||
<i class="fas fa-chevron-left me-1"></i> Anterior
|
||||
</button>
|
||||
<span class="mx-2">
|
||||
Página <strong>@Filters.Page</strong> de <strong>@TotalPaginas</strong>
|
||||
</span>
|
||||
<button class="btn btn-secondary btn-sm rounded-pill" @onclick="SiguientePagina" disabled="@(!PuedeAvanzar)">
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill" @onclick="SiguientePagina" disabled="@(!PuedeAvanzar)">
|
||||
Siguiente <i class="fas fa-chevron-right ms-1"></i>
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm rounded-pill" @onclick="UltimaPagina" disabled="@(Filters.Page == TotalPaginas)">
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill" @onclick="UltimaPagina" disabled="@(Filters.Page == TotalPaginas)">
|
||||
Última <i class="fas fa-angle-double-right ms-1"></i>
|
||||
</button>
|
||||
<div class="d-flex align-items-center ms-3">
|
||||
<input type="number"
|
||||
class="form-control form-control-sm rounded"
|
||||
style="width: 80px;"
|
||||
min="1"
|
||||
max="@TotalPaginas"
|
||||
@bind="PaginaDeseada" />
|
||||
<button class="btn btn-outline-primary btn-sm ms-2 rounded-pill" @onclick="IrAPagina">
|
||||
<i class="fas fa-arrow-right-to-bracket me-1"></i> Ir
|
||||
</button>
|
||||
class="form-control form-control-sm rounded"
|
||||
style="width: 80px;"
|
||||
min="1"
|
||||
max="@TotalPaginas"
|
||||
@bind="PaginaDeseada" />
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary btn-sm rounded-pill" @onclick="IrAPagina">
|
||||
<i class="fas fa-arrow-right-to-bracket me-1"></i> Ir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (SelectedQuote != null)
|
||||
{
|
||||
<!-- BACKDROP semitransparente -->
|
||||
<div class="position-fixed top-0 start-0 w-100 h-100" style="background: rgba(0,0,0,0.4);"></div>
|
||||
<!-- DRAWER LATERAL -->
|
||||
<div class="position-fixed top-0 end-0 h-100 bg-white shadow" style="width: 45%; z-index:1050;">
|
||||
<!-- CABECERA -->
|
||||
<div class="d-flex justify-content-between align-items-center border-bottom px-3 py-2">
|
||||
<h5 class="m-0">Detalle Presupuesto @SelectedQuote?.Quotenumber</h5>
|
||||
<button class="btn-close" @onclick="() => SelectedQuote = null"></button>
|
||||
</div>
|
||||
<!-- CONTENIDO -->
|
||||
<div class="p-3">
|
||||
<ul class="nav nav-tabs mb-3" role="tablist">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link @((activeTab == "Datos") ? "active bg-primary text-white" : "")"
|
||||
@onclick='() => activeTab = "Datos"'
|
||||
title="Datos generales">
|
||||
<i class="fas fa-info-circle me-1"></i> Datos
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link @((activeTab == "Items") ? "active bg-success text-white" : "")"
|
||||
@onclick='() => activeTab = "Items"'
|
||||
title="Productos e impuestos">
|
||||
<i class="fas fa-boxes-stacked me-1"></i> Items
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@if (activeTab == "Datos")
|
||||
{
|
||||
<dl class="row">
|
||||
<dt class="col-5">Cliente:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.CustomerName</dd>
|
||||
<dt class="col-5">Médico:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.ProfessionalName</dd>
|
||||
<dt class="col-5">Hospital:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.InstitutionName</dd>
|
||||
<dt class="col-5">Paciente:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.PatientName</dd>
|
||||
<dt class="col-5">Emisión:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.IssueDate.ToString("dd/MM/yyyy")</dd>
|
||||
<dt class="col-5">Estimada:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.EstimatedDate?.ToString("dd/MM/yyyy")</dd>
|
||||
<dt class="col-5">Unidad Negocio:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.BusinessUnitName</dd>
|
||||
<dt class="col-5">Moneda:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.Currency</dd>
|
||||
<dt class="col-5">Vendedor:</dt>
|
||||
<dd class="col-7">@SelectedQuote?.SalespersonName</dd>
|
||||
<dt class="col-5">Estado:</dt>
|
||||
<dd class="col-7">
|
||||
<span class="badge @GetStatusBadge(SelectedQuote?.Status ?? "")">@SelectedQuote?.Status</span>
|
||||
</dd>
|
||||
<dt class="col-5">Observaciones:</dt>
|
||||
<dd class="col-7">SN</dd>
|
||||
</dl>
|
||||
}
|
||||
else if (activeTab == "Items")
|
||||
{
|
||||
if (SelectedQuote?.Items == null || !SelectedQuote.Items.Any())
|
||||
{
|
||||
<p>No hay productos en este presupuesto.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h6 class="mt-2"><i class="fas fa-box-open me-1"></i> Productos cotizados</h6>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Descripción</th>
|
||||
<th>Cant.</th>
|
||||
<th>Precio U.</th>
|
||||
<th>Subtotal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in SelectedQuote.Items)
|
||||
{
|
||||
<tr>
|
||||
<td>@item.Description</td>
|
||||
<td>@item.Quantity</td>
|
||||
<td>@string.Format("{0:N2}", item.UnitPrice)</td>
|
||||
<td>@string.Format("{0:N2}", item.Quantity * item.UnitPrice)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
if (SelectedQuote?.Taxes != null && SelectedQuote.Taxes.Any())
|
||||
{
|
||||
<hr class="my-3" />
|
||||
<h6 class="mt-4"><i class="fas fa-receipt me-1"></i> Impuestos aplicados</h6>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Impuesto</th>
|
||||
<th>Código</th>
|
||||
<th>Porcentaje</th>
|
||||
<th>Importe</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var tax in SelectedQuote.Taxes)
|
||||
{
|
||||
<tr>
|
||||
<td>@tax.TaxName</td>
|
||||
<td>@tax.TaxCode</td>
|
||||
<td>@string.Format("{0:N2}%", tax.TaxRate)</td>
|
||||
<td>@string.Format("{0:N2}", tax.TaxAmount)</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
private QuoteSearchParams Filters = new() { PageSize = 9 };
|
||||
private PagedResult<QuoteDto>? PagedQuotes;
|
||||
|
||||
@ -129,7 +129,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr><td colspan="6" class="text-center text-muted py-4">Sin resultados</td></tr>
|
||||
<tr><td colspan="9" class="text-center text-muted py-4">Sin resultados</td></tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user