From bbe546b60dffecf9ff5f12d0ab66a2fd3c86217f Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:40:01 +0500 Subject: [PATCH 1/7] lesson 6 --- .../Constants/ApiResourceConstants.cs | 7 ++ .../Controllers/CategoriesController.cs | 18 +++- .../Controllers/ProductsController.cs | 43 ++++++++ .../WMS.WebUI/Exceptions/ApiException.cs | 8 ++ .../ApiResponse/PaginatedApiResponse.cs | 17 ++++ WMS.WebUI/WMS.WebUI/Program.cs | 4 +- .../QueryParams/ProductQueryParameters.cs | 12 +++ WMS.WebUI/WMS.WebUI/Services/ApiClient.cs | 66 +++++++++++++ WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs | 67 +++---------- WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs | 19 +--- .../Stores/Interfaces/ICategoryStore.cs | 5 +- .../Stores/Interfaces/IProductsStore.cs | 14 +-- .../WMS.WebUI/Stores/Mocks/CategoryDto.cs | 16 +++ .../Stores/Mocks/MockProductsStore.cs | 56 ----------- WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs | 97 +++++++++++++++++++ .../WMS.WebUI/ViewModels/CategoryViewModel.cs | 15 ++- .../WMS.WebUI/Views/Categories/Index.cshtml | 40 ++++++++ .../WMS.WebUI/Views/Products/Index.cshtml | 80 +++++++++++++++ WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj | 1 + WMS.WebUI/WMS.WebUI/wwwroot/css/site.css | 6 +- 20 files changed, 451 insertions(+), 140 deletions(-) create mode 100644 WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs create mode 100644 WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs create mode 100644 WMS.WebUI/WMS.WebUI/Services/ApiClient.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs delete mode 100644 WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs new file mode 100644 index 0000000..6da50ba --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs @@ -0,0 +1,7 @@ +namespace WMS.WebUI.Constants; + +public static class ApiResourceConstants +{ + public const string Products = nameof(Products); + public const string Categories = nameof(Categories); +} diff --git a/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs b/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs index 0736e03..24d57cc 100644 --- a/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs +++ b/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs @@ -14,12 +14,20 @@ public CategoriesController(ICategoryStore categoryStore) } // GET: Categories - public async Task Index(string? searchString) + public async Task Index(string? searchString,int? pageNumber) { - var categories = await _categoryStore.GetCategoriesAsync(searchString); - ViewBag.SearchString = searchString; - - return View(categories); + var categories = await _categoryStore.GetCategoriesAsync(searchString, pageNumber); + + ViewBag.SearchString = searchString ; + ViewBag.PageSize = categories.PageSize; + ViewBag.TotalPages = categories.PagesCount; + ViewBag.TotalItems = categories.TotalCount; + ViewBag.CurrentPage = categories.CurrentPage; + ViewBag.HasPreviousPage = categories.HasPreviousPage; + ViewBag.HasNextPage = categories.HasNextPage; + + + return View(categories.Data); } // GET: Categories/Details/5 diff --git a/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs new file mode 100644 index 0000000..0afd51d --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels; + +namespace WMS.WebUI.Controllers; + +public class ProductsController(IProductsStore store,ICategoryStore categoryStore) : Controller +{ + private readonly ICategoryStore _categoryStore = categoryStore; + private readonly IProductsStore _productsStore = store ?? throw new ArgumentNullException(nameof(store)); + + public async Task Index( + string? search, + int? pageNumber, + int? categoryId, + decimal? maxPrice, + decimal? minPrice, + bool? lowQuantityInStock) + { + var products = await _productsStore.GetProducts(new ProductQueryParameters()); + var categories = await _categoryStore.GetCategoriesAsync(); + + PopulateViewBag(products, search); + + return View(products.Data); + } + + private void PopulateViewBag( + PaginatedApiResponse products, + string? searchString) + { + ViewBag.SearchString = searchString; + ViewBag.PageSize = products.PageSize; + ViewBag.TotalPages = products.PagesCount; + ViewBag.TotalItems = products.TotalCount; + ViewBag.CurrentPage = products.CurrentPage; + ViewBag.HasPreviousPage = products.HasPreviousPage; + ViewBag.HasNextPage = products.HasNextPage; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs b/WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs new file mode 100644 index 0000000..d7b9a6b --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs @@ -0,0 +1,8 @@ +namespace WMS.WebUI.Exceptions; + +public class ApiException : Exception +{ + public ApiException() : base() { } + public ApiException(string message) : base(message) { } + public ApiException(string message, Exception inner) : base(message, inner) { } +} diff --git a/WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs b/WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs new file mode 100644 index 0000000..f95ff3a --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs @@ -0,0 +1,17 @@ +namespace WMS.WebUI.Models.PaginatedResponse; + +public class PaginatedApiResponse +{ + public List Data { get; set; } + public int CurrentPage { get; set; } + public int PageSize { get; set; } + public int PagesCount { get; set; } + public int TotalCount { get; set; } + public bool HasNextPage { get; set; } + public bool HasPreviousPage { get; set; } + + public PaginatedApiResponse() + { + Data = []; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs index 32f893d..57d4167 100644 --- a/WMS.WebUI/WMS.WebUI/Program.cs +++ b/WMS.WebUI/WMS.WebUI/Program.cs @@ -1,3 +1,4 @@ +using WMS.WebUI.Services; using WMS.WebUI.Stores; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.Stores.Mocks; @@ -8,7 +9,8 @@ builder.Services.AddControllersWithViews(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddSingleton(); Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ; diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs new file mode 100644 index 0000000..43afcf7 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs @@ -0,0 +1,12 @@ +namespace WMS.WebUI.QueryParams; + +public class ProductQueryParameters +{ + public string? Search { get; set; } + public int? CategoryId { get; set; } + public int? PageNumber { get; set; } + public int? PageSize { get; set; } = 10; + public decimal? MaxPrice { get; set; } + public decimal? MinPrice { get; set; } + public bool? LowQuantityInStock { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs new file mode 100644 index 0000000..aae3a41 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; +using System.Text; +using WMS.WebUI.Exceptions; + +namespace WMS.WebUI.Services; + +public class ApiClient +{ + private readonly HttpClient _client; + + public ApiClient() + { + _client = new() + { + BaseAddress = new Uri("https://localhost:7097/api/") + }; + } + + public async Task GetAsync(string resource) + { + var response = await _client.GetAsync(resource); + response.EnsureSuccessStatusCode(); + + response.EnsureSuccessStatusCode(); + + var json = await response.Content.ReadAsStringAsync(); + var result = JsonConvert.DeserializeObject(json) + ?? throw new ApiException($"Could not deserialize get response for resource {resource}."); + + return result; + } + + public async Task PostAsync(string resource, T body) + { + var content = GetStringContent(body); + var response = await _client.PostAsync(resource, content); + response.EnsureSuccessStatusCode(); + + var responseJson = await response.Content.ReadAsStringAsync(); + var result = JsonConvert.DeserializeObject(responseJson) + ?? throw new ApiException($"Could not deserialize post response for resource {resource}."); + + return result; + } + + public async Task PutAsync(string resource, TBody body) + { + var content = GetStringContent(body); + var response = await _client.PutAsync(resource, content); + response.EnsureSuccessStatusCode(); + } + + public async Task DeleteAsync(string resource, int id) + { + var response = await _client.DeleteAsync(resource + "/" + id); + response.EnsureSuccessStatusCode(); + } + + private static StringContent GetStringContent(T value) + { + var bodyJson = JsonConvert.SerializeObject(value); + var content = new StringContent(bodyJson, Encoding.UTF8, "application/json"); + + return content; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs index 2db82cc..04ca545 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using System.Text; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.Services; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.ViewModels; @@ -7,80 +7,45 @@ namespace WMS.WebUI.Stores; public class CategoryStore : ICategoryStore { - private readonly HttpClient _client; + private readonly ApiClient _client; + private const string RESOURCE = "categories"; - public CategoryStore() + public CategoryStore(ApiClient client) { - _client = new HttpClient(); - _client.BaseAddress = new Uri("https://localhost:7097/api/"); + _client = client; } public async Task CreateCategoryAsync(CategoryViewModel category) { - var json = JsonConvert.SerializeObject(category); - var request = new StringContent(json, Encoding.UTF8, "application/json"); - var response = await _client.PostAsync("categories", request); - - response.EnsureSuccessStatusCode(); - - var responseJson = await response.Content.ReadAsStringAsync(); - var createdCategory = JsonConvert.DeserializeObject(responseJson); - - if (createdCategory is null) - { - throw new JsonSerializationException("Error serializing Category response from API."); - } + var result = await _client.PostAsync(RESOURCE, category); - return createdCategory; + return result; } public async Task DeleteCategoryAsync(int id) { - var response = await _client.DeleteAsync($"categories/{id}"); - - response.EnsureSuccessStatusCode(); + await _client.DeleteAsync(RESOURCE, id); } - public async Task> GetCategoriesAsync(string? search = null) + public async Task> GetCategoriesAsync(string? search = null, int? pageNumber = 1) { - var response = await _client.GetAsync($"categories?search={search}"); - - response.EnsureSuccessStatusCode(); + pageNumber ??= 1; - var json = await response.Content.ReadAsStringAsync(); - var categories = JsonConvert.DeserializeObject>(json); + var queryParams = $"?search={search}&pageNumber={pageNumber}"; + var result = await _client.GetAsync>(RESOURCE + queryParams); - if (categories is null) - { - throw new JsonSerializationException("Error serializing Category response from API."); - } - - return categories; + return result; } public async Task GetCategoryByIdAsync(int id) { - var response = await _client.GetAsync($"categories/{id}"); + var category = await _client.GetAsync($"categories/{id}"); - response.EnsureSuccessStatusCode(); - - var json = await response.Content.ReadAsStringAsync(); - var category = JsonConvert.DeserializeObject(json); - - if (category is null) - { - throw new JsonSerializationException("Error serializing Category response from API."); - } - return category; } public async Task UpdateCategoryAsync(CategoryViewModel category) { - var json = JsonConvert.SerializeObject(category); - var request = new StringContent(json, Encoding.UTF8, "application/json"); - var response = await _client.PutAsync($"categories/{category.Id}", request); - - response.EnsureSuccessStatusCode(); + await _client.PutAsync($"categories/{category.Id}", category); } } diff --git a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs index 9a4a232..5f73dd9 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using WMS.WebUI.Services; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.ViewModels; @@ -6,26 +7,16 @@ namespace WMS.WebUI.Stores; public class DashboardStore : IDashboardStore { - private readonly HttpClient _client; + private readonly ApiClient _client; - public DashboardStore() + public DashboardStore(ApiClient client) { - _client = new HttpClient(); - _client.BaseAddress = new Uri("https://localhost:7097/api/"); + _client = client; } public async Task Get() { - var response = await _client.GetAsync("dashboard"); - response.EnsureSuccessStatusCode(); - - var json = await response.Content.ReadAsStringAsync(); - var dashboard = JsonConvert.DeserializeObject(json); - - if (dashboard is null) - { - throw new InvalidCastException("Could not convert json data to Dashboard format"); - } + var dashboard = await _client.GetAsync("dashboard"); return dashboard; } diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs index f4c6469..54188d0 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs @@ -1,10 +1,11 @@ -using WMS.WebUI.ViewModels; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.ViewModels; namespace WMS.WebUI.Stores.Interfaces; public interface ICategoryStore { - Task> GetCategoriesAsync(string? search = null); + Task> GetCategoriesAsync(string? search = null,int? pageNumber = 1); Task GetCategoryByIdAsync(int id); Task CreateCategoryAsync(CategoryViewModel category); Task UpdateCategoryAsync(CategoryViewModel category); diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs index 9de5f36..1ee92eb 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs @@ -1,12 +1,14 @@ -using WMS.WebUI.ViewModels; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels; namespace WMS.WebUI.Stores.Interfaces; public interface IProductsStore { - List GetProducts(); - ProductViewModel? GetById(int id); - ProductViewModel Create(ProductViewModel product); - void Update(ProductViewModel product); - void Delete(int id); + Task> GetProducts(ProductQueryParameters queryParameters); + Task? GetById(int id); + Task Create(ProductViewModel product); + Task Update(ProductViewModel product); + Task Delete(int id); } diff --git a/WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs b/WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs new file mode 100644 index 0000000..5a80327 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs @@ -0,0 +1,16 @@ +namespace WMS.WebUI.Stores.Mocks +{ + public class CategoryDto + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public int? ParentId { get; set; } + public string? Parent { get; set; } + public virtual ICollection Children { get; set; } + public CategoryDto() + { + Children = new List(); + } + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs deleted file mode 100644 index d3fdabb..0000000 --- a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs +++ /dev/null @@ -1,56 +0,0 @@ -using WMS.WebUI.Stores.Interfaces; -using WMS.WebUI.ViewModels; - -namespace WMS.WebUI.Stores.Mocks; - -public class MockProductsStore : IProductsStore -{ - private static int id = 1; - private static readonly List _products = []; - - public ProductViewModel Create(ProductViewModel product) - { - product.Id = id++; - _products.Add(product); - - return product; - } - - public void Delete(int id) - { - var product = _products.FirstOrDefault(x => x.Id == id); - - if (product is null) - { - return; - } - - var index = _products.IndexOf(product); - - if(index > 0) - { - _products.RemoveAt(index); - } - } - - public ProductViewModel? GetById(int id) - { - return _products.FirstOrDefault(x => x.Id == id); - } - - public List GetProducts() - { - return _products.ToList(); - } - - public void Update(ProductViewModel product) - { - var productToUpdate = _products.FirstOrDefault(x => x.Id == product.Id); - var index = _products.IndexOf(product); - - if (index > 0) - { - _products[index] = product; - } - } -} diff --git a/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs b/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs new file mode 100644 index 0000000..b7cdae0 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs @@ -0,0 +1,97 @@ +using System.Text; +using WMS.WebUI.Constants; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Services; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels; + +namespace WMS.WebUI.Stores; + +public class ProductStore : IProductsStore +{ + private readonly ApiClient _client; + + public ProductStore(ApiClient client) + { + _client = client; + } + + public async Task Create(ProductViewModel product) + { + var result = await _client.PostAsync(ApiResourceConstants.Products, product); + + return result; + } + + public async Task Delete(int id) + { + await _client.DeleteAsync(ApiResourceConstants.Products, id); + } + + public async Task> GetProducts(ProductQueryParameters queryParameters) + { + var queries = BuildQueryParameters(queryParameters); + var url = string.IsNullOrEmpty(queries) ? + ApiResourceConstants.Products : + ApiResourceConstants.Products + "?" + queries; + + var result = await _client.GetAsync>(url); + + return result; + + } + + public async Task GetById(int id) + { + var result = await _client.GetAsync(ApiResourceConstants.Products + "/" + id); + + return result; + } + + public async Task Update(ProductViewModel product) + { + await _client.PutAsync(ApiResourceConstants.Products, product); + } + + private static string BuildQueryParameters(ProductQueryParameters queryParameters) + { + StringBuilder queryBuilder = new(); + + if (queryParameters.PageNumber.HasValue) + { + queryBuilder.Append($"pageNumber={queryParameters.PageNumber}&"); + } + else + { + queryBuilder.Append($"pageNumber=1&"); + } + + if (!string.IsNullOrWhiteSpace(queryParameters.Search)) + { + queryBuilder.Append($"Search={queryParameters.Search}&"); + } + + if (queryParameters.CategoryId.HasValue) + { + queryBuilder.Append($"CategoryId={queryParameters.CategoryId}&"); + } + + if (queryParameters.MinPrice.HasValue) + { + queryBuilder.Append($"MinPrice={queryParameters.MinPrice}&"); + } + + if (queryParameters.MaxPrice.HasValue) + { + queryBuilder.Append($"MaxPrice={queryParameters.MaxPrice}&"); + } + + if (queryParameters.LowQuantityInStock.HasValue && queryParameters.LowQuantityInStock == true) + { + queryBuilder = queryBuilder.Append($"LowQuantityInStock={queryParameters.LowQuantityInStock}"); + } + + return queryBuilder.ToString(); + } +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs index 68a1716..209b9f8 100644 --- a/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs @@ -1,10 +1,21 @@ -namespace WMS.WebUI.ViewModels; +using WMS.WebUI.Stores.Mocks; + +namespace WMS.WebUI.ViewModels; public class CategoryViewModel { public int Id { get; set; } public string Name { get; set; } - public string? Description { get; set; } + public string Description { get; set; } + public int? ParentId { get; set; } + public string? Parent { get; set; } + public virtual ICollection Children { get; set; } + public virtual ICollection Products { get; set; } + public CategoryViewModel() + { + Children = new List(); + Products = new List(); + } } // read diff --git a/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml index 07762f6..e352236 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml @@ -2,6 +2,7 @@ @{ } +
@@ -40,6 +41,45 @@
+
+
+ + << + + + < + + + @if (ViewBag.CurrentPage > 1) + { + @(@ViewBag.CurrentPage - 1) + } + + + + + + @if (ViewBag.CurrentPage < ViewBag.TotalPages) + { + @(@ViewBag.CurrentPage + 1) + } + + + > + + + >> +
+ +
+

@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)

+
+
+ +
+
+
+ diff --git a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj index 424a883..fabc02c 100644 --- a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj +++ b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj @@ -7,6 +7,7 @@ + diff --git a/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css b/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css index a3d0220..6bb9689 100644 --- a/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css +++ b/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css @@ -69,9 +69,9 @@ body { background-color: #222b33; } - .e-grid .e-gridheader .e-headercell { - background-color: #222b33; - } + .e-gird .e-gridheader .e-headercell { + background-color: #222b33; + } .e-grid .e-gridpager { background-color: #1a222b; From a19e2392ea170df1a72d789d8ea1145ecf24fe05 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:56:42 +0500 Subject: [PATCH 2/7] Add Suplier and Customer VIews --- .../Constants/ApiResourceConstants.cs | 2 + .../Controllers/CustomersController.cs | 131 ++++++++++++++++++ .../Controllers/ProductsController.cs | 115 ++++++++++++++- .../Controllers/SuppliersController.cs | 128 +++++++++++++++++ WMS.WebUI/WMS.WebUI/Program.cs | 5 +- .../QueryParams/BaseQueryParameters.cs | 9 ++ .../QueryParams/CustomerQueryParameters.cs | 7 + .../QueryParams/ProductQueryParameters.cs | 7 +- .../QueryParams/SupplierQueryParameters.cs | 7 + WMS.WebUI/WMS.WebUI/Services/ApiClient.cs | 7 +- .../Stores/{ => DataStores}/CategoryStore.cs | 13 +- .../Stores/DataStores/CustomerStore.cs | 77 ++++++++++ .../Stores/{ => DataStores}/DashboardStore.cs | 2 +- .../Stores/{ => DataStores}/ProductStore.cs | 15 +- .../Stores/DataStores/SupplierStore.cs | 76 ++++++++++ .../Stores/Interfaces/ICustomerStore.cs | 14 ++ .../Stores/Interfaces/ISupplierStore.cs | 14 ++ .../CustomerActionViewModel.cs | 12 ++ .../CustomerDisplayViewModel.cs | 14 ++ .../WMS.WebUI/ViewModels/ProductViewModel.cs | 6 +- .../SupplierActionViewModel.cs | 15 ++ .../SupplierDisplayViewModel.cs | 13 ++ .../WMS.WebUI/Views/Categories/Delete.cshtml | 2 +- .../WMS.WebUI/Views/Customers/Create.cshtml | 59 ++++++++ .../WMS.WebUI/Views/Customers/Delete.cshtml | 53 +++++++ .../WMS.WebUI/Views/Customers/Details.cshtml | 60 ++++++++ .../WMS.WebUI/Views/Customers/Edit.cshtml | 58 ++++++++ .../WMS.WebUI/Views/Customers/Index.cshtml | 77 ++++++++++ .../WMS.WebUI/Views/Products/Create.cshtml | 72 ++++++++++ .../WMS.WebUI/Views/Products/Delete.cshtml | 44 ++++++ .../WMS.WebUI/Views/Products/Details.cshtml | 47 +++++++ .../WMS.WebUI/Views/Products/Edit.cshtml | 61 ++++++++ .../WMS.WebUI/Views/Products/Index.cshtml | 14 +- .../WMS.WebUI/Views/Shared/_Sidebar.cshtml | 36 ++++- .../WMS.WebUI/Views/Suppliers/Create.cshtml | 45 ++++++ .../WMS.WebUI/Views/Suppliers/Delete.cshtml | 41 ++++++ .../WMS.WebUI/Views/Suppliers/Details.cshtml | 50 +++++++ .../WMS.WebUI/Views/Suppliers/Edit.cshtml | 45 ++++++ .../WMS.WebUI/Views/Suppliers/Index.cshtml | 77 ++++++++++ 39 files changed, 1491 insertions(+), 39 deletions(-) create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs rename WMS.WebUI/WMS.WebUI/Stores/{ => DataStores}/CategoryStore.cs (81%) create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs rename WMS.WebUI/WMS.WebUI/Stores/{ => DataStores}/DashboardStore.cs (92%) rename WMS.WebUI/WMS.WebUI/Stores/{ => DataStores}/ProductStore.cs (83%) create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs index 6da50ba..66a003c 100644 --- a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs +++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs @@ -4,4 +4,6 @@ public static class ApiResourceConstants { public const string Products = nameof(Products); public const string Categories = nameof(Categories); + public const string Customers = nameof(Customers); + public const string Suppliers = nameof(Suppliers); } diff --git a/WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs b/WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs new file mode 100644 index 0000000..c7eb58f --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs @@ -0,0 +1,131 @@ +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.CustomerViewModels; + +namespace WMS.WebUI.Controllers; + +public class CustomersController(ICustomerStore customerStore) : Controller +{ + private readonly ICustomerStore _customerStore = customerStore; + public async Task Index( + string? searchString, + decimal? balanceGreaterThan, + decimal? balanceLessThan, + int? pageNumber) + { + var queryParameters = new CustomerQueryParameters() + { + Search = searchString, + BalanceGreaterThan = balanceGreaterThan, + BalanceLessThan = balanceLessThan, + PageNumber = pageNumber + }; + + var customers = await _customerStore.GetCustomers(queryParameters); + + PopulateViewBag(customers, queryParameters); + + return View(customers.Data); + } + public async Task Details(int id) + { + var customer = await _customerStore.GetById(id); + return View(customer); + } + [HttpGet] + public async Task Create() + { + return View(); + } + [HttpPost] + public async Task Create(CustomerActionViewModel customerActionViewModel) + { + if (!ModelState.IsValid) + { + return View(customerActionViewModel); + } + var createdCustomer = await _customerStore.Create(customerActionViewModel); + + return RedirectToAction(nameof(Details), new { id = createdCustomer.Id }); + } + [HttpGet] + public async Task Edit(int id) + { + var customer = await _customerStore.GetById(id); + + var customerForEdit = ParseCustomerActionViewModel(customer); + + return View(customerForEdit); + } + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Edit(int id,CustomerActionViewModel customerActionViewModel) + { + if (!ModelState.IsValid) + { + return View(customerActionViewModel); + } + if(customerActionViewModel.Id != id ) + { + return BadRequest("Does not match id with customer id"); + } + + await _customerStore.Update(customerActionViewModel); + + + return RedirectToAction(nameof(Details),new {id = customerActionViewModel.Id}); + } + [HttpGet] + public async Task Delete(int id) + { + var customer = await _customerStore.GetById(id); + + return View(customer); + } + [HttpPost,ActionName("Delete")] + [ValidateAntiForgeryToken] + public async Task DeleteConfirmed(int id) + { + await _customerStore.Delete(id); + return RedirectToAction(nameof(Index)); + } + private void PopulateViewBag(PaginatedApiResponse customers,CustomerQueryParameters queryParameters) + { + ViewBag.BalanceLessThan = queryParameters.BalanceLessThan; + ViewBag.BalanceGreaterThan= queryParameters.BalanceGreaterThan; + ViewBag.SearchString = queryParameters.Search; + + ViewBag.PageSize = customers.PageSize; + ViewBag.TotalPages = customers.PagesCount; + ViewBag.TotalItems = customers.TotalCount; + ViewBag.CurrentPage = customers.CurrentPage; + ViewBag.HasPreviousPage = customers.HasPreviousPage; + ViewBag.HasNextPage = customers.HasNextPage; + } + private CustomerActionViewModel ParseCustomerActionViewModel(CustomerDisplayViewModel model) + { + string[] nameParts = model.FullName.Split(new char[] { ' ' }, 2); + + string firstName = nameParts[0]; // First part is the first name + + // If there's more than one part, the rest is considered the last name + string lastName = (nameParts.Length > 1) ? nameParts[1] : ""; + + var customerForEdit = new CustomerActionViewModel() + { + Id = model.Id, + FirstName = firstName, + LastName = lastName, + Balance = model.Balance, + Address = model.Address, + Discount = model.Discount, + PhoneNumber = model.PhoneNumber, + }; + return customerForEdit; + } + +} diff --git a/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs index 0afd51d..91adc39 100644 --- a/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs +++ b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using WMS.WebUI.Models.PaginatedResponse; using WMS.WebUI.QueryParams; @@ -13,21 +14,125 @@ public class ProductsController(IProductsStore store,ICategoryStore categoryStor private readonly IProductsStore _productsStore = store ?? throw new ArgumentNullException(nameof(store)); public async Task Index( - string? search, + string? searchString, int? pageNumber, int? categoryId, decimal? maxPrice, decimal? minPrice, - bool? lowQuantityInStock) + string? isLowQuantity + ) { - var products = await _productsStore.GetProducts(new ProductQueryParameters()); + var queryParameters = new ProductQueryParameters() + { + Search = searchString, + PageNumber = pageNumber, + CategoryId = categoryId, + MaxPrice = maxPrice, + MinPrice = minPrice, + IsLowQuantity = isLowQuantity == "on", + }; + + var products = await _productsStore.GetProducts(queryParameters); + //Problem CAtegories get with pagination with max pagesize=15, I dont choose 16 category var categories = await _categoryStore.GetCategoriesAsync(); - PopulateViewBag(products, search); + ViewBag.Categories = new SelectList(categories.Data.OrderBy(x => x.Name), "Id", "Name", categoryId); + ViewBag.MinPrice = minPrice; + ViewBag.IsLowQuantity = isLowQuantity == "on"; + ViewBag.MaxPrice = maxPrice; + ViewBag.SearchString = searchString; + + PopulateViewBag(products, searchString); return View(products.Data); } + public async Task Details(int id) + { + var product = await _productsStore.GetById(id); + + if(product is null) + return NotFound(); + + return View(product); + } + public async Task Create() + { + var categories = await _categoryStore.GetCategoriesAsync(); + + ViewBag.Categories = new SelectList(categories.Data, "Id", "Name"); + + return View(); + } + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Create(ProductViewModel product) + { + if (!ModelState.IsValid) + { + var categories = await _categoryStore.GetCategoriesAsync(); + + ViewBag.Categories = new SelectList(categories.Data, "Id", "Name", categories); + return View(product); + } + var createdProduct = await _productsStore.Create(product); + return RedirectToAction(nameof(Details),new { id = createdProduct.Id }); + } + public async Task Edit(int id) + { + var product = await _productsStore.GetById(id); + + if (product is null) + return NotFound(); + + var categories = await _categoryStore.GetCategoriesAsync(); + + ViewBag.Categories = new SelectList(categories.Data, "Id", "Name"); + + return View(product); + } + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Edit(int id,ProductViewModel product) + { + if (!ModelState.IsValid) + { + var categories = await _categoryStore.GetCategoriesAsync(); + ViewBag.Categories = new SelectList(categories.Data, "Id", "Name"); + + return View(product); + } + if (product.Id != id) + { + return BadRequest("Does not match id with product id"); + } + await _productsStore.Update(product); + return RedirectToAction(nameof(Details),new { id = product.Id }); + } + + + [HttpGet] + public async Task Delete(int id) + { + var product = await _productsStore.GetById(id); + + if(product is null) + return NotFound(); + + return View(product); + } + [HttpPost(),ActionName(nameof(Delete))] + public async Task DeleteConfirmed(int id) + { + var product = await _productsStore.GetById(id); + + if (product is null) + return NotFound(); + + await _productsStore.Delete(id); + + return RedirectToAction(nameof(Index)); + } private void PopulateViewBag( PaginatedApiResponse products, string? searchString) diff --git a/WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs b/WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs new file mode 100644 index 0000000..943ad0a --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs @@ -0,0 +1,128 @@ +using Microsoft.AspNetCore.Mvc; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Stores.DataStores; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SupplierViewModels; + +namespace WMS.WebUI.Controllers +{ + public class SuppliersController(ISupplierStore store) : Controller + { + private readonly ISupplierStore _supplierStore = store; + public async Task Index( + string? searchString, + decimal? balanceGreaterThan, + decimal? balanceLessThan, + int? pageNumber) + { + var queryParameters = new SupplierQueryParameters() + { + Search = searchString, + BalanceGreaterThan = balanceGreaterThan, + BalanceLessThan = balanceLessThan, + PageNumber = pageNumber + }; + + var suppliers = await _supplierStore.GetSuppliers(queryParameters); + + PopulateViewBag(suppliers, queryParameters); + + return View(suppliers.Data); + } + public async Task Details(int id) + { + var supplier = await _supplierStore.GetById(id); + return View(supplier); + } + [HttpGet] + public async Task Create() + { + return View(); + } + [HttpPost] + public async Task Create(SupplierActionViewModel supplierActionViewModel) + { + if (!ModelState.IsValid) + { + return View(supplierActionViewModel); + } + var createdSupplier = await _supplierStore.Create(supplierActionViewModel); + + return RedirectToAction(nameof(Details), new { id = createdSupplier.Id }); + } + [HttpGet] + public async Task Edit(int id) + { + var supplier = await _supplierStore.GetById(id); + + var supplierForEdit = ParseSupplierActionViewModel(supplier); + + return View(supplierForEdit); + } + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Edit(int id, SupplierActionViewModel supplierActionViewModel) + { + if (!ModelState.IsValid) + { + return View(supplierActionViewModel); + } + if (supplierActionViewModel.Id != id) + { + return BadRequest("Does not match id with supplier id"); + } + + await _supplierStore.Update(supplierActionViewModel); + + + return RedirectToAction(nameof(Details), new { id = supplierActionViewModel.Id }); + } + [HttpGet] + public async Task Delete(int id) + { + var supplier = await _supplierStore.GetById(id); + + return View(supplier); + } + [HttpPost, ActionName("Delete")] + [ValidateAntiForgeryToken] + public async Task DeleteConfirmed(int id) + { + await _supplierStore.Delete(id); + return RedirectToAction(nameof(Index)); + } + private void PopulateViewBag(PaginatedApiResponse suppliers, SupplierQueryParameters queryParameters) + { + ViewBag.BalanceLessThan = queryParameters.BalanceLessThan; + ViewBag.BalanceGreaterThan= queryParameters.BalanceGreaterThan; + ViewBag.SearchString = queryParameters.Search; + + ViewBag.PageSize = suppliers.PageSize; + ViewBag.TotalPages = suppliers.PagesCount; + ViewBag.TotalItems = suppliers.TotalCount; + ViewBag.CurrentPage = suppliers.CurrentPage; + ViewBag.HasPreviousPage = suppliers.HasPreviousPage; + ViewBag.HasNextPage = suppliers.HasNextPage; + } + private SupplierActionViewModel ParseSupplierActionViewModel(SupplierDisplayViewModel model) + { + string[] nameParts = model.FullName.Split(new char[] { ' ' }, 2); + + string firstName = nameParts[0]; // First part is the first name + + // If there's more than one part, the rest is considered the last name + string lastName = (nameParts.Length > 1) ? nameParts[1] : ""; + + var supplierForEdit = new SupplierActionViewModel() + { + Id = model.Id, + FirstName = firstName, + LastName = lastName, + Balance = model.Balance, + PhoneNumber = model.PhoneNumber, + }; + return supplierForEdit; + } + } +} diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs index 57d4167..faa76cc 100644 --- a/WMS.WebUI/WMS.WebUI/Program.cs +++ b/WMS.WebUI/WMS.WebUI/Program.cs @@ -1,5 +1,5 @@ using WMS.WebUI.Services; -using WMS.WebUI.Stores; +using WMS.WebUI.Stores.DataStores; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.Stores.Mocks; @@ -10,6 +10,9 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + builder.Services.AddSingleton(); Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ; diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs new file mode 100644 index 0000000..b57e589 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs @@ -0,0 +1,9 @@ +namespace WMS.WebUI.QueryParams +{ + public abstract class BaseQueryParameters + { + public string? Search { get; set; } + public int? PageNumber { get; set; } = 1; + public int? PageSize { get; set; } = 15; + } +} diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs new file mode 100644 index 0000000..d105a6c --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs @@ -0,0 +1,7 @@ +namespace WMS.WebUI.QueryParams; + +public class CustomerQueryParameters : BaseQueryParameters +{ + public decimal? BalanceGreaterThan { get; set; } + public decimal? BalanceLessThan { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs index 43afcf7..b4d0ea4 100644 --- a/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs +++ b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs @@ -1,12 +1,9 @@ namespace WMS.WebUI.QueryParams; -public class ProductQueryParameters +public class ProductQueryParameters : BaseQueryParameters { - public string? Search { get; set; } public int? CategoryId { get; set; } - public int? PageNumber { get; set; } - public int? PageSize { get; set; } = 10; public decimal? MaxPrice { get; set; } public decimal? MinPrice { get; set; } - public bool? LowQuantityInStock { get; set; } + public bool? IsLowQuantity { get; set; } } diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs new file mode 100644 index 0000000..8b3c68b --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs @@ -0,0 +1,7 @@ +namespace WMS.WebUI.QueryParams; + +public class SupplierQueryParameters : BaseQueryParameters +{ + public decimal? BalanceGreaterThan { get; set; } + public decimal? BalanceLessThan { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs index aae3a41..08f84d6 100644 --- a/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs +++ b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs @@ -12,15 +12,14 @@ public ApiClient() { _client = new() { - BaseAddress = new Uri("https://localhost:7097/api/") + BaseAddress = new Uri("https://localhost:7108/api/") }; } public async Task GetAsync(string resource) { var response = await _client.GetAsync(resource); - response.EnsureSuccessStatusCode(); - + response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); @@ -30,7 +29,7 @@ public async Task GetAsync(string resource) return result; } - public async Task PostAsync(string resource, T body) + public async Task PostAsync(string resource, TBody body) { var content = GetStringContent(body); var response = await _client.PostAsync(resource, content); diff --git a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs similarity index 81% rename from WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs rename to WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs index 04ca545..5aee98d 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs @@ -1,14 +1,15 @@ -using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.Constants; +using WMS.WebUI.Models.PaginatedResponse; using WMS.WebUI.Services; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.ViewModels; -namespace WMS.WebUI.Stores; +namespace WMS.WebUI.Stores.DataStores; public class CategoryStore : ICategoryStore { private readonly ApiClient _client; - private const string RESOURCE = "categories"; + private const string RESOURCE = ApiResourceConstants.Categories; public CategoryStore(ApiClient client) { @@ -17,8 +18,8 @@ public CategoryStore(ApiClient client) public async Task CreateCategoryAsync(CategoryViewModel category) { - var result = await _client.PostAsync(RESOURCE, category); - + var result = await _client.PostAsync(RESOURCE, category); + return result; } @@ -40,7 +41,7 @@ public async Task> GetCategoriesAsync(st public async Task GetCategoryByIdAsync(int id) { var category = await _client.GetAsync($"categories/{id}"); - + return category; } diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs new file mode 100644 index 0000000..063ea23 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs @@ -0,0 +1,77 @@ +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; +using System.Text; +using WMS.WebUI.Constants; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Services; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.CustomerViewModels; + +namespace WMS.WebUI.Stores.DataStores; + +public class CustomerStore(ApiClient apiClient) : ICustomerStore +{ + private readonly ApiClient _apiClient = apiClient; + public async Task Create(CustomerActionViewModel customer) + { + var createdCustomer = await _apiClient.PostAsync(ApiResourceConstants.Customers,customer); + + return createdCustomer; + } + + public async Task Delete(int id) + { + await _apiClient.DeleteAsync(ApiResourceConstants.Customers,id); + } + + public async Task GetById(int id) + { + var customer = await _apiClient.GetAsync(ApiResourceConstants.Customers + "/" + id); + return customer; + } + + public async Task> GetCustomers(CustomerQueryParameters queryParameters) + { + var query = BuildQueryParameters(queryParameters); + + var url = string.IsNullOrEmpty(query) ? + ApiResourceConstants.Customers : + ApiResourceConstants.Customers + "?" + query; + + var customers = await _apiClient.GetAsync>(url); + + return customers; + } + + public async Task Update(CustomerActionViewModel customer) + { + await _apiClient.PutAsync(ApiResourceConstants.Customers, customer); + } + private string BuildQueryParameters(CustomerQueryParameters queryParameters) + { + var query = new StringBuilder(); + if (queryParameters.PageNumber.HasValue) + { + query.Append($"pageNumber={queryParameters.PageNumber}&"); + } + else + { + query.Append($"pageNumber=1&"); + } + if (!string.IsNullOrWhiteSpace(queryParameters.Search)) + { + query.Append($"Search={queryParameters.Search}&"); + } + if (queryParameters.BalanceGreaterThan.HasValue) + { + query.Append($"BalanceGreaterThan={queryParameters.BalanceGreaterThan}&"); + } + if (queryParameters.BalanceLessThan.HasValue) + { + query.Append($"BalanceLessThan={queryParameters.BalanceLessThan}&"); + } + return query.ToString(); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs similarity index 92% rename from WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs rename to WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs index 5f73dd9..1672f53 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs @@ -3,7 +3,7 @@ using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.ViewModels; -namespace WMS.WebUI.Stores; +namespace WMS.WebUI.Stores.DataStores; public class DashboardStore : IDashboardStore { diff --git a/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs similarity index 83% rename from WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs rename to WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs index b7cdae0..a5f81f1 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs @@ -6,7 +6,7 @@ using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.ViewModels; -namespace WMS.WebUI.Stores; +namespace WMS.WebUI.Stores.DataStores; public class ProductStore : IProductsStore { @@ -19,9 +19,9 @@ public ProductStore(ApiClient client) public async Task Create(ProductViewModel product) { - var result = await _client.PostAsync(ApiResourceConstants.Products, product); - - return result; + var result = await _client.PostAsync(ApiResourceConstants.Products, product); + + return result; } public async Task Delete(int id) @@ -39,7 +39,6 @@ public async Task> GetProducts(ProductQue var result = await _client.GetAsync>(url); return result; - } public async Task GetById(int id) @@ -51,7 +50,7 @@ public async Task GetById(int id) public async Task Update(ProductViewModel product) { - await _client.PutAsync(ApiResourceConstants.Products, product); + await _client.PutAsync(ApiResourceConstants.Products + "/" + product.Id, product); } private static string BuildQueryParameters(ProductQueryParameters queryParameters) @@ -87,9 +86,9 @@ private static string BuildQueryParameters(ProductQueryParameters queryParameter queryBuilder.Append($"MaxPrice={queryParameters.MaxPrice}&"); } - if (queryParameters.LowQuantityInStock.HasValue && queryParameters.LowQuantityInStock == true) + if (queryParameters.IsLowQuantity.HasValue && queryParameters.IsLowQuantity == true) { - queryBuilder = queryBuilder.Append($"LowQuantityInStock={queryParameters.LowQuantityInStock}"); + queryBuilder = queryBuilder.Append($"IsLowQuantity={queryParameters.IsLowQuantity}"); } return queryBuilder.ToString(); diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs new file mode 100644 index 0000000..7035584 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs @@ -0,0 +1,76 @@ +using System.Text; +using WMS.WebUI.Constants; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Services; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SupplierViewModels; + +namespace WMS.WebUI.Stores.DataStores; + +public class SupplierStore(ApiClient apiClient) : ISupplierStore +{ + private readonly ApiClient _apiClient = apiClient; + public async Task Create(SupplierActionViewModel supplier) + { + var createdSupplier = await _apiClient.PostAsync(ApiResourceConstants.Suppliers, supplier); + + return createdSupplier; + } + + public async Task Delete(int id) + { + await _apiClient.DeleteAsync(ApiResourceConstants.Suppliers,id); + } + + public async Task GetById(int id) + { + var supplier = await _apiClient.GetAsync(ApiResourceConstants.Suppliers + "/" + id); + return supplier; + } + + public async Task> GetSuppliers(SupplierQueryParameters queryParameters) + { + var query = BuildQueryParameters(queryParameters); + + var url = string.IsNullOrEmpty(query) ? + ApiResourceConstants.Suppliers : + ApiResourceConstants.Suppliers + "?" + query; + + var suppliers = await _apiClient.GetAsync>(url); + + return suppliers; + } + + public async Task Update(SupplierActionViewModel supplier) + { + await _apiClient.PutAsync(ApiResourceConstants.Suppliers, supplier); + } + private string BuildQueryParameters(SupplierQueryParameters queryParameters) + { + var query = new StringBuilder(); + if (queryParameters.PageNumber.HasValue) + { + query.Append($"pageNumber={queryParameters.PageNumber}&"); + } + else + { + query.Append($"pageNumber=1&"); + } + if (!string.IsNullOrWhiteSpace(queryParameters.Search)) + { + query.Append($"Search={queryParameters.Search}&"); + } + if (queryParameters.BalanceGreaterThan.HasValue) + { + query.Append($"BalanceGreaterThan={queryParameters.BalanceGreaterThan}&"); + } + if (queryParameters.BalanceLessThan.HasValue) + { + query.Append($"BalanceLessThan={queryParameters.BalanceLessThan}&"); + } + + return query.ToString(); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs new file mode 100644 index 0000000..4b5d1ca --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs @@ -0,0 +1,14 @@ +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels.CustomerViewModels; + +namespace WMS.WebUI.Stores.Interfaces; + +public interface ICustomerStore +{ + Task> GetCustomers(CustomerQueryParameters queryParameters); + TaskGetById(int id); + Task Create(CustomerActionViewModel customer); + Task Update(CustomerActionViewModel customer); + Task Delete(int id); +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs new file mode 100644 index 0000000..44a2188 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs @@ -0,0 +1,14 @@ +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels.SupplierViewModels; + +namespace WMS.WebUI.Stores.Interfaces; + +public interface ISupplierStore +{ + Task> GetSuppliers(SupplierQueryParameters queryParameters); + Task GetById(int id); + Task Create(SupplierActionViewModel supplier); + Task Update(SupplierActionViewModel supplier); + Task Delete(int id); +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs new file mode 100644 index 0000000..6aedcce --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs @@ -0,0 +1,12 @@ +namespace WMS.WebUI.ViewModels.CustomerViewModels; + +public class CustomerActionViewModel +{ + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string PhoneNumber { get; set; } + public string Address { get; set; } + public decimal Balance { get; set; } + public decimal? Discount { get; set; } = 0; +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs new file mode 100644 index 0000000..11fe7e1 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs @@ -0,0 +1,14 @@ +namespace WMS.WebUI.ViewModels.CustomerViewModels +{ + public class CustomerDisplayViewModel + { + public int Id { get; set; } + public string FullName { get; set; } + public string PhoneNumber { get; set; } + public string Address { get; set; } + public decimal Balance { get; set; } + public decimal? Discount { get; set; } = 0; + //public ICollection Sales { get; set; } + + } +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs index ea736c6..a59fd76 100644 --- a/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs +++ b/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs @@ -1,4 +1,6 @@ -namespace WMS.WebUI.ViewModels; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; + +namespace WMS.WebUI.ViewModels; public class ProductViewModel { @@ -9,7 +11,7 @@ public class ProductViewModel public decimal SupplyPrice { get; set; } public int QuantityInStock { get; set; } public int LowQuantityAmount { get; set; } - + [ValidateNever] public string Category { get; set; } public int CategoryId { get; set; } } diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs new file mode 100644 index 0000000..5d0bade --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs @@ -0,0 +1,15 @@ +namespace WMS.WebUI.ViewModels.SupplierViewModels; + +public class SupplierActionViewModel +{ + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string PhoneNumber { get; set; } + public decimal Balance { get; set; } + //public ICollection Supplies { get; set; } + //public SupplierDto() + //{ + // Supplies = new List(); + //} +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs new file mode 100644 index 0000000..e990e29 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs @@ -0,0 +1,13 @@ +using System.ComponentModel; + +namespace WMS.WebUI.ViewModels.SupplierViewModels; + +public class SupplierDisplayViewModel +{ + public int Id { get; set; } + [DisplayName("Full name")] + public string FullName{ get; set; } + [DisplayName("Phone number")] + public string PhoneNumber { get; set; } + public decimal Balance { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml index 41959fc..b77efc5 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml @@ -20,7 +20,7 @@
@Html.DisplayNameFor(model => model.Description)
-
+
@Html.DisplayFor(model => model.Description)
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml new file mode 100644 index 0000000..4610820 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml @@ -0,0 +1,59 @@ +@model WMS.WebUI.ViewModels.CustomerViewModels.CustomerActionViewModel + +@{ + ViewData["Title"] = "Create Customer"; +} +

Create Customer

+
+ +
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + Back + + +
+ +
+
+ +@section Scripts { + @{ + await Html.RenderPartialAsync("_ValidationScriptsPartial"); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml new file mode 100644 index 0000000..0145260 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml @@ -0,0 +1,53 @@ +@using WMS.WebUI.ViewModels.CustomerViewModels; +@model CustomerDisplayViewModel; + +

Are you sure want to delete ?

+
+ +
+
+
+ @Html.DisplayNameFor(model => model.Id) +
+
+ @Html.DisplayFor(model => model.Id) +
+
+ @Html.DisplayNameFor(model => model.FullName) +
+
+ @Html.DisplayFor(model => model.FullName) +
+
+ @Html.DisplayNameFor(model => model.PhoneNumber) +
+
+ @Html.DisplayFor(model => model.PhoneNumber) +
+
+ @Html.DisplayNameFor(model => model.Address) +
+
+ @Html.DisplayFor(model => model.Address) +
+
+ @Html.DisplayNameFor(model => model.Balance) +
+
+ @Html.DisplayFor(model => model.Balance) +
+
+ @Html.DisplayNameFor(model => model.Discount) +
+
+ @Html.DisplayFor(model => model.Discount) +
+
+
+ +
+
+ Back + +
+
\ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml new file mode 100644 index 0000000..9edcc2a --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml @@ -0,0 +1,60 @@ +@using WMS.WebUI.ViewModels.CustomerViewModels; +@model CustomerDisplayViewModel; + +
+

Supplier details

+ +
+ +
+
+ @Html.DisplayNameFor(model => model.Id) +
+
+ @Html.DisplayFor(model => model.Id) +
+
+ @Html.DisplayNameFor(model => model.FullName) +
+
+ @Html.DisplayFor(model => model.FullName) +
+
+ @Html.DisplayNameFor(model => model.PhoneNumber) +
+
+ @Html.DisplayFor(model => model.PhoneNumber) +
+
+ @Html.DisplayNameFor(model => model.Address) +
+
+ @Html.DisplayFor(model => model.Address) +
+
+ @Html.DisplayNameFor(model => model.Balance) +
+
+ @Html.DisplayFor(model => model.Balance) +
+
+ @Html.DisplayNameFor(model => model.Discount) +
+
+ @Html.DisplayFor(model => model.Discount) +
+ +
+ + +
\ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml new file mode 100644 index 0000000..620d66b --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml @@ -0,0 +1,58 @@ +@model WMS.WebUI.ViewModels.CustomerViewModels.CustomerActionViewModel + +@{ + ViewData["Title"] = "Edit Customer"; +} + + +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + Back + + +
+
+
+
+ +@section Scripts { + @{ + await Html.RenderPartialAsync("_ValidationScriptsPartial"); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml new file mode 100644 index 0000000..7b64e43 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml @@ -0,0 +1,77 @@ +@using WMS.WebUI.ViewModels.CustomerViewModels +@model IEnumerable + +
+
+
+
+
+ + +
+
+ +
+ +
+ +
+ +
+ +
+ New + +
+ +
+
+
+ +
+
+
+ + + + + + + + +
+
+
+ +
+
+
+ << + < + @if (ViewBag.CurrentPage > 1) + { + @(@ViewBag.CurrentPage - 1) + } + + @if (ViewBag.CurrentPage < ViewBag.TotalPages) + { + @(@ViewBag.CurrentPage + 1) + } + > + >> +
+
+

@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)

+
+
+
+ + diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml new file mode 100644 index 0000000..3a352d9 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml @@ -0,0 +1,72 @@ +@model WMS.WebUI.ViewModels.ProductViewModel + +@{ + ViewData["Title"] = "Create Product"; +} + +
+

Create Product

+
+ +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ + Back to List +
+
+
+ +@section Scripts { + @{ + await Html.RenderPartialAsync("_ValidationScriptsPartial"); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml new file mode 100644 index 0000000..d16a613 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml @@ -0,0 +1,44 @@ +@model WMS.WebUI.ViewModels.ProductViewModel + +@{ + ViewData["Title"] = "Delete Product"; +} +
+

Delete Product

+ +
+
+
+

Are you sure you want to delete this product?

+
+
+
Name
+
@Model.Name
+ +
Description
+
@Model.Description
+ +
Sale Price
+
@Model.SalePrice.ToString("C")
+ +
Supply Price
+
@Model.SupplyPrice.ToString("C")
+ +
Quantity In Stock
+
@Model.QuantityInStock
+ +
Low Quantity Amount
+
@Model.LowQuantityAmount
+ +
Category
+
@Model.Category
+
+
+ +
+ + Cancel +
+
+
+
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml new file mode 100644 index 0000000..d75203e --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml @@ -0,0 +1,47 @@ +@model WMS.WebUI.ViewModels.ProductViewModel + +@{ + ViewData["Title"] = "Product Details"; +} + +

Product Details

+ +
+
+
+
+
Name
+
@Model.Name
+ +
Description
+
@Model.Description
+ +
Sale Price
+
@Model.SalePrice.ToString("C")
+ +
Supply Price
+
@Model.SupplyPrice.ToString("C")
+ +
Quantity In Stock
+
@Model.QuantityInStock
+ +
Low Quantity Amount
+
@Model.LowQuantityAmount
+ +
Category
+
@Model.Category
+
+ + +
+
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml new file mode 100644 index 0000000..ad33f58 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml @@ -0,0 +1,61 @@ +@model WMS.WebUI.ViewModels.ProductViewModel + +@{ + ViewData["Title"] = "Edit Product"; +} + +

Edit Product

+ +
+
+
+
+ +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + Back to List +
+
+
+
+ +@section Scripts { + @{ + await Html.RenderPartialAsync("_ValidationScriptsPartial"); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml index 80dcf64..314f21d 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml @@ -2,8 +2,8 @@
-
-
+ +
@@ -23,8 +23,16 @@
+
+
+ + +
+
- New + + New +
diff --git a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml index 41ff20a..e681bcc 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml @@ -9,7 +9,7 @@ menuItems.Add(new { text = "Dashboard", - url = "/", + url = "/home", iconCss = "fa-solid fa-box" }); menuItems.Add(new @@ -46,13 +46,43 @@ { text = "Transactions", url = "#", - iconCss = "fa-solid fa-money-bill-transfer" + iconCss = "fa-solid fa-money-bill-transfer", + items = new List + { + new + { + text = "Sales", + url = "/sales", + iconCss = "fa-solid fa-shopping-cart" + }, + new + { + text = "Supplies", + url = "/supplies", + iconCss = "fa-solid fa-truck" + } + } }); menuItems.Add(new { text = "Partners", url = "#", - iconCss = "fa-solid fa-users" + iconCss = "fa-solid fa-users", + items = new List() + { + new + { + text = "Customers", + url = "/customers", + iconCss = "fa-solid fa-user-friends" + }, + new + { + text = "Suppliers", + url = "/suppliers", + iconCss = "fa-solid fa-truck" + } + } }); menuItems.Add(new diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml new file mode 100644 index 0000000..346c26f --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml @@ -0,0 +1,45 @@ +@using WMS.WebUI.ViewModels.SupplierViewModels; +@model SupplierActionViewModel; + +

Create Supplier

+
+
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + Back + + +
+
+
+
+@section Scripts { + @{ + await Html.RenderPartialAsync("_ValidationScriptsPartial"); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml new file mode 100644 index 0000000..2156eae --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml @@ -0,0 +1,41 @@ +@using WMS.WebUI.ViewModels.SupplierViewModels; +@model SupplierDisplayViewModel ; + +

Are you sure want to delete ?

+
+ +
+
+
+ @Html.DisplayNameFor(model => model.Id) +
+
+ @Html.DisplayFor(model => model.Id) +
+
+ @Html.DisplayNameFor(model => model.FullName) +
+
+ @Html.DisplayFor(model => model.FullName) +
+
+ @Html.DisplayNameFor(model => model.PhoneNumber) +
+
+ @Html.DisplayFor(model => model.PhoneNumber) +
+
+ @Html.DisplayNameFor(model => model.Balance) +
+
+ @Html.DisplayFor(model => model.Balance) +
+
+
+ +
+
+ Back + +
+
\ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml new file mode 100644 index 0000000..9072dc4 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml @@ -0,0 +1,50 @@ +@using WMS.WebUI.ViewModels.SupplierViewModels; +@model SupplierDisplayViewModel; + +
+

Supplier details

+ +
+ +
+
+ @Html.DisplayNameFor(model => model.Id) +
+
+ @Html.DisplayFor(model => model.Id) +
+
+ @Html.DisplayNameFor(model => model.FullName) +
+
+ @Html.DisplayFor(model => model.FullName) +
+
+ @Html.DisplayNameFor(model => model.PhoneNumber) +
+
+ @Html.DisplayFor(model => model.PhoneNumber) +
+
+ @Html.DisplayNameFor(model => model.Balance) +
+
+ @Html.DisplayFor(model => model.Balance) +
+ +
+
+
+ + +
\ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml new file mode 100644 index 0000000..d9d3f9f --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml @@ -0,0 +1,45 @@ +@using WMS.WebUI.ViewModels.SupplierViewModels; +@model SupplierActionViewModel; + +

Edit Supplier

+ +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + Back + + +
+
+
+
+@section Scripts { + @{ + await Html.RenderPartialAsync("_ValidationScriptsPartial"); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml new file mode 100644 index 0000000..076711d --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml @@ -0,0 +1,77 @@ +@using WMS.WebUI.ViewModels.SupplierViewModels +@model IEnumerable + +
+
+
+
+
+ + +
+
+ +
+ +
+ +
+ +
+ +
+ New + +
+ +
+
+
+ +
+
+
+ + + + + + + + +
+
+
+ +
+
+
+ << + < + @if (ViewBag.CurrentPage > 1) + { + @(@ViewBag.CurrentPage - 1) + } + + @if (ViewBag.CurrentPage < ViewBag.TotalPages) + { + @(@ViewBag.CurrentPage + 1) + } + > + >> +
+
+

@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)

+
+
+
+ + From 1f8df945cad66cd448e01490c700188383701edf Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Thu, 27 Jun 2024 18:07:04 +0500 Subject: [PATCH 3/7] Fix all bugs --- .../WMS.WebUI/Stores/DataStores/CustomerStore.cs | 2 +- .../WMS.WebUI/Stores/DataStores/SupplierStore.cs | 2 +- .../CustomerViewModels/CustomerActionViewModel.cs | 10 +++++++++- .../CustomerViewModels/CustomerDisplayViewModel.cs | 6 +++++- .../SupplierViewModels/SupplierActionViewModel.cs | 11 ++++++++++- WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml | 2 +- 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs index 063ea23..e160918 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs @@ -47,7 +47,7 @@ public async Task> GetCustomers(C public async Task Update(CustomerActionViewModel customer) { - await _apiClient.PutAsync(ApiResourceConstants.Customers, customer); + await _apiClient.PutAsync(ApiResourceConstants.Customers + "/" + customer.Id, customer); } private string BuildQueryParameters(CustomerQueryParameters queryParameters) { diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs index 7035584..1d11697 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs @@ -45,7 +45,7 @@ public async Task> GetSuppliers(S public async Task Update(SupplierActionViewModel supplier) { - await _apiClient.PutAsync(ApiResourceConstants.Suppliers, supplier); + await _apiClient.PutAsync(ApiResourceConstants.Suppliers + "/" + supplier.Id, supplier); } private string BuildQueryParameters(SupplierQueryParameters queryParameters) { diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs index 6aedcce..848a240 100644 --- a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs @@ -1,10 +1,18 @@ -namespace WMS.WebUI.ViewModels.CustomerViewModels; +using System.ComponentModel; + +namespace WMS.WebUI.ViewModels.CustomerViewModels; public class CustomerActionViewModel { public int Id { get; set; } + + [DisplayName("First name")] public string FirstName { get; set; } + + [DisplayName("Last name")] public string LastName { get; set; } + + [DisplayName("Phone number")] public string PhoneNumber { get; set; } public string Address { get; set; } public decimal Balance { get; set; } diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs index 11fe7e1..f542311 100644 --- a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs @@ -1,9 +1,13 @@ -namespace WMS.WebUI.ViewModels.CustomerViewModels +using System.ComponentModel; + +namespace WMS.WebUI.ViewModels.CustomerViewModels { public class CustomerDisplayViewModel { public int Id { get; set; } + [DisplayName("Full name")] public string FullName { get; set; } + [DisplayName("Phone number")] public string PhoneNumber { get; set; } public string Address { get; set; } public decimal Balance { get; set; } diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs index 5d0bade..fe71d24 100644 --- a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs @@ -1,11 +1,20 @@ -namespace WMS.WebUI.ViewModels.SupplierViewModels; +using System.ComponentModel; + +namespace WMS.WebUI.ViewModels.SupplierViewModels; public class SupplierActionViewModel { public int Id { get; set; } + + [DisplayName("First name")] public string FirstName { get; set; } + + [DisplayName("Last name")] public string LastName { get; set; } + + [DisplayName("Phone number")] public string PhoneNumber { get; set; } + public decimal Balance { get; set; } //public ICollection Supplies { get; set; } //public SupplierDto() diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml index 346c26f..6b21a0b 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml @@ -4,7 +4,7 @@

Create Supplier


-
+
From eebfd1b06c6e3984f2dab532c736a6e30d931c60 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:07:29 +0500 Subject: [PATCH 4/7] Oldest changes --- .../Constants/ApiResourceConstants.cs | 2 + .../Controllers/AdjustmentController.cs | 50 ++++++++++++ .../WMS.WebUI/Controllers/SalesController.cs | 57 ++++++++++++++ .../Controllers/SuppliesController.cs | 56 +++++++++++++ .../Models/Adjustment/Transactions.cs | 10 +++ WMS.WebUI/WMS.WebUI/Program.cs | 5 +- .../QueryParams/TransactionQueryParameters.cs | 9 +++ .../Stores/DataStores/CustomerStore.cs | 35 ++++----- .../WMS.WebUI/Stores/DataStores/SaleStore.cs | 68 ++++++++++++++++ .../Stores/DataStores/SupplyStore.cs | 66 ++++++++++++++++ .../WMS.WebUI/Stores/Interfaces/ISaleStore.cs | 13 ++++ .../Stores/Interfaces/ISupplyStore.cs | 14 ++++ .../SaleItemViewModels/SaleItemViewModel.cs | 15 ++++ .../SaleViewModels/SaleViewModel.cs | 20 +++++ .../SupplyItemViewModel.cs | 14 ++++ .../SupplyViewModels/SupplyViewModel.cs | 21 +++++ .../WMS.WebUI/Views/Customers/Index.cshtml | 7 +- .../WMS.WebUI/Views/Sales/Details.cshtml | 46 +++++++++++ WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml | 78 +++++++++++++++++++ .../WMS.WebUI/Views/Supplies/Index.cshtml | 77 ++++++++++++++++++ WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj | 4 +- WMS.WebUI/WMS.WebUI/appsettings.json | 5 +- 22 files changed, 646 insertions(+), 26 deletions(-) create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs create mode 100644 WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs index 66a003c..b13c9e0 100644 --- a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs +++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs @@ -6,4 +6,6 @@ public static class ApiResourceConstants public const string Categories = nameof(Categories); public const string Customers = nameof(Customers); public const string Suppliers = nameof(Suppliers); + public const string Sales = nameof(Sales); + public const string Supplies = nameof(Supplies); } diff --git a/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs b/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs new file mode 100644 index 0000000..c237f31 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs @@ -0,0 +1,50 @@ +using Microsoft.AspNetCore.Mvc; +using WMS.WebUI.Models.Adjustment; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Controllers; + +public class AdjustmentController(ISupplyStore supplyStore,ISaleStore saleStore) : Controller +{ + private readonly ISaleStore _saleStore = saleStore; + private readonly ISupplyStore _supplyStore = supplyStore; + public async Task Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber) + { + var queryParameters = new TransactionQueryParameters() + { + Search = searchString, + FromDate = fromDate, + ToDate = toDate, + PageNumber = pageNumber + }; + + var supplies = await _supplyStore.GetSupplies(queryParameters); + var sales = await _saleStore.GetSales(queryParameters); + + var transactions = new Transactions() + { + Sales = sales.Data, + Supplies = supplies.Data + }; + + // PopulateViewBag(transactions, queryParameters); + + return View(supplies.Data); + } + private void PopulateViewBag(PaginatedApiResponse sales, TransactionQueryParameters queryParameters) + { + ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd"); + ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd"); + ViewBag.SearchString = queryParameters.Search; + + ViewBag.PageSize = sales.PageSize; + ViewBag.TotalPages = sales.PagesCount; + ViewBag.TotalItems = sales.TotalCount; + ViewBag.CurrentPage = sales.CurrentPage; + ViewBag.HasPreviousPage = sales.HasPreviousPage; + ViewBag.HasNextPage = sales.HasNextPage; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs b/WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs new file mode 100644 index 0000000..57ae057 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SaleViewModels; + +namespace WMS.WebUI.Controllers; + +public class SalesController : Controller +{ + private readonly ICustomerStore _customerStore; + private readonly ISaleStore _salesStore; + + public SalesController(ISaleStore saleStore, ICustomerStore customerStore) + { + _customerStore = customerStore; + _salesStore = saleStore; + } + + public async Task Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber) + { + var queryParameters = new TransactionQueryParameters() + { + Search = searchString, + FromDate = fromDate, + ToDate = toDate, + PageNumber = pageNumber + }; + + var sales = await _salesStore.GetSales(queryParameters); + + PopulateViewBag(sales, queryParameters); + + return View(sales.Data); + } + + public async Task Details(int id) + { + var sale = await _salesStore.GetById(id); + return View(sale); + } + + private void PopulateViewBag(PaginatedApiResponse sales, TransactionQueryParameters queryParameters) + { + ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd"); + ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd"); + ViewBag.SearchString = queryParameters.Search; + + ViewBag.PageSize = sales.PageSize; + ViewBag.TotalPages = sales.PagesCount; + ViewBag.TotalItems = sales.TotalCount; + ViewBag.CurrentPage = sales.CurrentPage; + ViewBag.HasPreviousPage = sales.HasPreviousPage; + ViewBag.HasNextPage = sales.HasNextPage; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs b/WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs new file mode 100644 index 0000000..de3220b --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Mvc; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Controllers; + +public class SuppliesController : Controller +{ + private readonly ICustomerStore _customerStore; + private readonly ISupplyStore _supplyStore; + + public SuppliesController(ISupplyStore supplyStore, ICustomerStore customerStore) + { + _customerStore = customerStore; + _supplyStore = supplyStore; + } + + public async Task Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber) + { + var queryParameters = new TransactionQueryParameters() + { + Search = searchString, + FromDate = fromDate, + ToDate = toDate, + PageNumber = pageNumber + }; + + var supplies = await _supplyStore.GetSupplies(queryParameters); + + PopulateViewBag(supplies, queryParameters); + + return View(supplies.Data); + } + + public async Task Details(int id) + { + var supply = await _supplyStore.GetById(id); + return View(supply); + } + + private void PopulateViewBag(PaginatedApiResponse sales, TransactionQueryParameters queryParameters) + { + ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd"); + ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd"); + ViewBag.SearchString = queryParameters.Search; + + ViewBag.PageSize = sales.PageSize; + ViewBag.TotalPages = sales.PagesCount; + ViewBag.TotalItems = sales.TotalCount; + ViewBag.CurrentPage = sales.CurrentPage; + ViewBag.HasPreviousPage = sales.HasPreviousPage; + ViewBag.HasNextPage = sales.HasNextPage; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs b/WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs new file mode 100644 index 0000000..48dae94 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs @@ -0,0 +1,10 @@ +using WMS.WebUI.ViewModels.SaleViewModels; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Models.Adjustment; + +public class Transactions +{ + public IEnumerable Sales { get; set; } + public IEnumerable Supplies { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs index faa76cc..1d3bfb6 100644 --- a/WMS.WebUI/WMS.WebUI/Program.cs +++ b/WMS.WebUI/WMS.WebUI/Program.cs @@ -12,10 +12,11 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); - +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddSingleton(); -Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ; +Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(builder.Configuration.GetValue("Keys:Syncfusion")); var app = builder.Build(); diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs new file mode 100644 index 0000000..483ad92 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs @@ -0,0 +1,9 @@ +using Syncfusion.EJ2.Calendars; + +namespace WMS.WebUI.QueryParams; + +public class TransactionQueryParameters : BaseQueryParameters +{ + public DateTime? FromDate { get; set; } + public DateTime? ToDate { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs index e160918..6acba80 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs @@ -13,42 +13,41 @@ namespace WMS.WebUI.Stores.DataStores; public class CustomerStore(ApiClient apiClient) : ICustomerStore { private readonly ApiClient _apiClient = apiClient; - public async Task Create(CustomerActionViewModel customer) + public async Task> GetCustomers(CustomerQueryParameters queryParameters) { - var createdCustomer = await _apiClient.PostAsync(ApiResourceConstants.Customers,customer); + var query = BuildQueryParameters(queryParameters); - return createdCustomer; - } + var url = string.IsNullOrEmpty(query) ? + ApiResourceConstants.Customers : + ApiResourceConstants.Customers + "?" + query; - public async Task Delete(int id) - { - await _apiClient.DeleteAsync(ApiResourceConstants.Customers,id); - } + var customers = await _apiClient.GetAsync>(url); + return customers; + } public async Task GetById(int id) { var customer = await _apiClient.GetAsync(ApiResourceConstants.Customers + "/" + id); return customer; } - public async Task> GetCustomers(CustomerQueryParameters queryParameters) + public async Task Create(CustomerActionViewModel customer) { - var query = BuildQueryParameters(queryParameters); - - var url = string.IsNullOrEmpty(query) ? - ApiResourceConstants.Customers : - ApiResourceConstants.Customers + "?" + query; - - var customers = await _apiClient.GetAsync>(url); + var createdCustomer = await _apiClient.PostAsync(ApiResourceConstants.Customers,customer); - return customers; + return createdCustomer; } public async Task Update(CustomerActionViewModel customer) { await _apiClient.PutAsync(ApiResourceConstants.Customers + "/" + customer.Id, customer); } + public async Task Delete(int id) + { + await _apiClient.DeleteAsync(ApiResourceConstants.Customers,id); + } + private string BuildQueryParameters(CustomerQueryParameters queryParameters) { var query = new StringBuilder(); diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs new file mode 100644 index 0000000..2375792 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs @@ -0,0 +1,68 @@ +using Syncfusion.EJ2.Diagrams; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using WMS.WebUI.Constants; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Services; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SaleViewModels; + +namespace WMS.WebUI.Stores.DataStores; + +public class SaleStore(ApiClient apiClient) : ISaleStore +{ + private readonly ApiClient _apiClient = apiClient; + public async Task> GetSales(TransactionQueryParameters queryParameters) + { + var query = BuildQueryParameters(queryParameters); + var sales = await _apiClient.GetAsync>(ApiResourceConstants.Sales + "?" + query); + return sales; + } + public async Task GetById(int id) + { + var sale = await _apiClient.GetAsync(ApiResourceConstants.Sales + "/" + id); + return sale; + } + + public Task Create(SaleViewModel sale) + { + var createdSale = _apiClient.PostAsync(ApiResourceConstants.Sales, sale); + return createdSale; + } + public async Task Update(SaleViewModel sale) + { + await _apiClient.PutAsync(ApiResourceConstants.Sales, sale); + } + + public async Task Delete(int id) + { + await _apiClient.DeleteAsync(ApiResourceConstants.Sales, id); + } + private string BuildQueryParameters(TransactionQueryParameters queryParameters) + { + StringBuilder query = new StringBuilder(); + + if (queryParameters.PageNumber.HasValue) + { + query.Append($"pageNumber={queryParameters.PageNumber}&"); + } + else + { + query.Append($"pageNumber=1&"); + } + if (!string.IsNullOrWhiteSpace(queryParameters.Search)) + { + query.Append($"Search={queryParameters.Search}&"); + } + if (queryParameters.FromDate.HasValue) + { + query.Append($"FromDate={queryParameters.FromDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&"); + } + if (queryParameters.ToDate.HasValue) + { + query.Append($"ToDate={queryParameters.ToDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&"); + } + return query.ToString(); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs new file mode 100644 index 0000000..22b0723 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs @@ -0,0 +1,66 @@ +using System.Text; +using WMS.WebUI.Constants; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.Services; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Stores.DataStores; + +public class SupplyStore(ApiClient apiClient) : ISupplyStore +{ + private readonly ApiClient _apiClient = apiClient; + public async Task> GetSupplies(TransactionQueryParameters queryParameters) + { + var query = BuildQueryParameters(queryParameters); + var supplies = await _apiClient.GetAsync>(ApiResourceConstants.Supplies + "?" + query); + return supplies; + } + public async Task GetById(int id) + { + var supply = await _apiClient.GetAsync(ApiResourceConstants.Supplies + "/" + id); + return supply; + } + + public Task Create(SupplyViewModel supply) + { + var createdSupply = _apiClient.PostAsync(ApiResourceConstants.Supplies, supply); + return createdSupply; + } + public async Task Update(SupplyViewModel supply) + { + await _apiClient.PutAsync(ApiResourceConstants.Supplies, supply); + } + + public async Task Delete(int id) + { + await _apiClient.DeleteAsync(ApiResourceConstants.Supplies, id); + } + private string BuildQueryParameters(TransactionQueryParameters queryParameters) + { + StringBuilder query = new StringBuilder(); + + if (queryParameters.PageNumber.HasValue) + { + query.Append($"pageNumber={queryParameters.PageNumber}&"); + } + else + { + query.Append($"pageNumber=1&"); + } + if (!string.IsNullOrWhiteSpace(queryParameters.Search)) + { + query.Append($"Search={queryParameters.Search}&"); + } + if (queryParameters.FromDate.HasValue) + { + query.Append($"FromDate={queryParameters.FromDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&"); + } + if (queryParameters.ToDate.HasValue) + { + query.Append($"ToDate={queryParameters.ToDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&"); + } + return query.ToString(); + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs new file mode 100644 index 0000000..57084bf --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs @@ -0,0 +1,13 @@ +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels.SaleViewModels; + +namespace WMS.WebUI.Stores.Interfaces; +public interface ISaleStore +{ + Task> GetSales(TransactionQueryParameters queryParameters); + Task GetById(int id); + Task Create(SaleViewModel sale); + Task Update(SaleViewModel sale); + Task Delete(int id); +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs new file mode 100644 index 0000000..ce1a321 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs @@ -0,0 +1,14 @@ +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Stores.Interfaces; + +public interface ISupplyStore +{ + Task> GetSupplies(TransactionQueryParameters queryParameters); + Task GetById(int id); + Task Create(SupplyViewModel supply); + Task Update(SupplyViewModel supply); + Task Delete(int id); +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs new file mode 100644 index 0000000..a7912a4 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; + +namespace WMS.WebUI.ViewModels.SaleItemViewModels; + +public class SaleItemViewModel +{ + public int Id { get; set; } + public int Quantity { get; set; } + + [DisplayName("Unit price")] + public decimal UnitPrice { get; set; } + public int ProductId { get; set; } + public string Product { get; set; } + public int SaleId { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs new file mode 100644 index 0000000..133f3e7 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs @@ -0,0 +1,20 @@ +using System.ComponentModel; +using WMS.WebUI.ViewModels.SaleItemViewModels; + +namespace WMS.WebUI.ViewModels.SaleViewModels; + +public class SaleViewModel +{ + public int Id { get; set; } + + [DisplayName("Total due")] + public decimal TotalDue { get; set; } + + [DisplayName("Total paid")] + public decimal TotalPaid { get; set; } + public DateTime Date { get; set; } + public int CustomerId { get; set; } + public string Customer { get; set; } + public virtual ICollection SaleItems { get; set; } + public SaleViewModel() => SaleItems = []; +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs new file mode 100644 index 0000000..86fa9bb --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel; + +namespace WMS.WebUI.ViewModels.SupplyItemViewModels; + +public class SupplyItemViewModel +{ + public int Id { get; set; } + public int Quantity { get; set; } + [DisplayName("Unit price")] + public decimal UnitPrice { get; set; } + public int ProductId { get; set; } + public virtual string Product { get; set; } + public int SupplyId { get; set; } +} diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs new file mode 100644 index 0000000..6d099db --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; +using WMS.WebUI.ViewModels.SupplyItemViewModels; + +namespace WMS.WebUI.ViewModels.SupplyViewModels; + +public class SupplyViewModel +{ + public int Id { get; set; } + [DisplayName("Total due")] + public decimal TotalDue { get; set; } + [DisplayName("Total paid")] + public decimal TotalPaid { get; set; } + public DateTime Date { get; set; } + public int SupplierId { get; set; } + public string Supplier { get; set; } + public ICollection SupplyItems { get; set; } + public SupplyViewModel() + { + SupplyItems = []; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml index 7b64e43..3a7122f 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml @@ -1,10 +1,11 @@ @using WMS.WebUI.ViewModels.CustomerViewModels @model IEnumerable -
+
-
-
+
+ +
+
+
+ +
+ +
+ +
+ +
+ +
+ New + +
+ +
+ +
+ +
+
+
+ + + + + + + + + +
+
+
+ +
+
+
+ << + < + @if (ViewBag.CurrentPage > 1) + { + @(@ViewBag.CurrentPage - 1) + } + + @if (ViewBag.CurrentPage < ViewBag.TotalPages) + { + @(@ViewBag.CurrentPage + 1) + } + > + >> +
+
+

@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)

+
+
+
+ + diff --git a/WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml new file mode 100644 index 0000000..29ff616 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml @@ -0,0 +1,77 @@ +@using WMS.WebUI.ViewModels.SupplyViewModels +@model IEnumerable + +
+
+
+
+
+ + +
+
+
+ +
+ +
+ +
+ +
+ New + +
+ +
+
+
+ +
+
+
+ + + + + + + + + +
+
+
+ +
+
+
+ << + < + @if (ViewBag.CurrentPage > 1) + { + @(@ViewBag.CurrentPage - 1) + } + + @if (ViewBag.CurrentPage < ViewBag.TotalPages) + { + @(@ViewBag.CurrentPage + 1) + } + > + >> +
+
+

@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)

+
+
+
+ + diff --git a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj index fabc02c..527d341 100644 --- a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj +++ b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/WMS.WebUI/WMS.WebUI/appsettings.json b/WMS.WebUI/WMS.WebUI/appsettings.json index 10f68b8..430059c 100644 --- a/WMS.WebUI/WMS.WebUI/appsettings.json +++ b/WMS.WebUI/WMS.WebUI/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "Keys": { + "Syncfusion": "Ngo9BigBOggjHTQxAR8/V1NCaF5cXmZCf1FpRmJGdld5fUVHYVZUTXxaS00DNHVRdkdnWXhedHVUR2dZWUV2XUE=" + } } From 7c7ed307bb32e730c212fd4655ac19ac72a70d2b Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:33:27 +0500 Subject: [PATCH 5/7] Added Partner viewModels and Transactions --- .../Controllers/AdjustmentController.cs | 50 ----------------- .../Controllers/TransactionsController.cs | 55 +++++++++++++++++++ WMS.WebUI/WMS.WebUI/Helpers/Validator.cs | 13 +++++ .../WMS.WebUI/Stores/DataStores/SaleStore.cs | 8 ++- .../WMS.WebUI/Stores/Interfaces/ISaleStore.cs | 3 +- .../Stores/Interfaces/ITransactionsStore.cs | 10 ++++ .../ViewModels/DashboardViewModel.cs | 31 ++++++++++- .../WMS.WebUI/ViewModels/PartnerViewModel.cs | 15 +++++ 8 files changed, 130 insertions(+), 55 deletions(-) delete mode 100644 WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs create mode 100644 WMS.WebUI/WMS.WebUI/Helpers/Validator.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs diff --git a/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs b/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs deleted file mode 100644 index c237f31..0000000 --- a/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using WMS.WebUI.Models.Adjustment; -using WMS.WebUI.Models.PaginatedResponse; -using WMS.WebUI.QueryParams; -using WMS.WebUI.Stores.Interfaces; -using WMS.WebUI.ViewModels.SupplyViewModels; - -namespace WMS.WebUI.Controllers; - -public class AdjustmentController(ISupplyStore supplyStore,ISaleStore saleStore) : Controller -{ - private readonly ISaleStore _saleStore = saleStore; - private readonly ISupplyStore _supplyStore = supplyStore; - public async Task Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber) - { - var queryParameters = new TransactionQueryParameters() - { - Search = searchString, - FromDate = fromDate, - ToDate = toDate, - PageNumber = pageNumber - }; - - var supplies = await _supplyStore.GetSupplies(queryParameters); - var sales = await _saleStore.GetSales(queryParameters); - - var transactions = new Transactions() - { - Sales = sales.Data, - Supplies = supplies.Data - }; - - // PopulateViewBag(transactions, queryParameters); - - return View(supplies.Data); - } - private void PopulateViewBag(PaginatedApiResponse sales, TransactionQueryParameters queryParameters) - { - ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd"); - ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd"); - ViewBag.SearchString = queryParameters.Search; - - ViewBag.PageSize = sales.PageSize; - ViewBag.TotalPages = sales.PagesCount; - ViewBag.TotalItems = sales.TotalCount; - ViewBag.CurrentPage = sales.CurrentPage; - ViewBag.HasPreviousPage = sales.HasPreviousPage; - ViewBag.HasNextPage = sales.HasNextPage; - } -} diff --git a/WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs b/WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs new file mode 100644 index 0000000..3df277f --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Mvc; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels; +using Validator = WMS.WebUI.Helpers.Validator; + +namespace WMS.WebUI.Controllers; + +public class TransactionsController : Controller +{ + private readonly ITransactionsStore _transactionsStore; + private readonly IProductsStore _productsStore; + + public TransactionsController(ITransactionsStore transactionsStore, IProductsStore productsStore) + { + _transactionsStore = Validator.NotNull(transactionsStore); + _productsStore = Validator.NotNull(productsStore); + } + + public async Task Index(string? searchString = null, string? transactionType = null) + { + var transactions = await _transactionsStore.GetTransactionsAsync(searchString, transactionType); + + ViewBag.SelectedType = transactionType ?? "All"; + + return View(transactions); + } + + public async Task Create() + { + var partnersTask = _transactionsStore.GetPartnersAsync(); + var productsTask = _productsStore.GetProducts(new QueryParams.ProductQueryParameters()); + + await Task.WhenAll(partnersTask, productsTask); + + ViewBag.Types = new string[] { "Sale", "Supply" }; + ViewBag.SelectedType = "Sale"; + ViewBag.Partners = partnersTask.Result; + ViewBag.Products= productsTask.Result.Data; + + return View(); + } + + [HttpPost] + public async Task Create( + [FromBody] CreateTransactionViewModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(); + } + + await _transactionsStore.Create(null); + return View(); + } +} \ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Helpers/Validator.cs b/WMS.WebUI/WMS.WebUI/Helpers/Validator.cs new file mode 100644 index 0000000..2dc9c13 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Helpers/Validator.cs @@ -0,0 +1,13 @@ +using WMS.WebUI.ViewModels; + +namespace WMS.WebUI.Helpers; + +public static class Validator +{ + public static T NotNull(T value) where T : class + { + ArgumentNullException.ThrowIfNull(value); + + return value; + } +} \ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs index 2375792..e490b3f 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs @@ -6,6 +6,7 @@ using WMS.WebUI.QueryParams; using WMS.WebUI.Services; using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels; using WMS.WebUI.ViewModels.SaleViewModels; namespace WMS.WebUI.Stores.DataStores; @@ -25,10 +26,11 @@ public async Task GetById(int id) return sale; } - public Task Create(SaleViewModel sale) + public async Task Create(CreateTransactionViewModel transaction) { - var createdSale = _apiClient.PostAsync(ApiResourceConstants.Sales, sale); - return createdSale; + var transactionNew = new TransactionView(); + + return transactionNew; } public async Task Update(SaleViewModel sale) { diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs index 57084bf..29052ed 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs @@ -1,5 +1,6 @@ using WMS.WebUI.Models.PaginatedResponse; using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels; using WMS.WebUI.ViewModels.SaleViewModels; namespace WMS.WebUI.Stores.Interfaces; @@ -7,7 +8,7 @@ public interface ISaleStore { Task> GetSales(TransactionQueryParameters queryParameters); Task GetById(int id); - Task Create(SaleViewModel sale); + Task Create(CreateTransactionViewModel transaction); Task Update(SaleViewModel sale); Task Delete(int id); } diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs new file mode 100644 index 0000000..4fb4677 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs @@ -0,0 +1,10 @@ +using WMS.WebUI.ViewModels; + +namespace WMS.WebUI.Stores.Interfaces; + +public interface ITransactionsStore +{ + Task> GetTransactionsAsync(string? search, string? type); + Task> GetPartnersAsync(); + Task Create(CreateTransactionViewModel transaction); +} \ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs index d1262e1..cd005e0 100644 --- a/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs +++ b/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Globalization; +using System.Runtime.Serialization; namespace WMS.WebUI.ViewModels; @@ -61,7 +62,35 @@ public class SplineChart public class TransactionView { public int Id { get; set; } - public string Type { get; set; } + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public TransactionType Type { get; set; } public decimal Amount { get; set; } + public int PartnerId { get; set; } + public string Partner { get; set; } public DateTime Date { get; set; } +} + +public class CreateTransactionViewModel +{ + public TransactionType Type { get; set; } + public int PartnerId { get; set; } + public DateTime Date { get; set; } + public List Items { get; set; } +} + +public class TransactionItem +{ + public int ProductId { get; set; } + public int Quantity { get; set; } + public decimal UnitPrice { get; set; } +} + +public enum TransactionType +{ + [EnumMember(Value = "Sale")] + Sale, + [EnumMember(Value = "Supply")] + Supply, + [EnumMember(Value = "Refund")] + Refund } \ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs new file mode 100644 index 0000000..8503c58 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs @@ -0,0 +1,15 @@ +namespace WMS.WebUI.ViewModels; + +public class PartnerViewModel +{ + public int Id { get; set; } + public string FullName { get; set; } + public PartnerType Type { get; set; } + public string PhoneNumber { get; set; } +} + +public enum PartnerType +{ + Customer, + Supplier +} From 640234173cc8ae2b7bcdc5108b9c2cc20f9d217e Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:55:45 +0500 Subject: [PATCH 6/7] Changing Transactions but not Delete Sale and supply controllers --- WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs | 20 ++ .../WMS.WebUI/Mappings/SupplyMappings.cs | 21 +++ WMS.WebUI/WMS.WebUI/Program.cs | 2 + .../Stores/DataStores/TransactionsStore.cs | 56 ++++++ .../Stores/Mocks/MockDashboardStore.cs | 14 +- .../WMS.WebUI/Views/Shared/_Sidebar.cshtml | 2 +- .../Views/Transactions/Create.cshtml | 178 ++++++++++++++++++ .../WMS.WebUI/Views/Transactions/Index.cshtml | 82 ++++++++ 8 files changed, 367 insertions(+), 8 deletions(-) create mode 100644 WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs create mode 100644 WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs create mode 100644 WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml create mode 100644 WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml diff --git a/WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs b/WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs new file mode 100644 index 0000000..475da2c --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs @@ -0,0 +1,20 @@ +using WMS.WebUI.ViewModels; +using WMS.WebUI.ViewModels.SaleViewModels; + +namespace WMS.WebUI.Mappings; + +public static class SalesMappings +{ + public static TransactionView ToTransaction(this SaleViewModel sale) + { + return new TransactionView + { + Id = sale.Id, + Amount = sale.TotalPaid, + Date = sale.Date, + Partner = sale.Customer, + PartnerId = sale.CustomerId, + Type = TransactionType.Sale + }; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs b/WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs new file mode 100644 index 0000000..8876669 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs @@ -0,0 +1,21 @@ +using WMS.WebUI.ViewModels; +using WMS.WebUI.ViewModels.SaleViewModels; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Mappings; + +public static class SupplyMappings +{ + public static TransactionView ToTransaction(this SupplyViewModel supply) + { + return new TransactionView + { + Id = supply.Id, + Amount = supply.TotalPaid, + Date = supply.Date, + Partner = supply.Supplier, + PartnerId = supply.SupplierId, + Type = TransactionType.Supply, + }; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs index 1d3bfb6..7c8883c 100644 --- a/WMS.WebUI/WMS.WebUI/Program.cs +++ b/WMS.WebUI/WMS.WebUI/Program.cs @@ -1,4 +1,5 @@ using WMS.WebUI.Services; +using WMS.WebUI.Stores; using WMS.WebUI.Stores.DataStores; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.Stores.Mocks; @@ -13,6 +14,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs new file mode 100644 index 0000000..0a49309 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs @@ -0,0 +1,56 @@ +using WMS.WebUI.Mappings; +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels; +using WMS.WebUI.ViewModels.SaleViewModels; +using WMS.WebUI.ViewModels.SupplyViewModels; + +namespace WMS.WebUI.Stores; + +public class TransactionsStore : ITransactionsStore +{ + private readonly HttpClient _client; + + public TransactionsStore() + { + _client = new HttpClient(); + _client.BaseAddress = new Uri("https://localhost:7108/api/"); + } + + public async Task> GetTransactionsAsync(string? search, string? type) + { + var salesTask = _client.GetFromJsonAsync>($"sales?search={search}"); + var suppliesTask = _client.GetFromJsonAsync>($"supplies?search={search}"); + + await Task.WhenAll(salesTask, suppliesTask); + + var sales = salesTask.Result; + var supplies = suppliesTask.Result; + List transactions = []; + + sales?.Data.ForEach(sale => transactions.Add(sale.ToTransaction())); + supplies?.Data.ForEach(supply => transactions.Add(supply.ToTransaction())); + + return transactions; + } + + public async Task> GetPartnersAsync() + { + var customersTask = _client.GetFromJsonAsync>("customers"); + var suppliersTask = _client.GetFromJsonAsync>("suppliers"); + + await Task.WhenAll(customersTask, suppliersTask); + + customersTask.Result!.ForEach(el => el.Type = PartnerType.Customer); + suppliersTask.Result!.ForEach(el => el.Type = PartnerType.Supplier); + + return [.. customersTask.Result, .. suppliersTask.Result]; + } + + public async Task Create(CreateTransactionViewModel transaction) + { + var transactionNew = new TransactionView(); + + return transactionNew; + } +} \ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs index bf46fb4..8b3628c 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs @@ -156,42 +156,42 @@ public Task Get() Id = 1, Amount = 500, Date = DateTime.Now, - Type = "Sale" + Type = TransactionType.Sale, }, new TransactionView { Id = 2, Amount = 300, - Date = DateTime.Now, - Type = "Sale" + Type = TransactionType.Sale, + Date = DateTime.Now }, new TransactionView { Id = 3, Amount = 459, + Type = TransactionType.Supply, Date = DateTime.Now, - Type = "Supply" }, new TransactionView { Id = 4, Amount = 500, + Type = TransactionType.Supply, Date = DateTime.Now, - Type = "Supply" }, new TransactionView { Id = 5, Amount = 250, + Type = TransactionType.Refund, Date = DateTime.Now, - Type = "Refund" }, new TransactionView { Id = 7, Amount = 200, Date = DateTime.Now, - Type = "Sale" + Type = TransactionType.Sale, }, }; diff --git a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml index e681bcc..cbe8257 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml @@ -45,7 +45,7 @@ menuItems.Add(new { text = "Transactions", - url = "#", + url = "/transactions", iconCss = "fa-solid fa-money-bill-transfer", items = new List { diff --git a/WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml new file mode 100644 index 0000000..64ef6a5 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml @@ -0,0 +1,178 @@ +@model WMS.WebUI.ViewModels.TransactionView +@using System.Collections.Generic + +
+
+

Create Transaction

+
+ + + + + +
+ + + +
+ +
+
+ + + + +
+
+ + + + + + + + + +
+
+

0

+
+ + +
+
+ + \ No newline at end of file diff --git a/WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml new file mode 100644 index 0000000..cf7477c --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml @@ -0,0 +1,82 @@ +@using WMS.WebUI.ViewModels +@model List + +@{ + var transactionTypes = new string[] { "All", "Sales", "Supplies", "Refunds" }; +} + +
+ +
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+
+ +
+
+ + + + + + + + + +
+
+ + + + + \ No newline at end of file From 9cb275c174b8acb7a0ff4fb64c3a3b1ed4d801c0 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sun, 21 Jul 2024 12:03:48 +0500 Subject: [PATCH 7/7] a efe --- .../Stores/DataStores/TransactionsStore.cs | 10 +- .../WMS.WebUI/Views/Products/Create.cshtml | 99 ++++++------------- 2 files changed, 35 insertions(+), 74 deletions(-) diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs index 0a49309..5b9c54e 100644 --- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs @@ -36,15 +36,15 @@ public async Task> GetTransactionsAsync(string? search, st public async Task> GetPartnersAsync() { - var customersTask = _client.GetFromJsonAsync>("customers"); - var suppliersTask = _client.GetFromJsonAsync>("suppliers"); + var customersTask = _client.GetFromJsonAsync>("customers"); + var suppliersTask = _client.GetFromJsonAsync>("suppliers"); await Task.WhenAll(customersTask, suppliersTask); - customersTask.Result!.ForEach(el => el.Type = PartnerType.Customer); - suppliersTask.Result!.ForEach(el => el.Type = PartnerType.Supplier); + customersTask.Result!.Data.ForEach(el => el.Type = PartnerType.Customer); + suppliersTask.Result!.Data.ForEach(el => el.Type = PartnerType.Supplier); - return [.. customersTask.Result, .. suppliersTask.Result]; + return [.. customersTask.Result.Data, .. suppliersTask.Result.Data]; } public async Task Create(CreateTransactionViewModel transaction) diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml index 3a352d9..76d878a 100644 --- a/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml @@ -1,72 +1,33 @@ -@model WMS.WebUI.ViewModels.ProductViewModel +@using WMS.WebUI.ViewModels +@model ProductViewModel; -@{ - ViewData["Title"] = "Create Product"; -} - -
-

Create Product

-
- -
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
+
+ +

Create Product

+
+ + + + +
+
+ + +
+
+ + +
+
+
-
- -
- - -
-
-
- -
- - -
-
-
- - Back to List -
- -
-@section Scripts { - @{ - await Html.RenderPartialAsync("_ValidationScriptsPartial"); - } -} + + +
\ No newline at end of file