Browse Source

Merge pull request 'BISK2023-2-performance-analysis-feature' (#4) from BISK2023-2-performance-analysis-feature into dev

Reviewed-on: https://scm.barhendev.com/barhen/Biskilog_Accounting/pulls/4
pull/6/head
Benjamin Arhen 2 years ago
parent
commit
a4e2b6c95c
  1. 35
      Server/BiskAcdbContext.cs
  2. 7
      Server/BiskilogContext.cs
  3. 101
      Server/Controllers/AnalyticsController.cs
  4. 5
      Server/Program.cs
  5. 164
      Server/Services/AnalyticalService.cs
  6. 10
      Server/Services/AuthenticationService.cs
  7. 12
      Server/Services/ConnectionService.cs
  8. 2
      Server/appsettings.json
  9. 1
      Shared/ClientContractModels/Clientbusiness.cs
  10. 16
      Shared/CustomModels/CancelledSales.cs
  11. 15
      Shared/CustomModels/InDebtCustomers.cs
  12. 29
      Shared/CustomModels/MostPurchaseItem.cs
  13. 16
      Shared/CustomModels/ProductItem.cs
  14. 23
      Shared/CustomModels/ProductPriceChange.cs
  15. 22
      Shared/CustomModels/SaleItem.cs
  16. 54
      Shared/Interfaces/IAnalytics.cs
  17. 2
      Shared/Interfaces/IAuthService.cs
  18. 7
      Shared/Interfaces/ITokenService.cs
  19. 78
      Shared/ServiceRepo/TokenService.cs

35
Server/BiskAcdbContext.cs

@ -1,21 +1,46 @@
using System;
using System.Collections.Generic;
using Azure.Core;
using Biskilog_Accounting.Shared.Enums;
using Biskilog_Accounting.Shared.Interfaces;
using Biskilog_Accounting.Shared.POSModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Net.Http.Headers;
using System.Security.Claims;
namespace Biskilog_Accounting.Server.POSModels;
public partial class BiskAcdbContext : DbContext
{
private readonly HttpContext m_httpContext;
private readonly IConnectionService m_connection;
private readonly ITokenService m_tokenService;
public BiskAcdbContext()
{
}
public BiskAcdbContext(DbContextOptions<BiskAcdbContext> options)
: base(options)
public BiskAcdbContext(DbContextOptions<BiskAcdbContext> options, ITokenService tokenService, IConnectionService connection, IHttpContextAccessor a_httpContextAccessor = null)
: base(options)
{
m_tokenService = tokenService;
m_connection = connection;
m_httpContext = a_httpContextAccessor?.HttpContext;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
if (AuthEnums.Valid == m_tokenService.ValidateToken(token))
{
int? databaseId = m_tokenService.GetDatabaseIdFromToken(token);
string connectionString = m_connection.GetClientConnectionString(databaseId!.Value);
optionsBuilder.UseMySql(connectionString, new MariaDbServerVersion(new Version()));
}
else
{
m_httpContext.Abort();
}
}
}
public virtual DbSet<Creditpurchase> Creditpurchases { get; set; }
public virtual DbSet<Customeraccount> Customeraccounts { get; set; }

7
Server/BiskilogContext.cs

@ -90,6 +90,13 @@ public partial class BiskilogContext : DbContext
.HasDefaultValueSql("current_timestamp()")
.HasColumnType("datetime")
.HasColumnName("date_joined");
entity.Property(e => e.BusinessExternalId)
.HasMaxLength(50)
.HasDefaultValueSql("''")
.HasColumnName("businessExternalId")
.UseCollation("utf8mb4_general_ci")
.HasCharSet("utf8mb4");
});
modelBuilder.Entity<Clientinfo>(entity =>

101
Server/Controllers/AnalyticsController.cs

@ -0,0 +1,101 @@
using Biskilog_Accounting.Shared.CustomModels;
using Biskilog_Accounting.Shared.Interfaces;
using Biskilog_Accounting.Shared.POSModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using NuGet.Common;
namespace Biskilog_Accounting.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AnalyticsController : ControllerBase
{
private readonly IAnalytics m_analyticService;
public AnalyticsController(IAnalytics a_analytics)
{
m_analyticService = a_analytics;
}
/// <summary>
/// Endpoint to return analysis on CancelledSales within a specified period
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("cancelledsales/{a_start}/{a_end}")]
public IEnumerable<CancelledSales> GetCancelledSalesAsync(DateTime a_start, DateTime a_end)
{
return m_analyticService.GetCancelledSales(a_start, a_end);
}
/// <summary>
/// Endpoint to return analysis on Sales within a specified period
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("sales/{a_start}/{a_end}")]
public IEnumerable<Tblcart> GetSalesAsync(DateTime a_start, DateTime a_end)
{
return m_analyticService.GetSalesTransaction(a_start, a_end);
}
/// <summary>
/// Endpoint to return analysis on in-debt customers
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("debtors")]
public IEnumerable<InDebtCustomers> GetInDebtCustomers()
{
return m_analyticService.GetInDebtCustomers();
}
/// <summary>
/// Endpoint to return analysis on product price changes
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("pricechanges/{a_start}/{a_end}")]
public IEnumerable<ProductPriceChange> GetPriceChanges(DateTime a_start, DateTime a_end)
{
return m_analyticService.GetPriceChanges(a_start, a_end);
}
/// <summary>
/// Endpoint to return analysis on sales by employees
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("employeesales/{a_start}/{a_end}")]
public Dictionary<string, List<SaleItem>> GetEmployeeSales(DateTime a_start, DateTime a_end)
{
return m_analyticService.GetEmployeeSales(a_start, a_end);
}
/// <summary>
/// Endpoint to return analysis on product items low on stock
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("lowonstock")]
public IEnumerable<ProductItem> GetLowOnStockItems()
{
string token = Request.Headers[HeaderNames.Authorization]!;
return m_analyticService.GetOutOfStockItems();
}
/// <summary>
/// Endpoint to return analysis on the most purchased product item
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
[Authorize]
[HttpGet, Route("mostpurchaseditem/{a_start}/{a_end}")]
public IEnumerable<MostPurchasedItem> GetMostPurchased(DateTime a_start, DateTime a_end)
{
return m_analyticService.GetMostPurchasedItem(a_start, a_end);
}
}
}

5
Server/Program.cs

@ -9,6 +9,7 @@ using Biskilog_Accounting.Server;
using Biskilog_Accounting.ServiceRepo;
using Biskilog_Accounting.Shared.Interfaces;
using Biskilog_Accounting.Server.Services;
using Biskilog_Accounting.Server.POSModels;
var builder = WebApplication.CreateBuilder(args);
@ -21,8 +22,12 @@ builder.Services.AddEntityFrameworkMySql().AddDbContext<BiskilogContext>(options
{
options.UseMySql(builder.Configuration.GetConnectionString("Connection"), new MariaDbServerVersion(new Version()));
});
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddDbContext<BiskAcdbContext>();
builder.Services.AddScoped<IAuthService, AuthenticationService>();
builder.Services.AddScoped<ITokenService, TokenService>();
builder.Services.AddScoped<IConnectionService, ConnectionService>();
builder.Services.AddScoped<IAnalytics, AnalyticalService>();
builder.Services.AddCors(options =>
{

164
Server/Services/AnalyticalService.cs

@ -0,0 +1,164 @@
using Biskilog_Accounting.Server.POSModels;
using Biskilog_Accounting.Shared.CustomModels;
using Biskilog_Accounting.Shared.Interfaces;
using Biskilog_Accounting.Shared.POSModels;
using Microsoft.Net.Http.Headers;
using System.Data.Entity;
namespace Biskilog_Accounting.Server.Services
{
/// <summary>
/// Gets the KPIs/ Analysis of operations made with the software
/// </summary>
public class AnalyticalService : IAnalytics
{
private readonly BiskAcdbContext m_context;
private readonly ITokenService m_tokenService;
private readonly HttpContext m_httpContext;
public AnalyticalService(BiskAcdbContext a_context, ITokenService a_tokenService, IHttpContextAccessor a_httpContextAccessor)
{
m_context = a_context;
m_tokenService = a_tokenService;
m_httpContext = a_httpContextAccessor?.HttpContext;
}
public IEnumerable<CancelledSales> GetCancelledSales(DateTime a_start, DateTime a_end)
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
return from cSale in m_context.Tblcancelledtransactions
join aSale in m_context.Tblcarts on cSale.Transno equals aSale.Transno into activeSale
join cPurchase in m_context.Tblcustomerpurchases on cSale.Transno equals cPurchase.TransactionId into customerSales
from c in customerSales.DefaultIfEmpty()
join customer in m_context.Tblcustomers on c.CustomerId equals customer.CustomerId into Customers
from cc in Customers.DefaultIfEmpty()
where cSale.DateCancelled >= a_start && cSale.DateCancelled <= a_end && accessiblebranches.Contains(cSale.BranchId)
select new CancelledSales
{
CancelledTransaction = cSale,
Value = (from a in activeSale where accessiblebranches.Contains(a.BranchId) select a.Total).Sum(),
Customer = !String.IsNullOrEmpty(cc.CustomerId) ? $"{cc.Firstname} {cc.Surname}" : "Walk-IN Purchase"
};
}
public Dictionary<string, List<SaleItem>> GetEmployeeSales(DateTime a_start, DateTime a_end)
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
Dictionary<string, List<SaleItem>> sales = new Dictionary<string, List<SaleItem>>();
var employeeSales = m_context.Tblcarts.Where(c => c.Date >= a_start && c.Date <= a_end
&& accessiblebranches.Contains(c.BranchId)).Select(e => e.Cashier).Distinct().ToList();
foreach (var employeeName in employeeSales)
{
var list = (from a in employeeSales
join c in m_context.Tblcarts on a equals c.Cashier into Sales
from s in Sales
group s by s.Transno into saleItem
select new SaleItem
{
Total = saleItem.Sum(c => c.Total),
Transno = saleItem.Key,
Cashier = employeeName,
Date = saleItem.First().Date,
Status = saleItem.First().Status,
BranchId = saleItem.First().BranchId
}).ToList();
sales.Add(employeeName, list);
}
return sales;
}
public IEnumerable<InDebtCustomers> GetInDebtCustomers()
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
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)
{
yield return new InDebtCustomers
{
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,
};
}
}
public IEnumerable<MostPurchasedItem> GetMostPurchasedItem(DateTime a_start, DateTime a_end)
{
//TODO either rewrite query or increase memory on server to deal with comparison mode performance issue
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
var items = (from s in m_context.Tblcarts
join p in m_context.Tblproducts on s.Id equals p.Pcode
where s.Date >= a_start && s.Date <= a_end && s.BranchId == accessiblebranches.First()
group s by p into g
orderby g.Count() descending
select new MostPurchasedItem
{
ProductId = g.Key.Pcode,
ProductName = g.Key.ProductName,
NbrTimesSold = g.Count(),
Revenue = g.Sum(s => s.Price)
}).Take(50).ToList();
return items;
}
public IEnumerable<ProductItem> GetOutOfStockItems()
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
return (from item in m_context.Tblinventories
join p in m_context.Tblproducts on item.Pcode equals p.Pcode
join pu in m_context.Productaltunits on item.Pcode equals pu.Pcode into AltUnit
from au in AltUnit.DefaultIfEmpty()
join rs in m_context.Restocklevels on item.Pcode equals rs.ProductId
join un in m_context.Unitofmeasures on p.BaseUnit equals un.UnitCode
where p.Status!.ToLower() != "inactive" && accessiblebranches.Contains(item.BranchId) &&
((rs.WarnLevel >= item.Quantity && rs.Unit == p.BaseUnit) || (rs.WarnLevel >= (item.Quantity / au.QuantityUnit) &&
rs.Unit == au.UnitCode)
)
select new ProductItem
{
Product = p,
Stock = item,
BaseUnit = un.Unitshort!
});
}
public IEnumerable<ProductPriceChange> GetPriceChanges(DateTime a_start, DateTime a_end)
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
return from change in m_context.Tblpricechanges
join p in m_context.Tblproducts on change.Pcode equals p.Pcode
where change.ChangeDate >= a_start && change.ChangeDate <= a_end && accessiblebranches.Contains(change.BranchId)
select new ProductPriceChange
{
BranchId = change.BranchId,
ChangeDate = change.ChangeDate,
Pcode = change.Pcode,
CountId = change.CountId,
CurrentPrice = change.CurrentPrice,
PreviousPrice = change.PreviousPrice,
ProductName = p.ProductName
};
}
public IEnumerable<Tblcart> GetSalesTransaction(DateTime a_start, DateTime a_end)
{
string token = m_httpContext.Request.Headers[HeaderNames.Authorization]!;
IEnumerable<string> accessiblebranches = m_tokenService.BranchIds(token);
return m_context.Tblcarts.Where(t => t.Date >= a_start && t.Date <= a_end && accessiblebranches.Contains(t.BranchId));
}
}
}

10
Server/Services/AuthenticationService.cs

@ -55,11 +55,12 @@ namespace Biskilog_Accounting.Server.Services
List<int> businessIds = GetSiteaccesspermission(user.ClientId, user.UserId).Select(t => t.BusinessId).ToList();
Contract? contract = GetContract(user.ClientId, businessIds);
List<string> businesses = GetClientbusiness(user.ClientId, user.UserId).Select(t=>t.BusinessExternalId).ToList();
if (contract == null)
return AuthEnums.Invalid.ToString();
return m_tokenService.GenerateToken(user, contract, databasemap);
return m_tokenService.GenerateToken(user, contract, databasemap, businesses, false);
}
/// <summary>
@ -94,9 +95,12 @@ namespace Biskilog_Accounting.Server.Services
throw new NotImplementedException();
}
public List<Clientbusiness> GetClientbusiness(int a_clientId)
public List<Clientbusiness> GetClientbusiness(int a_clientId, int userId)
{
return m_context.Clientbusinesses.Where(i => i.ClientId == a_clientId).ToList();
return (from b in m_context.Clientbusinesses
join p in m_context.Siteaccesspermissions on new {b.ClientId, b.BusinessId} equals new {p.ClientId, p.BusinessId}
where p.UserId == userId && p.ClientId == a_clientId
select b).ToList();
}
public Databasemap GetClientDB(int a_clientId)

12
Server/Services/ConnectionService.cs

@ -10,13 +10,11 @@ namespace Biskilog_Accounting.Server.Services
public class ConnectionService : IConnectionService
{
private readonly BiskilogContext m_context;
private readonly ITokenService m_tokenService;
private readonly IConfiguration m_configuration;
public ConnectionService(BiskilogContext a_context, ITokenService a_tokenService, IConfiguration configuration)
public ConnectionService(BiskilogContext a_context, IConfiguration configuration)
{
m_context = a_context;
m_tokenService = a_tokenService;
m_configuration = configuration;
}
/// <summary>
@ -42,11 +40,11 @@ namespace Biskilog_Accounting.Server.Services
/// <returns>A configured BiskAcdbContext</returns>
public object PrepareDBContext(string a_connectionString)
{
throw new NotImplementedException();
//DbContextOptionsBuilder<BiskAcdbContext> acdbContext = new DbContextOptionsBuilder<BiskAcdbContext>();
//acdbContext.UseMySql(a_connectionString, new MariaDbServerVersion(new Version()));
DbContextOptionsBuilder<BiskAcdbContext> acdbContext = new DbContextOptionsBuilder<BiskAcdbContext>();
acdbContext.UseMySql(a_connectionString, new MariaDbServerVersion(new Version()));
return acdbContext;
//return new BiskAcdbContext(acdbContext.Options);
}
}
}

2
Server/appsettings.json

@ -7,7 +7,7 @@
},
"ConnectionStrings": {
"Connection": "server=54.37.19.162;database=dev_biskilogclients;user=biskilog;password=mefbuk-6niFsu-fytrew",
"PrivateConnection": "server={0};database={1};user=biskilog;password=mefbuk-6niFsu-fytrew"
"PrivateConnection": "server={0};database={1};user=biskilog;password=mefbuk-6niFsu-fytrew;default command timeout=0;"
},
"AllowedHosts": "*",
"JWT": {

1
Shared/ClientContractModels/Clientbusiness.cs

@ -17,4 +17,5 @@ public partial class Clientbusiness
public string BiskilogVersion { get; set; } = null!;
public DateTime DateJoined { get; set; }
public string BusinessExternalId { get; set; } = string.Empty!;
}

16
Shared/CustomModels/CancelledSales.cs

@ -0,0 +1,16 @@
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.CustomModels
{
public class CancelledSales
{
public Tblcancelledtransaction? CancelledTransaction { get; set; }
public string Customer { get; set; } = "WALK-IN Purchase";
public decimal? Value { get; set; }
}
}

15
Shared/CustomModels/InDebtCustomers.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.CustomModels
{
public class InDebtCustomers
{
public Tblcustomer Customer { get; set; }
public decimal Debt { get; set; } = 0;
}
}

29
Shared/CustomModels/MostPurchaseItem.cs

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Biskilog_Accounting.Shared.CustomModels
{
public class MostPurchasedItem
{
/// <summary>
/// Specifies the id of the product
/// </summary>
public string ProductId { get; set; }
/// <summary>
/// Specifies the name of the product
/// </summary>
public string ProductName { get; set; }
/// <summary>
/// The total revenue generated from the sale
/// </summary>
public decimal? Revenue { get; set; }
/// <summary>
/// This is the number of times the item has been sold
/// </summary>
public int? NbrTimesSold { get; set; }
}
}

16
Shared/CustomModels/ProductItem.cs

@ -0,0 +1,16 @@
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.CustomModels
{
public class ProductItem
{
public Tblproduct? Product { get; set; }
public Tblinventory? Stock { get; set; }
public string BaseUnit { get;set; } = string.Empty;
}
}

23
Shared/CustomModels/ProductPriceChange.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Biskilog_Accounting.Shared.CustomModels
{
public class ProductPriceChange
{
public string? Pcode { get; set; }
public string? ProductName { get; set; }
public decimal? PreviousPrice { get; set; }
public decimal? CurrentPrice { get; set; }
public DateTime? ChangeDate { get; set; }
public string BranchId { get; set; } = null!;
public string CountId { get; set; } = null!;
}
}

22
Shared/CustomModels/SaleItem.cs

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Biskilog_Accounting.Shared.CustomModels
{
public class SaleItem
{
public string? Transno { get; set; }
public DateTime? Date { get; set; }
public string? Cashier { get; set; }
public string? Status { get; set; }
public decimal? Total { get; set; }
public string BranchId { get; set; } = null!;
public string Customer { get; set; } = "Walk-In Purchase"!;
}
}

54
Shared/Interfaces/IAnalytics.cs

@ -0,0 +1,54 @@
using Biskilog_Accounting.Shared.CustomModels;
using Biskilog_Accounting.Shared.POSModels;
namespace Biskilog_Accounting.Shared.Interfaces
{
public interface IAnalytics
{
/// <summary>
/// Fetches a collection of sales transaction made from the specified start date to the end date
/// </summary>
/// <param name="a_start">Specified Start Date</param>
/// <param name="a_end">Specified end Date</param>
/// <returns></returns>
IEnumerable<Tblcart> GetSalesTransaction(DateTime a_start, DateTime a_end);
/// <summary>
/// Fetches a collection of in-debt customers
/// <returns></returns>
IEnumerable<InDebtCustomers> GetInDebtCustomers();
/// <summary>
/// Fetches a collection of Product Items which are currently out of stock
/// </summary>
/// <returns></returns>
IEnumerable<ProductItem> GetOutOfStockItems();
/// <summary>
/// Fetches a collection of the most purchased Product Items within a specified date range
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
/// <returns></returns>
IEnumerable<MostPurchasedItem> GetMostPurchasedItem(DateTime a_start, DateTime a_end);
/// <summary>
/// Fetches a collection of cancelled transaction within a specified date range
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
/// <returns></returns>
IEnumerable<CancelledSales> GetCancelledSales(DateTime a_start, DateTime a_end);
/// <summary>
/// Fetches a collection of transaction made by employees within a specified date range
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
/// <returns>A dictionary of transactions made by employees with employee name as key</returns>
Dictionary<string, List<SaleItem>> GetEmployeeSales(DateTime a_start, DateTime a_end);
/// <summary>
/// Fetches a collection of product price changes with a specified date range
/// </summary>
/// <param name="a_start"></param>
/// <param name="a_end"></param>
/// <returns></returns>
IEnumerable<ProductPriceChange> GetPriceChanges(DateTime a_start, DateTime a_end);
//void SetContraints(string a_token);
}
}

2
Shared/Interfaces/IAuthService.cs

@ -14,6 +14,6 @@ namespace Biskilog_Accounting.Shared.Interfaces
Contract? GetContract(int a_clientId, List<int> a_businessId);
Databasemap GetClientDB(int a_clientId);
List<Siteaccesspermission> GetSiteaccesspermission(int a_clientId, int a_userId);
List<Clientbusiness> GetClientbusiness(int a_clientId);
List<Clientbusiness> GetClientbusiness(int a_clientId, int userId);
}
}

7
Shared/Interfaces/ITokenService.cs

@ -6,10 +6,13 @@ namespace Biskilog_Accounting.Shared.Interfaces
public interface ITokenService
{
AuthEnums ValidateToken(string a_token);
string GenerateToken(Userauth a_user, Contract a_clientContract, Databasemap a_database);
string GenerateToken(Userauth a_user, Contract a_clientContract, Databasemap a_database, List<string> a_business, bool a_comparison);
int? GetDatabaseIdFromToken(string a_token);
int? GetUserIdFromToken(string a_token);
string? GetUserNameFromToken(string a_token);
string? GetBaseBranch(string a_token);
bool? GetComparison(string a_token);
IEnumerable<string> BranchIds(string a_token);
string? GetAllBranch(string a_token);
}
}

78
Shared/ServiceRepo/TokenService.cs

@ -43,7 +43,7 @@ namespace Biskilog_Accounting.ServiceRepo
/// Generates an access token based on the user
/// </summary>
/// <returns>A tokenized string</returns>
public string GenerateToken(Userauth a_user, Contract a_clientContract, Databasemap a_database)
public string GenerateToken(Userauth a_user, Contract a_clientContract, Databasemap a_database, List<string> a_business, bool a_comparison)
{
try
{
@ -56,6 +56,9 @@ namespace Biskilog_Accounting.ServiceRepo
new Claim("UserId", a_user.UserId.ToString()),
new Claim("Username", a_user.Username.ToString()),
new Claim("DbId",a_database.DbNo.ToString()),
new Claim("ComparisonMode",a_comparison.ToString()),
new Claim("BranchId",a_business[0].ToString()),
new Claim("BranchAccess",string.Join(", ", a_business.ToArray())),
new Claim("ClientId", a_user.ClientId.ToString()),
};
@ -120,5 +123,78 @@ namespace Biskilog_Accounting.ServiceRepo
}
return null;
}
/// <summary>
///Deserializes the token string if valid to return the specified branchId in the token string
/// </summary>
/// <param name="a_token"></param>
/// <returns>Username</returns>
public string? GetBaseBranch(string a_token)
{
if (ValidateToken(a_token) == AuthEnums.Valid)
{
string token = a_token.Substring(6).Trim();
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token);
return jwtToken.Claims.First(claim => claim.Type == "BranchId").Value;
}
return null;
}
public bool? GetComparison(string a_token)
{
if (ValidateToken(a_token) == AuthEnums.Valid)
{
string token = a_token.Substring(6).Trim();
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token);
return bool.Parse(jwtToken.Claims.First(claim => claim.Type == "ComparisonMode").Value);
}
return null;
}
/// <summary>
///Deserializes the token string if valid to return the specified list of branches a user has access to in the token string
/// </summary>
/// <param name="a_token"></param>
/// <returns>Username</returns>
public string? GetAllBranch(string a_token)
{
if (ValidateToken(a_token) == AuthEnums.Valid)
{
string token = a_token.Substring(6).Trim();
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token);
return jwtToken.Claims.First(claim => claim.Type == "BranchAccess").Value;
}
return null;
}
/// <summary>
/// Return a specified list of branches a user has access if comparison mode is set otherwise returns only the
/// active branch on the list
/// </summary>
/// <param name="a_token"></param>
/// <returns></returns>
public IEnumerable<string> BranchIds(string a_token)
{
List<string> branchIds = new List<string>();
if (ValidateToken(a_token) == AuthEnums.Valid)
{
bool comparison = GetComparison(a_token)!.Value;
if (comparison)
{
string? branches = GetAllBranch(a_token);
if (branches != null)
{
string[] branchArray = branches!.Split();
branchIds.AddRange(branchArray);
}
}
else
{
string? baseBranch = GetBaseBranch(a_token);
branchIds.Add(baseBranch!);
}
}
return branchIds.AsEnumerable();
}
}
}

Loading…
Cancel
Save