Leandro Hernan Rojas e276e9672c
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 7m16s
Add Authorization Quote
2025-05-29 19:21:57 -03:00

228 lines
8.6 KiB
Plaintext

@page "/quotes/authorize/{QuoteId:int}"
@using Domain.Dtos
@using phronCare.UIBlazor.Models.Sales
@using phronCare.UIBlazor.Services.Sales.Quotes
@using Blazored.Modal
@using Blazored.Modal.Services
@inject QuoteService quoteService
@inject NavigationManager nav
@inject IToastService toast
@inject IModalService Modal
<div class="card" style="zoom: 80%">
<div class="card-header d-flex justify-content-center align-items-center">
<h3 class="card-title m-0">
<i class="fas fa-file-signature text-secondary me-2"></i> Autorización de Presupuesto
</h3>
</div>
<div class="card-body">
@if (IsLoading)
{
<p>Cargando información del presupuesto...</p>
}
else if (LoadError)
{
<div class="alert alert-danger">
Ocurrió un error al intentar cargar el presupuesto.
</div>
}
else
{
<div class="mb-4">
<div class="row">
<div class="col"><strong>N°:</strong> @QuoteHeader.Quotenumber</div>
<div class="col"><strong>Fecha:</strong> @QuoteHeader.IssueDate.ToShortDateString()</div>
<div class="col"><strong>Cliente:</strong> @QuoteHeader.CustomerName</div>
</div>
<div class="row mt-1">
<div class="col"><strong>Médico:</strong> @QuoteHeader.ProfessionalName</div>
<div class="col"><strong>Hospital:</strong> @QuoteHeader.InstitutionName</div>
<div class="col"><strong>Paciente:</strong> @QuoteHeader.PatientName</div>
</div>
<div class="row mt-1">
<div class="col"><strong>Cirugía estimada:</strong> @QuoteHeader.EstimatedDate?.ToShortDateString()</div>
<div class="col"><strong>Importe total:</strong> @QuoteHeader.Total.ToString("C")</div>
<div class="col">
<strong>Estado:</strong>
<span class="badge @GetStatusColor(QuoteHeader.Status)">
@QuoteHeader.Status
</span>
</div>
</div>
</div>
<EditForm Model="FormModel" OnValidSubmit="OpenConfirmation">
<div class="text-end mb-2">
@if (FormModel.Items.Any(i => i.Approved))
{
<span class="badge bg-success px-3 py-2"><i class="fas fa-check-circle me-1"></i> Al menos un ítem será autorizado</span>
}
else
{
<span class="badge bg-danger px-3 py-2"><i class="fas fa-ban me-1"></i> Todos los ítems serán anulados</span>
}
</div>
<table class="table table-sm table-bordered">
<thead class="table-light text-center">
<tr>
<th style="width: 40px;">¿Aprobar?</th>
<th style="width: 60%;">Descripción</th>
<th>Cant.</th>
<th>Precio U.</th>
<th>Subtotal</th>
<th>Cant. Aprob.</th>
<th>Precio Aprob.</th>
</tr>
</thead>
<tbody>
@foreach (var item in FormModel.Items)
{
<tr>
<td class="text-center">
<input type="checkbox" class="form-check-input"
@bind="item.Approved" />
</td>
<td>@item.ProductDescription</td>
<td class="text-center">@item.Quantity</td>
<td class="text-end">@item.UnitPrice.ToString("N2")</td>
<td class="text-end">@item.Subtotal.ToString("N2")</td>
<td class="text-center">
<InputNumber @bind-Value="item.ApprovedQuantity"
class="form-control form-control-sm text-center"
disabled="@(item.Approved == false)" />
</td>
<td class="text-end">
<InputNumber @bind-Value="item.ApprovedUnitPrice"
class="form-control form-control-sm text-end"
disabled="@(item.Approved == false)" />
</td>
</tr>
}
</tbody>
</table>
<div class="d-flex justify-content-end mt-3">
<button type="submit" class="btn text-white me-2 @(FormModel.Items.Any(i => i.Approved) ? "btn-success" : "btn-danger")">
@(FormModel.Items.Any(i => i.Approved) ? "Confirmar Autorización" : "Confirmar Anulación")
</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar
</button>
</div>
</EditForm>
}
</div>
</div>
@code {
[Parameter] public int QuoteId { get; set; }
private QuoteDto? QuoteHeader;
private QuoteAuthorizationFormModel FormModel = new();
private bool IsLoading = true;
private bool LoadError = false;
protected override async Task OnInitializedAsync()
{
try
{
var quote = await quoteService.GetDtoByIdAsync(QuoteId);
if (quote?.Items == null || !quote.Items.Any())
{
LoadError = true;
return;
}
QuoteHeader = quote;
FormModel.Items = quote.Items.Select(x => new QuoteAuthorizationViewItem
{
Id = x.Id,
ProductDescription = x.Description,
Quantity = x.Quantity,
UnitPrice = x.UnitPrice,
Approved = false,
ApprovedQuantity = null,
ApprovedUnitPrice = null
}).ToList();
}
catch
{
LoadError = true;
}
finally
{
IsLoading = false;
}
}
private async Task OpenConfirmation()
{
var options = new ModalOptions()
{
HideHeader = true
};
var parameters = new ModalParameters();
parameters.Add("Message", "¿Desea continuar con esta operación?");
var modal = Modal.Show<Shared.Modals.ConfirmModal>("Confirmación", parameters,options);
var result = await modal.Result;
if (!result.Cancelled)
{
await AuthorizeQuote();
}
}
private async Task AuthorizeQuote()
{
var approvedItems = FormModel.Items
.Where(i => i.Approved)
.Select(i => new QuoteAuthorizationDto
{
Id = i.Id,
Approved = true,
ApprovedQuantity = i.ApprovedQuantity,
ApprovedUnitPrice = i.ApprovedUnitPrice
})
.ToList();
var payload = new QuoteAuthorizationRequest
{
QuoteId = QuoteId,
Items = approvedItems
};
var success = await quoteService.AuthorizeQuoteAsync(payload);
if (success)
{
if (!approvedItems.Any())
toast.ShowInfo("Presupuesto anulado correctamente.");
else
toast.ShowSuccess("Presupuesto autorizado con éxito.");
nav.NavigateTo("/quotes");
}
else
{
toast.ShowError("No se pudo procesar el presupuesto.");
}
}
private void Cancel() => nav.NavigateTo("/quotes");
private string GetStatusColor(string status) => status.ToLower() switch
{
"Anulado" => "bg-danger text-white",
"Emitido" => "bg-primary text-white",
"Aprobado" => "bg-success",
"Despacho" => "bg-info text-white",
"SinConsumo" => "bg-warning text-dark",
"Transito" => "bg-secondary text-white",
"Cerrado" => "bg-dark text-white",
_ => "bg-light text-dark"
};
public class QuoteAuthorizationFormModel
{
public List<QuoteAuthorizationViewItem> Items { get; set; } = new();
}
}