diff --git a/phronCare.UIBlazor/Pages/Sales/ProductForm.razor b/phronCare.UIBlazor/Pages/Sales/ProductForm.razor new file mode 100644 index 0000000..af51469 --- /dev/null +++ b/phronCare.UIBlazor/Pages/Sales/ProductForm.razor @@ -0,0 +1,167 @@ +@page "/sales/productform" +@page "/sales/productform/{ProductId:int?}" +@using System.ComponentModel.DataAnnotations +@using phronCare.UIBlazor.Services.Sales +@using phronCare.UIBlazor.Pages.Shared.Modals + +@inject ProductService ProductService +@inject ProductCategoryService ProductCategoryService +@inject BusinessUnitService BusinessUnitService +@inject IToastService ToastService +@inject NavigationManager Navigation +@inject IModalService Modal + +
+
+

@((ProductId.HasValue ? "Editar producto" : "Nuevo producto"))

+
+
+ + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + @foreach (var cat in _productCategories) + { + + } + + +
+ +
+ + + + @foreach (var unit in _businessUnits) + { + + } + + +
+
+
+
+ + + + + + + +
+ +
+ + + +
+ +
+ + + + + + + + + + +
+ +
+
+ + +
+
+
+
+
+ + +
+ +@code { + [Parameter] public int? ProductId { get; set; } + [Parameter] public string? returnUrl { get; set; } = "/sales/products"; + + private EProduct _model = new(); + private List _productCategories = new(); + private List _businessUnits = new(); + + protected override async Task OnInitializedAsync() + { + _productCategories = await ProductCategoryService.GetAllAsync(); + _businessUnits = await BusinessUnitService.GetAllAsync(); + + if (ProductId.HasValue) + { + _model = await ProductService.GetByIdAsync(ProductId.Value); + } + } + + private async Task HandleValidSubmit() + { + var parameters = new ModalParameters(); + parameters.Add("Message", "¿Desea guardar los cambios del producto?"); + var modal = Modal.Show("Confirmación", parameters); + var result = await modal.Result; + + if (result.Cancelled) + return; + + try + { + HttpResponseMessage response; + + if (_model.Id == 0) + response = await ProductService.CreateAsync(_model); + else + response = await ProductService.UpdateAsync(_model); + + if (response.IsSuccessStatusCode) + { + ToastService.ShowSuccess("Producto guardado correctamente."); + NavigateBack(); + } + else + { + var error = await response.Content.ReadAsStringAsync(); + ToastService.ShowError($"Error: {error}"); + } + } + catch (Exception ex) + { + ToastService.ShowError($"Error: {ex.Message}"); + } + } + + private void NavigateBack() + { + Navigation.NavigateTo(returnUrl ?? "/sales/products"); + } +} diff --git a/phronCare.UIBlazor/Pages/Sales/Products.razor b/phronCare.UIBlazor/Pages/Sales/Products.razor new file mode 100644 index 0000000..9bac85f --- /dev/null +++ b/phronCare.UIBlazor/Pages/Sales/Products.razor @@ -0,0 +1,183 @@ +@page "/sales/products" +@using phronCare.UIBlazor.Services.Sales +@using phronCare.UIBlazor.Data +@using Domain.Entities +@using Domain.Generics +@inject IToastService toastService +@inject NavigationManager Navigation +@inject ProductService productService + +
+
+

Búsqueda de productos

+
+
+
+ + + + + +
+
+
+ @if (TablaProductos != null && TablaProductos.Any()) + { + + } + else + { +

No hay resultados.

+ } +
+
+ +
+ +@code { + private ProductSearchParams SearchParams = new(); + private PagedResult? PagedResult; + private List> TablaProductos = new(); + private List TableColumns = new() + { + "Id", "Nombre", "Descripción", "Precio", "Moneda", "Negocio", "Categoría", "Activo" + }; + private int PaginaDeseada = 1; + + private List botones; + + protected override void OnInitialized() + { + botones = new List + { + new PhTable.ButtonOptions + { + Caption = "Editar", + ElementClass = "btn btn-primary btn-sm", + UrlAction = "/sales/products/edit/", + OnClickAction = async (id) => + { + if (int.TryParse(id, out var productId)) + { + Navigation.NavigateTo($"/sales/productform/{productId}"); + } + } + } + }; + } + + private async Task BuscarProductos() => await CargarProductos(); + + private async Task CargarProductos() + { + PagedResult = await productService.SearchProductsAsync(SearchParams); + if (PagedResult?.Items is not null) + { + TablaProductos = PagedResult.Items.Select(p => new Dictionary + { + { "Id", p.Id }, + { "Nombre", p.Name ?? string.Empty }, + { "Descripción", p.Description ?? string.Empty }, + { "Precio", p.Baseprice }, + { "Moneda", p.Currency ?? string.Empty }, + { "Negocio", p.Businessunits?.Code ?? string.Empty }, + { "Categoría", p.Category?.Description ?? string.Empty }, + { "Activo", p.Isactive ? "Sí" : "No" } + }).ToList(); + } + } + + private async Task PrimeraPagina() { SearchParams.Page = 1; await BuscarProductos(); } + private async Task UltimaPagina() { SearchParams.Page = TotalPaginas; await BuscarProductos(); } + private async Task SiguientePagina() => await CambiarPagina(1); + private async Task AnteriorPagina() => await CambiarPagina(-1); + + private async Task CambiarPagina(int delta) + { + var nuevaPagina = SearchParams.Page + delta; + if (nuevaPagina >= 1 && nuevaPagina <= TotalPaginas) + { + SearchParams.Page = nuevaPagina; + await BuscarProductos(); + } + } + + private async Task IrAPagina() + { + if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas) + { + SearchParams.Page = PaginaDeseada; + await BuscarProductos(); + } + else + { + toastService.ShowWarning("Número de página fuera de rango."); + } + } + private async Task ExportarExcel() + { + // Crea el objeto de parámetros para la búsqueda + var searchParams = new ProductSearchParams + { + Term = SearchParams.Term, // Aquí podés obtener los filtros de los campos en el formulario + Page = 1, + PageSize = int.MaxValue // Puedes ajustar el tamaño de la página para exportar todos los registros + }; + try + { + await productService.ExportFilteredAsync(searchParams); + toastService.ShowSuccess("Exportación completada exitosamente."); + } + catch (Exception ex) + { + toastService.ShowError($"{ex.Message}"); + } + } + + private void NuevoProducto() => Navigation.NavigateTo("/sales/productform/"); + private void Cancel() => Navigation.NavigateTo("/DashboardPanel"); + + private bool PuedeRetroceder => PagedResult != null && SearchParams.Page > 1; + private bool PuedeAvanzar => PagedResult != null && SearchParams.Page < TotalPaginas; + private int TotalPaginas => PagedResult is null ? 1 : + (int)Math.Ceiling((double)(PagedResult.TotalItems) / SearchParams.PageSize); +} diff --git a/phronCare.UIBlazor/Program.cs b/phronCare.UIBlazor/Program.cs index ea5c9a5..bff4b3d 100644 --- a/phronCare.UIBlazor/Program.cs +++ b/phronCare.UIBlazor/Program.cs @@ -42,6 +42,9 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); #endregion #region UI builder.Services.AddBlazoredModal(); diff --git a/phronCare.UIBlazor/Services/Sales/BusinessUnitService.cs b/phronCare.UIBlazor/Services/Sales/BusinessUnitService.cs new file mode 100644 index 0000000..76c90e6 --- /dev/null +++ b/phronCare.UIBlazor/Services/Sales/BusinessUnitService.cs @@ -0,0 +1,21 @@ +using Domain.Entities; +using System.Net.Http.Json; + +namespace phronCare.UIBlazor.Services.Sales +{ + public class BusinessUnitService + { + private readonly HttpClient _http; + + public BusinessUnitService(HttpClient http) + { + _http = http; + } + public async Task> GetAllAsync() + { + var result = await _http.GetFromJsonAsync>("/api/BusinessUnit/All"); + return result ?? new List(); + } + + } +} diff --git a/phronCare.UIBlazor/Services/Sales/CustomerService.cs b/phronCare.UIBlazor/Services/Sales/CustomerService.cs index c9cba35..2fe7e5b 100644 --- a/phronCare.UIBlazor/Services/Sales/CustomerService.cs +++ b/phronCare.UIBlazor/Services/Sales/CustomerService.cs @@ -6,7 +6,6 @@ using System.Text; using Microsoft.JSInterop; using System.Reflection; - namespace phronCare.UIBlazor.Services.Sales { public class CustomerService @@ -55,13 +54,4 @@ namespace phronCare.UIBlazor.Services.Sales } } } - - //public class CustomerSearchParams - //{ - // public string? Name { get; set; } - // public string? Email { get; set; } - // public string? Document { get; set; } - // public int Page { get; set; } = 1; - // public int PageSize { get; set; } = 10; - //} } diff --git a/phronCare.UIBlazor/Services/Sales/ProductCategoryService.cs b/phronCare.UIBlazor/Services/Sales/ProductCategoryService.cs new file mode 100644 index 0000000..06e8194 --- /dev/null +++ b/phronCare.UIBlazor/Services/Sales/ProductCategoryService.cs @@ -0,0 +1,19 @@ +using Domain.Entities; +using System.Net.Http.Json; + +namespace phronCare.UIBlazor.Services.Sales +{ + public class ProductCategoryService + { + private readonly HttpClient _http; + public ProductCategoryService(HttpClient http) + { + _http = http; + } + public async Task> GetAllAsync() + { + var result = await _http.GetFromJsonAsync>("/api/ProductCategory/All"); + return result ?? new List(); + } + } +} diff --git a/phronCare.UIBlazor/Services/Sales/ProductService.cs b/phronCare.UIBlazor/Services/Sales/ProductService.cs new file mode 100644 index 0000000..204a766 --- /dev/null +++ b/phronCare.UIBlazor/Services/Sales/ProductService.cs @@ -0,0 +1,80 @@ +using Domain.Entities; +using Domain.Generics; +using System.Net.Http.Json; +using System.Text.Json; +using System.Text; +using Microsoft.JSInterop; +using System.Reflection; + +namespace phronCare.UIBlazor.Services.Sales +{ + public class ProductService + { + private readonly HttpClient _http; + private readonly IJSRuntime _js; + + public ProductService(HttpClient http, IJSRuntime js) + { + _http = http; + _js = js; + } + + public async Task> GetAllAsync() + { + var result = await _http.GetFromJsonAsync>("/api/Product/GetAll"); + return result ?? new List(); + } + + public async Task GetByIdAsync(int id) + { + var result = await _http.GetFromJsonAsync($"/api/Product/{id}"); + return result ?? new EProduct(); + } + + public async Task CreateAsync(EProduct product) + { + return await _http.PostAsJsonAsync("/api/Product/Create", product); + } + + public async Task UpdateAsync(EProduct product) + { + return await _http.PutAsJsonAsync("/api/Product/Update", product); + } + + public async Task?> SearchProductsAsync(ProductSearchParams searchParams) + { + var url = $"api/Product/search?" + + $"term={searchParams.Term}&" + + $"page={searchParams.Page}&" + + $"pageSize={searchParams.PageSize}"; + return await _http.GetFromJsonAsync>(url); + } + + public async Task ExportFilteredAsync(ProductSearchParams searchParams) + { + try + { + var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json"); + var response = await _http.PostAsync("api/Product/exportfiltered", content); + + if (!response.IsSuccessStatusCode) + { + var errorContent = await response.Content.ReadAsStringAsync(); + throw new Exception(errorContent); + } + + var bytes = await response.Content.ReadAsByteArrayAsync(); + var base64 = Convert.ToBase64String(bytes); + var timestamp = DateTime.Now.ToString("yyyyMMddHHmm"); + var fileName = $"{timestamp}_productos.xlsx"; + await _js.InvokeVoidAsync("saveAsFile", fileName, base64); + } + catch (Exception ex) + { + var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod"; + var message = ex.Message ?? "No message provided"; + throw new Exception($"{message}", ex); + } + } + } +} diff --git a/phronCare.UIBlazor/Shared/NavMenu.razor b/phronCare.UIBlazor/Shared/NavMenu.razor index 01ae7da..4af9436 100644 --- a/phronCare.UIBlazor/Shared/NavMenu.razor +++ b/phronCare.UIBlazor/Shared/NavMenu.razor @@ -76,6 +76,11 @@ Crear + }