Created Sales View and Database prodecures for displaying items.

Created and binded a View, created logic behind Cart Product Model
This commit is contained in:
s459315 2022-07-23 17:09:13 +02:00
parent ff6653c1bd
commit 57d2ab60a7
23 changed files with 324 additions and 39 deletions

View File

@ -72,6 +72,7 @@
<Build Include="dbo\Tables\Product.sql" />
<Build Include="dbo\Tables\Inventory.sql" />
<Build Include="dbo\Stored Procedures\spUserLookup.sql" />
<Build Include="dbo\Stored Procedures\spProductGetAll.sql" />
</ItemGroup>
<ItemGroup>
<RefactorLog Include="RMData.refactorlog" />

View File

@ -0,0 +1,9 @@
CREATE PROCEDURE [dbo].[spProductGetAll]
AS
BEGIN
SET NOCOUNT ON;
select Id, ProductName, [Description], RetailPrice, QuantityInStock
from [dbo].[Product]
order by ProductName;
END

View File

@ -4,7 +4,7 @@
[ProductName] NVARCHAR(100) NOT NULL,
[Description] NVARCHAR(MAX) NOT NULL,
[RetailPrice] MONEY NOT NULL,
[QuantityInStock] INT NOT NULL DEFAULT 1,
[CreatedDate] DATETIME2 NOT NULL DEFAULT getutcdate(),
[LastModified] DATETIME2 NOT NULL DEFAULT getutcdate(),
[LastModified] DATETIME2 NOT NULL DEFAULT getutcdate()
)

View File

@ -0,0 +1,22 @@
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 ProductController : ApiController
{
public List<ProductModel> Get()
{
ProductData data = new ProductData();
return data.GetProducts();
}
}
}

View File

@ -213,6 +213,7 @@
<Compile Include="Areas\HelpPage\XmlDocumentationProvider.cs" />
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\ProductController.cs" />
<Compile Include="Controllers\UserController.cs" />
<Compile Include="Controllers\ValuesController.cs" />
<Compile Include="Global.asax.cs">

View File

@ -0,0 +1,22 @@
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 ProductData
{
public List<ProductModel> GetProducts()
{
SqlDataAccess sql = new SqlDataAccess();
var output = sql.LoadData<ProductModel, dynamic>("dbo.spProductGetAll", new { }, "RMData");
return output;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace RMDataManagerLibrary.Models
{
public class ProductModel
{
public int Id { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
public decimal RetailPrice { get; set; }
public int QuantityInStock { get; set; }
}
}

View File

@ -45,7 +45,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DataAcccess\ProductData.cs" />
<Compile Include="DataAcccess\UserData.cs" />
<Compile Include="Models\ProductModel.cs" />
<Compile Include="Models\UserModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Internal\DataAccess\SqlDataAccess.cs" />

View File

@ -13,21 +13,30 @@ namespace RMWPFInterfaceLibrary.Api
{
public class APIHelper : IAPIHelper
{
private HttpClient apiClient;
private HttpClient _apiClient;
private ILoggedInUserModel _loggedInUser;
public APIHelper(ILoggedInUserModel loggedInUser)
{
InitializeClient();
_loggedInUser = loggedInUser;
}
public HttpClient ApiClient
{
get
{
return _apiClient;
}
}
private void InitializeClient()
{
string api = ConfigurationManager.AppSettings["api"];
apiClient = new HttpClient();
apiClient.BaseAddress = new Uri(api);
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_apiClient = new HttpClient();
_apiClient.BaseAddress = new Uri(api);
_apiClient.DefaultRequestHeaders.Accept.Clear();
_apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<AuthenticatedUser> Authenticate(string username, string password)
@ -39,7 +48,7 @@ namespace RMWPFInterfaceLibrary.Api
new KeyValuePair<string, string>("password", password),
});
using (HttpResponseMessage response = await apiClient.PostAsync("/Token", data))
using (HttpResponseMessage response = await _apiClient.PostAsync("/Token", data))
{
if (response.IsSuccessStatusCode)
{
@ -55,12 +64,12 @@ namespace RMWPFInterfaceLibrary.Api
public async Task GetLogedInUserInfo(string token)
{
apiClient.DefaultRequestHeaders.Clear();
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
apiClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
_apiClient.DefaultRequestHeaders.Clear();
_apiClient.DefaultRequestHeaders.Accept.Clear();
_apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_apiClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
using (HttpResponseMessage response = await apiClient.GetAsync("api/User"))
using (HttpResponseMessage response = await _apiClient.GetAsync("api/User"))
{
if (response.IsSuccessStatusCode)
{

View File

@ -1,10 +1,12 @@
using RMWPFUserInterface.Models;
using System.Net.Http;
using System.Threading.Tasks;
namespace RMWPFInterfaceLibrary.Api
{
public interface IAPIHelper
{
HttpClient ApiClient { get; }
Task<AuthenticatedUser> Authenticate(string username, string password);
Task GetLogedInUserInfo(string token);
}

View File

@ -0,0 +1,11 @@
using RMWPFInterfaceLibrary.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace RMWPFInterfaceLibrary.Api
{
public interface IProductEndPoint
{
Task<List<ProductModel>> GetAll();
}
}

View File

@ -0,0 +1,36 @@
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 ProductEndPoint : IProductEndPoint
{
private IAPIHelper _apiHelper;
public ProductEndPoint(IAPIHelper apiHelper)
{
_apiHelper = apiHelper;
}
public async Task<List<ProductModel>> GetAll()
{
using (HttpResponseMessage response = await _apiHelper.ApiClient.GetAsync("api/Product"))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<List<ProductModel>>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RMWPFInterfaceLibrary.Models
{
public class CartItemModel
{
public ProductModel Product { get; set; }
public int QuantityInCart { get; set; }
public string DisplayText
{
get
{
return $"{Product.ProductName} ({QuantityInCart})";
}
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RMWPFInterfaceLibrary.Models
{
public class ProductModel
{
public int Id { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
public decimal RetailPrice { get; set; }
public int QuantityInStock { get; set; }
}
}

View File

@ -50,9 +50,13 @@
<ItemGroup>
<Compile Include="Api\APIHelper.cs" />
<Compile Include="Api\IAPIHelper.cs" />
<Compile Include="Api\IProductEndPoint.cs" />
<Compile Include="Api\ProductEndPoint.cs" />
<Compile Include="Models\AuthenticatedUser.cs" />
<Compile Include="Models\CartItemModel.cs" />
<Compile Include="Models\ILoggedInUserModel.cs" />
<Compile Include="Models\LoggedInUserModel.cs" />
<Compile Include="Models\ProductModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -27,8 +27,9 @@ namespace RMWPFUserInterface
}
protected override void Configure()
{
_container.Instance(_container);
_container.Instance(_container)
.PerRequest<IProductEndPoint, ProductEndPoint>();
_container
.Singleton<IWindowManager, WindowManager>()
.Singleton<IEventAggregator, EventAggregator>()

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RMWPFUserInterface.EventModels
{
public class LogOnEvent
{
}
}

View File

@ -81,6 +81,7 @@
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="BootStrapper.cs" />
<Compile Include="EventModels\LogOnEvent.cs" />
<Compile Include="Helpers\PasswordBoxHelper.cs" />
<Compile Include="Models\AuthenticatedUser.cs" />
<Compile Include="ViewModels\LoginViewModel.cs" />

View File

@ -1,5 +1,6 @@
using Caliburn.Micro;
using RMWPFInterfaceLibrary.Api;
using RMWPFUserInterface.EventModels;
using RMWPFUserInterface.Helpers;
using System;
using System.Collections.Generic;
@ -14,10 +15,12 @@ namespace RMWPFUserInterface.ViewModels
private string _userName;
private string _password;
private IAPIHelper _apiHelper;
private IEventAggregator _events;
public LoginViewModel(IAPIHelper apiHelper)
public LoginViewModel(IAPIHelper apiHelper, IEventAggregator events)
{
_apiHelper = apiHelper;
_events = events;
}
public string UserName
{
@ -96,6 +99,8 @@ namespace RMWPFUserInterface.ViewModels
// Capture more information
await _apiHelper.GetLogedInUserInfo(result.Access_Token);
await _events.PublishOnUIThreadAsync(new LogOnEvent());
}
catch (Exception ex)
{

View File

@ -1,4 +1,6 @@
using Caliburn.Micro;
using RMWPFInterfaceLibrary.Api;
using RMWPFInterfaceLibrary.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -10,9 +12,27 @@ namespace RMWPFUserInterface.ViewModels
{
public class SalesViewModel : Screen
{
private BindingList<string> _products;
IProductEndPoint _productEndPoint;
public SalesViewModel(IProductEndPoint productEndPoint)
{
_productEndPoint = productEndPoint;
}
public BindingList<string> Products
protected override async void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
await LoadProducts();
}
private async Task LoadProducts()
{
var prods = await _productEndPoint.GetAll();
Products = new BindingList<ProductModel>(prods);
}
private BindingList<ProductModel> _products;
public BindingList<ProductModel> Products
{
get { return _products; }
set
@ -22,27 +42,42 @@ namespace RMWPFUserInterface.ViewModels
}
}
private BindingList<string> _cart;
private ProductModel _selectedProduct;
public BindingList<string> Cart
public ProductModel SelectedProduct
{
get { return _selectedProduct; }
set
{
_selectedProduct = value;
NotifyOfPropertyChange(() => SelectedProduct);
NotifyOfPropertyChange(() => CanAddToCart);
}
}
private BindingList<CartItemModel> _cart = new BindingList<CartItemModel>();
public BindingList<CartItemModel> Cart
{
get { return _cart; }
set
{
Cart = value;
{
_cart = value;
NotifyOfPropertyChange(() => Cart);
}
}
private string _itemQuantity;
private int _itemQuantity = 1;
public string ItemQuantity
public int ItemQuantity
{
get { return _itemQuantity; }
set
{
ItemQuantity = value;
_itemQuantity = value;
NotifyOfPropertyChange(() => ItemQuantity);
NotifyOfPropertyChange(() => CanAddToCart);
}
}
@ -50,8 +85,14 @@ namespace RMWPFUserInterface.ViewModels
{
get
{
// replace with calulation;
return "$0.00";
decimal subTotal = 0;
foreach (var item in Cart)
{
subTotal += item.Product.RetailPrice * item.QuantityInCart;
}
return subTotal.ToString("C");
}
}
@ -79,14 +120,36 @@ namespace RMWPFUserInterface.ViewModels
{
bool output = false;
// Make sure item is selected and quantity is typed in
if (ItemQuantity > 0 && SelectedProduct?.QuantityInStock >= ItemQuantity)
{
output = true;
}
return output;
}
}
public void AddToCart()
{
CartItemModel existingItem = Cart.FirstOrDefault(x => x.Product == SelectedProduct);
if (existingItem != null)
{
existingItem.QuantityInCart += ItemQuantity;
}
else
{
CartItemModel item = new CartItemModel
{
Product = SelectedProduct,
QuantityInCart = ItemQuantity
};
Cart.Add(item);
}
SelectedProduct.QuantityInStock -= ItemQuantity;
ItemQuantity = 1;
NotifyOfPropertyChange(() => SubTotal);
Cart.ResetBindings();
}
public bool CanRemoveFromCart
@ -102,7 +165,7 @@ namespace RMWPFUserInterface.ViewModels
}
public void RemoveFromCart()
{
NotifyOfPropertyChange(() => SubTotal);
}
public bool CanCheckOut

View File

@ -2,18 +2,35 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Caliburn.Micro;
using RMWPFUserInterface.EventModels;
namespace RMWPFUserInterface.ViewModels
{
public class ShellViewModel : Conductor<Object>
public class ShellViewModel : Conductor<Object>, IHandle<LogOnEvent>
{
private LoginViewModel _loginVM;
public ShellViewModel(LoginViewModel loginVM)
private IEventAggregator _events;
private SalesViewModel _salesVM;
private SimpleContainer _container;
public ShellViewModel(IEventAggregator events, SalesViewModel salesVM,
SimpleContainer container)
{
_loginVM = loginVM;
ActivateItemAsync(_loginVM);
_salesVM = salesVM;
_container = container;
_events = events;
_events.SubscribeOnUIThread(this);
ActivateItemAsync(_container.GetInstance<LoginViewModel>());
}
public Task HandleAsync(LogOnEvent message, CancellationToken cancellationToken)
{
ActivateItemAsync(_salesVM);
return Task.CompletedTask;
}
}
}

View File

@ -32,13 +32,19 @@
<!-- Column 0 -->
<TextBlock Text="Items" Grid.Row="1" Grid.Column="0"/>
<ListBox x:Name="Products" Grid.Row="2" Grid.Column="0"
MinHeight="200" MinWidth="150"/>
MinHeight="200" MinWidth="150" SelectedItem="{Binding SelectedProduct}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ProductName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- Column 1 -->
<StackPanel Orientation="Vertical" Grid.Column="1"
Grid.Row="2" Margin="20 0" >
<TextBlock Text="Quantity" />
<TextBlock x:Name="ItemQuantity" MinWidth="100" Margin="0 0 0 10"/>
<TextBox x:Name="ItemQuantity" MinWidth="100" Margin="0 0 0 10"/>
<Button x:Name="AddToCart" Content="Add to Cart" Margin="0 0 0 30"
Padding="5"/>
<Button x:Name="RemoveFromCart" Content="Remove from Cart"
@ -48,7 +54,13 @@
<!-- Column 2 -->
<TextBlock Text="Cart" Grid.Row="1" Grid.Column="2"/>
<ListBox x:Name="Cart" Grid.Row="2" Grid.Column="2"
MinHeight="200" MinWidth="150"/>
MinHeight="200" MinWidth="150">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayText}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<DockPanel Grid.Row="3" Grid.Column="2">
<TextBlock Text="SubTotal: " Margin="0 0 15 0"/>

View File

@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RMWPFUserInterface.Views"
mc:Ignorable="d"
Title="ShellView" Height="450" Width="800">
Title="ShellView" Height="600" Width="1000">
<DockPanel>
<Menu DockPanel.Dock="Top" FontSize="18">
<MenuItem Header="_File">
@ -16,7 +16,7 @@
</MenuItem>
</Menu>
<Grid>
<ContentControl x:Name="ActiveItem" Margin="5" />
<ContentControl x:Name="ActiveItem" Margin="20 5 20 20" />
</Grid>
</DockPanel>
</Window>