diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs new file mode 100644 index 0000000..b13c9e0 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs @@ -0,0 +1,11 @@ +namespace WMS.WebUI.Constants; + +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); + public const string Sales = nameof(Sales); + public const string Supplies = nameof(Supplies); +} 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/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 new file mode 100644 index 0000000..91adc39 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs @@ -0,0 +1,148 @@ +using Microsoft.AspNetCore.Http.HttpResults; +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? searchString, + int? pageNumber, + int? categoryId, + decimal? maxPrice, + decimal? minPrice, + string? isLowQuantity + ) + { + 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(); + + 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) + { + 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/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/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/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/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/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/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/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/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/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..7c8883c 100644 --- a/WMS.WebUI/WMS.WebUI/Program.cs +++ b/WMS.WebUI/WMS.WebUI/Program.cs @@ -1,4 +1,6 @@ +using WMS.WebUI.Services; using WMS.WebUI.Stores; +using WMS.WebUI.Stores.DataStores; using WMS.WebUI.Stores.Interfaces; using WMS.WebUI.Stores.Mocks; @@ -8,9 +10,15 @@ builder.Services.AddControllersWithViews(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); - -Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ; +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddSingleton(); + +Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(builder.Configuration.GetValue("Keys:Syncfusion")); var app = builder.Build(); 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 new file mode 100644 index 0000000..b4d0ea4 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs @@ -0,0 +1,9 @@ +namespace WMS.WebUI.QueryParams; + +public class ProductQueryParameters : BaseQueryParameters +{ + public int? CategoryId { get; set; } + public decimal? MaxPrice { get; set; } + public decimal? MinPrice { 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/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/Services/ApiClient.cs b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs new file mode 100644 index 0000000..08f84d6 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs @@ -0,0 +1,65 @@ +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:7108/api/") + }; + } + + public async Task GetAsync(string resource) + { + var response = await _client.GetAsync(resource); + + 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, TBody 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 deleted file mode 100644 index 2db82cc..0000000 --- a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Newtonsoft.Json; -using System.Text; -using WMS.WebUI.Stores.Interfaces; -using WMS.WebUI.ViewModels; - -namespace WMS.WebUI.Stores; - -public class CategoryStore : ICategoryStore -{ - private readonly HttpClient _client; - - public CategoryStore() - { - _client = new HttpClient(); - _client.BaseAddress = new Uri("https://localhost:7097/api/"); - } - - 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."); - } - - return createdCategory; - } - - public async Task DeleteCategoryAsync(int id) - { - var response = await _client.DeleteAsync($"categories/{id}"); - - response.EnsureSuccessStatusCode(); - } - - public async Task> GetCategoriesAsync(string? search = null) - { - var response = await _client.GetAsync($"categories?search={search}"); - - response.EnsureSuccessStatusCode(); - - var json = await response.Content.ReadAsStringAsync(); - var categories = JsonConvert.DeserializeObject>(json); - - if (categories is null) - { - throw new JsonSerializationException("Error serializing Category response from API."); - } - - return categories; - } - - public async Task GetCategoryByIdAsync(int id) - { - var response = 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(); - } -} diff --git a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs deleted file mode 100644 index 9a4a232..0000000 --- a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Newtonsoft.Json; -using WMS.WebUI.Stores.Interfaces; -using WMS.WebUI.ViewModels; - -namespace WMS.WebUI.Stores; - -public class DashboardStore : IDashboardStore -{ - private readonly HttpClient _client; - - public DashboardStore() - { - _client = new HttpClient(); - _client.BaseAddress = new Uri("https://localhost:7097/api/"); - } - - 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"); - } - - return dashboard; - } -} diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs new file mode 100644 index 0000000..5aee98d --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs @@ -0,0 +1,52 @@ +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.DataStores; + +public class CategoryStore : ICategoryStore +{ + private readonly ApiClient _client; + private const string RESOURCE = ApiResourceConstants.Categories; + + public CategoryStore(ApiClient client) + { + _client = client; + } + + public async Task CreateCategoryAsync(CategoryViewModel category) + { + var result = await _client.PostAsync(RESOURCE, category); + + return result; + } + + public async Task DeleteCategoryAsync(int id) + { + await _client.DeleteAsync(RESOURCE, id); + } + + public async Task> GetCategoriesAsync(string? search = null, int? pageNumber = 1) + { + pageNumber ??= 1; + + var queryParams = $"?search={search}&pageNumber={pageNumber}"; + var result = await _client.GetAsync>(RESOURCE + queryParams); + + return result; + } + + public async Task GetCategoryByIdAsync(int id) + { + var category = await _client.GetAsync($"categories/{id}"); + + return category; + } + + public async Task UpdateCategoryAsync(CategoryViewModel category) + { + await _client.PutAsync($"categories/{category.Id}", 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..6acba80 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs @@ -0,0 +1,76 @@ +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> 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 GetById(int id) + { + var customer = await _apiClient.GetAsync(ApiResourceConstants.Customers + "/" + id); + return customer; + } + + public async Task Create(CustomerActionViewModel customer) + { + var createdCustomer = await _apiClient.PostAsync(ApiResourceConstants.Customers,customer); + + 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(); + 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/DataStores/DashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs new file mode 100644 index 0000000..1672f53 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using WMS.WebUI.Services; +using WMS.WebUI.Stores.Interfaces; +using WMS.WebUI.ViewModels; + +namespace WMS.WebUI.Stores.DataStores; + +public class DashboardStore : IDashboardStore +{ + private readonly ApiClient _client; + + public DashboardStore(ApiClient client) + { + _client = client; + } + + public async Task Get() + { + var dashboard = await _client.GetAsync("dashboard"); + + return dashboard; + } +} diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs new file mode 100644 index 0000000..a5f81f1 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs @@ -0,0 +1,96 @@ +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.DataStores; + +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.Id, 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.IsLowQuantity.HasValue && queryParameters.IsLowQuantity == true) + { + queryBuilder = queryBuilder.Append($"IsLowQuantity={queryParameters.IsLowQuantity}"); + } + + return queryBuilder.ToString(); + } +} 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..e490b3f --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs @@ -0,0 +1,70 @@ +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; +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 async Task Create(CreateTransactionViewModel transaction) + { + var transactionNew = new TransactionView(); + + return transactionNew; + } + 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/SupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs new file mode 100644 index 0000000..1d11697 --- /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.Id, 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/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/DataStores/TransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs new file mode 100644 index 0000000..5b9c54e --- /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!.Data.ForEach(el => el.Type = PartnerType.Customer); + suppliersTask.Result!.Data.ForEach(el => el.Type = PartnerType.Supplier); + + return [.. customersTask.Result.Data, .. suppliersTask.Result.Data]; + } + + 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/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/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/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/Interfaces/ISaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs new file mode 100644 index 0000000..29052ed --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs @@ -0,0 +1,14 @@ +using WMS.WebUI.Models.PaginatedResponse; +using WMS.WebUI.QueryParams; +using WMS.WebUI.ViewModels; +using WMS.WebUI.ViewModels.SaleViewModels; + +namespace WMS.WebUI.Stores.Interfaces; +public interface ISaleStore +{ + Task> GetSales(TransactionQueryParameters queryParameters); + Task GetById(int id); + Task Create(CreateTransactionViewModel transaction); + Task Update(SaleViewModel sale); + 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/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/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/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/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/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/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/ViewModels/CustomerViewModels/CustomerActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs new file mode 100644 index 0000000..848a240 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs @@ -0,0 +1,20 @@ +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; } + 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..f542311 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs @@ -0,0 +1,18 @@ +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; } + public decimal? Discount { get; set; } = 0; + //public ICollection Sales { get; set; } + + } +} 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 +} 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/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/SupplierViewModels/SupplierActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs new file mode 100644 index 0000000..fe71d24 --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs @@ -0,0 +1,24 @@ +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() + //{ + // 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/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/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/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/Views/Products/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml new file mode 100644 index 0000000..76d878a --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml @@ -0,0 +1,33 @@ +@using WMS.WebUI.ViewModels +@model ProductViewModel; + +
+ +

Create Product

+
+ + + + +
+
+ + +
+
+ + +
+
+ +
+ + + +
\ No newline at end of file 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 new file mode 100644 index 0000000..314f21d --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml @@ -0,0 +1,88 @@ +@model List + +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+ 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/Sales/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml new file mode 100644 index 0000000..f1ffa2b --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml @@ -0,0 +1,46 @@ +@model WMS.WebUI.ViewModels.SaleViewModels.SaleViewModel +@{ + ViewData["Title"] = "Sale Details"; +} + +

@ViewData["Title"]

+ +
+

Sale Information

+
+
+
+
Sale ID
+
@Model.Id
+ +
Date
+
@Model.Date.ToString("dd MMM yyyy")
+ +
Customer
+
@Model.Customer
+ +
Total Due
+
@Model.TotalDue.ToString("C")
+ +
Total Paid
+
@Model.TotalPaid.ToString("C")
+
+
+
+
+
+ + + + + + + +
+
+
+ +Back to List diff --git a/WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml new file mode 100644 index 0000000..b5c2d4e --- /dev/null +++ b/WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml @@ -0,0 +1,78 @@ +@using WMS.WebUI.ViewModels.SaleViewModels +@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/Shared/_Sidebar.cshtml b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml index 41ff20a..cbe8257 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 @@ -45,14 +45,44 @@ menuItems.Add(new { text = "Transactions", - url = "#", - iconCss = "fa-solid fa-money-bill-transfer" + url = "/transactions", + 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..6b21a0b --- /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)

+
+
+
+ + 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/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 diff --git a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj index 424a883..527d341 100644 --- a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj +++ b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj @@ -7,8 +7,9 @@ - - + + + 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=" + } } 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;