All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 4m49s
325 lines
12 KiB
Plaintext
325 lines
12 KiB
Plaintext
@page "/sales/customerform"
|
|
@page "/sales/customerform/{CustomerId:int}"
|
|
@using phronCare.UIBlazor.Services.Sales
|
|
|
|
@inject HttpClient _httpClient
|
|
@inject NavigationManager Navigation
|
|
@inject IToastService toastService
|
|
@inject AuthenticationStateProvider authenticationStateProvider
|
|
@inject AccountTypeService accountTypeService
|
|
@inject TaxConditionService taxConditionService
|
|
|
|
|
|
<EditForm Model="@customer" OnValidSubmit="@HandleValidSubmit">
|
|
<DataAnnotationsValidator />
|
|
<ValidationSummary />
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="Name">Nombre / Razón Social:</label>
|
|
<InputText id="Name" @bind-Value="customer.Name" class="form-control" />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="BusinessName">Sucursal / Nombre Comercial:</label>
|
|
<InputText id="BusinessName" @bind-Value="customer.BusinessName" class="form-control" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="AccounttypesId">Tipo de Cuenta:</label>
|
|
<InputSelect id="AccounttypesId" @bind-Value="customer.AccounttypesId" class="form-control">
|
|
<option value="">-- Seleccionar --</option>
|
|
@foreach (var type in accountTypes)
|
|
{
|
|
<option value="@type.Id">@type.Name</option>
|
|
}
|
|
</InputSelect>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="TaxConditionId">Condición Fiscal:</label>
|
|
<InputSelect id="TaxConditionId" @bind-Value="customer.TaxConditionId" class="form-control">
|
|
<option value="">-- Seleccionar --</option>
|
|
@foreach (var tax in taxConditions)
|
|
{
|
|
<option value="@tax.Id">@tax.Description</option>
|
|
}
|
|
</InputSelect>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<label for="HasCreditAccount">¿Cuenta Corriente?</label><br />
|
|
<InputCheckbox id="HasCreditAccount" @bind-Value="customer.HasCreditAccount" />
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="CreditLimit">Límite de Crédito:</label>
|
|
<InputNumber id="CreditLimit" @bind-Value="customer.CreditLimit" class="form-control" />
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="Active">Activo:</label><br />
|
|
<InputCheckbox id="Active" @bind-Value="customer.Active" />
|
|
</div>
|
|
</div>
|
|
<hr />
|
|
<h5>Documentos</h5>
|
|
|
|
<div class="row align-items-end">
|
|
<div class="col-sm-4">
|
|
<label for="TipoDocumento">Tipo:</label>
|
|
<InputSelect id="TipoDocumento" class="form-control" @bind-Value="documentFormModel.DocumenttypesId">
|
|
<option value="">Seleccione</option>
|
|
@foreach (var tipo in documentTypes)
|
|
{
|
|
<option value="@tipo.Id">@tipo.Name</option>
|
|
}
|
|
</InputSelect>
|
|
</div>
|
|
<div class="col-sm-4">
|
|
<label for="NumeroDocumento">Número:</label>
|
|
<InputText id="NumeroDocumento" class="form-control" @bind-Value="documentFormModel.DocumentNumber" />
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<button type="button" class="btn btn-success" @onclick="AddCustomerDocument">Agregar</button>
|
|
</div>
|
|
</div>
|
|
|
|
<br />
|
|
|
|
@if (customer.PhSCustomerDocuments?.Any() == true)
|
|
{
|
|
<table class="table table-sm table-bordered">
|
|
<thead>
|
|
<tr>
|
|
<th>Tipo</th>
|
|
<th>Número</th>
|
|
<th style="width:50px;"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var doc in customer.PhSCustomerDocuments)
|
|
{
|
|
<tr>
|
|
<td>@documentTypes.FirstOrDefault(t => t.Id == doc.DocumenttypesId)?.Name</td>
|
|
<td>@doc.DocumentNumber</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-danger" @onclick="() => RemoveCustomerDocument(doc)">🗑</button>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
}
|
|
|
|
<h5 class="mt-4 mb-2">Direcciones</h5>
|
|
|
|
@foreach (var address in customer.PhSCustomerAddresses)
|
|
{
|
|
<div class="mb-4 border rounded-lg p-4 space-y-3 shadow-sm bg-light">
|
|
<div class="row g-2">
|
|
<div class="col-md-6">
|
|
<InputText class="form-control" @bind-Value="address.BusinessName" placeholder="Nombre de la sucursal" />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<InputText class="form-control" @bind-Value="address.Streetaddress1" placeholder="Calle y número" />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<InputText class="form-control" @bind-Value="address.Streetaddress2" placeholder="Piso, departamento, etc." />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<InputText class="form-control" @bind-Value="address.City" placeholder="Ciudad" />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<select class="form-control" value="@address.Country" @onchange="e => OnCountryChanged(e, address)">
|
|
<option value="">Seleccionar país</option>
|
|
@foreach (var country in countries)
|
|
{
|
|
<option value="@country">@country</option>
|
|
}
|
|
</select>
|
|
|
|
</div>
|
|
<div class="col-md-6">
|
|
@if (address.Country == "Argentina")
|
|
{
|
|
<select class="form-control" @bind="address.Stateprovince">
|
|
<option value="">Seleccionar provincia</option>
|
|
@foreach (var province in argentinaProvinces)
|
|
{
|
|
<option value="@province">@province</option>
|
|
}
|
|
</select>
|
|
}
|
|
else
|
|
{
|
|
<InputText class="form-control" @bind-Value="address.Stateprovince" placeholder="Provincia / Estado" />
|
|
}
|
|
</div>
|
|
<div class="col-md-4">
|
|
<InputText class="form-control" @bind-Value="address.Postalcode" placeholder="Código Postal" />
|
|
</div>
|
|
<div class="col-md-4">
|
|
<InputText class="form-control" @bind-Value="address.Phonenumber" placeholder="Teléfono" />
|
|
</div>
|
|
<div class="col-md-4">
|
|
<InputText class="form-control" @bind-Value="address.Email" placeholder="Email" />
|
|
</div>
|
|
<div class="col-12">
|
|
<InputTextArea class="form-control" @bind-Value="address.Notes" placeholder="Notas" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 text-end">
|
|
<button type="button" class="btn btn-sm btn-outline-danger" @onclick="() => RemoveAddress(address)">
|
|
<i class="bi bi-trash"></i> Eliminar dirección
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<button type="button" class="btn btn-outline-primary mt-2" @onclick="AddAddress">
|
|
<i class="bi bi-plus-circle"></i> Agregar dirección
|
|
</button>
|
|
</EditForm>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public int? CustomerId { get; set; }
|
|
|
|
private ECustomer customer { get; set; } = new();
|
|
private List<EAccountType> accountTypes = new();
|
|
private List<ETaxCondition> taxConditions = new();
|
|
private List<EDocumentType> documentTypes = new();
|
|
private ECustomerDocument documentFormModel = new();
|
|
private ECustomerAddress AddressForModel = new();
|
|
private List<ECustomerAddress> addresses => customer.PhSCustomerAddresses.ToList();
|
|
|
|
private string returnUrl = "/sales/customers";
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadAccountTypes();
|
|
await LoadTaxConditions();
|
|
await LoadDocumentTypes();
|
|
|
|
if (CustomerId.HasValue)
|
|
{
|
|
// Cargar datos del cliente existente desde la API
|
|
customer = await _httpClient.GetFromJsonAsync<ECustomer>($"/api/Customer/GetById/{CustomerId.Value}") ?? new();
|
|
}
|
|
}
|
|
|
|
private async Task LoadAccountTypes()
|
|
{
|
|
accountTypes = await accountTypeService.GetAllAsync();
|
|
}
|
|
private async Task LoadTaxConditions()
|
|
{
|
|
taxConditions = await taxConditionService.GetAllAsync();
|
|
}
|
|
private async Task LoadDocumentTypes()
|
|
{
|
|
var result = await _httpClient.GetFromJsonAsync<List<EDocumentType>>("/api/DocumentType/GetAll");
|
|
documentTypes = result ?? new();
|
|
}
|
|
|
|
private void AddCustomerDocument()
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(documentFormModel.DocumentNumber))
|
|
{
|
|
customer.PhSCustomerDocuments.Add(documentFormModel);
|
|
documentFormModel = new();
|
|
}
|
|
}
|
|
private void RemoveCustomerDocument(ECustomerDocument document)
|
|
{
|
|
customer.PhSCustomerDocuments.Remove(document);
|
|
}
|
|
|
|
private void AddCustomerAddress()
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(AddressForModel.Streetaddress1))
|
|
{
|
|
customer.PhSCustomerAddresses.Add(AddressForModel);
|
|
AddressForModel = new(); // limpiar el formulario
|
|
}
|
|
}
|
|
private void RemoveCustomerAddress(ECustomerAddress address)
|
|
{
|
|
customer.PhSCustomerAddresses.Remove(address);
|
|
}
|
|
|
|
private List<string> countries = new()
|
|
{
|
|
"Argentina", "Brasil", "Chile", "Uruguay", "Paraguay", "Bolivia", "Perú", "Colombia", "Venezuela", "México",
|
|
"Estados Unidos", "Canadá", "España", "Reino Unido", "Alemania", "Francia", "Italia", "China", "India", "Japón"
|
|
};
|
|
|
|
private List<string> argentinaProvinces = new()
|
|
{
|
|
"Buenos Aires", "Catamarca", "Chaco", "Chubut", "Córdoba", "Corrientes", "Entre Ríos", "Formosa", "Jujuy",
|
|
"La Pampa", "La Rioja", "Mendoza", "Misiones", "Neuquén", "Río Negro", "Salta", "San Juan", "San Luis",
|
|
"Santa Cruz", "Santa Fe", "Santiago del Estero", "Tierra del Fuego", "Tucumán", "Ciudad Autónoma de Buenos Aires"
|
|
};
|
|
private void OnCountryChanged(ChangeEventArgs e, ECustomerAddress address)
|
|
{
|
|
address.Country = e.Value?.ToString();
|
|
if (address.Country != "Argentina")
|
|
{
|
|
address.Stateprovince = string.Empty;
|
|
}
|
|
}
|
|
private void AddAddress()
|
|
{
|
|
customer.PhSCustomerAddresses.Add(new());
|
|
}
|
|
|
|
private void RemoveAddress(ECustomerAddress address)
|
|
{
|
|
customer.PhSCustomerAddresses.Remove(address);
|
|
}
|
|
|
|
private void OnCountryChanged(ECustomerAddress address)
|
|
{
|
|
if (address.Country != "Argentina")
|
|
{
|
|
address.Stateprovince = string.Empty;
|
|
}
|
|
}
|
|
private async Task HandleValidSubmit()
|
|
{
|
|
try
|
|
{
|
|
HttpResponseMessage response;
|
|
|
|
if (CustomerId.HasValue)
|
|
{
|
|
response = await _httpClient.PutAsJsonAsync("/api/Customer/Update", customer);
|
|
}
|
|
else
|
|
{
|
|
response = await _httpClient.PostAsJsonAsync("/api/Customer/Create", customer);
|
|
}
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
toastService.ShowSuccess("Cliente guardado exitosamente");
|
|
Navigation.NavigateTo(returnUrl);
|
|
}
|
|
else
|
|
{
|
|
var error = await response.Content.ReadAsStringAsync();
|
|
toastService.ShowError($"Error: {error}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
toastService.ShowError($"Error: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void Cancel()
|
|
{
|
|
Navigation.NavigateTo(returnUrl);
|
|
}
|
|
}
|