BaseCalculation Engine
This commit is contained in:
108
WebAPI/Calculators/BaseCalc.cs
Normal file
108
WebAPI/Calculators/BaseCalc.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user