Browse Source

Analysis controller completed

pull/4/head
Benjamin Arhen 2 years ago
parent
commit
e912e6279d
  1. 104
      Server/Controllers/AnalyticsController.cs
  2. 172
      Server/Services/AnalyticalService.cs
  3. 29
      Shared/CustomModels/MostPurchaseItem.cs
  4. 2
      Shared/CustomModels/ProductItem.cs
  5. 22
      Shared/CustomModels/SaleItem.cs
  6. 5
      Shared/Interfaces/IAnalytics.cs

104
Server/Controllers/AnalyticsController.cs

@ -1,16 +1,10 @@
using Biskilog_Accounting.Server.POSModels;
using Biskilog_Accounting.Server.Services;
using Biskilog_Accounting.Shared.CustomModels;
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;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Net.Http.Headers;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using NuGet.Common;
namespace Biskilog_Accounting.Server.Controllers
{
@ -18,12 +12,12 @@ namespace Biskilog_Accounting.Server.Controllers
[ApiController]
public class AnalyticsController : ControllerBase
{
private readonly IConnectionService m_connection;
private readonly ITokenService m_tokenService;
public AnalyticsController(ITokenService tokenService, IConnectionService connection)
private readonly IAnalytics m_analyticService;
public AnalyticsController(ITokenService tokenService, IAnalytics a_analytics)
{
m_tokenService = tokenService;
m_connection = connection;
m_analyticService = a_analytics;
}
/// <summary>
@ -36,18 +30,9 @@ namespace Biskilog_Accounting.Server.Controllers
public IEnumerable<CancelledSales> GetCancelledSalesAsync(DateTime a_start, DateTime a_end)
{
string token = Request.Headers[HeaderNames.Authorization]!;
int? databaseId = m_tokenService.GetDatabaseIdFromToken(token);
string connectionString = m_connection.GetClientConnectionString(databaseId!.Value);
bool? comparisonMode = m_tokenService.GetComparison(token);
string? currentBranch = m_tokenService.GetBaseBranch(token);
m_analyticService.SetContraints(token);
//Creates a new db context
BiskAcdbContext newContext = (BiskAcdbContext)m_connection.PrepareDBContext(connectionString);
AnalyticalService analysis = new(newContext, comparisonMode!.Value, currentBranch!);
var result = analysis.GetCancelledSales(a_start, a_end);
return result;
return m_analyticService.GetCancelledSales(a_start, a_end);
}
/// <summary>
/// Endpoint to return analysis on Sales within a specified period
@ -59,16 +44,9 @@ namespace Biskilog_Accounting.Server.Controllers
public IEnumerable<Tblcart> GetSalesAsync(DateTime a_start, DateTime a_end)
{
string token = Request.Headers[HeaderNames.Authorization]!;
int? databaseId = m_tokenService.GetDatabaseIdFromToken(token);
string connectionString = m_connection.GetClientConnectionString(databaseId!.Value);
bool? comparisonMode = m_tokenService.GetComparison(token);
string? currentBranch = m_tokenService.GetBaseBranch(token);
//Creates a new db context
BiskAcdbContext newContext = (BiskAcdbContext)m_connection.PrepareDBContext(connectionString);
AnalyticalService analysis = new(newContext, comparisonMode!.Value, currentBranch!);
return analysis.GetSalesTransaction(a_start, a_end);
m_analyticService.SetContraints(token);
return m_analyticService.GetSalesTransaction(a_start, a_end);
}
/// <summary>
/// Endpoint to return analysis on in-debt customers
@ -80,17 +58,65 @@ namespace Biskilog_Accounting.Server.Controllers
public IEnumerable<InDebtCustomers> GetInDebtCustomers()
{
string token = Request.Headers[HeaderNames.Authorization]!;
int? databaseId = m_tokenService.GetDatabaseIdFromToken(token);
string connectionString = m_connection.GetClientConnectionString(databaseId!.Value);
bool? comparisonMode = m_tokenService.GetComparison(token);
string? currentBranch = m_tokenService.GetBaseBranch(token);
//Creates a new db context
BiskAcdbContext newContext = (BiskAcdbContext)m_connection.PrepareDBContext(connectionString);
m_analyticService.SetContraints(token);
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)
{
string token = Request.Headers[HeaderNames.Authorization]!;
AnalyticalService analysis = new(newContext, comparisonMode!.Value, currentBranch!);
return analysis.GetInDebtCustomers();
m_analyticService.SetContraints(token);
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)
{
string token = Request.Headers[HeaderNames.Authorization]!;
m_analyticService.SetContraints(token);
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]!;
m_analyticService.SetContraints(token);
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)
{
string token = Request.Headers[HeaderNames.Authorization]!;
m_analyticService.SetContraints(token);
return m_analyticService.GetMostPurchasedItem(a_start, a_end);
}
}
}

172
Server/Services/AnalyticalService.cs

@ -1,8 +1,11 @@
using Biskilog_Accounting.Server.POSModels;
using Azure.Core;
using Biskilog_Accounting.Server.POSModels;
using Biskilog_Accounting.ServiceRepo;
using Biskilog_Accounting.Shared.CustomModels;
using Biskilog_Accounting.Shared.Interfaces;
using Biskilog_Accounting.Shared.POSModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Net.Http.Headers;
using System.Data.Entity;
using System.Runtime.CompilerServices;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
@ -15,13 +18,13 @@ namespace Biskilog_Accounting.Server.Services
public class AnalyticalService : IAnalytics
{
private readonly BiskAcdbContext m_context;
private readonly ITokenService m_tokenService;
private bool m_comparisonMode;
private string m_activeBranch;
public AnalyticalService(BiskAcdbContext a_context, bool a_comparisonMode, string a_activeBranchId)
public AnalyticalService(BiskAcdbContext a_context, ITokenService a_tokenService)
{
m_context = a_context;
m_comparisonMode = a_comparisonMode;
m_activeBranch = a_activeBranchId;
m_tokenService = a_tokenService;
}
public IEnumerable<CancelledSales> GetCancelledSales(DateTime a_start, DateTime a_end)
{
@ -61,56 +64,143 @@ namespace Biskilog_Accounting.Server.Services
}
}
public IEnumerable<Dictionary<string, List<Tblcart>>> GetEmployeeSales(DateTime a_start, DateTime a_end)
public Dictionary<string, List<SaleItem>> GetEmployeeSales(DateTime a_start, DateTime a_end)
{
throw new NotImplementedException();
Dictionary<string, List<SaleItem>> sales = new Dictionary<string, List<SaleItem>>();
if (m_comparisonMode)
{
var employeeSales = m_context.Tblcarts.Where(c => c.Date >= a_start && c.Date <= a_end).Select(e => e.Cashier).Distinct();
foreach (string 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);
}
}
else
{
var employeeSales = m_context.Tblcarts.Where(c => c.Date >= a_start && c.Date <= a_end && c.BranchId == m_activeBranch).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()
{
if (m_comparisonMode)
{
return from c in m_context.Tblcustomers
join a in m_context.Customeraccounts on c.CustomerId equals a.CustomerId into CustomerAccounts
from ac in CustomerAccounts.OrderByDescending(ac => ac.Date).Take(1).DefaultIfEmpty()
where ac.Balance < 0
orderby ac.Date descending
select new InDebtCustomers
{
Customer = c,
Debt = ac != null ? ac.Balance : 0
};
var listDebts = m_context.Customeraccounts.Where(t => t.Balance < 0).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,
};
}
}
else
{
return null;
var listDebts = m_context.Customeraccounts.Where(t => t.Balance < 0 && t.BranchId == m_activeBranch).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<ProductItem> GetMostPurchasedItem(DateTime a_start, DateTime a_end)
public IEnumerable<MostPurchasedItem> GetMostPurchasedItem(DateTime a_start, DateTime a_end)
{
throw new NotImplementedException();
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
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()
{
//if (m_comparisonMode)
//{
// return from r in m_context.Restocklevels
// join i in m_context.Tblinventories on r.ProductId equals i.Pcode
// join p in m_context.Tblproducts on i.Pcode equals p.Pcode
// where i.Quantity == r.WarnLevel
// select new ProductItem
// {
// Product = p,
// Stock = i,
// Unitofmeasure =
// }
//}
//else {
//}
return null;
if (m_comparisonMode)
{
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" &&
((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!
});
}
else
{
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" && item.BranchId == m_activeBranch &&
((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!
});
}
//return null;
}
public IEnumerable<ProductPriceChange> GetPriceChanges(DateTime a_start, DateTime a_end)
@ -119,7 +209,7 @@ namespace Biskilog_Accounting.Server.Services
{
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
where change.ChangeDate >= a_start && change.ChangeDate <= a_end
select new ProductPriceChange
{
BranchId = change.BranchId,
@ -135,7 +225,7 @@ namespace Biskilog_Accounting.Server.Services
{
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 && change.BranchId == m_activeBranch
where change.ChangeDate >= a_start && change.ChangeDate <= a_end && change.BranchId == m_activeBranch
select new ProductPriceChange
{
BranchId = change.BranchId,
@ -161,5 +251,11 @@ namespace Biskilog_Accounting.Server.Services
return m_context.Tblcarts.Where(t => t.Date >= a_start && t.Date <= a_end && t.BranchId == m_activeBranch);
}
}
public void SetContraints(string a_token)
{
m_comparisonMode = m_tokenService.GetComparison(a_token)!.Value;
m_activeBranch = m_tokenService.GetBaseBranch(a_token)!;
}
}
}

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; }
}
}

2
Shared/CustomModels/ProductItem.cs

@ -11,6 +11,6 @@ namespace Biskilog_Accounting.Shared.CustomModels
{
public Tblproduct? Product { get; set; }
public Tblinventory? Stock { get; set; }
public List<Unitofmeasure> Unitofmeasure { get; set; } = new List<Unitofmeasure>();
public string BaseUnit { get;set; } = string.Empty;
}
}

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"!;
}
}

5
Shared/Interfaces/IAnalytics.cs

@ -27,7 +27,7 @@ namespace Biskilog_Accounting.Shared.Interfaces
/// <param name="a_start"></param>
/// <param name="a_end"></param>
/// <returns></returns>
IEnumerable<ProductItem> GetMostPurchasedItem(DateTime a_start, DateTime a_end);
IEnumerable<MostPurchasedItem> GetMostPurchasedItem(DateTime a_start, DateTime a_end);
/// <summary>
/// Fetches a collection of cancelled transaction within a specified date range
/// </summary>
@ -41,7 +41,7 @@ namespace Biskilog_Accounting.Shared.Interfaces
/// <param name="a_start"></param>
/// <param name="a_end"></param>
/// <returns>A dictionary of transactions made by employees with employee name as key</returns>
IEnumerable<Dictionary<string, List<Tblcart>>> GetEmployeeSales(DateTime a_start, DateTime a_end);
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>
@ -49,5 +49,6 @@ namespace Biskilog_Accounting.Shared.Interfaces
/// <param name="a_end"></param>
/// <returns></returns>
IEnumerable<ProductPriceChange> GetPriceChanges(DateTime a_start, DateTime a_end);
void SetContraints(string a_token);
}
}

Loading…
Cancel
Save