diff --git a/RMData/RMData.sqlproj b/RMData/RMData.sqlproj index a8988d0..d5d7e5b 100644 --- a/RMData/RMData.sqlproj +++ b/RMData/RMData.sqlproj @@ -73,6 +73,10 @@ + + + + diff --git a/RMData/dbo/Stored Procedures/spProductGetById.sql b/RMData/dbo/Stored Procedures/spProductGetById.sql new file mode 100644 index 0000000..7e5248e --- /dev/null +++ b/RMData/dbo/Stored Procedures/spProductGetById.sql @@ -0,0 +1,10 @@ +CREATE PROCEDURE [dbo].[spProductGetById] + @Id int +AS +BEGIN + SET NOCOUNT ON; + + select Id, ProductName, [Description], RetailPrice, QuantityInStock, IsTaxable + from [dbo].[Product] + where Id = @Id; +END diff --git a/RMData/dbo/Stored Procedures/spSaleDetailInsert.sql b/RMData/dbo/Stored Procedures/spSaleDetailInsert.sql new file mode 100644 index 0000000..bb502e8 --- /dev/null +++ b/RMData/dbo/Stored Procedures/spSaleDetailInsert.sql @@ -0,0 +1,14 @@ +CREATE PROCEDURE [dbo].[spSaleDetailInsert] + @SaleId int, + @ProductId int, + @Quantity int, + @PurchasePrice money, + @Tax money +AS +BEGIN + SET NOCOUNT ON; + + INSERT INTO dbo.SaleDetail(SaleId, ProductId, Quantity, PurchasePrice, Tax) + VALUES (@SaleId, @ProductId, @Quantity, @PurchasePrice, @Tax) + +END \ No newline at end of file diff --git a/RMData/dbo/Stored Procedures/spSaleInsert.sql b/RMData/dbo/Stored Procedures/spSaleInsert.sql new file mode 100644 index 0000000..2a2a40d --- /dev/null +++ b/RMData/dbo/Stored Procedures/spSaleInsert.sql @@ -0,0 +1,16 @@ +CREATE PROCEDURE [dbo].[spSaleInsert] + @Id int output, + @CashierId nvarchar(128), + @SaleDate datetime2, + @SubTotal money, + @Tax money, + @Total money +AS +BEGIN + SET NOCOUNT ON; + + INSERT INTO dbo.Sale(CashierId, SaleDate, SubTotal, Tax, Total) + VALUES (@CashierId, @SaleDate, @SubTotal, @Tax, @Total); + + SELECT @Id = @@IDENTITY; +END \ No newline at end of file diff --git a/RMData/dbo/Stored Procedures/spSaleLookUp.sql b/RMData/dbo/Stored Procedures/spSaleLookUp.sql new file mode 100644 index 0000000..4cdee49 --- /dev/null +++ b/RMData/dbo/Stored Procedures/spSaleLookUp.sql @@ -0,0 +1,11 @@ +CREATE PROCEDURE [dbo].[spSaleLookUp] + @CashierId nvarchar(128), + @SaleDate datetime2 +AS +BEGIN + SET NOCOUNT ON; + + Select Id + from dbo.Sale + where CashierId = @CashierId and SaleDate = @SaleDate; +END diff --git a/RMDataManager/Controllers/SaleController.cs b/RMDataManager/Controllers/SaleController.cs new file mode 100644 index 0000000..cd445db --- /dev/null +++ b/RMDataManager/Controllers/SaleController.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNet.Identity; +using RMDataManagerLibrary.DataAcccess; +using RMDataManagerLibrary.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Web.Http; + +namespace RMDataManager.Controllers +{ + [Authorize] + public class SaleController : ApiController + { + public void Post(SaleModel sale) + { + string cashierId = RequestContext.Principal.Identity.GetUserId(); + SaleData data = new SaleData(); + + data.SaveSale(sale, cashierId); + } + } +} diff --git a/RMDataManager/RMDataManager.csproj b/RMDataManager/RMDataManager.csproj index ca6a8ed..4f9dd0f 100644 --- a/RMDataManager/RMDataManager.csproj +++ b/RMDataManager/RMDataManager.csproj @@ -214,6 +214,7 @@ + diff --git a/RMDataManager/Web.config b/RMDataManager/Web.config index 120ea28..210a360 100644 --- a/RMDataManager/Web.config +++ b/RMDataManager/Web.config @@ -13,6 +13,7 @@ + diff --git a/RMDataManagerLibrary/ConfigHelper.cs b/RMDataManagerLibrary/ConfigHelper.cs new file mode 100644 index 0000000..4d8bba2 --- /dev/null +++ b/RMDataManagerLibrary/ConfigHelper.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RMDataManagerLibrary +{ + public class ConfigHelper + { + public static decimal GetTaxRate() + { + string rateText = ConfigurationManager.AppSettings["taxRate"]; + + bool isValidTaxRate = Decimal.TryParse(rateText, out decimal output); + + if (isValidTaxRate == false) + { + throw new ConfigurationErrorsException("The taxRate is not setup properly"); + } + + return output; + } + } +} diff --git a/RMDataManagerLibrary/DataAcccess/ProductData.cs b/RMDataManagerLibrary/DataAcccess/ProductData.cs index db78ae4..a1b1cf6 100644 --- a/RMDataManagerLibrary/DataAcccess/ProductData.cs +++ b/RMDataManagerLibrary/DataAcccess/ProductData.cs @@ -18,5 +18,14 @@ namespace RMDataManagerLibrary.DataAcccess return output; } + + public ProductModel GetProductById(int productId) + { + SqlDataAccess sql = new SqlDataAccess(); + + var output = sql.LoadData("dbo.spProductGetById", new {Id = productId}, "RMData").FirstOrDefault(); + + return output; + } } } diff --git a/RMDataManagerLibrary/DataAcccess/SaleData.cs b/RMDataManagerLibrary/DataAcccess/SaleData.cs new file mode 100644 index 0000000..10c195b --- /dev/null +++ b/RMDataManagerLibrary/DataAcccess/SaleData.cs @@ -0,0 +1,76 @@ +using RMDataManagerLibrary.Internal.DataAccess; +using RMDataManagerLibrary.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RMDataManagerLibrary.DataAcccess +{ + public class SaleData + { + //TODO: Make this SOLID/DRY/BETTER + public void SaveSale(SaleModel saleInfo, string cashierId) + { + List details = new List(); + ProductData products = new ProductData(); + decimal taxRate = ConfigHelper.GetTaxRate()/100; + + foreach (var item in saleInfo.SaleDetails) + { + var detail = new SaleDetailDBModel + { + ProductId = item.ProductId, + Quantity = item.Quantity + }; + + // get the information about this product + var productInfo = products.GetProductById(item.ProductId); + + if (productInfo == null) + { + throw new Exception($"Product with Id {item.ProductId} could not be found in DB"); + } + + detail.PurchasePrice = productInfo.RetailPrice * detail.Quantity; + + if (productInfo.IsTaxable) + { + detail.Tax = detail.PurchasePrice * taxRate; + } + + details.Add(detail); + } + + SaleDBModel sale = new SaleDBModel + { + SubTotal = details.Sum(x => x.PurchasePrice), + Tax = details.Sum(x => x.Tax), + CashierId = cashierId + }; + + sale.Total = sale.SubTotal + sale.Tax; + + //save + SqlDataAccess sql = new SqlDataAccess(); + sql.SaveData("dbo.spSaleInsert", sale, "RMData"); + + // get id from saleModel + + sale.Id = sql.LoadData("spSaleLookUp",new { sale.CashierId, sale.SaleDate }, "RMData").FirstOrDefault(); + + // finish filling up sale details + foreach (var item in details) + { + item.SaleId = sale.Id; + + // Save Details + + sql.SaveData("dbo.spSaleDetailInsert", item, "RMData"); + } + + + } + } +} diff --git a/RMDataManagerLibrary/Models/SaleDBModel.cs b/RMDataManagerLibrary/Models/SaleDBModel.cs new file mode 100644 index 0000000..1e40a09 --- /dev/null +++ b/RMDataManagerLibrary/Models/SaleDBModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RMDataManagerLibrary.Models +{ + public class SaleDBModel + { + public int Id { get; set; } + public string CashierId { get; set; } + public DateTime SaleDate { get; set; } = DateTime.UtcNow; + public decimal SubTotal { get; set; } + public decimal Tax { get; set; } + public decimal Total { get; set; } + + + } +} diff --git a/RMDataManagerLibrary/Models/SaleDetailDBModel.cs b/RMDataManagerLibrary/Models/SaleDetailDBModel.cs new file mode 100644 index 0000000..07f14b5 --- /dev/null +++ b/RMDataManagerLibrary/Models/SaleDetailDBModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RMDataManagerLibrary.Models +{ + public class SaleDetailDBModel + { + public int SaleId { get; set; } + public int ProductId { get; set; } + public int Quantity { get; set; } + public decimal PurchasePrice { get; set; } + public decimal Tax { get; set; } + } +} diff --git a/RMDataManagerLibrary/Models/SaleDetailModel.cs b/RMDataManagerLibrary/Models/SaleDetailModel.cs new file mode 100644 index 0000000..d26f2d0 --- /dev/null +++ b/RMDataManagerLibrary/Models/SaleDetailModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace RMDataManagerLibrary.Models +{ + public class SaleDetailModel + { + public int ProductId { get; set; } + public int Quantity { get; set; } + } +} \ No newline at end of file diff --git a/RMDataManagerLibrary/Models/SaleModel.cs b/RMDataManagerLibrary/Models/SaleModel.cs new file mode 100644 index 0000000..ac68bca --- /dev/null +++ b/RMDataManagerLibrary/Models/SaleModel.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace RMDataManagerLibrary.Models +{ + public class SaleModel + { + public List SaleDetails { get; set; } + } +} \ No newline at end of file diff --git a/RMDataManagerLibrary/RMDataManagerLibrary.csproj b/RMDataManagerLibrary/RMDataManagerLibrary.csproj index 5ee02f4..1ff33d7 100644 --- a/RMDataManagerLibrary/RMDataManagerLibrary.csproj +++ b/RMDataManagerLibrary/RMDataManagerLibrary.csproj @@ -45,9 +45,15 @@ + + + + + + diff --git a/RMWPFInterfaceLibrary/Api/ISaleEndPoint.cs b/RMWPFInterfaceLibrary/Api/ISaleEndPoint.cs new file mode 100644 index 0000000..b9d9028 --- /dev/null +++ b/RMWPFInterfaceLibrary/Api/ISaleEndPoint.cs @@ -0,0 +1,10 @@ +using RMWPFInterfaceLibrary.Models; +using System.Threading.Tasks; + +namespace RMWPFInterfaceLibrary.Api +{ + public interface ISaleEndPoint + { + Task PostSale(SaleModel sale); + } +} \ No newline at end of file diff --git a/RMWPFInterfaceLibrary/Api/SaleEndPoint.cs b/RMWPFInterfaceLibrary/Api/SaleEndPoint.cs new file mode 100644 index 0000000..3c3a010 --- /dev/null +++ b/RMWPFInterfaceLibrary/Api/SaleEndPoint.cs @@ -0,0 +1,34 @@ +using RMWPFInterfaceLibrary.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace RMWPFInterfaceLibrary.Api +{ + public class SaleEndPoint : ISaleEndPoint + { + private IAPIHelper _apiHelper; + public SaleEndPoint(IAPIHelper apiHelper) + { + _apiHelper = apiHelper; + } + + public async Task PostSale(SaleModel sale) + { + using (HttpResponseMessage response = await _apiHelper.ApiClient.PostAsJsonAsync("api/Sale", sale)) + { + if (response.IsSuccessStatusCode) + { + // Log call + } + else + { + throw new Exception(response.ReasonPhrase); + } + } + } + } +} diff --git a/RMWPFInterfaceLibrary/Models/SaleDetailModel.cs b/RMWPFInterfaceLibrary/Models/SaleDetailModel.cs new file mode 100644 index 0000000..1d4d0d4 --- /dev/null +++ b/RMWPFInterfaceLibrary/Models/SaleDetailModel.cs @@ -0,0 +1,8 @@ +namespace RMWPFInterfaceLibrary.Models +{ + public class SaleDetailModel + { + public int ProductId { get; set; } + public int Quantity { get; set; } + } +} \ No newline at end of file diff --git a/RMWPFInterfaceLibrary/Models/SaleModel.cs b/RMWPFInterfaceLibrary/Models/SaleModel.cs new file mode 100644 index 0000000..9807f07 --- /dev/null +++ b/RMWPFInterfaceLibrary/Models/SaleModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RMWPFInterfaceLibrary.Models +{ + public class SaleModel + { + public List SaleDetails { get; set; } = new List(); + } +} diff --git a/RMWPFInterfaceLibrary/RMWPFInterfaceLibrary.csproj b/RMWPFInterfaceLibrary/RMWPFInterfaceLibrary.csproj index 3be943e..fc9c8d3 100644 --- a/RMWPFInterfaceLibrary/RMWPFInterfaceLibrary.csproj +++ b/RMWPFInterfaceLibrary/RMWPFInterfaceLibrary.csproj @@ -51,7 +51,9 @@ + + @@ -59,6 +61,8 @@ + + diff --git a/RMWPFUserInterface/BootStrapper.cs b/RMWPFUserInterface/BootStrapper.cs index c568307..a4072b3 100644 --- a/RMWPFUserInterface/BootStrapper.cs +++ b/RMWPFUserInterface/BootStrapper.cs @@ -29,7 +29,8 @@ namespace RMWPFUserInterface protected override void Configure() { _container.Instance(_container) - .PerRequest(); + .PerRequest() + .PerRequest(); _container .Singleton() diff --git a/RMWPFUserInterface/ViewModels/LoginViewModel.cs b/RMWPFUserInterface/ViewModels/LoginViewModel.cs index 58b6e16..1a87fb1 100644 --- a/RMWPFUserInterface/ViewModels/LoginViewModel.cs +++ b/RMWPFUserInterface/ViewModels/LoginViewModel.cs @@ -12,8 +12,8 @@ namespace RMWPFUserInterface.ViewModels { public class LoginViewModel : Screen { - private string _userName; - private string _password; + private string _userName ="test@test"; + private string _password = "Test1234."; private IAPIHelper _apiHelper; private IEventAggregator _events; diff --git a/RMWPFUserInterface/ViewModels/SalesViewModel.cs b/RMWPFUserInterface/ViewModels/SalesViewModel.cs index b0bc128..fbcd142 100644 --- a/RMWPFUserInterface/ViewModels/SalesViewModel.cs +++ b/RMWPFUserInterface/ViewModels/SalesViewModel.cs @@ -15,10 +15,13 @@ namespace RMWPFUserInterface.ViewModels { IProductEndPoint _productEndPoint; IConfigHelper _configHelper; - public SalesViewModel(IProductEndPoint productEndPoint, IConfigHelper configHelper) + ISaleEndPoint _saleEndPoint; + + public SalesViewModel(IProductEndPoint productEndPoint, IConfigHelper configHelper, ISaleEndPoint saleEndPoint) { _productEndPoint = productEndPoint; _configHelper = configHelper; + _saleEndPoint = saleEndPoint; } protected override async void OnViewLoaded(object view) @@ -170,6 +173,7 @@ namespace RMWPFUserInterface.ViewModels NotifyOfPropertyChange(() => SubTotal); NotifyOfPropertyChange(() => Tax); NotifyOfPropertyChange(() => Total); + NotifyOfPropertyChange(() => CanCheckOut); Cart.ResetBindings(); } @@ -189,6 +193,7 @@ namespace RMWPFUserInterface.ViewModels NotifyOfPropertyChange(() => SubTotal); NotifyOfPropertyChange(() => Tax); NotifyOfPropertyChange(() => Total); + NotifyOfPropertyChange(() => CanCheckOut); } public bool CanCheckOut @@ -197,14 +202,29 @@ namespace RMWPFUserInterface.ViewModels { bool output = false; - // Make sure there is something in the cart + if ( Cart.Count > 0) + { + output = true; + } return output; } } - public void CheckOut() + public async Task CheckOut() { + SaleModel sale = new SaleModel(); + foreach (var item in Cart) + { + sale.SaleDetails.Add(new SaleDetailModel + { + ProductId = item.Product.Id, + Quantity = item.QuantityInCart + }); + + } + + await _saleEndPoint.PostSale(sale); } } } diff --git a/RMWPFUserInterface/Views/SalesView.xaml b/RMWPFUserInterface/Views/SalesView.xaml index c9f499f..83ef5ed 100644 --- a/RMWPFUserInterface/Views/SalesView.xaml +++ b/RMWPFUserInterface/Views/SalesView.xaml @@ -43,7 +43,7 @@ - +