62 changed files with 2539 additions and 231 deletions
			
			
		| @ -1,35 +1,38 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> | |||
| 
 | |||
|   <PropertyGroup> | |||
|     <TargetFramework>net7.0</TargetFramework> | |||
|     <Nullable>enable</Nullable> | |||
|     <ImplicitUsings>enable</ImplicitUsings> | |||
|     <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest> | |||
|     <AssemblyName>$(AssemblyName.Replace(' ', '_'))</AssemblyName> | |||
|   </PropertyGroup> | |||
| 	<PropertyGroup> | |||
| 		<TargetFramework>net7.0</TargetFramework> | |||
| 		<Nullable>enable</Nullable> | |||
| 		<ImplicitUsings>enable</ImplicitUsings> | |||
| 		<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest> | |||
| 		<AssemblyName>$(AssemblyName.Replace(' ', '_'))</AssemblyName> | |||
| 	</PropertyGroup> | |||
| 
 | |||
|   <ItemGroup> | |||
|     <None Include="..\.editorconfig" Link=".editorconfig" /> | |||
|   </ItemGroup> | |||
| 	<ItemGroup> | |||
| 		<None Include="..\.editorconfig" Link=".editorconfig" /> | |||
| 	</ItemGroup> | |||
| 
 | |||
|   <ItemGroup> | |||
|     <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" /> | |||
|     <PackageReference Include="Blazored.LocalStorage" Version="4.3.0" /> | |||
|     <PackageReference Include="Blazored.SessionStorage" Version="2.3.0" /> | |||
|     <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" /> | |||
|     <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" PrivateAssets="all" /> | |||
|     <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" /> | |||
| 	<PackageReference Include="Blazor-ApexCharts" Version="0.9.21-beta" /> | |||
| 	<PackageReference Include="Microsoft.Fast.Components.FluentUI" Version="2.3.6" /> | |||
| 	<PackageReference Include="Radzen.Blazor" Version="4.12.0" /> | |||
|   </ItemGroup> | |||
| 	<ItemGroup> | |||
| 		<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" /> | |||
| 		<PackageReference Include="BlazorDateRangePicker" Version="4.3.0" /> | |||
| 		<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" /> | |||
| 		<PackageReference Include="Blazored.SessionStorage" Version="2.3.0" /> | |||
| 		<PackageReference Include="Faso.Blazor.SpinKit" Version="1.0.1" /> | |||
| 		<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" /> | |||
| 		<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" PrivateAssets="all" /> | |||
| 		<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" /> | |||
| 		<PackageReference Include="Blazor-ApexCharts" Version="0.9.21-beta" /> | |||
| 		<PackageReference Include="Microsoft.Fast.Components.FluentUI" Version="2.3.6" /> | |||
| 		<PackageReference Include="NETStandardBarcode" Version="1.0.2" /> | |||
| 		<PackageReference Include="Radzen.Blazor" Version="4.12.0" /> | |||
| 	</ItemGroup> | |||
| 
 | |||
|   <ItemGroup> | |||
|     <ProjectReference Include="..\Shared\Biskilog Accounting.Shared.csproj" /> | |||
|   </ItemGroup> | |||
| 	<ItemGroup> | |||
| 		<ProjectReference Include="..\Shared\Biskilog Accounting.Shared.csproj" /> | |||
| 	</ItemGroup> | |||
| 
 | |||
|   <ItemGroup> | |||
|     <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" /> | |||
|   </ItemGroup> | |||
| 	<ItemGroup> | |||
| 		<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" /> | |||
| 	</ItemGroup> | |||
| 
 | |||
| </Project> | |||
|  | |||
| @ -0,0 +1,26 @@ | |||
| using Microsoft.JSInterop; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Elements | |||
| { | |||
|     public partial class Headbar | |||
|     { | |||
|         protected override void OnInitialized() | |||
|         { | |||
|             m_searchService.ClearTextBox += ClearTextBox; | |||
|             base.OnInitialized(); | |||
|         } | |||
| 
 | |||
|         private void ClearTextBox() | |||
|         { | |||
|             ClearInputField("mainSearch"); | |||
|         } | |||
|         private async Task ClearInputField(string elementId) | |||
|         { | |||
|             await JSRuntime.InvokeVoidAsync("eval", $"document.getElementById('{elementId}').value = ''"); | |||
|         } | |||
|         private void SearchInput(string a_key) | |||
|         { | |||
|             m_searchService.PerformSearch(a_key); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,19 @@ | |||
| @page "/products/brands" | |||
| @using Biskilog_Accounting.Shared.Interfaces; | |||
| @using Biskilog_Accounting.Shared.POSModels; | |||
| @inject IProduct m_productRepo | |||
| @inject ContextMenuService ContextMenuService | |||
| @inject DialogService m_dialogService | |||
| @inject ISearchService m_searchControl | |||
| @implements IDisposable | |||
| 
 | |||
| <div class="row" style="display:grid;justify-content:space-between;padding: 5px;margin-right:10px;"> | |||
|     <h3>Product Brands</h3> | |||
| </div> | |||
| <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_brands" TItem="Tblbrand" GridLines="DataGridGridLines.Horizontal"> | |||
|     <Columns> | |||
|         <RadzenDataGridColumn TItem="Tblbrand" Property="Id" Title="Brand ID" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="Tblbrand" Property="Brand" Title="Brand Name" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="Tblbrand" Property="BranchId" Title="Branch" Resizable Reorderable /> | |||
|     </Columns> | |||
| </RadzenDataGrid> | |||
| @ -0,0 +1,37 @@ | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Product | |||
| { | |||
|     public partial class Brands | |||
|     { | |||
|         private IEnumerable<Tblbrand> m_brands { get; set; } = new List<Tblbrand>(); | |||
|         protected override void OnInitialized() | |||
|         { | |||
|             m_productRepo.BrandsChanged += BrandFetchComplete; | |||
|             m_searchControl.SearchValueChanged += SearchValueChanged; | |||
| 
 | |||
|             LoadBrands(string.Empty); | |||
|             base.OnInitialized(); | |||
|         } | |||
| 
 | |||
|         private void SearchValueChanged(string a_searchKey) | |||
|         { | |||
|             LoadBrands(a_searchKey); | |||
|         } | |||
| 
 | |||
|         public void Dispose() | |||
|         { | |||
|             m_productRepo.BrandsChanged -= BrandFetchComplete; | |||
|             m_searchControl.SearchValueChanged -= SearchValueChanged; | |||
|         } | |||
|         private void BrandFetchComplete(object? sender, EventArgs e) | |||
|         { | |||
|             LoadBrands(string.Empty); | |||
|         } | |||
|         private void LoadBrands(string a_productKey) | |||
|         { | |||
|             m_brands = m_productRepo.GetBrands(a_productKey); | |||
|             StateHasChanged(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,19 @@ | |||
| @page "/products/categories" | |||
| @using Biskilog_Accounting.Shared.POSModels; | |||
| @using Biskilog_Accounting.Shared.Interfaces | |||
| @inject IProduct m_productRepo | |||
| @inject ContextMenuService ContextMenuService | |||
| @inject DialogService m_dialogService | |||
| @inject ISearchService m_searchControl | |||
| @implements IDisposable | |||
| 
 | |||
| <div class="row" style="display:flex;justify-content:space-between;padding: 5px;margin-right:10px;"> | |||
|     <h3>Categories</h3> | |||
| </div> | |||
| <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_categories" TItem="Tblcategory" GridLines="DataGridGridLines.Horizontal"> | |||
|     <Columns> | |||
|         <RadzenDataGridColumn TItem="Tblcategory" Property="Id" Title="Category ID" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="Tblcategory" Property="Category" Title="Category Name" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="Tblcategory" Property="BranchId" Title="Branch" Resizable Reorderable /> | |||
|     </Columns> | |||
| </RadzenDataGrid> | |||
| @ -0,0 +1,37 @@ | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Product | |||
| { | |||
|     public partial class Categories | |||
|     { | |||
|         private IEnumerable<Tblcategory> m_categories { get; set; } = new List<Tblcategory>(); | |||
|         protected override void OnInitialized() | |||
|         { | |||
|             m_productRepo.CategoriesChanged += CategoryFetchComplete; | |||
|             m_searchControl.SearchValueChanged += SearchValueChanged; | |||
| 
 | |||
|             LoadCategories(string.Empty); | |||
|             base.OnInitialized(); | |||
|         } | |||
| 
 | |||
|         private void SearchValueChanged(string a_searchKey) | |||
|         { | |||
|             LoadCategories(a_searchKey); | |||
|         } | |||
| 
 | |||
|         public void Dispose() | |||
|         { | |||
|             m_productRepo.CategoriesChanged -= CategoryFetchComplete; | |||
|             m_searchControl.SearchValueChanged -= SearchValueChanged; | |||
|         } | |||
|         private void CategoryFetchComplete(object? sender, EventArgs e) | |||
|         { | |||
|             LoadCategories(string.Empty); | |||
|         } | |||
|         private void LoadCategories(string a_productKey) | |||
|         { | |||
|             m_categories = m_productRepo.GetCategories(a_productKey); | |||
|             StateHasChanged(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,186 @@ | |||
| @page "/products/{product}" | |||
| @using Biskilog_Accounting.Shared.CustomModels; | |||
| @using Biskilog_Accounting.Shared.Interfaces; | |||
| @inject IProduct m_productRepo | |||
| @inject ICalculator m_calculator | |||
| 
 | |||
| <RadzenCard Style="margin-bottom: 20px;"> | |||
|     <div class="row" style="justify-content: end;height: 20px;display: grid;"> | |||
|         <RadzenStack Orientation="Radzen.Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem"> | |||
|             <RadzenSwitch @bind-Value="m_editMode" /> | |||
|             <RadzenLabel Text="Edit Mode" /> | |||
|         </RadzenStack> | |||
|     </div> | |||
|     <div class="row align-items-center" style="justify-content: center;"> | |||
|         <img src="assets/img/box.png" style="width:200px;" /> | |||
|     </div> | |||
|     @if (m_editMode) | |||
|     { | |||
|         <div class="row"> | |||
|             <div class="col-md-6 align-items-center d-flex"> | |||
|                 <RadzenFieldset Text="Product Info" Style="width:100%;"> | |||
|                     <div class="row"> | |||
|                         <div class="col-md-4 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Product Id" /> | |||
|                         </div> | |||
|                         <div class="col-md-8"> | |||
|                             <RadzenTextBox Disabled="true" style="width: 100%;" Name="pcode" @bind-Value=@(Product.Product!.Pcode) /> | |||
|                         </div> | |||
|                     </div> | |||
|                     <div class="row" style="margin-top:5px;"> | |||
|                         <div class="col-md-4 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Product Name" /> | |||
|                         </div> | |||
|                         <div class="col-md-8"> | |||
|                             <RadzenTextBox Disabled="true" style="width: 100%;" Name="productName" @bind-Value=@(Product.Product!.ProductName) /> | |||
|                         </div> | |||
|                     </div> | |||
| 
 | |||
|                     <div class="row" style="margin-top:5px;"> | |||
|                         <div class="col-md-4 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Description" /> <b></b> | |||
|                         </div> | |||
|                         <div class="col-md-8"> | |||
|                             <RadzenTextArea Disabled="true" @bind-Value=@(Product.Product!.Pdesc) Cols="25" Rows="4" /> | |||
|                         </div> | |||
|                     </div> | |||
| 
 | |||
|                 </RadzenFieldset> | |||
|             </div> | |||
|             <div class="col-md-6"> | |||
|                 <RadzenFieldset Text="Other Units Of Measure"> | |||
|                     <div class="row" style="justify-content: end;height: 20px;display: grid;"> | |||
|                         <RadzenButton Icon="add_circle_outline" ButtonStyle="ButtonStyle.Light" /> | |||
|                     </div> | |||
|                     <div class="row" style="margin-top:5px;"> | |||
|                         <div class="col-md-6 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Unit Of Measure" /> <b></b> | |||
|                         </div> | |||
|                         <div class="col-md-6 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Quantity" /> <b></b> | |||
|                         </div> | |||
|                     </div> | |||
|                     @foreach (ProductUnits unit in Product.Units) | |||
|                     { | |||
|                         <div class="row" style="margin-top:5px;"> | |||
|                             <div class="col-md-6 align-items-center d-flex"> | |||
|                                 <RadzenDropDown @bind-Value=@(unit.UnitCode) Data=@(m_productRepo.GetUnitofmeasures()) TextProperty="UnitName" ValueProperty="UnitCode" /> | |||
|                             </div> | |||
|                             <div class="col-md-6 align-items-center d-flex"> | |||
|                                 <RadzenNumeric Placeholder="10" Step="1" @bind-Value=@(unit.QuantityUnit) /> | |||
|                             </div> | |||
|                         </div> | |||
|                     } | |||
|                 </RadzenFieldset> | |||
|             </div> | |||
|         </div> | |||
|         <div class="row"> | |||
|             <div class="col-md-6 align-items-center d-flex"> | |||
|                 <RadzenFieldset Text="Base Unit" Style="width:100%;"> | |||
|                     <div class="row"> | |||
|                         <div class="col-md-4 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Base Unit" /> | |||
|                         </div> | |||
|                         <div class="col-md-8"> | |||
|                             <RadzenDropDown @bind-Value=@(Product.BaseUnit) Data=@(m_productRepo.GetUnitofmeasures()) TextProperty="UnitName" ValueProperty="UnitCode" /> | |||
|                         </div> | |||
|                     </div> | |||
|                 </RadzenFieldset> | |||
|             </div> | |||
|             <div class="col-md-6"> | |||
|                 <RadzenFieldset Text="Re-order Level"> | |||
|                     <div class="row"> | |||
|                         <div class="col-md-6 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Quantity" /> | |||
|                         </div> | |||
|                         <div class="col-md-6 align-items-center d-flex"> | |||
|                             <RadzenNumeric Placeholder="10" Step="1" @bind-Value=@(Product.Restocklevel!.WarnLevel) /> | |||
|                         </div> | |||
|                     </div> | |||
|                     <div class="row" style="margin-top:5px;"> | |||
|                         <div class="col-md-6 align-items-center d-flex"> | |||
|                             <RadzenLabel Text="Unit Of Measure" /> | |||
|                         </div> | |||
|                         <div class="col-md-6 align-items-center d-flex"> | |||
|                             <RadzenDropDown @bind-Value=@(Product.Restocklevel!.Unit) Data=@(m_reorderUnits) TextProperty="UnitName" ValueProperty="UnitCode" /> | |||
|                         </div> | |||
|                     </div> | |||
|                 </RadzenFieldset> | |||
|             </div> | |||
|         </div> | |||
|         <div class="row" style="display:flex;justify-content:safe center;margin-top:10px;margin-bottom:10px;"> | |||
|             <RadzenButton Text="Save" Style="width:fit-content;background-color:green;margin-right:10px;" /> | |||
|             <RadzenButton Text="Cancel" Style="width:fit-content;background-color:Darkred;" /> | |||
|         </div> | |||
|     } | |||
|     else | |||
|     { | |||
|         //Read Only View | |||
|         <RadzenFieldset Text="Product Info" Style="width:100%;"> | |||
|             <div class="row"> | |||
|                 <div class="col-md-4 align-items-center d-flex"> | |||
|                     <RadzenLabel Text="Product Id" /> | |||
|                 </div> | |||
|                 <div class="col-md-8"> | |||
|                     <RadzenTextBox Disabled="true" style="width: 100%;" Name="pcode" @bind-Value=@(Product.Product!.Pcode) /> | |||
|                 </div> | |||
|             </div> | |||
|             <div class="row" style="margin-top:5px;"> | |||
|                 <div class="col-md-4 align-items-center d-flex"> | |||
|                     <RadzenLabel Text="Product Name" /> | |||
|                 </div> | |||
|                 <div class="col-md-8"> | |||
|                     <RadzenTextBox Disabled="true" style="width: 100%;" Name="productName" @bind-Value=@(Product.Product!.ProductName) /> | |||
|                 </div> | |||
|             </div> | |||
| 
 | |||
|             <div class="row" style="margin-top:5px;"> | |||
|                 <div class="col-md-4 align-items-center d-flex"> | |||
|                     <RadzenLabel Text="Description" /> <b></b> | |||
|                 </div> | |||
|                 <div class="col-md-8"> | |||
|                     <RadzenTextArea Disabled="true" @bind-Value=@(Product.Product!.Pdesc) Cols="45" Rows="4" /> | |||
|                 </div> | |||
|             </div> | |||
|             <div class="row" style="margin-top:5px;"> | |||
|                 <div class="col-md-4 align-items-center d-flex"> | |||
|                     <RadzenLabel Text="Base Unit" /> <b></b> | |||
|                 </div> | |||
|                 <div class="col-md-8"> | |||
|                     <RadzenTextBox Disabled="true" Value=@(m_productRepo.GetUnitName(Product.Product!.BaseUnit)) /> | |||
|                 </div> | |||
|             </div> | |||
|             <div class="row" style="margin-top:5px;"> | |||
|                 <div class="col-md-4 align-items-center d-flex"> | |||
|                     <RadzenLabel Text="Quantity" /> <b></b> | |||
|                 </div> | |||
|                 <div class="col-md-8"> | |||
|                     <RadzenNumeric Disabled="true" @bind-Value=@(Product.Stock!.Quantity) /> | |||
|                 </div> | |||
|             </div> | |||
|             <div class="row" style="margin-top:5px;"> | |||
|                 <RadzenDataGrid Data="@(Product.Units.OrderBy(t  => t.PriceUnit))" TItem="ProductUnits" GridLines="DataGridGridLines.Horizontal"> | |||
|                     <Columns> | |||
|                         <RadzenDataGridColumn TItem="ProductUnits" Property="UnitCode" Title="Unit Of Measure"> | |||
|                             <Template Context="detail"> | |||
|                                 @(m_productRepo.GetUnitName(detail.UnitCode)) | |||
|                             </Template> | |||
|                         </RadzenDataGridColumn> | |||
|                         <RadzenDataGridColumn TItem="ProductUnits" Property="QuantityUnit" Title="Quantity" /> | |||
|                         <RadzenDataGridColumn TItem="ProductUnits" Property="PriceUnit" Title="Price Per Unit"> | |||
|                             <Template Context="detail"> | |||
|                                 @(m_calculator.FormatMoneyWithCurrency((double)detail.PriceUnit)) | |||
|                             </Template> | |||
|                         </RadzenDataGridColumn> | |||
|                     </Columns> | |||
|                 </RadzenDataGrid> | |||
|             </div> | |||
|         </RadzenFieldset> | |||
|         <div class="row" style="display:flex;justify-content:safe center;margin-top:10px;margin-bottom:10px;"> | |||
|             <RadzenButton Text="Print Barcode" Style="width:fit-content;margin-right:10px;background-color:forestgreen;" /> | |||
|             <RadzenButton Text="Print Tags" Style="width:fit-content;margin-right:10px;background-color:cornflowerblue;" /> | |||
|             <RadzenButton Text="Add Stock" Style="width:fit-content;background-color:#435971;" /> | |||
|         </div> | |||
|     } | |||
| 
 | |||
| </RadzenCard> | |||
| @ -0,0 +1,25 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Microsoft.AspNetCore.Components; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Product.Elements | |||
| { | |||
|     public partial class ProductDialog | |||
|     { | |||
|         [Parameter] | |||
|         public ProductItem Product { get; set; } | |||
| 
 | |||
|         private bool m_editMode { get; set; } = false; | |||
|         private List<ProductUnits> m_reorderUnits { get; set; } = new List<ProductUnits>(); | |||
|         protected override void OnParametersSet() | |||
|         { | |||
|             var list = Product.Units.Select(c => c.UnitCode); | |||
|             m_reorderUnits = m_productRepo.GetUnitofmeasures().Where(t => t.UnitCode == Product.BaseUnit || list.Contains(t.UnitCode)) | |||
|                 .Select(t => new ProductUnits | |||
|                 { | |||
|                     UnitCode = t.UnitCode, | |||
|                     UnitName = t.Unitname, | |||
|                 }).ToList(); | |||
|             base.OnParametersSet(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,29 @@ | |||
| @page "/products/inventory" | |||
| @using Biskilog_Accounting.Shared.CustomModels; | |||
| @using Biskilog_Accounting.Shared.Interfaces; | |||
| @inject IProduct m_productRepo | |||
| @inject ContextMenuService ContextMenuService | |||
| @inject DialogService m_dialogService | |||
| @inject ISearchService m_searchControl | |||
| @implements IDisposable | |||
| 
 | |||
| 
 | |||
| <div class="row" style="display:flex;justify-content:space-between;padding: 5px;margin-right:10px;"> | |||
|     <h3>Products</h3> | |||
| </div> | |||
| <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_products" TItem="ProductItem" GridLines="DataGridGridLines.Horizontal" | |||
|                 SelectionMode="DataGridSelectionMode.Single" @bind-Value=@m_selectedProducts CellContextMenu="@OnCellContextMenu"> | |||
|     <Columns> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="Product.Pcode" Title="Product ID" Width="15%" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="Product.ProductName" Title="Product Name" Width="20%" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="Product.Pdesc" Title="Description" Width="25%" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="Stock.Quantity" Title="Quantity" Width="10%" Resizable Reorderable /> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="BaseUnit" Title="Unit" Width="10%" Reorderable Resizable> | |||
|             <Template Context="detail"> | |||
|                 @(m_productRepo.GetUnitName(detail.BaseUnit)) | |||
|             </Template> | |||
|         </RadzenDataGridColumn> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="Product.Status" Title="Status" Width="10%" Reorderable Resizable /> | |||
|         <RadzenDataGridColumn TItem="ProductItem" Property="Product.BranchId" Title="Branch" Width="10%" Resizable Reorderable /> | |||
|     </Columns> | |||
| </RadzenDataGrid> | |||
| @ -0,0 +1,68 @@ | |||
| using Biskilog_Accounting.Client.Pages.Product.Elements; | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Radzen; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Product | |||
| { | |||
|     public partial class Products | |||
|     { | |||
|         private IEnumerable<ProductItem> m_products { get; set; } = Enumerable.Empty<ProductItem>(); | |||
|         private IList<ProductItem> m_selectedProducts { get; set; } = new List<ProductItem>(); | |||
| 
 | |||
|         protected override void OnInitialized() | |||
|         { | |||
|             m_productRepo.ProductsChanged += ProductsFetchComplete; | |||
|             m_searchControl.SearchValueChanged += SearchValueChanged; | |||
| 
 | |||
|             LoadProducts(string.Empty); | |||
|             base.OnInitialized(); | |||
|         } | |||
| 
 | |||
|         private void SearchValueChanged(string a_searchKey) | |||
|         { | |||
|             LoadProducts(a_searchKey); | |||
|         } | |||
| 
 | |||
|         public void Dispose() | |||
|         { | |||
|             m_productRepo.ProductsChanged -= ProductsFetchComplete; | |||
|             m_searchControl.SearchValueChanged -= SearchValueChanged; | |||
|         } | |||
|         private void ProductsFetchComplete(object? sender, EventArgs e) | |||
|         { | |||
|             LoadProducts(string.Empty); | |||
|         } | |||
|         private void LoadProducts(string a_productKey) | |||
|         { | |||
|             m_products = m_productRepo.GetProducts(a_productKey); | |||
|             StateHasChanged(); | |||
|         } | |||
|         private void OnCellContextMenu(DataGridCellMouseEventArgs<ProductItem> args) | |||
|         { | |||
|             m_selectedProducts = new List<ProductItem>() { args.Data }; | |||
| 
 | |||
|             ContextMenuService.Open(args, | |||
|                 new List<ContextMenuItem> { | |||
|                 new ContextMenuItem(){ Text = "Open", Value = 1 }, | |||
|                 new ContextMenuItem(){ Text = m_selectedProducts.First().Product!.Status == "INACTIVE" ? | |||
|                 "Activate" : "Deactivate", Value = 2}, | |||
|                 new ContextMenuItem(){ Text = "Change Price", Value = 3}, | |||
|                 new ContextMenuItem(){ Text = "Add Stock", Value = 4}, | |||
|                 new ContextMenuItem(){ Text = "View Performance History", Value = 5}, | |||
|                 }, | |||
|             (e) => | |||
|             { | |||
|                 OpenProductDialog(m_selectedProducts.First()); | |||
|                 Console.WriteLine($"Menu item with Value={e.Value} clicked. Column: {args.Column.Property}, EmployeeID: {args.Data.Product.Pcode}"); | |||
|             } | |||
|              ); | |||
|         } | |||
| 
 | |||
|         async Task OpenProductDialog(ProductItem a_productItem) | |||
|         { | |||
|             await m_dialogService.OpenAsync<ProductDialog>($"{a_productItem.Product!.ProductName}", | |||
|                new Dictionary<string, object>() { { "Product", a_productItem } }, | |||
|                new DialogOptions() { Width = "1020px", Height = "900px", Resizable = false, Draggable = true }); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,95 @@ | |||
| @page "/transactions/receipt/{receiptID}" | |||
| @using Biskilog_Accounting.Shared.Interfaces; | |||
| @using Biskilog_Accounting.Shared.POSModels; | |||
| @inject ICalculator m_calculator | |||
| @inject IProduct m_productRepo | |||
| @inject ISalesInterface m_saleInterface | |||
| @inject ICompanyInfo m_companyInfo | |||
| 
 | |||
| <div class="container" style="padding-top:10px;"> | |||
|     <div class="row"> | |||
|         <div class="row" style="display:grid;justify-content:center;"> | |||
|             <small>@(m_companyName)</small> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:center;"> | |||
|             <small>@m_branch?.BranchName</small> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:center;"> | |||
|             <small>@m_branch?.City</small> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:center;"> | |||
|             <small>@m_branch?.BranchTelephone</small> | |||
|         </div> | |||
|         <hr /> | |||
|         <div class="row" style="display:block;justify-content:space-between;"> | |||
|             <small> <em>Date</em> </small> | |||
|             <small> @m_date </small> | |||
|         </div> | |||
|         <div class="row" style="display:block;justify-content:space-between;"> | |||
|             <small> <em>Cashier</em> </small> | |||
|             <small> @m_cashier </small> | |||
|         </div> | |||
|         <div class="row" style="display:block;justify-content:space-between;"> | |||
|             <small> <em>Receipt Number</em> </small> | |||
|             <small> <em>@ReceiptId</em> </small> | |||
|         </div> | |||
|         <hr /> | |||
|         <RadzenDataGrid TItem="Tblcart" Data="ReceiptDetail" GridLines="DataGridGridLines.Horizontal" Style="padding:0px;"> | |||
|             <Columns> | |||
|                 <RadzenDataGridColumn TItem="Tblcart" Property="Transno" Title="Item" Width="60%"> | |||
|                     <Template Context="detail"> | |||
|                         <small>@detail.Id <br />x@(detail.Quantity) @(detail.Unit)</small> | |||
|                     </Template> | |||
|                 </RadzenDataGridColumn> | |||
|                 <RadzenDataGridColumn TItem="Tblcart" Property="Total" Title="Total" Width="40%"> | |||
|                     <Template Context="detail"> | |||
|                         <small>@(m_calculator.FormatMoneyWithCurrency((double)detail.Total))</small> | |||
|                     </Template> | |||
|                 </RadzenDataGridColumn> | |||
|             </Columns> | |||
|         </RadzenDataGrid> | |||
|         <div class="row" style="display:grid;justify-content:end;"> | |||
|             <RadzenStack Orientation="Radzen.Orientation.Horizontal"> | |||
|                 <small> <em>Sub Total</em> </small> | |||
|                 <small> <em>@m_subtotal</em> </small> | |||
|             </RadzenStack> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:end;"> | |||
|             <RadzenStack Orientation="Radzen.Orientation.Horizontal"> | |||
|                 <small> <em>Discount</em> </small> | |||
|                 <small> <em>@m_discount</em> </small> | |||
|             </RadzenStack> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:end;"> | |||
|             <RadzenStack Orientation="Radzen.Orientation.Horizontal"> | |||
|                 <small> <em>VAT</em> </small> | |||
|                 <small> <em>@m_vat</em> </small> | |||
|             </RadzenStack> | |||
|         </div> | |||
|         <hr /> | |||
|         <div class="row" style="display:grid;justify-content:end;"> | |||
|             <RadzenStack Orientation="Radzen.Orientation.Horizontal"> | |||
|                 <small> <em>Bill Total</em> </small> | |||
|                 <small> <em>@m_total</em> </small> | |||
|             </RadzenStack> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:end;"> | |||
|             <RadzenStack Orientation="Radzen.Orientation.Horizontal"> | |||
|                 <small> <em>Balance</em> </small> | |||
|                 <small> <em>@m_balance</em> </small> | |||
|             </RadzenStack> | |||
|         </div> | |||
|         <div class="row" style="display:grid;justify-content:end;"> | |||
|             <RadzenStack Orientation="Radzen.Orientation.Horizontal"> | |||
|                 <small> <em>Tendered</em> </small> | |||
|                 <small> <em>@m_tendered</em> </small> | |||
|             </RadzenStack> | |||
|         </div> | |||
|         <hr /> | |||
|         <div class="row" style="display:grid;justify-content:center;"> | |||
|             <small style="margin-bottom: 5px;margin-left: 20px"><em>COME BACK SOON !!! CHEERS</em> </small> | |||
|             <div id="barcode">@barcode</div> | |||
|             <div id="barcode_text">@barcode_text</div> | |||
|         </div> | |||
|     </div> | |||
| </div> | |||
| @ -0,0 +1,67 @@ | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Microsoft.AspNetCore.Components; | |||
| using Net.ConnectCode.Barcode; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Transactions.Elements | |||
| { | |||
|     public partial class ReceiptDialog | |||
|     { | |||
|         [Parameter] | |||
|         public string ReceiptId { get; set; } | |||
| 
 | |||
|         private IEnumerable<Tblcart> ReceiptDetail { get; set; } = Enumerable.Empty<Tblcart>(); | |||
|         string barcode = ""; | |||
|         string barcode_text = ""; | |||
|         private string m_balance { get; set; } | |||
|         private string m_tendered { get; set; } | |||
|         private string m_total { get; set; } | |||
|         private string m_subtotal { get; set; } | |||
|         private string m_discount { get; set; } = "0.00"; | |||
|         private string m_vat { get; set; } | |||
|         private string m_cashier { get; set; } | |||
|         private string m_date { get; set; } | |||
|         private Tblbranch m_branch { get; set; } | |||
|         private string m_companyName { get; set; } = string.Empty; | |||
|         void GenerateBarcode() | |||
|         { | |||
|             BarcodeFonts bcf = new BarcodeFonts(); | |||
|             bcf.BarcodeType = BarcodeFonts.BarcodeEnum.Code39; | |||
|             bcf.CheckDigit = BarcodeFonts.YesNoEnum.Yes; | |||
|             bcf.Data = ReceiptId; | |||
|             bcf.encode(); | |||
|             barcode = bcf.EncodedData; | |||
|             barcode_text = ReceiptId; | |||
|         } | |||
|         protected override async Task OnParametersSetAsync() | |||
|         { | |||
|             ReceiptDetail = await m_saleInterface.GetReceiptDetail(ReceiptId); | |||
|             SetParams(); | |||
|             GenerateBarcode(); | |||
|             StateHasChanged(); | |||
|             return; | |||
|         } | |||
|         private void SetParams() | |||
|         { | |||
|             if (ReceiptDetail.Count() > 0) | |||
|             { | |||
|                 double total = (double)ReceiptDetail.Sum(t => t.Total).Value; | |||
|                 double discount = (double)ReceiptDetail.First().Discount.Value; | |||
|                 double vat = (double)ReceiptDetail.First().ValueAddTax.Value; | |||
|                 double billTotal = (vat + total); | |||
| 
 | |||
|                 m_cashier = ReceiptDetail.First().Cashier; | |||
| 
 | |||
|                 m_subtotal = m_calculator.FormatMoneyWithCurrency(total); | |||
|                 m_tendered = m_calculator.FormatMoneyWithCurrency((double)ReceiptDetail.First().Tendered.Value); | |||
|                 m_balance = m_calculator.FormatMoneyWithCurrency((double)ReceiptDetail.First().Balance.Value); | |||
|                 m_vat = (vat).ToString("0.00") + "%"; | |||
|                 m_date = ReceiptDetail.First().Date.Value.ToString("dd MMMM, yyyy HH:mm:ss"); | |||
|                 m_total = m_calculator.FormatMoneyWithCurrency(billTotal); | |||
| 
 | |||
|                 string branchId = ReceiptDetail.First().BranchId; | |||
|                 m_branch = m_companyInfo.FetchBranches().ToList().First(t => t.BranchId == branchId); | |||
|                 m_companyName = m_companyInfo.GetCompanyName(); | |||
|             } | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,25 @@ | |||
| @using Biskilog_Accounting.Shared.Interfaces | |||
| @inject ICalculator m_calculator | |||
| <RadzenCard Style="margin-bottom:10px;"> | |||
|     <div class="row" style="margin:8px;display:grid;justify-content:center;"> | |||
|         @if (RecentTrans) | |||
|         { | |||
|             <h5>Transaction summary for the past @(TotalNbrTransactions) transactions</h5> | |||
|              | |||
|         }else{ | |||
|         <h5>Transaction summary for the period between : @(StartRange.ToString("dd MMM, yyyy")) to @(EndRange.ToString("dd MMM, yyyy"))</h5> | |||
|         } | |||
|     </div> | |||
|     <div class="row" style="margin:8px;"> | |||
|         <small>Total number of transactions made during the period : <b>@(TotalNbrTransactions)</b> </small> | |||
|     </div> | |||
|     <div class="row" style="margin:8px;"> | |||
|         <small>Total Revenue Generated during the period : <b>@(m_calculator.FormatMoneyWithCurrency(TotalRevenue))</b></small> | |||
|     </div> | |||
|     <div class="row" style="margin:8px;"> | |||
|         <small>Total number of cancelled transactions during the period : <b>@(TotalNbrCancelledRevenue)</b> </small> | |||
|     </div> | |||
|     <div class="row" style="margin:8px;"> | |||
|         <small>Total Revenue lost to cancelled receipts during the period : <b>@(m_calculator.FormatMoneyWithCurrency(TotalCancelledRevenue))</b></small> | |||
|     </div> | |||
| </RadzenCard> | |||
| @ -0,0 +1,24 @@ | |||
| using Microsoft.AspNetCore.Components; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Transactions.Elements | |||
| { | |||
|     public partial class SaleSummary | |||
|     { | |||
|         [Parameter] | |||
|         public DateTime StartRange { get; set; } | |||
|         [Parameter] | |||
|         public DateTime EndRange { get; set; } | |||
|         [Parameter] | |||
|         public double TotalRevenue { get; set; } | |||
|         [Parameter] | |||
|         public int TotalNbrTransactions { get; set; } | |||
|         [Parameter] | |||
|         public int TotalNbrCancelledRevenue { get; set; } | |||
|         [Parameter] | |||
|         public string TopSalesMan { get; set; } | |||
|         [Parameter] | |||
|         public double TotalCancelledRevenue { get; set; } | |||
|         [Parameter] | |||
|         public bool RecentTrans { get; set; } | |||
|     } | |||
| } | |||
| @ -0,0 +1,77 @@ | |||
| @page "/transactions/sales" | |||
| @using Biskilog_Accounting.Shared.CustomModels; | |||
| @using Biskilog_Accounting.Shared.Interfaces; | |||
| @using Biskilog_Accounting.Client.Pages.Transactions.Elements; | |||
| @using BlazorDateRangePicker | |||
| @using Faso.Blazor.SpinKit | |||
| @inject ICalculator m_calculator | |||
| @inject ISalesInterface m_salesRepo | |||
| @inject ContextMenuService ContextMenuService | |||
| @inject DialogService m_dialogService | |||
| @inject ISearchService m_searchControl | |||
| @implements IDisposable | |||
| @inject IMainInterface m_mainInterface | |||
| 
 | |||
| <h3>Sales</h3> | |||
| <div class="row" style="display:grid;justify-content:end;margin:5px;"> | |||
|     <DateRangePicker @bind-StartDate="m_startDate" @bind-EndDate="m_endDate" Ranges="m_ranges" ShowCustomRangeLabel="true" OnRangeSelect="@LoadTransactions"> | |||
|         <PickerTemplate> | |||
|             <div id="@context.Id" @onclick="context.Toggle" style="background: #fff; cursor: pointer; padding: 5px 10px; width: 250px; border: 1px solid #ccc;"> | |||
|                 <i class="tf-icons bx bx-calendar"></i>  | |||
|                 <span>@context.FormattedRange @(string.IsNullOrEmpty(context.FormattedRange) ? "Choose dates..." : "")</span> | |||
|                 <i class="oi oi-chevron-bottom float-right"></i> | |||
|             </div> | |||
|         </PickerTemplate> | |||
|         <ButtonsTemplate> | |||
|             <button class="cancelBtn btn btn-sm btn-default" | |||
|                     @onclick="@context.ClickCancel" type="button"> | |||
|                 Cancel | |||
|             </button> | |||
|             <button class="cancelBtn btn btn-sm btn-default" | |||
|                     @onclick="@(e => ResetClick(e, context))" type="button"> | |||
|                 Reset | |||
|             </button> | |||
|             <button class="applyBtn btn btn-sm btn-primary" @onclick="@context.ClickApply" | |||
|                     disabled="@(context.TStartDate == null || context.TEndDate == null)" | |||
|                     type="button"> | |||
|                 Apply | |||
|             </button> | |||
|         </ButtonsTemplate> | |||
|     </DateRangePicker> | |||
| </div> | |||
| @if (!m_lookUpMode) | |||
| { | |||
|     <SaleSummary StartRange="m_startDate.Value.LocalDateTime" EndRange="m_endDate.Value.LocalDateTime"  | |||
|     TotalRevenue="m_totalRevenue" TotalNbrTransactions="m_totalNbrRevenue" TotalCancelledRevenue="m_totalCancelledRevenue"  | |||
|     TotalNbrCancelledRevenue="m_totalNbrCancelled" RecentTrans="m_recent"/> | |||
| } | |||
| <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_salesItems" TItem="SaleItem" | |||
|                 GridLines="DataGridGridLines.Horizontal" RowClick="@(args => m_mainInterface.ShowReceipt(args.Data.Transno))"> | |||
|     <Columns> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="Transno" Title="Transaction ID" /> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="Date" Title="Timestamp" /> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="Cashier" Title="Cashier" /> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="Customer" Title="Customer" /> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="Status" Title="Status" Width="10%" /> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="Total" Title="Total"> | |||
|             <Template Context="detail"> | |||
|                 @( | |||
|                     m_calculator.FormatMoneyWithCurrency((double)detail.Total) | |||
|                     ) | |||
|             </Template> | |||
|         </RadzenDataGridColumn> | |||
|         <RadzenDataGridColumn TItem="SaleItem" Property="BranchId" Title="Branch" Resizable Reorderable /> | |||
|     </Columns> | |||
| </RadzenDataGrid> | |||
| 
 | |||
| @if (m_fetching) | |||
| { | |||
|     <div id="loading-div-background"> | |||
|         <div id="loading-div" class="ui-corner-all"> | |||
|             <div class="spinnermain-container"> | |||
|                 <SpinKitChasingDots /> | |||
|             </div> | |||
|             <h6 style="color:#fff;font-weight:normal;">Please wait fetching transaction details....</h6> | |||
|         </div> | |||
|     </div> | |||
| } | |||
| @ -0,0 +1,102 @@ | |||
| using Biskilog_Accounting.Client.Pages.Product; | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using BlazorDateRangePicker; | |||
| using Microsoft.AspNetCore.Components.Web; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Pages.Transactions | |||
| { | |||
|     public partial class Sales | |||
|     { | |||
|         private IEnumerable<SaleItem> m_salesItems { get; set; } = Enumerable.Empty<SaleItem>(); | |||
|         private DateTimeOffset? m_startDate { get; set; } = DateTimeOffset.Now; | |||
|         private DateTimeOffset? m_endDate { get; set; } = DateTimeOffset.Now; | |||
|         private Dictionary<string, DateRange> m_ranges = new Dictionary<string, DateRange>(); | |||
|         private double m_totalRevenue { get; set; } | |||
|         private double m_totalCancelledRevenue { get; set; } | |||
|         private int m_totalNbrRevenue { get; set; } | |||
|         private int m_totalNbrCancelled { get; set; } | |||
|         private bool m_lookUpMode { get; set; } | |||
|         private bool m_fetching { get; set; } | |||
|         private bool m_recent { get; set; } | |||
| 
 | |||
|         protected override void OnInitialized() | |||
|         { | |||
|             PopulateRange(); | |||
|             m_salesRepo.TransactionsChanged += TransactionsChanged; | |||
|             m_searchControl.SearchValueChanged += SearchValueChanged; | |||
|             m_salesRepo.FetchStart += FetchStart; | |||
|             m_salesRepo.FetchComplete += FetchComplete; | |||
| 
 | |||
|             m_salesItems = m_salesRepo.GetRecentTransaction(); | |||
|             SetParams(); | |||
|             m_recent = true; | |||
|             base.OnInitialized(); | |||
|         } | |||
| 
 | |||
|         private void FetchComplete(object? sender, EventArgs e) | |||
|         { | |||
|             m_fetching = false; | |||
|             StateHasChanged(); | |||
|         } | |||
| 
 | |||
|         private void FetchStart(object? sender, EventArgs e) | |||
|         { | |||
|             m_fetching = true; | |||
|             StateHasChanged(); | |||
|         } | |||
| 
 | |||
|         void ResetClick(MouseEventArgs e, DateRangePicker picker) | |||
|         { | |||
|             m_startDate = DateTimeOffset.UtcNow; | |||
|             m_endDate = DateTimeOffset.UtcNow; | |||
|             // Close the picker
 | |||
|             picker.Close(); | |||
|             // Fire OnRangeSelectEvent
 | |||
|             picker.OnRangeSelect.InvokeAsync(new DateRange()); | |||
|         } | |||
|         private void PopulateRange() | |||
|         { | |||
|             m_ranges.Clear(); | |||
|             m_ranges.Add("Today", new DateRange() { Start = DateTime.Now, End = DateTime.Now.AddDays(1) }); | |||
|             m_ranges.Add("Yesterday", new DateRange() { Start = DateTime.Now.AddDays(-1), End = DateTime.Now }); | |||
|             m_ranges.Add("Last 7 Days", new DateRange() { Start = DateTime.Now.AddDays(-7), End = DateTime.Now }); | |||
|             m_ranges.Add("Last 30 Days", new DateRange() { Start = DateTime.Now.AddDays(-30), End = DateTime.Now }); | |||
|         } | |||
|         private void TransactionsChanged(object? sender, EventArgs e) | |||
|         { | |||
|             m_salesItems = m_salesRepo.GetTransactions(m_startDate.Value.Date, m_endDate.Value.Date); | |||
|             SetParams(); | |||
|             StateHasChanged(); | |||
|         } | |||
| 
 | |||
|         private void SearchValueChanged(string a_searchKey) | |||
|         { | |||
|             m_salesRepo.FetchReceipt(a_searchKey); | |||
|             m_lookUpMode = !string.IsNullOrEmpty(a_searchKey); | |||
|         } | |||
| 
 | |||
|         public void Dispose() | |||
|         { | |||
|             m_salesRepo.TransactionsChanged -= TransactionsChanged; | |||
|             m_searchControl.SearchValueChanged -= SearchValueChanged; | |||
|             m_salesRepo.FetchStart -= FetchStart; | |||
|             m_salesRepo.FetchComplete -= FetchComplete; | |||
|         } | |||
|         private void SetParams() | |||
|         { | |||
|             m_totalRevenue = (double)m_salesItems.Where(c => c.Status == "SOLD").Sum(t => t.Total).Value; | |||
|             m_totalNbrRevenue = m_salesItems.Where(c => c.Status == "SOLD").Count(); | |||
|             m_totalNbrCancelled = m_salesItems.Where(c => c.Status != "SOLD").Count(); | |||
|             m_totalCancelledRevenue = (double)m_salesItems.Where(c => c.Status != "SOLD").Sum(t => t.Total).Value; | |||
|             m_recent = false; | |||
|         } | |||
|         private void LoadTransactions() | |||
|         { | |||
|             m_searchControl.SearchValueChanged -= SearchValueChanged; | |||
|             m_searchControl.Clear(); | |||
|             m_lookUpMode = false; | |||
|             m_salesRepo.FetchTransaction(m_startDate.Value.Date, m_endDate.Value.Date); | |||
|             m_searchControl.SearchValueChanged += SearchValueChanged; | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,98 @@ | |||
| using Biskilog_Accounting.Client.Pages.Transactions.Elements; | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Radzen; | |||
| using System.Text.Json; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Repos | |||
| { | |||
|     public class MainInterfaceService : IMainInterface, ICompanyInfo | |||
|     { | |||
|         private readonly HttpClient m_http; | |||
|         private readonly DialogService m_dialogService; | |||
|         private DateTime m_currentTradeDate; | |||
|         private DateTime m_previousTradeDate; | |||
|         private IEnumerable<Tblbranch> m_branches; | |||
|         private Tblcompanydetail m_info; | |||
| 
 | |||
|         public MainInterfaceService(DialogService a_dialogService, HttpClient http) | |||
|         { | |||
|             m_dialogService = a_dialogService; | |||
|             m_currentTradeDate = new DateTime(2023, 05, 01); | |||
|             m_previousTradeDate = new DateTime(2023, 04, 01); | |||
|             m_http = http; | |||
|              | |||
|         } | |||
| 
 | |||
|         async Task OpenReceiptDialog(string a_receiptId) | |||
|         { | |||
|             await m_dialogService.OpenSideAsync<ReceiptDialog>("Receipt", | |||
|                 new Dictionary<string, object>() { { "ReceiptId", a_receiptId } }, | |||
|                 options: new SideDialogOptions | |||
|                 { | |||
|                     CloseDialogOnOverlayClick = true, | |||
|                     Position = DialogPosition.Right, | |||
|                     ShowMask = true, | |||
|                     ShowTitle = false, | |||
|                 }); | |||
|         } | |||
|         public void ShowReceipt(string a_receiptId) | |||
|         { | |||
|             OpenReceiptDialog(a_receiptId); | |||
|         } | |||
| 
 | |||
|         public DateOnly CurrentTradeDate() | |||
|         { | |||
|             return DateOnly.FromDateTime(m_currentTradeDate); | |||
|         } | |||
| 
 | |||
|         public DateOnly PreviousTradeDate() | |||
|         { | |||
|             return DateOnly.FromDateTime(m_previousTradeDate); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<Tblbranch> FetchBranches() | |||
|         { | |||
|             return m_branches; | |||
|         } | |||
| 
 | |||
|         public async Task<Tblcompanydetail> GetCompanyInfoAsync() | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/companyinfo/info"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var recent = JsonSerializer.Deserialize<Tblcompanydetail>(jsonContent, options); | |||
|                 m_info = recent; | |||
|                 return recent; | |||
|             } | |||
|             return null; | |||
|         } | |||
| 
 | |||
|         public async Task<IEnumerable<Tblbranch>> GetBranches() | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/companyinfo/branches"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var recent = JsonSerializer.Deserialize<IEnumerable<Tblbranch>>(jsonContent, options); | |||
|                 m_branches = recent; | |||
|                 return recent; | |||
|             } | |||
|             return null; | |||
|         } | |||
| 
 | |||
|         public string GetCompanyName() | |||
|         { | |||
|             return m_info.CompanyName; | |||
|         } | |||
| 
 | |||
|         public string GetBranchName(string a_branchId) | |||
|         { | |||
|             return m_branches.First(b => b.BranchId == a_branchId).BranchName; | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,143 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using System.Text.Json; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using System.Text.RegularExpressions; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Repos | |||
| { | |||
|     public class ProductRepository : IProduct | |||
|     { | |||
|         private IEnumerable<ProductItem> m_products; | |||
|         private IEnumerable<Unitofmeasure> m_units; | |||
|         private IEnumerable<Tblbrand> m_brands; | |||
|         private IEnumerable<Tblcategory> m_categories; | |||
|         private readonly HttpClient m_http; | |||
| 
 | |||
|         public event EventHandler ProductsChanged; | |||
|         public event EventHandler UnitsChanged; | |||
|         public event EventHandler BrandsChanged; | |||
|         public event EventHandler CategoriesChanged; | |||
| 
 | |||
|         public ProductRepository(HttpClient a_http) | |||
|         { | |||
|             m_products = new List<ProductItem>(); | |||
|             m_units = new List<Unitofmeasure>(); | |||
|             m_brands = new List<Tblbrand>(); | |||
|             m_categories = new List<Tblcategory>(); | |||
|             m_http = a_http; | |||
|         } | |||
|         public async Task FetchProducts() | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/products/fetch"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var products = JsonSerializer.Deserialize<List<ProductItem>>(jsonContent, options); | |||
|                 m_products = products; | |||
|                 ProductsChanged?.Invoke(this, EventArgs.Empty); | |||
|             } | |||
|         } | |||
| 
 | |||
|         public ProductItem GetProductById(string a_id) | |||
|         { | |||
|             if (m_products.Count() > 0) | |||
|             { | |||
|                 return m_products.First(i => i.Product.Pcode == a_id); | |||
|             } | |||
|             return null; | |||
|         } | |||
| 
 | |||
|         public ProductItem GetProductByName(string name) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<ProductItem> GetProducts(string a_productKey) | |||
|         { | |||
|             a_productKey = Regex.Replace(a_productKey, @"\s", "").ToLower(); | |||
|             return m_products.Where(p => Regex.Replace(p.Product!.ProductName!, @"\s", "").ToLower().StartsWith(a_productKey) || | |||
|             Regex.Replace(p.Product!.Pcode!, @"\s", "").ToLower().StartsWith(a_productKey) || | |||
|             Regex.Replace(p.Product!.Pdesc!, @"\s", "").ToLower().StartsWith(a_productKey)); | |||
|         } | |||
| 
 | |||
|         public void RefreshList() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<Unitofmeasure> GetUnitofmeasures() | |||
|         { | |||
|             return m_units; | |||
|         } | |||
| 
 | |||
|         public async Task FetchUnits() | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/products/units"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var units = JsonSerializer.Deserialize<List<Unitofmeasure>>(jsonContent, options); | |||
|                 m_units = units; | |||
|                 UnitsChanged?.Invoke(this, EventArgs.Empty); | |||
|             } | |||
|         } | |||
| 
 | |||
|         public string GetUnitName(string a_unitCode) | |||
|         { | |||
|             return m_units?.FirstOrDefault(u => u.UnitCode == a_unitCode)?.Unitname; | |||
|         } | |||
| 
 | |||
|         public IEnumerable<Tblbrand> GetBrands(string a_brandKey = "") | |||
|         { | |||
|             a_brandKey = Regex.Replace(a_brandKey, @"\s", "").ToLower(); | |||
|             return m_brands.Where(b => Regex.Replace(b.Id, @"\s", "").ToLower().StartsWith(a_brandKey) || | |||
|             Regex.Replace(b.Brand!, @"\s", "").ToLower().StartsWith(a_brandKey)); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<Tblcategory> GetCategories(string a_categoryKey = "") | |||
|         { | |||
|             a_categoryKey = Regex.Replace(a_categoryKey, @"\s", "").ToLower(); | |||
|             return m_categories.Where(c => Regex.Replace(c.Id, @"\s", "").ToLower().StartsWith(a_categoryKey) || | |||
|             Regex.Replace(c.Category!, @"\s", "").ToLower().StartsWith(a_categoryKey)); | |||
|         } | |||
| 
 | |||
|         public async Task FetchBrands() | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/products/brands"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var brands = JsonSerializer.Deserialize<List<Tblbrand>>(jsonContent, options); | |||
|                 m_brands = brands; | |||
|                 BrandsChanged?.Invoke(this, EventArgs.Empty); | |||
|             } | |||
|         } | |||
| 
 | |||
|         public async Task FetchCategories() | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/products/categories"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var categories = JsonSerializer.Deserialize<List<Tblcategory>>(jsonContent, options); | |||
|                 m_categories = categories; | |||
|                 CategoriesChanged?.Invoke(this, EventArgs.Empty); | |||
|             } | |||
|         } | |||
| 
 | |||
|         public IEnumerable<ProductItem> GetLowstockItems() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public Task FetchLowStockProducts() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,98 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using System.Text.Json; | |||
| 
 | |||
| namespace Biskilog_Accounting.Client.Repos | |||
| { | |||
|     public class SalesRepository : ISalesInterface | |||
|     { | |||
|         private IEnumerable<SaleItem> m_transactions; | |||
|         private IEnumerable<SaleItem> m_recentTransactions; | |||
|         private readonly HttpClient m_http; | |||
| 
 | |||
|         public event EventHandler TransactionsChanged; | |||
|         public event EventHandler FetchComplete; | |||
|         public event EventHandler FetchStart; | |||
| 
 | |||
|         public SalesRepository(HttpClient a_http) | |||
|         { | |||
|             m_recentTransactions = m_transactions = new List<SaleItem>(); | |||
|             m_http = a_http; | |||
|         } | |||
| 
 | |||
|         public async Task FetchRecentTransaction(int a_limit) | |||
|         { | |||
|             FetchStart?.Invoke(this, EventArgs.Empty); | |||
|             var response = await m_http.GetAsync($"api/analytics/sales/recent/{a_limit}"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var recent = JsonSerializer.Deserialize<List<SaleItem>>(jsonContent, options); | |||
|                 m_recentTransactions = recent; | |||
|             } | |||
|             FetchComplete?.Invoke(this, EventArgs.Empty); | |||
|         } | |||
| 
 | |||
|         public async Task FetchTransaction(DateTime a_start, DateTime a_end) | |||
|         { | |||
|             FetchStart?.Invoke(this, EventArgs.Empty); | |||
|             string start = a_start.ToString("yyyy-MM-dd"); | |||
|             string end = a_end.ToString("yyyy-MM-dd"); | |||
|             var response = await m_http.GetAsync($"api/sales/transactions/{start}/{end}"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var recent = JsonSerializer.Deserialize<List<SaleItem>>(jsonContent, options); | |||
|                 m_transactions = recent; | |||
|                 TransactionsChanged?.Invoke(this, new EventArgs()); | |||
|             } | |||
|             FetchComplete?.Invoke(this, EventArgs.Empty); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<SaleItem> GetTransactions(DateTime a_start, DateTime a_end) | |||
|         { | |||
|             return m_transactions; | |||
|         } | |||
| 
 | |||
|         public IEnumerable<SaleItem> GetRecentTransaction() | |||
|         { | |||
|             return m_recentTransactions; | |||
|         } | |||
| 
 | |||
|         public async Task FetchReceipt(string a_receiptId) | |||
|         { | |||
|             FetchStart?.Invoke(this, EventArgs.Empty); | |||
|             var response = await m_http.GetAsync($"api/sales/transactions/lookup/{a_receiptId}"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var recent = JsonSerializer.Deserialize<List<SaleItem>>(jsonContent, options); | |||
|                 m_transactions = recent; | |||
|                 TransactionsChanged?.Invoke(this, new EventArgs()); | |||
|             } | |||
|             FetchComplete?.Invoke(this, EventArgs.Empty); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<SaleItem> GetReceipt(string a_receiptId) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public async Task<IEnumerable<Tblcart>> GetReceiptDetail(string a_receiptId) | |||
|         { | |||
|             var response = await m_http.GetAsync($"api/sales/receipt/lookup/{a_receiptId}"); | |||
|             if (response.IsSuccessStatusCode) | |||
|             { | |||
|                 var jsonContent = await response.Content.ReadAsStringAsync(); | |||
|                 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; | |||
|                 var recent = JsonSerializer.Deserialize<List<Tblcart>>(jsonContent, options); | |||
|                 return recent; | |||
|             } | |||
|             return null; | |||
|         } | |||
|     } | |||
| } | |||
| After Width: | Height: | Size: 19 KiB | 
								
									Binary file not shown.
								
							
						
					
								
									Binary file not shown.
								
							
						
					
								
									Binary file not shown.
								
							
						
					| @ -0,0 +1,37 @@ | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Http; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| 
 | |||
| namespace Biskilog_Accounting.Server.Controllers | |||
| { | |||
|     [Route("api/[controller]")]
 | |||
|     [ApiController] | |||
|     public class CompanyInfoController : ControllerBase | |||
|     { | |||
|         private readonly ICompanyInfo m_companyInfo; | |||
|         public CompanyInfoController(ICompanyInfo a_companyInfo) | |||
|         { | |||
|             m_companyInfo = a_companyInfo; | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return company information
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("info")] | |||
|         public Task<Tblcompanydetail> GetCompanyInfo() | |||
|         { | |||
|             return m_companyInfo.GetCompanyInfoAsync(); | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return branch information in the company
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("branches")] | |||
|         public Task<IEnumerable<Tblbranch>> Getbranches() | |||
|         { | |||
|             return m_companyInfo.GetBranches(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,55 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| 
 | |||
| namespace Biskilog_Accounting.Server.Controllers | |||
| { | |||
|     [Route("api/[controller]")]
 | |||
|     [ApiController] | |||
|     public class ProductsController : ControllerBase | |||
|     { | |||
|         private readonly IProduct m_productService; | |||
|         public ProductsController(IProduct a_productService) | |||
|         { | |||
|             m_productService = a_productService; | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return all units of measure for products
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("units")] | |||
|         public IEnumerable<Unitofmeasure> GetUnits() | |||
|         { | |||
|             return m_productService.GetUnitofmeasures(); | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return all products
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("fetch")] | |||
|         public IEnumerable<ProductItem> GetProducts() | |||
|         { | |||
|             return m_productService.GetProducts(); | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return all product categories
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("categories")] | |||
|         public IEnumerable<Tblcategory> GetCategories() | |||
|         { | |||
|             return m_productService.GetCategories(); | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return all product brands
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("brands")] | |||
|         public IEnumerable<Tblbrand> GetBrands() | |||
|         { | |||
|             return m_productService.GetBrands(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,49 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Http; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| 
 | |||
| namespace Biskilog_Accounting.Server.Controllers | |||
| { | |||
|     [Route("api/[controller]")]
 | |||
|     [ApiController] | |||
|     public class SalesController : ControllerBase | |||
|     { | |||
|         private readonly ISalesInterface m_salesService; | |||
|         public SalesController(ISalesInterface a_salesService) | |||
|         { | |||
|             m_salesService = a_salesService; | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return Sales within a specified period
 | |||
|         /// </summary>
 | |||
|         /// <param name="a_start"></param>
 | |||
|         /// <param name="a_end"></param>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("transactions/{a_start}/{a_end}")] | |||
|         public IEnumerable<SaleItem> GetSalesAsync(DateTime a_start, DateTime a_end) | |||
|         { | |||
|             return m_salesService.GetTransactions(a_start, a_end); | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return Sales using the specified transaction id
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("transactions/lookup/{a_receipt}")] | |||
|         public IEnumerable<SaleItem> GetSaleAsync(string a_receipt) | |||
|         { | |||
|             return m_salesService.GetReceipt(a_receipt); | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Endpoint to return receipt details
 | |||
|         /// </summary>
 | |||
|         [Authorize] | |||
|         [HttpGet, Route("receipt/lookup/{a_receipt}")] | |||
|         public IEnumerable<Tblcart> GetReceiptAsync(string a_receipt) | |||
|         { | |||
|             return m_salesService.GetReceiptDetail(a_receipt).Result.ToList(); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,53 @@ | |||
| using Biskilog_Accounting.Server.POSModels; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| 
 | |||
| namespace Biskilog_Accounting.Server.Services | |||
| { | |||
|     public class CompanyService : ICompanyInfo | |||
|     { | |||
|         private readonly BiskAcdbContext m_context; | |||
|         private readonly ITokenService m_tokenService; | |||
|         private readonly HttpContext m_httpContext; | |||
| 
 | |||
|         private Tblcompanydetail m_companyInfo { get; set; } | |||
|         private IEnumerable<Tblbranch> m_companyBranches { get; set; } | |||
|         public CompanyService(BiskAcdbContext a_context, ITokenService a_tokenService, IHttpContextAccessor a_httpContextAccessor) | |||
|         { | |||
|             m_context = a_context; | |||
|             m_tokenService = a_tokenService; | |||
|             m_httpContext = a_httpContextAccessor?.HttpContext; | |||
|             m_companyInfo = new Tblcompanydetail(); | |||
|             m_companyBranches = new List<Tblbranch>(); | |||
|              | |||
|             GetCompanyInfoAsync(); | |||
|             GetBranches(); | |||
|         } | |||
|         public IEnumerable<Tblbranch> FetchBranches() | |||
|         { | |||
|             return m_companyBranches; | |||
|         } | |||
| 
 | |||
|         public async Task<IEnumerable<Tblbranch>> GetBranches() | |||
|         { | |||
|             m_companyBranches = m_context.Tblbranches; | |||
|             return await Task.FromResult(m_companyBranches); | |||
|         } | |||
| 
 | |||
|         public string GetBranchName(string a_branchId) | |||
|         { | |||
|             return m_companyBranches.FirstOrDefault(b => b.BranchId == a_branchId).BranchName; | |||
|         } | |||
| 
 | |||
|         public Task<Tblcompanydetail> GetCompanyInfoAsync() | |||
|         { | |||
|             m_companyInfo = m_context.Tblcompanydetails.First(); | |||
|             return Task.FromResult(m_companyInfo); | |||
|         } | |||
| 
 | |||
|         public string GetCompanyName() | |||
|         { | |||
|             return m_companyInfo.CompanyName; | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,200 @@ | |||
| using Biskilog_Accounting.Server.POSModels; | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Enums; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using Microsoft.Net.Http.Headers; | |||
| using MySqlConnector; | |||
| using System.Data; | |||
| using System.Data.Common; | |||
| 
 | |||
| namespace Biskilog_Accounting.Server.Services | |||
| { | |||
|     public class ProductRepo : IProduct | |||
|     { | |||
|         private readonly BiskAcdbContext m_context; | |||
|         private readonly ITokenService m_tokenService; | |||
|         private readonly HttpContext m_httpContext; | |||
| 
 | |||
|         public event EventHandler ProductsChanged; | |||
|         public event EventHandler UnitsChanged; | |||
|         public event EventHandler BrandsChanged; | |||
|         public event EventHandler CategoriesChanged; | |||
| 
 | |||
|         public ProductRepo(BiskAcdbContext a_context, ITokenService a_tokenService, IHttpContextAccessor a_httpContextAccessor) | |||
|         { | |||
|             m_context = a_context; | |||
|             m_tokenService = a_tokenService; | |||
|             m_httpContext = a_httpContextAccessor?.HttpContext; | |||
|         } | |||
|         /// <summary>
 | |||
|         /// Gets all products from the server
 | |||
|         /// </summary>
 | |||
|         /// <returns></returns>
 | |||
|         public IEnumerable<ProductItem> GetProducts(string a_productKey = "") | |||
|         { | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 using (var command = m_context.Database.GetDbConnection().CreateCommand()) | |||
|                 { | |||
|                     command.CommandText = "CALL GetProducts(@p0)"; | |||
|                     command.Parameters.Add(new MySqlParameter("@p0", string.Join(", ", accessiblebranches.ToArray()))); | |||
| 
 | |||
|                     m_context.Database.OpenConnection(); | |||
| 
 | |||
|                     using (var reader = command.ExecuteReader()) | |||
|                     { | |||
|                         while (reader.Read()) | |||
|                         { | |||
|                             List<ProductUnits> pUnits = new List<ProductUnits>(); | |||
| 
 | |||
|                             yield return new ProductItem | |||
|                             { | |||
|                                 Product = new Tblproduct | |||
|                                 { | |||
|                                     Pcode = reader.GetString(0), | |||
|                                     ProductName = reader.GetString(1), | |||
|                                     Pdesc = reader.GetString(2), | |||
|                                     BaseUnit = reader.GetString(3), | |||
|                                     Costprice = reader.GetDecimal(4), | |||
|                                     Status = reader.GetString(5), | |||
|                                     Price = reader.GetDecimal(6), | |||
|                                     BranchId = reader.GetString(7), | |||
|                                 }, | |||
|                                 BaseUnit = reader.GetString(3), | |||
|                                 Stock = new Tblinventory | |||
|                                 { | |||
|                                     Quantity = reader.GetInt32(8) | |||
|                                 }, | |||
|                                 Restocklevel = new Restocklevel | |||
|                                 { | |||
|                                     WarnLevel = reader.GetInt32(9), | |||
|                                     Unit = reader.GetString(10), | |||
|                                 }, | |||
|                                 Units = GetAltUnits(reader) | |||
|                             }; | |||
|                         } | |||
|                     } | |||
|                 } | |||
|             } | |||
|         } | |||
|         private List<ProductUnits> GetAltUnits(DbDataReader a_reader) | |||
|         { | |||
|             List<ProductUnits> pUnits = new List<ProductUnits>(); | |||
|             for (int i = 1; i < 5; i++) | |||
|             { | |||
|                 if (!a_reader.IsDBNull(a_reader.GetOrdinal($"AltUnit{i}"))) | |||
|                 { | |||
|                     pUnits.Add(new ProductUnits | |||
|                     { | |||
|                         UnitCode = a_reader.GetFieldValue<string>($"AltUnit{i}"), | |||
|                         QuantityUnit = a_reader.GetFieldValue<int>($"AltUnit{i}QTY"), | |||
|                         PriceUnit = a_reader.GetFieldValue<decimal>($"AltUnit{i}Price"), | |||
|                         DistinctiveCode = a_reader.GetFieldValue<string>($"AltUnit{i}distinctiveCode") | |||
|                     }); | |||
|                 } | |||
|                 else | |||
|                 { | |||
|                     return pUnits; | |||
|                 } | |||
|             } | |||
|             return pUnits; | |||
|         } | |||
| 
 | |||
|         public IEnumerable<Unitofmeasure> GetUnitofmeasures() | |||
|         { | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 return m_context.Unitofmeasures.Where(b => accessiblebranches.Contains(b.BranchId)); | |||
|             } | |||
|             return new List<Unitofmeasure>(); | |||
|         } | |||
| 
 | |||
| 
 | |||
| 
 | |||
|         public IEnumerable<Tblbrand> GetBrands(string a_brandKey = "") | |||
|         { | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 return m_context.Tblbrands.Where(b => accessiblebranches.Contains(b.BranchId)); | |||
|             } | |||
|             return new List<Tblbrand>(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<Tblcategory> GetCategories(string a_categoryKey = "") | |||
|         { | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 return m_context.Tblcategories.Where(b => accessiblebranches.Contains(b.BranchId)); | |||
|             } | |||
|             return new List<Tblcategory>(); | |||
|         } | |||
| 
 | |||
|         #region Only Need to implement in the client Side
 | |||
|         public Task FetchUnits() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
|         public Task FetchProducts() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public ProductItem GetProductById(string a_id) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public ProductItem GetProductByName(string name) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public void RefreshList() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public string GetUnitName(string a_unitCode) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
|         public Task FetchBrands() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public Task FetchCategories() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<ProductItem> GetLowstockItems() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public Task FetchLowStockProducts() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
|     } | |||
|     #endregion
 | |||
| } | |||
| @ -0,0 +1,169 @@ | |||
| using Biskilog_Accounting.Server.POSModels; | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.Enums; | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using Microsoft.Net.Http.Headers; | |||
| using MySqlConnector; | |||
| using System.Drawing.Drawing2D; | |||
| 
 | |||
| namespace Biskilog_Accounting.Server.Services | |||
| { | |||
|     public class SalesService : ISalesInterface | |||
|     { | |||
|         private readonly BiskAcdbContext m_context; | |||
|         private readonly ITokenService m_tokenService; | |||
|         private readonly HttpContext m_httpContext; | |||
| 
 | |||
|         public event EventHandler TransactionsChanged; | |||
|         public event EventHandler FetchComplete; | |||
|         public event EventHandler FetchStart; | |||
| 
 | |||
|         public SalesService(BiskAcdbContext a_context, ITokenService a_tokenService, IHttpContextAccessor a_httpContextAccessor) | |||
|         { | |||
|             m_context = a_context; | |||
|             m_tokenService = a_tokenService; | |||
|             m_httpContext = a_httpContextAccessor?.HttpContext; | |||
|         } | |||
| 
 | |||
|         public Task FetchRecentTransaction(int a_limit) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<SaleItem> GetRecentTransaction() | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<SaleItem> GetTransactions(DateTime a_start, DateTime a_end) | |||
|         { | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 using (var command = m_context.Database.GetDbConnection().CreateCommand()) | |||
|                 { | |||
|                     command.CommandText = "CALL GetTransactionsByDate(@p0,@p1,@p2)"; | |||
|                     command.Parameters.Add(new MySqlParameter("@p0", a_start.ToString("yyyy-MM-dd"))); | |||
|                     command.Parameters.Add(new MySqlParameter("@p1", a_end.ToString("yyyy-MM-dd"))); | |||
|                     command.Parameters.Add(new MySqlParameter("@p2", string.Join(", ", accessiblebranches.ToArray()))); | |||
| 
 | |||
|                     m_context.Database.OpenConnection(); | |||
| 
 | |||
|                     using (var reader = command.ExecuteReader()) | |||
|                     { | |||
|                         while (reader.Read()) | |||
|                         { | |||
|                             yield return new SaleItem | |||
|                             { | |||
|                                 Transno = reader.GetString(0), | |||
|                                 Total = (decimal)reader.GetDouble(1), | |||
|                                 Date = reader.GetDateTime(2), | |||
|                                 Cashier = reader.GetString(3), | |||
|                                 BranchId = reader.GetString(4), | |||
|                                 Customer = reader.GetString(5), | |||
|                                 Status = reader.GetString(6), | |||
|                             }; | |||
|                         } | |||
|                     } | |||
|                 } | |||
|             } | |||
|         } | |||
| 
 | |||
|         public Task FetchTransaction(DateTime a_start, DateTime a_end) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public Task FetchReceipt(string a_receiptId) | |||
|         { | |||
|             throw new NotImplementedException(); | |||
|         } | |||
| 
 | |||
|         public IEnumerable<SaleItem> GetReceipt(string a_receiptId) | |||
|         { | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 using (var command = m_context.Database.GetDbConnection().CreateCommand()) | |||
|                 { | |||
|                     command.CommandText = "CALL GetTransactionsById(@p0,@p1)"; | |||
|                     command.Parameters.Add(new MySqlParameter("@p0", a_receiptId)); | |||
|                     command.Parameters.Add(new MySqlParameter("@p1", string.Join(", ", accessiblebranches.ToArray()))); | |||
| 
 | |||
|                     m_context.Database.OpenConnection(); | |||
| 
 | |||
|                     using (var reader = command.ExecuteReader()) | |||
|                     { | |||
|                         while (reader.Read()) | |||
|                         { | |||
|                             yield return new SaleItem | |||
|                             { | |||
|                                 Transno = reader.GetString(0), | |||
|                                 Total = (decimal)reader.GetDouble(1), | |||
|                                 Date = reader.GetDateTime(2), | |||
|                                 Cashier = reader.GetString(3), | |||
|                                 BranchId = reader.GetString(4), | |||
|                                 Customer = reader.GetString(5), | |||
|                                 Status = reader.GetString(6), | |||
|                             }; | |||
|                         } | |||
|                     } | |||
|                 } | |||
|             } | |||
|         } | |||
| 
 | |||
|         public Task<IEnumerable<Tblcart>> GetReceiptDetail(string a_receiptId) | |||
|         { | |||
|             List<Tblcart> details = new List<Tblcart>(); | |||
|             string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; | |||
| 
 | |||
|             if (AuthEnums.Valid == m_tokenService.ValidateToken(token)) | |||
|             { | |||
|                 IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); | |||
| 
 | |||
|                 using (var command = m_context.Database.GetDbConnection().CreateCommand()) | |||
|                 { | |||
|                     command.CommandText = "CALL GetReceiptDetails(@p0,@p1)"; | |||
|                     command.Parameters.Add(new MySqlParameter("@p0", a_receiptId)); | |||
|                     command.Parameters.Add(new MySqlParameter("@p1", string.Join(", ", accessiblebranches.ToArray()))); | |||
| 
 | |||
|                     m_context.Database.OpenConnection(); | |||
| 
 | |||
|                     using (var reader = command.ExecuteReader()) | |||
|                     { | |||
|                         while (reader.Read()) | |||
|                         { | |||
|                             details.Add(new Tblcart | |||
|                             { | |||
|                                 Transno = a_receiptId, | |||
|                                 Id = reader.GetString(0), | |||
|                                 Quantity = reader.GetInt32(1), | |||
|                                 Date = reader.GetDateTime(2), | |||
|                                 Price = reader.GetDecimal(3), | |||
|                                 Cashier = reader.GetString(4), | |||
|                                 Status = reader.GetString(5), | |||
|                                 Total = (decimal)reader.GetDouble(6), | |||
|                                 Unit = reader.GetString(7), | |||
|                                 Costprice = reader.GetDecimal(8), | |||
|                                 BranchId = reader.GetString(9), | |||
|                                 CountId = reader.GetString(10), | |||
|                                 Tendered = reader.GetDecimal(11), | |||
|                                 Balance = reader.GetDecimal(12), | |||
|                                 ValueAddTax = reader.GetDecimal(13) | |||
|                             }); | |||
|                         } | |||
|                     } | |||
|                 } | |||
|             } | |||
|             return Task.FromResult(details.AsEnumerable()); | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,26 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.CustomModels | |||
| { | |||
|     public class ProductUnits | |||
|     { | |||
|         public string? Pcode { get; set; } | |||
| 
 | |||
|         public string? UnitCode { get; set; } | |||
|         public string? UnitName { get; set; } | |||
| 
 | |||
|         public string? UnitBarcode { get; set; } | |||
| 
 | |||
|         public decimal? PriceUnit { get; set; } | |||
| 
 | |||
|         public int? QuantityUnit { get; set; } | |||
| 
 | |||
|         public string DistinctiveCode { get; set; } = null!; | |||
| 
 | |||
|         public string BranchId { get; set; } = null!; | |||
|     } | |||
| } | |||
| @ -0,0 +1,18 @@ | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.Interfaces | |||
| { | |||
|     public interface ICompanyInfo | |||
|     { | |||
|         IEnumerable<Tblbranch> FetchBranches(); | |||
|         Task<Tblcompanydetail> GetCompanyInfoAsync(); | |||
|         Task<IEnumerable<Tblbranch>> GetBranches(); | |||
|         string GetCompanyName(); | |||
|         string GetBranchName(string a_branchId); | |||
|     } | |||
| } | |||
| @ -0,0 +1,15 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.Interfaces | |||
| { | |||
|     public interface IMainInterface | |||
|     { | |||
|         void ShowReceipt(string a_receipt); | |||
|         DateOnly CurrentTradeDate(); | |||
|         DateOnly PreviousTradeDate(); | |||
|     } | |||
| } | |||
| @ -0,0 +1,32 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.Interfaces | |||
| { | |||
|     public interface IProduct | |||
|     { | |||
|         IEnumerable<Unitofmeasure> GetUnitofmeasures(); | |||
|         IEnumerable<ProductItem> GetProducts(string a_productKey = ""); | |||
|         IEnumerable<Tblbrand> GetBrands(string a_brandKey = ""); | |||
|         IEnumerable<Tblcategory> GetCategories(string a_categoryKey = ""); | |||
|         IEnumerable<ProductItem> GetLowstockItems(); | |||
|         Task FetchProducts(); | |||
|         Task FetchLowStockProducts(); | |||
|         Task FetchUnits(); | |||
|         Task FetchBrands(); | |||
|         Task FetchCategories(); | |||
|         void RefreshList(); | |||
|         ProductItem GetProductById(string a_id); | |||
|         ProductItem GetProductByName(string name); | |||
|         string GetUnitName(string a_unitCode); | |||
|         event EventHandler ProductsChanged; | |||
|         event EventHandler UnitsChanged; | |||
|         event EventHandler BrandsChanged; | |||
|         event EventHandler CategoriesChanged; | |||
|     } | |||
| } | |||
| @ -0,0 +1,24 @@ | |||
| using Biskilog_Accounting.Shared.CustomModels; | |||
| using Biskilog_Accounting.Shared.POSModels; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.Interfaces | |||
| { | |||
|     public interface ISalesInterface | |||
|     { | |||
|         Task FetchRecentTransaction(int a_limit); | |||
|         Task FetchTransaction(DateTime a_start, DateTime a_end); | |||
|         IEnumerable<SaleItem> GetTransactions(DateTime a_start, DateTime a_end); | |||
|         IEnumerable<SaleItem> GetRecentTransaction(); | |||
|         Task FetchReceipt(string a_receiptId); | |||
|         IEnumerable<SaleItem> GetReceipt(string a_receiptId); | |||
|         Task<IEnumerable<Tblcart>> GetReceiptDetail(string a_receiptId); | |||
|         event EventHandler TransactionsChanged; | |||
|         event EventHandler FetchComplete; | |||
|         event EventHandler FetchStart; | |||
|     } | |||
| } | |||
| @ -0,0 +1,16 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.Interfaces | |||
| { | |||
|     public interface ISearchService | |||
|     { | |||
|         public event Action<string> SearchValueChanged; | |||
|         public event Action ClearTextBox; | |||
|         void PerformSearch(string a_searchKey); | |||
|         void Clear(); | |||
|     } | |||
| } | |||
| @ -0,0 +1,33 @@ | |||
| using Biskilog_Accounting.Shared.Interfaces; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| 
 | |||
| namespace Biskilog_Accounting.Shared.ServiceRepo | |||
| { | |||
|     public class SearchService : ISearchService | |||
|     { | |||
|         public event Action<string> SearchValueChanged; | |||
|         public event Action ClearTextBox; | |||
| 
 | |||
|         // Method that raises the event
 | |||
|         protected virtual void OnSearchValueChanged(string a_searchKey) | |||
|         { | |||
|             SearchValueChanged?.Invoke(a_searchKey); | |||
|         } | |||
| 
 | |||
|         // Method that triggers the event
 | |||
|         public void PerformSearch(string a_searchKey) | |||
|         { | |||
|             OnSearchValueChanged(a_searchKey); | |||
|         } | |||
| 
 | |||
|         public void Clear() | |||
|         { | |||
|             ClearTextBox?.Invoke(); | |||
|         } | |||
|     } | |||
| 
 | |||
| } | |||
					Loading…
					
					
				
		Reference in new issue