Calculations in R6
This commit is contained in:
@@ -40,6 +40,30 @@ public class BaseCalc
|
||||
Formula.All(c => char.IsDigit(c) || c == '[' || c == ']' || c == '+' || c == '-');
|
||||
}
|
||||
|
||||
public double Calculate(IReadOnlyDictionary<string, double> ingredients)
|
||||
{
|
||||
if (ingredients == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ingredients));
|
||||
}
|
||||
|
||||
var codes = GetCodes();
|
||||
var missing = codes.Where(x => !ingredients.ContainsKey(x)).ToList();
|
||||
if (missing.Any())
|
||||
{
|
||||
throw new ArgumentException($"Missing ingredients: {string.Join(", ", missing)}");
|
||||
}
|
||||
|
||||
var formula = ingredients.Aggregate(Formula,
|
||||
(current, ingredient) => current.Replace($"[{ingredient.Key}]", ingredient.Value.ToString(CultureInfo.InvariantCulture)));
|
||||
if (formula.Contains('['))
|
||||
{
|
||||
throw new Exception($"Not all placeholders were replaced. Value{1} [{formula}]");
|
||||
}
|
||||
Entity expr = formula;
|
||||
return (double)expr.EvalNumerical();
|
||||
}
|
||||
|
||||
public Record CalculateT3(List<Record> records)
|
||||
{
|
||||
var resultCode = ResultCode;
|
||||
@@ -81,7 +105,6 @@ public class BaseCalc
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public Record CalculateT1(List<Record> records)
|
||||
{
|
||||
var resultCode = ResultCode;
|
||||
@@ -121,8 +144,7 @@ public class BaseCalc
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetCodes()
|
||||
public List<string> GetCodes()
|
||||
{
|
||||
var codes = new List<string>();
|
||||
var endIndex = -1;
|
||||
@@ -143,4 +165,9 @@ public class BaseCalc
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
public string GetResultCode()
|
||||
{
|
||||
return ResultCode;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using Google.Apis.Sheets.v4.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DiunaBI.Core.Models;
|
||||
using DiunaBI.Core.Database.Context;
|
||||
using DiunaBI.Core.Services.Calculations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace DiunaBI.Plugins.Morska.Processors;
|
||||
@@ -22,7 +23,7 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
private int Year { get; set; }
|
||||
private string? CostSource { get; set; }
|
||||
private string? SellSource { get; set; }
|
||||
private List<Record> Mappings = new List<Record>();
|
||||
private List<string> SellCodesConfiguration { get; set; } = new();
|
||||
|
||||
public MorskaD6Processor(
|
||||
AppDbContext db,
|
||||
@@ -60,7 +61,6 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadConfiguration(Layer processWorker)
|
||||
{
|
||||
if (processWorker.Records == null)
|
||||
@@ -88,17 +88,22 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
throw new InvalidOperationException("SourceLayerCosts record not found");
|
||||
}
|
||||
|
||||
Mappings = processWorker.Records.Where(x => x.Code!.StartsWith("Sell-Code-")).ToList();
|
||||
if (Mappings.Count == 0)
|
||||
SellCodesConfiguration = processWorker.Records
|
||||
.Where(x => string.Equals(x.Code, "Sell-Code", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(x => x.Desc1!.Trim())
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
if (!SellCodesConfiguration.Any())
|
||||
{
|
||||
throw new InvalidOperationException("No Sell-Code- records found");
|
||||
throw new InvalidOperationException("Sell-Code records not found");
|
||||
}
|
||||
|
||||
_logger.LogDebug(
|
||||
"{ProcessorType}: Configuration loaded - Year: {Year}, SourceCost: {CostSource}, SourceSell: {SellSource}",
|
||||
ProcessorType, Year, CostSource, SellSource);
|
||||
}
|
||||
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
var errors = new List<string>();
|
||||
@@ -114,7 +119,6 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
|
||||
_logger.LogDebug("{ProcessorType}: Configuration validation passed", ProcessorType);
|
||||
}
|
||||
|
||||
private void PerformProcessing(Layer processWorker)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
@@ -135,7 +139,6 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
"{ProcessorType}: Successfully processed {RecordCount} records for layer {LayerName} ({LayerId})",
|
||||
ProcessorType, newRecords.Count, processedLayer.Name, processedLayer.Id);
|
||||
}
|
||||
|
||||
private Layer GetOrCreateProcessedLayer(Layer processWorker)
|
||||
{
|
||||
var processedLayer = _db.Layers
|
||||
@@ -172,7 +175,6 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
|
||||
return processedLayer;
|
||||
}
|
||||
|
||||
private List<Layer> GetDataSources()
|
||||
{
|
||||
var costDataSource = _db.Layers
|
||||
@@ -201,7 +203,6 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
|
||||
return [costDataSource, sellDataSource];
|
||||
}
|
||||
|
||||
private List<Record> ProcessRecords(List<Layer> dataSources)
|
||||
{
|
||||
var newRecords = new List<Record>();
|
||||
@@ -240,7 +241,7 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
}
|
||||
|
||||
var groupedData = firstDataSource.Records
|
||||
.Where(record => record.Code != null && record.Code.Length >= 8 && record.Value1.HasValue)
|
||||
.Where(record => record is { Code: { Length: >= 8 }, Value1: not null })
|
||||
.Select(record => new
|
||||
{
|
||||
Month = record.Code!.Substring(4, 2),
|
||||
@@ -275,13 +276,28 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
|
||||
foreach (var groupedRecord in groupedData)
|
||||
{
|
||||
// hack for 2206 ([2206]=[2206]+[2203]
|
||||
double value = groupedRecord.TotalValue;
|
||||
if (groupedRecord.FinalCode.StartsWith("2206"))
|
||||
{
|
||||
var month = groupedRecord.FinalCode.Substring(4, 2);
|
||||
var toSumUp = groupedData.FirstOrDefault(x => x.FinalCode == $"2203{month}");
|
||||
if (toSumUp == null)
|
||||
{
|
||||
_logger.LogWarning("{ProcessorType}: 2203{month} not found (to sum up with 2206{month}", ProcessorType, month, month);
|
||||
}
|
||||
else
|
||||
{
|
||||
value+= toSumUp.TotalValue;
|
||||
}
|
||||
}
|
||||
var newRecord = new Record
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Code = groupedRecord.FinalCode,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ModifiedAt = DateTime.UtcNow,
|
||||
Value1 = groupedRecord.TotalValue,
|
||||
Value1 = value,
|
||||
Desc1 = groupedRecord.Department
|
||||
};
|
||||
|
||||
@@ -303,25 +319,52 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
return newRecords;
|
||||
}
|
||||
|
||||
// Create mapping dictionary from Mappings
|
||||
var mappingDictionary = new Dictionary<string, string>();
|
||||
foreach (var mapping in Mappings)
|
||||
{
|
||||
if (mapping.Code != null && mapping.Desc1 != null)
|
||||
{
|
||||
// Extract code from "Sell-Code-XXXX" -> "XXXX"
|
||||
var sourceCode = mapping.Code.Replace("Sell-Code-", "");
|
||||
var targetCode = mapping.Desc1;
|
||||
mappingDictionary[sourceCode] = targetCode;
|
||||
|
||||
_logger.LogDebug("{ProcessorType}: Loaded mapping {SourceCode} -> {TargetCode}",
|
||||
ProcessorType, sourceCode, targetCode);
|
||||
foreach (var sellCodeConfig in SellCodesConfiguration)
|
||||
{
|
||||
var calc = new BaseCalc(sellCodeConfig);
|
||||
if (!calc.IsFormulaCorrect())
|
||||
{
|
||||
_logger.LogDebug("{ProcessorType}: Invalid formula: {SellCodeConfig}", ProcessorType, sellCodeConfig);
|
||||
continue;
|
||||
}
|
||||
var codes = calc.GetCodes();
|
||||
var resultCode = calc.GetResultCode();
|
||||
|
||||
for (var i = 1; i <= 12; i++)
|
||||
{
|
||||
var monthRecords = secondDataSource.Records
|
||||
.Where(x => x.Code is { Length: 6 } && x.Code.EndsWith($"{i:D2}") && x.Value1.HasValue)
|
||||
.ToList();
|
||||
if (monthRecords.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var ingredients = monthRecords.ToDictionary(x => x.Code!.Substring(0, 4), x => x.Value1!.Value);
|
||||
double result = 0;
|
||||
try
|
||||
{
|
||||
result = calc.Calculate(ingredients);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "{ProcessorType}: Failed to calculate sell code {ResultCode} for month {Month}",
|
||||
ProcessorType, resultCode, i);
|
||||
}
|
||||
|
||||
var newRecord = new Record
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Code = $"{resultCode}{i:D2}",
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ModifiedAt = DateTime.UtcNow,
|
||||
Value1 = result
|
||||
};
|
||||
newRecords.Add(newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// Dictionary to collect results (key: target code with month, value: sum)
|
||||
var sellResults = new Dictionary<string, double>();
|
||||
|
||||
/*
|
||||
// Process records from secondDataSource
|
||||
foreach (var record in secondDataSource.Records)
|
||||
{
|
||||
@@ -391,10 +434,9 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
_logger.LogInformation(
|
||||
"{ProcessorType}: Processed {GroupCount} unique grouped records from {OriginalCount} original records",
|
||||
ProcessorType, newRecords.Count, firstDataSource.Records.Count);
|
||||
|
||||
*/
|
||||
return newRecords;
|
||||
}
|
||||
|
||||
private void SaveProcessedLayer(Layer processedLayer, List<Record> newRecords)
|
||||
{
|
||||
var existsInDb = _db.Layers.Any(x => x.Id == processedLayer.Id);
|
||||
@@ -416,7 +458,6 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
_logger.LogDebug("{ProcessorType}: Saved {RecordCount} records for layer {LayerId}",
|
||||
ProcessorType, newRecords.Count, processedLayer.Id);
|
||||
}
|
||||
|
||||
private void SaveRecords(Guid layerId, ICollection<Record> records)
|
||||
{
|
||||
// Remove existing records for this layer
|
||||
@@ -442,12 +483,10 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
_logger.LogDebug("{ProcessorType}: Added {RecordCount} new records for layer {LayerId}",
|
||||
ProcessorType, records.Count, layerId);
|
||||
}
|
||||
|
||||
private string? GetRecordValue(ICollection<Record> records, string code)
|
||||
{
|
||||
return records.FirstOrDefault(x => x.Code == code)?.Desc1;
|
||||
}
|
||||
|
||||
private string GetDepartmentByType(string type, string originalDepartment)
|
||||
{
|
||||
var typesThatUseDepartment = new[] { "02", "09", "10", "11", "12", "13", "14", "15" };
|
||||
@@ -481,6 +520,8 @@ public class MorskaD6Processor : MorskaBaseProcessor
|
||||
}
|
||||
}
|
||||
|
||||
// Export to Google
|
||||
|
||||
private void UpdateGoogleSheetReport(Guid sourceId)
|
||||
{
|
||||
const string googleSheetName = "Raport_R6_DRAFT_2025";
|
||||
|
||||
Reference in New Issue
Block a user