All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 11m36s
217 lines
8.6 KiB
Plaintext
217 lines
8.6 KiB
Plaintext
@page "/stock/productform"
|
|
@page "/stock/productform/{ProductId:int}"
|
|
|
|
@using Domain.Entities
|
|
@using phronCare.UIBlazor.Services.Lookups
|
|
@using phronCare.UIBlazor.Services.Stock
|
|
@using phronCare.UIBlazor.Shared.Modals
|
|
@using System.ComponentModel.DataAnnotations
|
|
@using Blazored.Typeahead
|
|
|
|
@inject NavigationManager Navigation
|
|
@inject LSProductService productService
|
|
@inject IStockLookUpService lookUpService
|
|
@inject IToastService toastService
|
|
@inject IModalService modalService
|
|
|
|
<div class="card" style="zoom:90%">
|
|
<div class="card-header text-center">
|
|
<h3 class="card-title">@(ProductId.HasValue ? "Editar producto" : "Nuevo producto")</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<EditForm Model="product" OnValidSubmit="HandleValidSubmit">
|
|
<DataAnnotationsValidator />
|
|
<ValidationSummary />
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label>Código Fábrica *</label>
|
|
<InputText class="form-control" @bind-Value="product.FactoryCode" />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label>Código Externo</label>
|
|
<InputText class="form-control" @bind-Value="product.ExternalCode" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-2">
|
|
<div class="col-md-6">
|
|
<label>Nombre *</label>
|
|
<InputText class="form-control" @bind-Value="product.Name" />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label>Descripción *</label>
|
|
<InputText class="form-control" @bind-Value="product.Descripcion" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-2">
|
|
<div class="col-md-6">
|
|
<label>Tipo de Producto *</label>
|
|
<InputSelect class="form-control" @bind-Value="product.ProductType">
|
|
<option value="">-- Seleccionar --</option>
|
|
<option value="1">Implantable</option>
|
|
<option value="2">Instrumental</option>
|
|
<option value="3">Inyectable</option>
|
|
</InputSelect>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label>Trazabilidad *</label>
|
|
<InputSelect class="form-control" @bind-Value="product.TraceabilityType">
|
|
<option value="">-- Seleccionar --</option>
|
|
<option value="1">No aplica</option>
|
|
<option value="2">Por cantidad</option>
|
|
<option value="3">Por lote y vencimiento</option>
|
|
</InputSelect>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-2">
|
|
<div class="col-md-6">
|
|
<label>División *</label>
|
|
<BlazoredTypeahead
|
|
TItem="ELookUpItem" TValue="ELookUpItem"
|
|
SearchMethod="@(filter => lookUpService.GetProductDivisionsAsync(filter).ContinueWith(t => t.Result.AsEnumerable()))"
|
|
Value="_selectedDivision" ValueChanged="OnDivisionSelected"
|
|
ValueExpression="@(() => _selectedDivision)"
|
|
Placeholder="Buscar división..." TextProperty="Nombre"
|
|
MaximumSuggestions="5" class="form-control form-control-sm" style="height: 38px;">
|
|
<ResultTemplate Context="item">@item.Nombre</ResultTemplate>
|
|
<SelectedTemplate Context="item">@item.Nombre</SelectedTemplate>
|
|
</BlazoredTypeahead>
|
|
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label>Unidad de Medida *</label>
|
|
<BlazoredTypeahead id="unit" TItem="ELookUpItem" TValue="ELookUpItem"
|
|
SearchMethod="@(filter => lookUpService.GetUnitsOfMeasureAsync(filter).ContinueWith(t => t.Result.AsEnumerable()))"
|
|
Value="_selectedUnit" ValueChanged="OnUnitSelected"
|
|
ValueExpression="@(() => _selectedUnit)"
|
|
Placeholder="Buscar unidad..." TextProperty="Nombre" MaximumSuggestions="5"
|
|
class="form-control form-control-sm" style="height: 38px;">
|
|
<ResultTemplate Context="item">@item.Nombre</ResultTemplate>
|
|
<SelectedTemplate Context="item">@item.Nombre</SelectedTemplate>
|
|
</BlazoredTypeahead>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-md-6 d-flex align-items-center">
|
|
<div class="form-check form-switch">
|
|
<InputCheckbox id="PlusProcess" class="form-check-input" @bind-Value="product.PlusProcess" />
|
|
<label class="form-check-label ms-2">Requiere proceso adicional</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</EditForm>
|
|
</div>
|
|
|
|
<div class="card-footer d-flex justify-content-end">
|
|
<button class="btn btn-primary me-2" @onclick="HandleValidSubmit" disabled="@isSaving">
|
|
@(isSaving ? "Guardando..." : "Guardar")
|
|
</button>
|
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar</button>
|
|
</div>
|
|
</div>
|
|
|
|
@code {
|
|
[Parameter] public int? ProductId { get; set; }
|
|
|
|
private ELSProduct product = new();
|
|
private bool isSaving = false;
|
|
private ELookUpItem? _selectedDivision;
|
|
private ELookUpItem? _selectedUnit;
|
|
|
|
private ELSProductDivision? selectedDivision;
|
|
private ELSUnitOfMeasure? selectedUnit;
|
|
private string returnUrl = "/stock/products";
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
if (ProductId.HasValue)
|
|
{
|
|
product = await productService.GetByIdAsync(ProductId.Value) ?? new();
|
|
|
|
// Precargar División
|
|
var divisionList = await lookUpService.GetProductDivisionsAsync("");
|
|
_selectedDivision = divisionList.FirstOrDefault(d => d.Id == product.DivisionId);
|
|
|
|
// Precargar Unidad
|
|
var unitList = await lookUpService.GetUnitsOfMeasureAsync("");
|
|
_selectedUnit = unitList.FirstOrDefault(u => u.Id == product.UnitId);
|
|
}
|
|
else
|
|
{
|
|
product = new();
|
|
}
|
|
}
|
|
private void OnDivisionSelected(ELookUpItem? selected)
|
|
{
|
|
_selectedDivision = selected;
|
|
if (selected != null)
|
|
product.DivisionId = selected.Id;
|
|
}
|
|
private void OnUnitSelected(ELookUpItem? selected)
|
|
{
|
|
_selectedUnit = selected;
|
|
if (selected != null)
|
|
product.UnitId = selected.Id;
|
|
}
|
|
|
|
private async Task HandleValidSubmit()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(product.FactoryCode) ||
|
|
string.IsNullOrWhiteSpace(product.Name) ||
|
|
string.IsNullOrWhiteSpace(product.Descripcion) ||
|
|
product.ProductType <= 0 ||
|
|
product.TraceabilityType <= 0 ||
|
|
_selectedDivision is null ||
|
|
_selectedUnit is null)
|
|
{
|
|
toastService.ShowWarning("Por favor complete todos los campos obligatorios antes de guardar.");
|
|
return;
|
|
}
|
|
var modal = modalService.Show<ConfirmModal>("Confirmación", new ModalParameters
|
|
{
|
|
{ "Message", "¿Desea guardar este producto?" }
|
|
});
|
|
var result = await modal.Result;
|
|
|
|
if (result.Cancelled) return;
|
|
|
|
try
|
|
{
|
|
isSaving = true;
|
|
product.DivisionId = _selectedDivision?.Id;
|
|
product.UnitId = _selectedUnit?.Id ?? 0;
|
|
|
|
HttpResponseMessage response;
|
|
if (ProductId.HasValue)
|
|
response = await productService.UpdateAsync(product);
|
|
else
|
|
response = await productService.CreateAsync(product);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
toastService.ShowSuccess("Producto guardado correctamente.");
|
|
Navigation.NavigateTo("/stock/products");
|
|
}
|
|
else
|
|
{
|
|
var error = await response.Content.ReadAsStringAsync();
|
|
toastService.ShowError($"Error: {error}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
toastService.ShowError($"Error: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
isSaving = false;
|
|
}
|
|
}
|
|
|
|
private void Cancel() => Navigation.NavigateTo(returnUrl);
|
|
}
|