diff --git a/Inflow.Domain/ResourceParameters/ProductResourceParameters.cs b/Inflow.Domain/ResourceParameters/ProductResourceParameters.cs index 61b2b27..5c26fac 100644 --- a/Inflow.Domain/ResourceParameters/ProductResourceParameters.cs +++ b/Inflow.Domain/ResourceParameters/ProductResourceParameters.cs @@ -5,5 +5,10 @@ namespace Inflow.ResourceParameters public class ProductResourceParameters : ResourceParametersBase { public override string OrderBy { get; set; } = "name"; + public int? CategoryId { get; set; } + public decimal? Price { get; set; } + public decimal? PriceLessThan { get; set; } + public decimal? PriceGreaterThan { get; set; } + public DateTime? ExpireDate { get; set; } } } \ No newline at end of file diff --git a/Inflow.Domain/ResourceParameters/ResourceParametersBase.cs b/Inflow.Domain/ResourceParameters/ResourceParametersBase.cs index 91c6d7a..e90dac2 100644 --- a/Inflow.Domain/ResourceParameters/ResourceParametersBase.cs +++ b/Inflow.Domain/ResourceParameters/ResourceParametersBase.cs @@ -2,11 +2,9 @@ { public abstract class ResourceParametersBase { - protected virtual int MaxPageSize { get; set; } = 500; - + protected virtual int MaxPageSize { get; set; } = 25; public virtual string? SearchString { get; set; } public abstract string OrderBy { get; set; } - public int PageNumber { get; set; } = 1; private int _pageSize = 15; diff --git a/Inflow.Domain/ResourceParameters/SaleItemResourceParameters.cs b/Inflow.Domain/ResourceParameters/SaleItemResourceParameters.cs index f485c7c..483798f 100644 --- a/Inflow.Domain/ResourceParameters/SaleItemResourceParameters.cs +++ b/Inflow.Domain/ResourceParameters/SaleItemResourceParameters.cs @@ -3,5 +3,10 @@ public class SaleItemResourceParameters : ResourceParametersBase { public override string OrderBy { get; set; } = "id"; + public int? ProductId { get; set; } + public int? SaleId { get; set; } + public decimal? UnitPrice { get; set; } + public decimal? UnitPriceLessThan { get; set; } + public decimal? UnitPriceGreaterThan { get; set; } } } diff --git a/Inflow.Domain/ResourceParameters/SaleResourceParameters.cs b/Inflow.Domain/ResourceParameters/SaleResourceParameters.cs index d727c45..663cad5 100644 --- a/Inflow.Domain/ResourceParameters/SaleResourceParameters.cs +++ b/Inflow.Domain/ResourceParameters/SaleResourceParameters.cs @@ -2,6 +2,8 @@ { public class SaleResourceParameters : ResourceParametersBase { + public int? CustomerId { get; set; } + public DateTime? SaleDate { get; set; } public override string OrderBy { get; set; } = "id"; } } diff --git a/Inflow.Domain/ResourceParameters/SupplyItemResourceParameters.cs b/Inflow.Domain/ResourceParameters/SupplyItemResourceParameters.cs index 7457617..e831b3a 100644 --- a/Inflow.Domain/ResourceParameters/SupplyItemResourceParameters.cs +++ b/Inflow.Domain/ResourceParameters/SupplyItemResourceParameters.cs @@ -1,13 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Inflow.Domain.ResourceParameters +namespace Inflow.Domain.ResourceParameters { public class SupplyItemResourceParameters : ResourceParametersBase { + public int? ProductId { get; set; } + public int? SupplyId { get; set; } + public decimal? UnitPrice { get; set; } + public decimal? UnitPriceLessThan { get; set; } + public decimal? UnitPriceGreaterThan { get; set; } public override string OrderBy { get; set; } = "id"; } } diff --git a/Inflow.Domain/ResourceParameters/SupplyResourceParameters.cs b/Inflow.Domain/ResourceParameters/SupplyResourceParameters.cs index d188814..d960297 100644 --- a/Inflow.Domain/ResourceParameters/SupplyResourceParameters.cs +++ b/Inflow.Domain/ResourceParameters/SupplyResourceParameters.cs @@ -2,6 +2,8 @@ { public class SupplyResourceParameters : ResourceParametersBase { + public int? SupplierId { get; set; } + public DateTime? SupplyDate { get; set; } public override string OrderBy { get; set; } = "id"; } } diff --git a/Inflow.Service/CategoryService.cs b/Inflow.Service/CategoryService.cs new file mode 100644 index 0000000..4d4b743 --- /dev/null +++ b/Inflow.Service/CategoryService.cs @@ -0,0 +1,113 @@ +using AutoMapper; +using Inflow.Domain.DTOs.Category; +using Inflow.Domain.Entities; +using Inflow.Domain.Exeptions; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace DiyorMarket.Services +{ + public class CategoryService : ICategoryService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public CategoryService(IMapper mapper, + InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetCategories(CategoryResourceParameters categoryResourceParameters) + { + var query = _context.Categories.Include(s => s.Products).IgnoreAutoIncludes().AsQueryable(); + + if (!string.IsNullOrWhiteSpace(categoryResourceParameters.SearchString)) + { + query = query.Where(x => x.Name.Contains(categoryResourceParameters.SearchString)); + } + + if (!string.IsNullOrEmpty(categoryResourceParameters.OrderBy)) + { + query = categoryResourceParameters.OrderBy.ToLowerInvariant() switch + { + "name" => query.OrderBy(x => x.Name), + "namedesc" => query.OrderByDescending(x => x.Name), + _ => query.OrderBy(x => x.Name), + }; + } + + var categories = query.ToPaginatedList(categoryResourceParameters.PageSize, categoryResourceParameters.PageNumber); + var categoryDtos = _mapper.Map>(categories); + var paginatedResult = new PaginatedList(categoryDtos, categories.TotalCount, categories.CurrentPage, categories.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetAllCategories() + { + var categories = _context.Categories.Include(s => s.Products).ToList(); + + return _mapper.Map>(categories) ?? Enumerable.Empty(); + } + + public CategoryDto? GetCategoryById(int id) + { + var category = _context.Categories + .Include(c => c.Products) + .IgnoreAutoIncludes() + .FirstOrDefault(x => x.Id == id); + + if (category is null) + { + throw new EntityNotFoundException($"Category with id: {id} not found"); + } + + var categoryDto = _mapper.Map(category); + + return categoryDto; + } + + public CategoryDto CreateCategory(CategoryForCreateDto categoryToCreate) + { + var categoryEntity = _mapper.Map(categoryToCreate); + + _context.Categories.Add(categoryEntity); + + _context.SaveChanges(); + + var categoryDto = _mapper.Map(categoryEntity); + + return categoryDto; + } + + public CategoryDto UpdateCategory(CategoryForUpdateDto categoryToUpdate) + { + var categoryEntity = _mapper.Map(categoryToUpdate); + + _context.Categories.Update(categoryEntity); + _context.SaveChanges(); + + var updatedCategoryDto = _mapper.Map(categoryEntity); + + return updatedCategoryDto; + } + + public void DeleteCategory(int id) + { + var category = _context.Categories.FirstOrDefault(x => x.Id == id); + + if (category is not null) + { + _context.Categories.Remove(category); + } + + _context.SaveChanges(); + } + } +} diff --git a/Inflow.Service/CustomerService.cs b/Inflow.Service/CustomerService.cs new file mode 100644 index 0000000..d6a0573 --- /dev/null +++ b/Inflow.Service/CustomerService.cs @@ -0,0 +1,107 @@ +using AutoMapper; +using Inflow.Domain.DTOs.Customer; +using Inflow.Domain.Entities; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; + +namespace DiyorMarket.Services +{ + public class CustomerService : ICustomerService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public CustomerService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetCustomers(CustomerResourceParameters customerResourceParameters) + { + var query = _context.Customers.AsQueryable(); + + if (!string.IsNullOrWhiteSpace(customerResourceParameters.SearchString)) + { + query = query.Where(x => x.FirstName.Contains(customerResourceParameters.SearchString) + || x.LastName.Contains(customerResourceParameters.SearchString) + || x.PhoneNumber.Contains(customerResourceParameters.SearchString)); + } + + if (!string.IsNullOrEmpty(customerResourceParameters.OrderBy)) + { + query = customerResourceParameters.OrderBy.ToLowerInvariant() switch + { + "firstname" => query.OrderBy(x => x.FirstName), + "firstnamedesc" => query.OrderByDescending(x => x.FirstName), + "lastname" => query.OrderBy(x => x.LastName), + "lastnamedesc" => query.OrderByDescending(x => x.LastName), + "phonenumber" => query.OrderBy(x => x.PhoneNumber), + "phonenumberdesc" => query.OrderByDescending(x => x.PhoneNumber), + _ => query.OrderBy(x => x.FirstName), + }; + } + + var customers = query.ToPaginatedList(customerResourceParameters.PageSize, customerResourceParameters.PageNumber); + + var customerDtos = _mapper.Map>(customers); + + var paginatedResult = new PaginatedList(customerDtos, customers.TotalCount, customers.CurrentPage, customers.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetCustomers() + { + var customers = _context.Customers.ToList(); + + return _mapper.Map>(customers) ?? Enumerable.Empty(); + } + + public CustomerDto? GetCustomerById(int id) + { + var customer = _context.Customers.FirstOrDefault(x => x.Id == id); + + var customerDto = _mapper.Map(customer); + + return customerDto; + } + + public CustomerDto CreateCustomer(CustomerForCreateDto customerToCreate) + { + var customerEntity = _mapper.Map(customerToCreate); + + _context.Customers.Add(customerEntity); + _context.SaveChanges(); + + var customerDto = _mapper.Map(customerEntity); + + return customerDto; + } + + public CustomerDto UpdateCustomer(CustomerForUpdateDto customerToUpdate) + { + var customerEntity = _mapper.Map(customerToUpdate); + + _context.Customers.Update(customerEntity); + _context.SaveChanges(); + + var customerDto = _mapper.Map(customerEntity); + + return customerDto; + } + + public void DeleteCustomer(int id) + { + var customer = _context.Customers.FirstOrDefault(x => x.Id == id); + if (customer is not null) + { + _context.Customers.Remove(customer); + } + _context.SaveChanges(); + } + } +} diff --git a/Inflow.Service/DashboardService.cs b/Inflow.Service/DashboardService.cs new file mode 100644 index 0000000..b2dc1bc --- /dev/null +++ b/Inflow.Service/DashboardService.cs @@ -0,0 +1,130 @@ +using Inflow.Domain.DTOs.Dashboard; +using Inflow.Domain.Interfaces.Services; +using Inflow.Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace DiyorMarket.Services; + +public class DashboardService : IDashboardService +{ + private readonly InflowDbContext _context; + + public DashboardService(InflowDbContext context) + { + _context = context; + } + + public DashboardDto GetDashboard() + { + var summary = GetSummary(); + var salesByCategory = GetDoughChartData(); + var splineChartData = GetSpliteChartData(); + var transactions = GetTransactions(); + + return new DashboardDto(summary, salesByCategory, splineChartData, transactions); + } + + private IEnumerable GetDoughChartData() + { + var salesByCategory = from category in _context.Categories + join product in _context.Products on category.Id equals product.CategoryId + join saleItem in _context.SaleItems on product.Id equals saleItem.ProductId + group saleItem by category.Name into groupedCategories + select new SalesByCategoryDto(groupedCategories.Key, groupedCategories.Count()); + + return salesByCategory; + } + + private Summary GetSummary() + { + var salesItems = _context.SaleItems + .Where(x => x.Sale.SaleDate.Month >= DateTime.Now.AddMonths(-2).Month) + .AsNoTracking(); + + var salesTotal = salesItems.Sum(si => si.Quantity * si.UnitPrice); + + var total = salesTotal * (decimal)0.2; + + var salesCount = _context.Sales.Count(); + var suppliesCount = _context.Supplies.Count(); + + return new Summary(total, salesCount, suppliesCount); + } + + private IEnumerable GetSpliteChartData() + { + var startDate = DateTime.Now.AddYears(-1); + + var incomeTotal = _context.Sales + .Include(x => x.SaleItems) + .ToList() + .GroupBy(x => x.SaleDate.ToString("MMMM")) + .Select(k => new SpliteChartData() + { + Month = k.Key, + Income = k.Sum(x => x.SaleItems.Sum(si => si.Quantity * si.UnitPrice)) + }); + + var expenseTotal = _context.Supplies + .Include(x => x.SupplyItems) + .ToList() + .GroupBy(x => x.SupplyDate.ToString("MMMM")) + .Select(k => new SpliteChartData() + { + Month = k.Key, + Expense = k.Sum(x => x.SupplyItems.Sum(si => si.Quantity * si.UnitPrice)) + }); + + var lastYear = Enumerable.Range(0, 12) + .Select(x => DateTime.Now.AddMonths(-x).ToString("MMMM")) + .ToList(); + + var data = from month in lastYear + join income in incomeTotal on month equals income.Month into joinedIncome + from income in joinedIncome.DefaultIfEmpty() + join expense in expenseTotal on month equals expense.Month into joinedExpense + from expense in joinedExpense.DefaultIfEmpty() + select new SpliteChartData() + { + Month = month, + Income = income?.Income ?? 0, + Expense = expense?.Expense ?? 0 + }; + + return data; + } + + private IEnumerable GetTransactions() + { + var sales = _context.Sales + .OrderByDescending(s => s.SaleDate) + .Include(x => x.SaleItems) + .Take(10) + .AsNoTracking() + .ToList(); + var supplies = _context.Supplies + .OrderByDescending(s => s.SupplyDate) + .Include(x => x.SupplyItems) + .Take(10) + .AsNoTracking() + .ToList(); + + List incomes = sales.Select(x => new TransactionDto + { + Id = x.Id, + Type = "Income", + Amount = x.SaleItems.Sum(si => si.Quantity * si.UnitPrice), + Date = x.SaleDate + }).ToList(); + + List expenses = supplies.Select(x => new TransactionDto + { + Id = x.Id, + Type = "Expense", + Amount = x.SupplyItems.Sum(si => si.Quantity * si.UnitPrice), + Date = x.SupplyDate + }).ToList(); + + return incomes.Concat(expenses).OrderByDescending(x => x.Date).Take(10); + } +} diff --git a/Inflow.Service/EmailSender.cs b/Inflow.Service/EmailSender.cs new file mode 100644 index 0000000..55532ce --- /dev/null +++ b/Inflow.Service/EmailSender.cs @@ -0,0 +1,36 @@ +using Inflow.Domain.Intefaces.Services; +using System.Net; +using System.Net.Mail; + +namespace DiyorMarket.Services +{ + public class EmailSender : IEmailSender + { + public async Task SendEmail(string email, string subject, string massege) + { + MailAddress fromAddress = new MailAddress("gieosovazamat@gmail.com", "Azamat"); + MailAddress toAddress = new MailAddress(email); + MailMessage mailMessage = new MailMessage(fromAddress, toAddress); + mailMessage.Body = massege; + mailMessage.Subject = subject; + + SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587); + smtpClient.EnableSsl = true; + smtpClient.UseDefaultCredentials = false; + smtpClient.Credentials = new NetworkCredential("gieosovazamat@gmail.com", "dhrk hrxo qrec cedz"); + + try + { + await smtpClient.SendMailAsync(mailMessage); + } + catch (Exception ex) + { + throw new Exception($"Error: {ex}"); + } + finally + { + smtpClient.Dispose(); + } + } + } +} diff --git a/Inflow.Service/Inflow.Service.csproj b/Inflow.Service/Inflow.Service.csproj index d16b751..0e51d6a 100644 --- a/Inflow.Service/Inflow.Service.csproj +++ b/Inflow.Service/Inflow.Service.csproj @@ -7,7 +7,12 @@ + + + + + diff --git a/Inflow.Service/ProductService.cs b/Inflow.Service/ProductService.cs new file mode 100644 index 0000000..4549b50 --- /dev/null +++ b/Inflow.Service/ProductService.cs @@ -0,0 +1,146 @@ +using AutoMapper; +using Inflow.Domain.DTOs.Product; +using Inflow.Domain.Entities; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; +using Inflow.ResourceParameters; +using Microsoft.EntityFrameworkCore; + +namespace DiyorMarket.Services +{ + public class ProductService : IProductService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public ProductService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetProducts(ProductResourceParameters productResourceParameters) + { + var query = _context.Products + .Include(p => p.Category) + .AsQueryable(); + + if (productResourceParameters.ExpireDate is not null) + { + query = query.Where(x => x.ExpireDate.Date == productResourceParameters.ExpireDate.Value.Date); + } + + if (productResourceParameters.CategoryId is not null && productResourceParameters.CategoryId != 0) + { + query = query.Where(x => x.CategoryId == productResourceParameters.CategoryId); + } + + if (!string.IsNullOrWhiteSpace(productResourceParameters.SearchString)) + { + query = query.Where(x => x.Name.Contains(productResourceParameters.SearchString) + || x.Description.Contains(productResourceParameters.SearchString)); + } + + if (productResourceParameters.Price is not null) + { + query = query.Where(x => x.Price == productResourceParameters.Price); + } + + if (productResourceParameters.PriceLessThan is not null) + { + query = query.Where(x => x.Price < productResourceParameters.PriceLessThan); + } + + if (productResourceParameters.PriceGreaterThan is not null) + { + query = query.Where(x => x.Price > productResourceParameters.PriceGreaterThan); + + } + + if (!string.IsNullOrEmpty(productResourceParameters.OrderBy)) + { + query = productResourceParameters.OrderBy.ToLowerInvariant() switch + { + "name" => query.OrderBy(x => x.Name), + "namedesc" => query.OrderByDescending(x => x.Name), + "description" => query.OrderBy(x => x.Description), + "descriptiondesc" => query.OrderByDescending(x => x.Description), + "price" => query.OrderBy(x => x.Price), + "pricedesc" => query.OrderByDescending(x => x.Price), + "expiredate" => query.OrderBy(x => x.ExpireDate), + "expiredatedesc" => query.OrderByDescending(x => x.ExpireDate), + _ => query.OrderBy(x => x.Name), + }; + } + + var products = query.ToPaginatedList(productResourceParameters.PageSize, productResourceParameters.PageNumber); + + foreach (var product in products) + { + product.Category = _context.Categories.FirstOrDefault(x => x.Id == product.CategoryId); + } + + var productDtos = _mapper.Map>(products); + + var paginatedResult = new PaginatedList(productDtos.ToList(), products.TotalCount, products.CurrentPage, products.PageSize); + + return paginatedResult.ToResponse(); + + } + + public IEnumerable GetAllProducts() + { + var products = _context.Products + .Include(x => x.Category) + .AsSplitQuery() + .OrderBy(x => x.Name) + .ThenBy(x => x.Category.Name) + .ToList(); + + return _mapper.Map>(products) ?? Enumerable.Empty(); + } + + public ProductDto? GetProductById(int id) + { + var product = _context.Products + .Include(p => p.Category) + .FirstOrDefault(x => x.Id == id); + + var productDto = _mapper.Map(product); + + return productDto; + } + + public ProductDto CreateProduct(ProductForCreateDto productToCreate) + { + var productEntity = _mapper.Map(productToCreate); + + _context.Products.Add(productEntity); + _context.SaveChanges(); + + var productDto = _mapper.Map(productEntity); + + return productDto; + } + + public void UpdateProduct(ProductForUpdateDto productToUpdate) + { + var productEntity = _mapper.Map(productToUpdate); + + _context.Products.Update(productEntity); + _context.SaveChanges(); + } + + public void DeleteProduct(int id) + { + var product = _context.Products.FirstOrDefault(x => x.Id == id); + if (product is not null) + { + _context.Products.Remove(product); + } + _context.SaveChanges(); + } + } +} diff --git a/Inflow.Service/SaleItemService.cs b/Inflow.Service/SaleItemService.cs new file mode 100644 index 0000000..6fe1202 --- /dev/null +++ b/Inflow.Service/SaleItemService.cs @@ -0,0 +1,137 @@ +using AutoMapper; +using Inflow.Domain.DTOs.SaleItem; +using Inflow.Domain.DTOsSaleItem; +using Inflow.Domain.Entities; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace DiyorMarket.Services +{ + public class SaleItemService : ISaleItemService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public SaleItemService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetSaleItems(SaleItemResourceParameters saleItemResourceParameters) + { + var query = _context.SaleItems.AsQueryable(); + + if (saleItemResourceParameters.ProductId is not null) + { + query = query.Where(x => x.ProductId == saleItemResourceParameters.ProductId); + } + + if (saleItemResourceParameters.SaleId is not null) + { + query = query.Where(x => x.SaleId == saleItemResourceParameters.SaleId); + } + + if (saleItemResourceParameters.UnitPrice is not null) + { + query = query.Where(x => x.UnitPrice == saleItemResourceParameters.UnitPrice); + } + + if (saleItemResourceParameters.UnitPriceLessThan is not null) + { + query = query.Where(x => x.UnitPrice < saleItemResourceParameters.UnitPriceLessThan); + } + + if (saleItemResourceParameters.UnitPriceGreaterThan is not null) + { + query = query.Where(x => x.UnitPrice > saleItemResourceParameters.UnitPriceGreaterThan); + + } + + if (!string.IsNullOrEmpty(saleItemResourceParameters.OrderBy)) + { + query = saleItemResourceParameters.OrderBy.ToLowerInvariant() switch + { + "id" => query.OrderBy(x => x.Id), + "iddesc" => query.OrderByDescending(x => x.Id), + "unitprice" => query.OrderBy(x => x.UnitPrice), + "unitpricedesc" => query.OrderByDescending(x => x.UnitPrice), + "saleid" => query.OrderBy(x => x.SaleId), + "saleiddesc" => query.OrderByDescending(x => x.SaleId), + "productid" => query.OrderBy(x => x.ProductId), + "productiddesc" => query.OrderByDescending(x => x.ProductId), + _ => query.OrderBy(x => x.Id), + }; + } + + var saleItems = query.ToPaginatedList(saleItemResourceParameters.PageSize, saleItemResourceParameters.PageNumber); + + var saleItemDtos = _mapper.Map>(saleItems); + + var paginatedResult = new PaginatedList(saleItemDtos, saleItems.TotalCount, saleItems.CurrentPage, saleItems.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetAllSaleItems() + { + var saleItems = _context.SaleItems.ToList(); + + return _mapper.Map>(saleItems) ?? Enumerable.Empty(); + } + + public IEnumerable GetSalesSaleItems(int salesId) + { + var salesSaleItems = _context.SaleItems + .Include(x => x.Product) + .IgnoreAutoIncludes() + .Where(x => x.SaleId == salesId). + ToList(); + + return _mapper.Map>(salesSaleItems) ?? Enumerable.Empty(); + } + + public SaleItemDto? GetSaleItemById(int id) + { + var saleItem = _context.SaleItems.FirstOrDefault(x => x.Id == id); + + var saleItemDto = _mapper.Map(saleItem); + + return saleItemDto; + } + + public SaleItemDto CreateSaleItem(SaleItemForCreateDto saleItemToCreate) + { + var saleItemEntity = _mapper.Map(saleItemToCreate); + + _context.SaleItems.Add(saleItemEntity); + _context.SaveChanges(); + + var saleItemDto = _mapper.Map(saleItemEntity); + + return saleItemDto; + } + + public void UpdateSaleItem(SaleItemForUpdateDto saleItemToUpdate) + { + var saleItemEntity = _mapper.Map(saleItemToUpdate); + + _context.SaleItems.Update(saleItemEntity); + _context.SaveChanges(); + } + + public void DeleteSaleItem(int id) + { + var saleItem = _context.SaleItems.FirstOrDefault(x => x.Id == id); + if (saleItem is not null) + { + _context.SaleItems.Remove(saleItem); + } + _context.SaveChanges(); + } + } +} diff --git a/Inflow.Service/SaleService.cs b/Inflow.Service/SaleService.cs new file mode 100644 index 0000000..c28131a --- /dev/null +++ b/Inflow.Service/SaleService.cs @@ -0,0 +1,158 @@ +using AutoMapper; +using Inflow.Domain.DTOs.Sale; +using Inflow.Domain.Entities; +using Inflow.Domain.Exeptions; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace DiyorMarket.Services +{ + public class SaleService : ISaleService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public SaleService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetSales(SaleResourceParameters saleResourceParameters) + { + var query = GetFiltrSaleResParameters(saleResourceParameters); + + var sales = query.ToPaginatedList(saleResourceParameters.PageSize, saleResourceParameters.PageNumber); + + var saleDtos = _mapper.Map>(sales); + + var paginatedResult = new PaginatedList(saleDtos, sales.TotalCount, sales.CurrentPage, sales.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetAllSales() + { + var sales = _context.Sales + .Include(x => x.SaleItems) + .IgnoreAutoIncludes() + .ToList(); + + return _mapper.Map>(sales) ?? Enumerable.Empty(); + } + + public SaleDto? GetSaleById(int id) + { + var sale = _context.Sales + .Include(x => x.SaleItems) + .IgnoreAutoIncludes() + .FirstOrDefault(x => x.Id == id); + + var saleDto = _mapper.Map(sale); + + return saleDto; + } + + public IEnumerable GetCustomersSale(int customersId) + { + var customersSale = _context.Sales + .Include(x => x.SaleItems) + .IgnoreAutoIncludes() + .Where(x => x.CustomerId == customersId). + ToList(); + + return _mapper.Map>(customersSale) ?? Enumerable.Empty(); + } + + public SaleDto CreateSale(SaleForCreateDto saleToCreate) + { + var saleEntity = _mapper.Map(saleToCreate); + + foreach (var saleItem in saleEntity.SaleItems) + { + var item = _context.Products.FirstOrDefault(x => x.Id == saleItem.ProductId); + + if (item is null) + { + throw new EntityNotFoundException($"Product with id: {saleItem.ProductId} does not exist"); + } + + if (item.QuantityInStock < saleItem.Quantity) + { + throw new LowStockException($"{item.QuantityInStock} {item.Name}s left in stock. Requested: {saleItem.Quantity}"); + } + + item.QuantityInStock -= saleItem.Quantity; + } + + _context.Sales.Add(saleEntity); + _context.SaveChanges(); + + var saleDto = _mapper.Map(saleEntity); + + return saleDto; + } + + public void UpdateSale(SaleForUpdateDto saleToUpdate) + { + var saleEntity = _mapper.Map(saleToUpdate); + + _context.Sales.Update(saleEntity); + _context.SaveChanges(); + } + + public void DeleteSale(int id) + { + var sale = _context.Sales.FirstOrDefault(x => x.Id == id); + if (sale is not null) + { + _context.Sales.Remove(sale); + } + _context.SaveChanges(); + } + + private IQueryable GetFiltrSaleResParameters( + SaleResourceParameters saleResourceParameters) + { + var query = _context.Sales + .Include(x => x.SaleItems) + .IgnoreAutoIncludes() + .AsQueryable(); + + if (saleResourceParameters.SaleDate is not null) + { + query = query.Where(x => x.SaleDate.Date == saleResourceParameters.SaleDate.Value.Date); + } + + if (saleResourceParameters.CustomerId is not null) + { + query = query.Where(x => x.CustomerId == saleResourceParameters.CustomerId); + } + + if (!string.IsNullOrWhiteSpace(saleResourceParameters.SearchString)) + { + query = query.Include(s => s.Customer) + .Where(x => x.Customer.FirstName.ToLower() + .Contains(saleResourceParameters.SearchString.ToLower())); + } + + if (!string.IsNullOrEmpty(saleResourceParameters.OrderBy)) + { + query = saleResourceParameters.OrderBy.ToLowerInvariant() switch + { + "id" => query.OrderBy(x => x.Id), + "iddesc" => query.OrderByDescending(x => x.Id), + "expiredate" => query.OrderBy(x => x.SaleDate), + "expiredatedesc" => query.OrderByDescending(x => x.SaleDate), + _ => query.OrderBy(x => x.Id), + }; + } + + return query; + } + } +} diff --git a/Inflow.Service/SupplierService.cs b/Inflow.Service/SupplierService.cs new file mode 100644 index 0000000..3ecaf7f --- /dev/null +++ b/Inflow.Service/SupplierService.cs @@ -0,0 +1,110 @@ +using AutoMapper; +using Inflow.Domain.DTOs.Supplier; +using Inflow.Domain.Entities; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; + +namespace DiyorMarket.Services +{ + public class SupplierService : ISupplierService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public SupplierService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetSuppliers(SupplierResourceParameters supplierResourceParameters) + { + var query = _context.Suppliers.AsQueryable(); + + if (!string.IsNullOrWhiteSpace(supplierResourceParameters.SearchString)) + { + query = query.Where(x => x.FirstName.Contains(supplierResourceParameters.SearchString) + || x.LastName.Contains(supplierResourceParameters.SearchString) + || x.PhoneNumber.Contains(supplierResourceParameters.SearchString) + || x.Company.Contains(supplierResourceParameters.SearchString)); + } + + if (!string.IsNullOrEmpty(supplierResourceParameters.OrderBy)) + { + query = supplierResourceParameters.OrderBy.ToLowerInvariant() switch + { + "firstname" => query.OrderBy(x => x.FirstName), + "firstnamedesc" => query.OrderByDescending(x => x.FirstName), + "lastname" => query.OrderBy(x => x.LastName), + "lastnamedesc" => query.OrderByDescending(x => x.LastName), + "phonenumber" => query.OrderBy(x => x.PhoneNumber), + "phonenumberdesc" => query.OrderByDescending(x => x.PhoneNumber), + "company" => query.OrderBy(x => x.Company), + "companydesc" => query.OrderByDescending(x => x.Company), + _ => query.OrderBy(x => x.FirstName), + }; + } + + var suppliers = query.ToPaginatedList(supplierResourceParameters.PageSize, supplierResourceParameters.PageNumber); + + var supplierDtos = _mapper.Map>(suppliers); + + var paginatedResult = new PaginatedList(supplierDtos, suppliers.TotalCount, suppliers.CurrentPage, suppliers.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetAllSuppliers() + { + var suppliers = _context.Suppliers.ToList(); + + return _mapper.Map>(suppliers) ?? Enumerable.Empty(); + } + + public SupplierDto? GetSupplierById(int id) + { + var supplier = _context.Suppliers.FirstOrDefault(x => x.Id == id); + + var supplierDto = _mapper.Map(supplier); + + return supplierDto; + } + + public SupplierDto CreateSupplier(SupplierForCreateDto supplierToCreate) + { + var supplierEntity = _mapper.Map(supplierToCreate); + + _context.Suppliers.Add(supplierEntity); + _context.SaveChanges(); + + var supplierDto = _mapper.Map(supplierEntity); + + return supplierDto; + } + + public SupplierDto UpdateSupplier(SupplierForUpdateDto supplierToUpdate) + { + var supplierEntity = _mapper.Map(supplierToUpdate); + + _context.Suppliers.Update(supplierEntity); + _context.SaveChanges(); + + var supplierDto = _mapper.Map(supplierEntity); + + return supplierDto; + } + + public void DeleteSupplier(int id) + { + var supplier = _context.Suppliers.FirstOrDefault(x => x.Id == id); + if (supplier is not null) + { + _context.Suppliers.Remove(supplier); + } + _context.SaveChanges(); + } + } +} diff --git a/Inflow.Service/SupplyItemService.cs b/Inflow.Service/SupplyItemService.cs new file mode 100644 index 0000000..71eb615 --- /dev/null +++ b/Inflow.Service/SupplyItemService.cs @@ -0,0 +1,124 @@ +using AutoMapper; +using Inflow.Domain.DTOs.SupplyItem; +using Inflow.Domain.Entities; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; + +namespace DiyorMarket.Services +{ + public class SupplyItemService : ISupplyItemService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public SupplyItemService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetSupplyItems(SupplyItemResourceParameters supplyItemResourceParameters) + { + var query = _context.SupplyItems.AsQueryable(); + + if (supplyItemResourceParameters.ProductId is not null) + { + query = query.Where(x => x.ProductId == supplyItemResourceParameters.ProductId); + } + + if (supplyItemResourceParameters.SupplyId is not null) + { + query = query.Where(x => x.SupplyId == supplyItemResourceParameters.SupplyId); + } + + if (supplyItemResourceParameters.UnitPrice is not null) + { + query = query.Where(x => x.UnitPrice == supplyItemResourceParameters.UnitPrice); + } + + if (supplyItemResourceParameters.UnitPriceLessThan is not null) + { + query = query.Where(x => x.UnitPrice < supplyItemResourceParameters.UnitPriceLessThan); + } + + if (supplyItemResourceParameters.UnitPriceGreaterThan is not null) + { + query = query.Where(x => x.UnitPrice > supplyItemResourceParameters.UnitPriceGreaterThan); + + } + + if (!string.IsNullOrEmpty(supplyItemResourceParameters.OrderBy)) + { + query = supplyItemResourceParameters.OrderBy.ToLowerInvariant() switch + { + "id" => query.OrderBy(x => x.Id), + "iddesc" => query.OrderByDescending(x => x.Id), + "unitprice" => query.OrderBy(x => x.UnitPrice), + "unitpricedesc" => query.OrderByDescending(x => x.UnitPrice), + "saleid" => query.OrderBy(x => x.SupplyId), + "saleiddesc" => query.OrderByDescending(x => x.SupplyId), + "productid" => query.OrderBy(x => x.ProductId), + "productiddesc" => query.OrderByDescending(x => x.ProductId), + _ => query.OrderBy(x => x.Id), + }; + } + + var supplyItems = query.ToPaginatedList(supplyItemResourceParameters.PageSize, supplyItemResourceParameters.PageNumber); + + var supplyItemDtos = _mapper.Map>(supplyItems); + + var paginatedResult = new PaginatedList(supplyItemDtos, supplyItems.TotalCount, supplyItems.CurrentPage, supplyItems.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetAllSupplyItems() + { + var supplyItems = _context.SupplyItems.ToList(); + + return _mapper.Map>(supplyItems) ?? Enumerable.Empty(); + } + + public SupplyItemDto? GetSupplyItemById(int id) + { + var supplyItem = _context.SupplyItems.FirstOrDefault(x => x.Id == id); + + var supplyItemDto = _mapper.Map(supplyItem); + + return supplyItemDto; + } + + public SupplyItemDto CreateSupplyItem(SupplyItemForCreateDto supplyItemToCreate) + { + var supplyItemEntity = _mapper.Map(supplyItemToCreate); + + _context.SupplyItems.Add(supplyItemEntity); + _context.SaveChanges(); + + var supplyItemDto = _mapper.Map(supplyItemEntity); + + return supplyItemDto; + } + + public void UpdateSupplyItem(SupplyItemForUpdateDto supplyItemToUpdate) + { + var supplyItemEntity = _mapper.Map(supplyItemToUpdate); + + _context.SupplyItems.Update(supplyItemEntity); + _context.SaveChanges(); + } + + public void DeleteSupplyItem(int id) + { + var supplyItem = _context.SupplyItems.FirstOrDefault(x => x.Id == id); + if (supplyItem is not null) + { + _context.SupplyItems.Remove(supplyItem); + } + _context.SaveChanges(); + } + } +} diff --git a/Inflow.Service/SupplyService.cs b/Inflow.Service/SupplyService.cs new file mode 100644 index 0000000..387a7be --- /dev/null +++ b/Inflow.Service/SupplyService.cs @@ -0,0 +1,140 @@ +using AutoMapper; +using Inflow.Domain.DTOs.Supply; +using Inflow.Domain.Entities; +using Inflow.Domain.Exeptions; +using Inflow.Domain.Interfaces.Services; +using Inflow.Domain.Pagniation; +using Inflow.Domain.ResourceParameters; +using Inflow.Domain.Responses; +using Inflow.Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace DiyorMarket.Services +{ + public class SupplyService : ISupplyService + { + private readonly IMapper _mapper; + private readonly InflowDbContext _context; + + public SupplyService(IMapper mapper, InflowDbContext context) + { + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public GetBaseResponse GetSupplies( + SupplyResourceParameters supplyResourceParameters) + { + var query = GetQuerySupplyResParameters(supplyResourceParameters); + + var supplies = query.ToPaginatedList(supplyResourceParameters.PageSize, supplyResourceParameters.PageNumber); + + foreach (var supply in supplies) + { + supply.Supplier = _context.Suppliers.FirstOrDefault(x => x.Id == supply.SupplierId); + } + + var supplyDtos = _mapper.Map>(supplies); + + var paginatedResult = new PaginatedList(supplyDtos.ToList(), supplies.TotalCount, supplies.CurrentPage, supplies.PageSize); + + return paginatedResult.ToResponse(); + } + + public IEnumerable GetAllSupplies() + { + var supplies = _context.Supplies.ToList(); + + return _mapper.Map>(supplies) ?? Enumerable.Empty(); + } + + public SupplyDto? GetSupplyById(int id) + { + var supply = _context.Supplies + .Include(s => s.Supplier) + .FirstOrDefault(x => x.Id == id); + + var supplyDto = _mapper.Map(supply); + + return supplyDto; + } + + public SupplyDto CreateSupply(SupplyForCreateDto supplyToCreate) + { + var supplyEntity = _mapper.Map(supplyToCreate); + + foreach (var supplyItem in supplyEntity.SupplyItems) + { + var item = _context.Products.FirstOrDefault(x => x.Id == supplyItem.ProductId); + + if (item is null) + { + throw new EntityNotFoundException($"Product with id: {supplyItem.ProductId} does not exist"); + } + + item.QuantityInStock += supplyItem.Quantity; + } + + _context.Supplies.Add(supplyEntity); + _context.SaveChanges(); + + var supplyDto = _mapper.Map(supplyEntity); + + return supplyDto; + } + + public void UpdateSupply(SupplyForUpdateDto supplyToUpdate) + { + var supplyEntity = _mapper.Map(supplyToUpdate); + + _context.Supplies.Update(supplyEntity); + _context.SaveChanges(); + } + + public void DeleteSupply(int id) + { + var supply = _context.Supplies.FirstOrDefault(x => x.Id == id); + if (supply is not null) + { + _context.Supplies.Remove(supply); + } + _context.SaveChanges(); + } + + private IQueryable GetQuerySupplyResParameters( + SupplyResourceParameters supplyResourceParameters) + { + var query = _context.Supplies + .Include(x => x.SupplyItems) + .IgnoreAutoIncludes() + .AsNoTracking() + .AsQueryable(); + + if (supplyResourceParameters.SupplyDate is not null) + { + query = query.Where(x => x.SupplyDate.Date + >= supplyResourceParameters.SupplyDate.Value.Date + && x.SupplyDate.Date <= DateTime.Now.Date); + } + + if (supplyResourceParameters.SupplierId is not null) + { + query = query.Where(x => x.SupplierId == supplyResourceParameters.SupplierId); + } + + if (!string.IsNullOrEmpty(supplyResourceParameters.OrderBy)) + { + query = supplyResourceParameters.OrderBy.ToLowerInvariant() switch + { + "id" => query.OrderBy(x => x.Id), + "iddesc" => query.OrderByDescending(x => x.Id), + "supplydate" => query.OrderBy(x => x.SupplyDate), + "supplydatedesc" => query.OrderByDescending(x => x.SupplyDate), + _ => query.OrderBy(x => x.Id), + }; + } + + return query; + } + } +}