Browse Source

Added Users and Customers page

pull/14/head
Benjamin Arhen 2 years ago
parent
commit
2cb95bb84a
  1. 95
      Client/Elements/Headbar.razor
  2. 2
      Client/Layouts/MainLayout.razor
  3. 13
      Client/Layouts/MainLayout.razor.cs
  4. 44
      Client/Models/NavItem.cs
  5. 38
      Client/Pages/Customers/Customers.razor
  6. 17
      Client/Pages/Customers/Customers.razor.cs
  7. 2
      Client/Pages/Dashboard/Dashboard.razor.cs
  8. 26
      Client/Pages/Dashboard/Elements/ChartElement.razor.cs
  9. 10
      Client/Pages/Dashboard/Elements/ProductPriceHistory.razor.cs
  10. 1
      Client/Pages/Product/Brands.razor
  11. 1
      Client/Pages/Product/Categories.razor
  12. 1
      Client/Pages/Product/Products.razor
  13. 23
      Client/Pages/Users/Users.razor
  14. 17
      Client/Pages/Users/Users.razor.cs
  15. 2
      Client/Program.cs
  16. 44
      Client/Repos/MainInterfaceService.cs
  17. 2
      Client/wwwroot/assets/vendor/css/theme-default.css
  18. 18752
      Client/wwwroot/css/app.css
  19. 4
      Client/wwwroot/index.html
  20. 2
      Server/Controllers/AnalyticsController.cs
  21. 29
      Server/Controllers/CustomerController.cs
  22. 28
      Server/Controllers/UsersController.cs
  23. 2
      Server/Program.cs
  24. 4
      Server/Services/AnalyticalService.cs
  25. 71
      Server/Services/CustomerService.cs
  26. 43
      Server/Services/UserService.cs
  27. 2
      Shared/CustomModels/CustomerAccounts.cs
  28. 2
      Shared/Interfaces/IAnalytics.cs
  29. 11
      Shared/Interfaces/ICustomer.cs
  30. 15
      Shared/Interfaces/IUser.cs

95
Client/Elements/Headbar.razor

@ -27,102 +27,7 @@
<!-- /Search --> <!-- /Search -->
<ul class="navbar-nav flex-row align-items-center ms-auto"> <ul class="navbar-nav flex-row align-items-center ms-auto">
@*<!-- Place this tag where you want the button to render. -->
<li class="nav-item lh-1 me-3">
<a class="github-button"
href="https://github.com/themeselection/sneat-html-admin-template-free"
data-icon="octicon-star"
data-size="large"
data-show-count="true"
aria-label="Star themeselection/sneat-html-admin-template-free on GitHub">Star</a>
</li>*@
<RadzenButton Variant="Variant.Outlined" Text="New" Icon="add_circle_outline" ButtonStyle="ButtonStyle.Success" />
<li class="nav-item dropdown notification-ui show">
<a class="nav-link dropdown-toggle notification-ui_icon" href="javascript:void()" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-bell"></i>
<span class="unread-notification"></span>
</a>
<div class="dropdown-menu notification-ui_dd show" aria-labelledby="navbarDropdown">
<div class="notification-ui_dd-header">
<small class="text-center">Notification</small>
</div>
<div class="notification-ui_dd-content">
<a href="#!" class="notification-list notification-list--unread text-dark">
<div class="notification-list_img">
<img src="images/users/user1.jpg" alt="user">
</div>
<div class="notification-list_detail">
<p><b>John Doe</b> <br><span class="text-muted">reacted to your post</span></p>
<p class="nt-link text-truncate">How to travel long way home from here.</p>
</div>
<p><small>10 mins ago</small></p>
</a>
</div>
<div class="notification-ui_dd-footer">
<a href="#!" class="btn btn-success btn-block">View All</a>
</div>
</div>
</li>
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
<div class="avatar avatar-online">
<img src="../assets/img/avatars/1.png" alt class="w-px-40 h-auto rounded-circle" />
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar-online">
<img src="../assets/img/avatars/1.png" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block">John Doe</span>
<small class="text-muted">Admin</small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="#">
<i class="bx bx-user me-2"></i>
<span class="align-middle">My Profile</span>
</a>
</li>
<li>
<a class="dropdown-item" href="#">
<i class="bx bx-cog me-2"></i>
<span class="align-middle">Settings</span>
</a>
</li>
<li>
<a class="dropdown-item" href="#">
<span class="d-flex align-items-center align-middle">
<i class="flex-shrink-0 bx bx-credit-card me-2"></i>
<span class="flex-grow-1 align-middle">Billing</span>
<span class="flex-shrink-0 badge badge-center rounded-pill bg-danger w-px-20 h-px-20">4</span>
</span>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="auth-login-basic.html">
<i class="bx bx-power-off me-2"></i>
<span class="align-middle">Log Out</span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul> </ul>
</div> </div>
</nav> </nav>

2
Client/Layouts/MainLayout.razor

@ -9,6 +9,8 @@
@inject DialogService m_dialogService @inject DialogService m_dialogService
@inject ISalesInterface m_salesService @inject ISalesInterface m_salesService
@inject ICompanyInfo m_companyInfo @inject ICompanyInfo m_companyInfo
@inject IUser m_userService
@inject ICustomer m_customerService
<RadzenDialog /> <RadzenDialog />
<RadzenContextMenu /> <RadzenContextMenu />

13
Client/Layouts/MainLayout.razor.cs

@ -20,6 +20,8 @@ namespace Biskilog_Accounting.Client.Layouts
var fetchBrands = m_productRepo.FetchBrands(); var fetchBrands = m_productRepo.FetchBrands();
var fetchCategories = m_productRepo.FetchCategories(); var fetchCategories = m_productRepo.FetchCategories();
var fetchRecentSale = m_salesService.FetchRecentTransaction(250); var fetchRecentSale = m_salesService.FetchRecentTransaction(250);
var fetchUsers = m_userService.GetUsers();
var fetchCustomers = m_customerService.GetCustomers();
// Wait for all tasks to complete // Wait for all tasks to complete
await Task.WhenAll( await Task.WhenAll(
fetchCompanyData, fetchCompanyData,
@ -28,7 +30,8 @@ namespace Biskilog_Accounting.Client.Layouts
fetchUnits, fetchUnits,
fetchBrands, fetchBrands,
fetchCategories, fetchCategories,
fetchRecentSale fetchRecentSale,
fetchUsers
); );
}); });
@ -58,8 +61,12 @@ namespace Biskilog_Accounting.Client.Layouts
} }
async Task OpenReceiptDialog() async Task OpenReceiptDialog()
{ {
await m_dialogService.OpenSideAsync<ReceiptDialog>("Receipt", options: new SideDialogOptions { await m_dialogService.OpenSideAsync<ReceiptDialog>("Receipt", options: new SideDialogOptions
CloseDialogOnOverlayClick = true, Position = DialogPosition.Right,ShowMask = true }); {
CloseDialogOnOverlayClick = true,
Position = DialogPosition.Right,
ShowMask = true
});
} }
} }
} }

44
Client/Models/NavItem.cs

@ -104,13 +104,13 @@
// Title = "Bulk Price Changes", // Title = "Bulk Price Changes",
// Link = "", // Link = "",
//}, //},
new NavItem //new NavItem
{ //{
Id = 3.5, // Id = 3.5,
Description = "Inventory", // Description = "Inventory",
Title = "Products Statistics", // Title = "Products Statistics",
Link = "", // Link = "",
} //}
} }
}, },
@ -131,22 +131,22 @@
Link = "users", Link = "users",
Title = "Users" Title = "Users"
}, },
new NavItem() //new NavItem()
{ // {
Id = 6, // Id = 6,
Description = "Warehouse Management", // Description = "Warehouse Management",
Icon = "bxs-factory", // Icon = "bxs-factory",
Title = "Warehouse Management", // Title = "Warehouse Management",
Children = new List<NavItem> { // Children = new List<NavItem> {
new NavItem(){ // new NavItem(){
Id = 6.1, // Id = 6.1,
Description = "Item Inventory for the warehouse", // Description = "Item Inventory for the warehouse",
Title = "Inventory", // Title = "Inventory",
Link = "", // Link = "",
}, // },
}, // },
}, // },
}; };

38
Client/Pages/Customers/Customers.razor

@ -0,0 +1,38 @@
@page "/customers"
@using Biskilog_Accounting.Shared.CustomModels;
@using Biskilog_Accounting.Shared.Interfaces;
@using Biskilog_Accounting.Client.Pages.Transactions.Elements;
@using BlazorDateRangePicker;
@inject ICalculator m_calculator
@inject ContextMenuService ContextMenuService
@inject DialogService m_dialogService
@inject ISearchService m_searchControl
@implements IDisposable
@inject IMainInterface m_mainInterface
@inject ICustomer m_customerService
<h3>Customers</h3>
<RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_customers" TItem="CustomerAccounts"
GridLines="DataGridGridLines.Horizontal">
<Columns>
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.Firstname" Title="Name">
<Template Context="detail">
@(detail.Customer.Firstname + " ") @(detail.Customer.Surname)
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.Telephone" Title="Telephone" />
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.Address" Title="Address" />
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.DateAdded" Title="Date Added" />
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.Status" Title="Status" Width="10%" />
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.Debt" Title="Balance">
<Template Context="detail">
@(
m_calculator.FormatMoneyWithCurrency((double)detail.Debt)
)
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="CustomerAccounts" Property="Customer.BranchId" Title="Branch" Resizable Reorderable />
</Columns>
</RadzenDataGrid>
@code {
}

17
Client/Pages/Customers/Customers.razor.cs

@ -0,0 +1,17 @@
using Biskilog_Accounting.Client.Pages.Users;
using Biskilog_Accounting.Shared.CustomModels;
namespace Biskilog_Accounting.Client.Pages.Customers
{
public partial class Customers
{
private IEnumerable<CustomerAccounts> m_customers { get; set; } = Enumerable.Empty<CustomerAccounts>();
protected override void OnInitialized()
{
m_customers = m_customerService.FetchCustomers();
base.OnInitialized();
}
public void Dispose()
{ }
}
}

2
Client/Pages/Dashboard/Dashboard.razor.cs

@ -131,7 +131,7 @@ namespace Biskilog_Accounting.Client.Pages.Dashboard
{ {
var jsonContent = await response.Content.ReadAsStringAsync(); var jsonContent = await response.Content.ReadAsStringAsync();
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var debt = JsonSerializer.Deserialize<List<InDebtCustomers>>(jsonContent, options); var debt = JsonSerializer.Deserialize<List<CustomerAccounts>>(jsonContent, options);
m_totalDebt = (double)debt.Sum(c => c.Debt); m_totalDebt = (double)debt.Sum(c => c.Debt);
m_loadingDebtSummary = false; m_loadingDebtSummary = false;
StateHasChanged(); StateHasChanged();

26
Client/Pages/Dashboard/Elements/ChartElement.razor.cs

@ -18,7 +18,7 @@ namespace Biskilog_Accounting.Client.Pages.Dashboard.Elements
[Parameter] [Parameter]
public IEnumerable<WeeklyCategorySummary> CategorySummary { get; set; } = Enumerable.Empty<WeeklyCategorySummary>(); public IEnumerable<WeeklyCategorySummary> CategorySummary { get; set; } = Enumerable.Empty<WeeklyCategorySummary>();
private ApexChartOptions<WeeklySaleItem> m_options; private ApexChartOptions<WeeklySaleItem> m_options;
private ApexChartOptions<WeeklyCategorySummary> options = new ApexChartOptions<WeeklyCategorySummary>(); private ApexChartOptions<WeeklyCategorySummary> options;
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
@ -45,9 +45,18 @@ namespace Biskilog_Accounting.Client.Pages.Dashboard.Elements
} }
}, },
}; };
options.Colors = new List<string> { "#11726d", "#096a71", "#003445", "#e69138" }; options = new ApexChartOptions<WeeklyCategorySummary>
{
options.Fill = new Fill Chart = new Chart
{
Height = 400,
},
Colors = new List<string>
{
"#11726d", "#54ff00", "#003445", "#e69138", "#a2896d",
"#b13a2c", "#b0cba8", "#e4e1da", "#696cff", "#03c3ec"
},
Fill = new Fill
{ {
Type = new List<FillType> { FillType.Gradient, FillType.Gradient }, Type = new List<FillType> { FillType.Gradient, FillType.Gradient },
Gradient = new FillGradient Gradient = new FillGradient
@ -56,9 +65,9 @@ namespace Biskilog_Accounting.Client.Pages.Dashboard.Elements
OpacityFrom = 0.2, OpacityFrom = 0.2,
OpacityTo = 0.9, OpacityTo = 0.9,
} }
}; },
options.Yaxis = new List<YAxis> Yaxis = new List<YAxis>
{ {
new YAxis new YAxis
{ {
@ -68,6 +77,11 @@ namespace Biskilog_Accounting.Client.Pages.Dashboard.Elements
return Number(value).toLocaleString();}" return Number(value).toLocaleString();}"
} }
} }
},
Legend = new Legend
{
Position = LegendPosition.Bottom,
}
}; };
base.OnParametersSet(); base.OnParametersSet();
} }

10
Client/Pages/Dashboard/Elements/ProductPriceHistory.razor.cs

@ -70,7 +70,15 @@ namespace Biskilog_Accounting.Client.Pages.Dashboard.Elements
if (!IsLoading) if (!IsLoading)
{ {
options.Colors = new List<string> { "#f4c414" }; options.Colors = new List<string> { "#f4c414" };
options.Title = new Title
{
Floating = true,
Style = new TitleStyle
{
FontSize = "10.5px",
Color = "#8f9193",
}
};
options.Fill = new Fill options.Fill = new Fill
{ {
Type = new List<FillType> { FillType.Gradient, FillType.Gradient }, Type = new List<FillType> { FillType.Gradient, FillType.Gradient },

1
Client/Pages/Product/Brands.razor

@ -12,7 +12,6 @@
</div> </div>
<RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_brands" TItem="Tblbrand" GridLines="DataGridGridLines.Horizontal"> <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_brands" TItem="Tblbrand" GridLines="DataGridGridLines.Horizontal">
<Columns> <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="Brand" Title="Brand Name" Resizable Reorderable />
<RadzenDataGridColumn TItem="Tblbrand" Property="BranchId" Title="Branch" Resizable Reorderable /> <RadzenDataGridColumn TItem="Tblbrand" Property="BranchId" Title="Branch" Resizable Reorderable />
</Columns> </Columns>

1
Client/Pages/Product/Categories.razor

@ -12,7 +12,6 @@
</div> </div>
<RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_categories" TItem="Tblcategory" GridLines="DataGridGridLines.Horizontal"> <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_categories" TItem="Tblcategory" GridLines="DataGridGridLines.Horizontal">
<Columns> <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="Category" Title="Category Name" Resizable Reorderable />
<RadzenDataGridColumn TItem="Tblcategory" Property="BranchId" Title="Branch" Resizable Reorderable /> <RadzenDataGridColumn TItem="Tblcategory" Property="BranchId" Title="Branch" Resizable Reorderable />
</Columns> </Columns>

1
Client/Pages/Product/Products.razor

@ -14,7 +14,6 @@
<RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_products" TItem="ProductItem" GridLines="DataGridGridLines.Horizontal" <RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_products" TItem="ProductItem" GridLines="DataGridGridLines.Horizontal"
SelectionMode="DataGridSelectionMode.Single" @bind-Value=@m_selectedProducts CellContextMenu="@OnCellContextMenu"> SelectionMode="DataGridSelectionMode.Single" @bind-Value=@m_selectedProducts CellContextMenu="@OnCellContextMenu">
<Columns> <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.ProductName" Title="Product Name" Width="20%" Resizable Reorderable />
<RadzenDataGridColumn TItem="ProductItem" Property="Product.Pdesc" Title="Description" Width="25%" 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="Stock.Quantity" Title="Quantity" Width="10%" Resizable Reorderable />

23
Client/Pages/Users/Users.razor

@ -0,0 +1,23 @@
@page "/users"
@using Biskilog_Accounting.Shared.Interfaces;
@using Biskilog_Accounting.Shared.POSModels;
@inject IUser m_userService;
<h3>Users</h3>
<RadzenDataGrid AllowPaging="true" PageSize="50" AllowSorting="true" Data="@m_users" TItem="Tbluser"
GridLines="DataGridGridLines.Horizontal">
<Columns>
<RadzenDataGridColumn TItem="Tbluser" Property="Username" Title="Username" />
<RadzenDataGridColumn TItem="Tbluser" Property="Firstname" Title="Name">
<Template Context="detail">
@(detail.Firstname + "") @(detail.Surname)
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Tbluser" Property="StreetAddress1" Title="Address" />
<RadzenDataGridColumn TItem="Tbluser" Property="AccessLevel" Title="Level" />
<RadzenDataGridColumn TItem="Tbluser" Property="LastLogin" Title="Last Login" />
<RadzenDataGridColumn TItem="Tbluser" Property="BranchId" Title="Branch" Resizable Reorderable />
</Columns>
</RadzenDataGrid>
@code {
}

17
Client/Pages/Users/Users.razor.cs

@ -0,0 +1,17 @@
using Biskilog_Accounting.Shared.POSModels;
namespace Biskilog_Accounting.Client.Pages.Users
{
public partial class Users
{
private IEnumerable<Tbluser> m_users { get; set; } = Enumerable.Empty<Tbluser>();
protected override void OnInitialized()
{
m_users = m_userService.FetchUsers();
base.OnInitialized();
}
public void Dispose()
{ }
}
}

2
Client/Program.cs

@ -31,6 +31,8 @@ builder.Services.AddScoped<IProduct, ProductRepository>();
builder.Services.AddScoped<ISalesInterface, SalesRepository>(); builder.Services.AddScoped<ISalesInterface, SalesRepository>();
builder.Services.AddScoped<IMainInterface, MainInterfaceService>(); builder.Services.AddScoped<IMainInterface, MainInterfaceService>();
builder.Services.AddScoped<ICompanyInfo, MainInterfaceService>(); builder.Services.AddScoped<ICompanyInfo, MainInterfaceService>();
builder.Services.AddScoped<IUser, MainInterfaceService>();
builder.Services.AddScoped<ICustomer, MainInterfaceService>();
builder.Services.AddFluentUIComponents(options => builder.Services.AddFluentUIComponents(options =>
{ {
options.HostingModel = BlazorHostingModel.WebAssembly; options.HostingModel = BlazorHostingModel.WebAssembly;

44
Client/Repos/MainInterfaceService.cs

@ -7,13 +7,15 @@ using System.Text.Json;
namespace Biskilog_Accounting.Client.Repos namespace Biskilog_Accounting.Client.Repos
{ {
public class MainInterfaceService : IMainInterface, ICompanyInfo public class MainInterfaceService : IMainInterface, ICompanyInfo, IUser, ICustomer
{ {
private readonly HttpClient m_http; private readonly HttpClient m_http;
private readonly DialogService m_dialogService; private readonly DialogService m_dialogService;
private DateTime m_currentTradeDate; private DateTime m_currentTradeDate;
private DateTime m_previousTradeDate; private DateTime m_previousTradeDate;
private IEnumerable<Tblbranch> m_branches; private IEnumerable<Tblbranch> m_branches { get; set; } = new List<Tblbranch>();
private IEnumerable<Tbluser> m_users { get; set; } = new List<Tbluser>();
private IEnumerable<CustomerAccounts> m_customers { get; set; } = new List<CustomerAccounts>();
private Tblcompanydetail m_info; private Tblcompanydetail m_info;
public MainInterfaceService(DialogService a_dialogService, HttpClient http) public MainInterfaceService(DialogService a_dialogService, HttpClient http)
@ -94,5 +96,43 @@ namespace Biskilog_Accounting.Client.Repos
{ {
return m_branches.First(b => b.BranchId == a_branchId).BranchName; return m_branches.First(b => b.BranchId == a_branchId).BranchName;
} }
public IEnumerable<Tbluser> FetchUsers()
{
return m_users;
}
public async Task<IEnumerable<Tbluser>> GetUsers()
{
var response = await m_http.GetAsync($"api/users/accounts");
if (response.IsSuccessStatusCode)
{
var jsonContent = await response.Content.ReadAsStringAsync();
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var recent = JsonSerializer.Deserialize<IEnumerable<Tbluser>>(jsonContent, options);
m_users = recent;
return recent;
}
return null;
}
public IEnumerable<CustomerAccounts> FetchCustomers()
{
return m_customers;
}
public async Task<IEnumerable<CustomerAccounts>> GetCustomers()
{
var response = await m_http.GetAsync($"api/customer/accounts");
if (response.IsSuccessStatusCode)
{
var jsonContent = await response.Content.ReadAsStringAsync();
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var recent = JsonSerializer.Deserialize<IEnumerable<CustomerAccounts>>(jsonContent, options);
m_customers = recent;
return recent;
}
return null;
}
} }
} }

2
Client/wwwroot/assets/vendor/css/theme-default.css

@ -779,7 +779,7 @@ html:not(.layout-menu-collapsed) .bg-menu-theme .menu-inner .menu-item .menu-lin
} }
.bg-footer-theme { .bg-footer-theme {
background-color: #f5f5f9 !important; background-color: #ccd6db !important;
color: #697a8d; color: #697a8d;
} }
.bg-footer-theme .footer-link { .bg-footer-theme .footer-link {

18752
Client/wwwroot/css/app.css

File diff suppressed because one or more lines are too long

4
Client/wwwroot/index.html

@ -26,10 +26,6 @@
<!-- Icons. Uncomment required icon fonts --> <!-- Icons. Uncomment required icon fonts -->
<link rel="stylesheet" href="assets/vendor/fonts/boxicons.css" /> <link rel="stylesheet" href="assets/vendor/fonts/boxicons.css" />
<!-- Core CSS -->
<link rel="stylesheet" href="assets/vendor/css/core.css" class="template-customizer-core-css" />
<link rel="stylesheet" href="assets/vendor/css/theme-default.css" class="template-customizer-theme-css" />
<!-- Vendors CSS --> <!-- Vendors CSS -->
<link rel="stylesheet" href="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" /> <link rel="stylesheet" href="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />

2
Server/Controllers/AnalyticsController.cs

@ -56,7 +56,7 @@ namespace Biskilog_Accounting.Server.Controllers
/// <param name="a_end"></param> /// <param name="a_end"></param>
[Authorize] [Authorize]
[HttpGet, Route("debtors")] [HttpGet, Route("debtors")]
public IEnumerable<InDebtCustomers> GetInDebtCustomers() public IEnumerable<CustomerAccounts> GetInDebtCustomers()
{ {
return m_analyticService.GetInDebtCustomers(); return m_analyticService.GetInDebtCustomers();
} }

29
Server/Controllers/CustomerController.cs

@ -0,0 +1,29 @@
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 CustomerController : ControllerBase
{
private readonly ICustomer m_customerService;
public CustomerController(ICustomer a_customerService)
{
m_customerService = a_customerService;
}
/// <summary>
/// Endpoint to return all customers
/// </summary>
[Authorize]
[HttpGet, Route("accounts")]
public IEnumerable<CustomerAccounts> GetCustomers()
{
return m_customerService.FetchCustomers();
}
}
}

28
Server/Controllers/UsersController.cs

@ -0,0 +1,28 @@
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 UsersController : ControllerBase
{
private readonly IUser m_userService;
public UsersController(IUser a_userService)
{
m_userService = a_userService;
}
/// <summary>
/// Endpoint to return all users
/// </summary>
[Authorize]
[HttpGet, Route("accounts")]
public IEnumerable<Tbluser> GetUsers()
{
return m_userService.FetchUsers();
}
}
}

2
Server/Program.cs

@ -30,6 +30,8 @@ builder.Services.AddScoped<IConnectionService, ConnectionService>();
builder.Services.AddScoped<IAnalytics, AnalyticalService>(); builder.Services.AddScoped<IAnalytics, AnalyticalService>();
builder.Services.AddScoped<IProduct, ProductRepo>(); builder.Services.AddScoped<IProduct, ProductRepo>();
builder.Services.AddScoped<ISalesInterface, SalesService>(); builder.Services.AddScoped<ISalesInterface, SalesService>();
builder.Services.AddScoped<IUser, UserService>();
builder.Services.AddScoped<ICustomer, CustomerService>();
builder.Services.AddCors(options => builder.Services.AddCors(options =>
{ {

4
Server/Services/AnalyticalService.cs

@ -78,7 +78,7 @@ namespace Biskilog_Accounting.Server.Services
return sales; return sales;
} }
public IEnumerable<InDebtCustomers> GetInDebtCustomers() public IEnumerable<CustomerAccounts> GetInDebtCustomers()
{ {
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!; string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token); IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
@ -86,7 +86,7 @@ namespace Biskilog_Accounting.Server.Services
var listDebts = m_context.Customeraccounts.Where(t => t.Balance < 0 && accessiblebranches.Contains(t.BranchId)).OrderByDescending(d => d.Date).Select(t => t.CustomerId).Distinct().ToList(); var listDebts = m_context.Customeraccounts.Where(t => t.Balance < 0 && accessiblebranches.Contains(t.BranchId)).OrderByDescending(d => d.Date).Select(t => t.CustomerId).Distinct().ToList();
foreach (var customerId in listDebts) foreach (var customerId in listDebts)
{ {
yield return new InDebtCustomers yield return new CustomerAccounts
{ {
Customer = m_context.Tblcustomers.FirstOrDefault(i => i.CustomerId == customerId), Customer = m_context.Tblcustomers.FirstOrDefault(i => i.CustomerId == customerId),
Debt = m_context.Customeraccounts.OrderByDescending(d => d.Date).FirstOrDefault(t => t.Balance < 0 && t.CustomerId == customerId).Balance, Debt = m_context.Customeraccounts.OrderByDescending(d => d.Date).FirstOrDefault(t => t.Balance < 0 && t.CustomerId == customerId).Balance,

71
Server/Services/CustomerService.cs

@ -0,0 +1,71 @@
using Biskilog_Accounting.Server.POSModels;
using Biskilog_Accounting.Shared.CustomModels;
using Biskilog_Accounting.Shared.Enums;
using Biskilog_Accounting.Shared.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Net.Http.Headers;
using MySqlConnector;
using System.Drawing.Drawing2D;
namespace Biskilog_Accounting.Server.Services
{
public class CustomerService : ICustomer
{
private readonly BiskAcdbContext m_context;
private readonly ITokenService m_tokenService;
private readonly HttpContext m_httpContext;
public CustomerService(BiskAcdbContext a_context, ITokenService a_tokenService, IHttpContextAccessor a_httpContextAccessor)
{
m_context = a_context;
m_tokenService = a_tokenService;
m_httpContext = a_httpContextAccessor?.HttpContext;
}
public IEnumerable<CustomerAccounts> FetchCustomers()
{
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 GetCustomers(@p0)";
command.Parameters.Add(new MySqlParameter("@p0", string.Join(", ", accessiblebranches.ToArray())));
m_context.Database.OpenConnection();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return new CustomerAccounts
{
Customer = new Shared.POSModels.Tblcustomer
{
CustomerId = reader.GetString(0),
BranchId = reader.GetString(1),
Firstname = reader.GetString(2),
Surname = reader.GetString(3),
Address = reader.GetString(4),
Telephone = reader.GetString(5),
DateAdded = reader.GetDateTime(6),
Status = reader.GetString(7),
Email = reader.GetString(8),
FinancialStatus = reader.GetString(9),
},
Debt = reader.GetDecimal(10)
};
}
}
}
}
}
public Task<IEnumerable<CustomerAccounts>> GetCustomers()
{
throw new NotImplementedException();
}
}
}

43
Server/Services/UserService.cs

@ -0,0 +1,43 @@
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 UserService : IUser
{
private readonly BiskAcdbContext m_context;
private readonly ITokenService m_tokenService;
private readonly HttpContext m_httpContext;
public UserService(BiskAcdbContext a_context, ITokenService a_tokenService, IHttpContextAccessor a_httpContextAccessor)
{
m_context = a_context;
m_tokenService = a_tokenService;
m_httpContext = a_httpContextAccessor?.HttpContext;
}
public IEnumerable<Tbluser> FetchUsers()
{
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.Tblusers.Where(b => accessiblebranches.Contains(b.BranchId));
}
return new List<Tbluser>();
}
public Task<IEnumerable<Tbluser>> GetUsers()
{
throw new NotImplementedException();
}
}
}

2
Shared/CustomModels/InDebtCustomers.cs → Shared/CustomModels/CustomerAccounts.cs

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace Biskilog_Accounting.Shared.CustomModels namespace Biskilog_Accounting.Shared.CustomModels
{ {
public class InDebtCustomers public class CustomerAccounts
{ {
public Tblcustomer Customer { get; set; } public Tblcustomer Customer { get; set; }
public decimal Debt { get; set; } = 0; public decimal Debt { get; set; } = 0;

2
Shared/Interfaces/IAnalytics.cs

@ -20,7 +20,7 @@ namespace Biskilog_Accounting.Shared.Interfaces
/// <summary> /// <summary>
/// Fetches a collection of in-debt customers /// Fetches a collection of in-debt customers
/// <returns></returns> /// <returns></returns>
IEnumerable<InDebtCustomers> GetInDebtCustomers(); IEnumerable<CustomerAccounts> GetInDebtCustomers();
/// <summary> /// <summary>
/// Fetches a collection of Product Items which are currently out of stock /// Fetches a collection of Product Items which are currently out of stock
/// </summary> /// </summary>

11
Shared/Interfaces/ICustomer.cs

@ -0,0 +1,11 @@
using Biskilog_Accounting.Shared.CustomModels;
using Biskilog_Accounting.Shared.POSModels;
namespace Biskilog_Accounting.Shared.Interfaces
{
public interface ICustomer
{
IEnumerable<CustomerAccounts> FetchCustomers();
Task<IEnumerable<CustomerAccounts>> GetCustomers();
}
}

15
Shared/Interfaces/IUser.cs

@ -0,0 +1,15 @@
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 IUser
{
IEnumerable<Tbluser> FetchUsers();
Task<IEnumerable<Tbluser>> GetUsers();
}
}
Loading…
Cancel
Save