BaseCalculation Engine

This commit is contained in:
Michał Zieliski
2024-05-24 20:38:32 +02:00
parent 25cf75e883
commit 7e084b4af2
5 changed files with 252 additions and 5 deletions

View File

@@ -0,0 +1,108 @@
using System.Globalization;
using DiunaBIWebAPI.dataProcessors;
using WebAPI.Models;
using AngouriMath;
using AngouriMath.Extensions;
namespace WebAPI.Calculator
{
public class BaseCalc
{
public string Expresion { get; set; }
private string ResultCode { get; set; }
private string Formula { get; set; }
public BaseCalc(string expresion)
{
Expresion = expresion;
Formula = Expresion.Split("=")[1];
ResultCode = Expresion.Split("=")[0];
}
public bool IsFormulaCorrect()
{
// check left side of expression
if (!ResultCode.StartsWith("[") || !ResultCode.EndsWith("]"))
{
return false;
}
if (!ResultCode.Substring(1, ResultCode.Length - 2).All(char.IsDigit))
{
return false;
}
ResultCode = ResultCode.Substring(1, ResultCode.Length - 2);
// check right side of expression
if (!(!string.IsNullOrEmpty(Formula) &&
Formula.All(c => char.IsDigit(c) || c == '[' || c == ']' || c == '+')))
{
return false;
}
return true;
}
public Record CalculateT3(List<Record> records)
{
Record result = new Record
{
Id = Guid.NewGuid(),
Code = this.ResultCode,
CreatedAt = DateTime.UtcNow,
ModifiedAt = DateTime.UtcNow,
};
List<string> codes = GetCodes();
List<Record> ingredients = new List<Record>();
foreach (string code in codes)
{
Record? ingredient = records.FirstOrDefault(r => r.Code == code);
if (ingredient == null)
{
throw new Exception($"Record for code {code} not found.");
}
ingredients.Add(ingredient);
}
for (int i = 1; i <= 32; i++)
{
string formula = Formula;
foreach (Record ingredient in ingredients)
{
formula = formula.Replace($"[{ingredient.Code}]", ProcessHelper.getValue(ingredient, i)?.ToString(CultureInfo.InvariantCulture));
}
if (formula.Contains("["))
{
throw new Exception($"Not all placeholders were replaced. Value{i} [{formula}]");
}
Entity expr = formula;
double val = (double)expr.EvalNumerical();
ProcessHelper.setValue(result, i, (double)expr.EvalNumerical());
}
return result;
}
private List<string> GetCodes()
{
List<string> codes = new List<string>();
int endIndex = -1;
while (true)
{
int startIndex = Formula.IndexOf("[", endIndex + 1, StringComparison.CurrentCulture);
endIndex = Formula.IndexOf("]", startIndex + 1, StringComparison.CurrentCulture);
if (startIndex == -1 || endIndex == -1)
{
break;
}
string valueCode = Formula.Substring(startIndex + 1, endIndex - startIndex - 1);
codes.Add(valueCode);
}
return codes;
}
}
}

View File

@@ -375,7 +375,7 @@ namespace WebAPI.Controllers
} }
if (processType == "T3-MultiSourceYearSummary") if (processType == "T3-MultiSourceYearSummary")
{ {
T3MultiSourceYearSummaryProcessor processor = new T3MultiSourceYearSummaryProcessor(db, googleSheetValues, this); T3MultiSourceYearSummaryProcessor processor = new T3MultiSourceYearSummaryProcessor(db, googleSheetValues, this, logsController);
processor.process(processWorker!); processor.process(processWorker!);
logsController.AddEntry(new LogEntry logsController.AddEntry(new LogEntry
@@ -433,7 +433,7 @@ namespace WebAPI.Controllers
} }
case "T3-MultiSourceSummary": case "T3-MultiSourceSummary":
{ {
T3MultiSourceSummaryProcessor processor = new T3MultiSourceSummaryProcessor(db, googleSheetValues, this); T3MultiSourceSummaryProcessor processor = new T3MultiSourceSummaryProcessor(db, googleSheetValues, this, logsController);
processor.process(processWorker!); processor.process(processWorker!);
break; break;
} }

View File

@@ -8,6 +8,7 @@
<PropertyGroup Condition=" '$(RunConfiguration)' == 'WebAPI' " /> <PropertyGroup Condition=" '$(RunConfiguration)' == 'WebAPI' " />
<ItemGroup> <ItemGroup>
<PackageReference Include="AngouriMath" Version="1.4.0-preview.3" />
<PackageReference Include="CsvHelper" Version="30.0.1" /> <PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="Google.Apis.Auth" Version="1.63.0" /> <PackageReference Include="Google.Apis.Auth" Version="1.63.0" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.63.0.3155" /> <PackageReference Include="Google.Apis.Drive.v3" Version="1.63.0.3155" />

View File

@@ -1,6 +1,7 @@
using DiunaBIWebAPI.dataProcessors; using DiunaBIWebAPI.dataProcessors;
using Google.Apis.Sheets.v4; using Google.Apis.Sheets.v4;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using WebAPI.Calculator;
using WebAPI.Controllers; using WebAPI.Controllers;
using WebAPI.Models; using WebAPI.Models;
@@ -11,15 +12,18 @@ namespace WebAPI.dataProcessors
private readonly AppDbContext db; private readonly AppDbContext db;
private readonly SpreadsheetsResource.ValuesResource googleSheetValues; private readonly SpreadsheetsResource.ValuesResource googleSheetValues;
private readonly LayersController controller; private readonly LayersController controller;
private readonly LogsController logsController;
public T3MultiSourceSummaryProcessor( public T3MultiSourceSummaryProcessor(
AppDbContext _db, AppDbContext _db,
SpreadsheetsResource.ValuesResource _googleSheetValues, SpreadsheetsResource.ValuesResource _googleSheetValues,
LayersController _controller) LayersController _controller,
LogsController _logsController)
{ {
db = _db; db = _db;
googleSheetValues = _googleSheetValues; googleSheetValues = _googleSheetValues;
controller = _controller; controller = _controller;
logsController = _logsController;
} }
public void process(Layer processWorker) public void process(Layer processWorker)
@@ -105,6 +109,71 @@ namespace WebAPI.dataProcessors
} }
newRecords.Add(processedRecord); newRecords.Add(processedRecord);
} }
// Dynamic Codes
List<Record>? dynamicCodes = processWorker.Records?.Where(x => x.Code == "DynamicCode").ToList();
if (dynamicCodes != null && dynamicCodes.Any())
{
foreach (Record dynamicCode in dynamicCodes)
{
try
{
if (dynamicCode.Desc1 == null)
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Formula in Record {dynamicCode.Id} is missing.",
CreatedAt = DateTime.UtcNow
});
continue;
}
BaseCalc calc = new BaseCalc(dynamicCode.Desc1);
if (!calc.IsFormulaCorrect())
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Formula {calc.Expresion} in Record {dynamicCode.Id} is not correct",
CreatedAt = DateTime.UtcNow
});
continue;
}
try
{
newRecords.Add(calc.CalculateT3(newRecords));
}
catch (Exception e)
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Formula {calc.Expresion} in Record {dynamicCode.Id} error: {e.Message}",
CreatedAt = DateTime.UtcNow
});
}
}
catch (Exception e)
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Calculation error {dynamicCode.Id}: {e.Message} ",
CreatedAt = DateTime.UtcNow
});
}
}
}
if (isNew) if (isNew)
{ {

View File

@@ -1,6 +1,7 @@
using DiunaBIWebAPI.dataProcessors; using DiunaBIWebAPI.dataProcessors;
using Google.Apis.Sheets.v4; using Google.Apis.Sheets.v4;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using WebAPI.Calculator;
using WebAPI.Controllers; using WebAPI.Controllers;
using WebAPI.Models; using WebAPI.Models;
@@ -11,15 +12,18 @@ namespace WebAPI.dataProcessors
private readonly AppDbContext db; private readonly AppDbContext db;
private readonly SpreadsheetsResource.ValuesResource googleSheetValues; private readonly SpreadsheetsResource.ValuesResource googleSheetValues;
private readonly LayersController controller; private readonly LayersController controller;
private readonly LogsController logsController;
public T3MultiSourceYearSummaryProcessor( public T3MultiSourceYearSummaryProcessor(
AppDbContext _db, AppDbContext _db,
SpreadsheetsResource.ValuesResource _googleSheetValues, SpreadsheetsResource.ValuesResource _googleSheetValues,
LayersController _controller) LayersController _controller,
LogsController _logsController)
{ {
db = _db; db = _db;
googleSheetValues = _googleSheetValues; googleSheetValues = _googleSheetValues;
controller = _controller; controller = _controller;
logsController = _logsController;
} }
public void process(Layer processWorker) public void process(Layer processWorker)
@@ -140,8 +144,73 @@ namespace WebAPI.dataProcessors
} }
} }
newRecords.Add(processedRecord); newRecords.Add(processedRecord);
} }
// Dynamic Codes
List<Record>? dynamicCodes = processWorker.Records?.Where(x => x.Code == "DynamicCode").ToList();
if (dynamicCodes != null && dynamicCodes.Any())
{
foreach (Record dynamicCode in dynamicCodes)
{
try
{
if (dynamicCode.Desc1 == null)
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Formula in Record {dynamicCode.Id} is missing.",
CreatedAt = DateTime.UtcNow
});
continue;
}
BaseCalc calc = new BaseCalc(dynamicCode.Desc1);
if (!calc.IsFormulaCorrect())
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Formula {calc.Expresion} in Record {dynamicCode.Id} is not correct",
CreatedAt = DateTime.UtcNow
});
continue;
}
try
{
newRecords.Add(calc.CalculateT3(newRecords));
}
catch (Exception e)
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Formula {calc.Expresion} in Record {dynamicCode.Id} error: {e.Message}",
CreatedAt = DateTime.UtcNow
});
}
}
catch (Exception e)
{
logsController.AddEntry(new LogEntry
{
Title = $"{processWorker!.Name}, {processWorker.Id}",
Type = LogEntryType.warning,
LogType = LogType.process,
Message = $"Calculation error {dynamicCode.Id}: {e.Message} ",
CreatedAt = DateTime.UtcNow
});
}
}
}
if (isNew) if (isNew)
{ {
db.Layers.Add(processedLayer); db.Layers.Add(processedLayer);