Improve keyuser export workflow
This commit is contained in:
@@ -62,13 +62,45 @@ public sealed class DashboardPageService : IDashboardPageService
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
var consolidatedRows = BuildConsolidatedRows(await db.ExportSettings.FirstOrDefaultAsync() ?? new());
|
||||
var latestSuccessfulSiteRun = logs
|
||||
.Where(log => log.Status == "OK")
|
||||
.Select(log => (DateTime?)log.Timestamp)
|
||||
.OrderByDescending(timestamp => timestamp)
|
||||
.FirstOrDefault();
|
||||
var latestConsolidatedRun = consolidatedRows
|
||||
.Select(row => row.LastModified)
|
||||
.OrderByDescending(timestamp => timestamp)
|
||||
.FirstOrDefault();
|
||||
|
||||
return new DashboardPageState
|
||||
{
|
||||
DashboardRows = rows,
|
||||
ConsolidatedRows = BuildConsolidatedRows(await db.ExportSettings.FirstOrDefaultAsync() ?? new())
|
||||
ConsolidatedRows = consolidatedRows,
|
||||
ReadinessWarnings = BuildReadinessWarnings(sites, sourceSystems),
|
||||
IsConsolidatedStale = latestSuccessfulSiteRun.HasValue &&
|
||||
(!latestConsolidatedRun.HasValue || latestSuccessfulSiteRun.Value > latestConsolidatedRun.Value),
|
||||
LatestSuccessfulSiteRun = latestSuccessfulSiteRun,
|
||||
LatestConsolidatedRun = latestConsolidatedRun
|
||||
};
|
||||
}
|
||||
|
||||
private static List<string> BuildReadinessWarnings(List<Site> activeSites, List<SourceSystemDefinition> sourceSystems)
|
||||
{
|
||||
var warnings = new List<string>();
|
||||
foreach (var site in activeSites.OrderBy(x => x.Land).ThenBy(x => x.TSC))
|
||||
{
|
||||
var sourceSystem = sourceSystems.FirstOrDefault(x => string.Equals(x.Code, site.SourceSystem, StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.Equals(sourceSystem?.ConnectionKind, SourceSystemConnectionKinds.ManualExcel, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(site.ManualImportFilePath))
|
||||
warnings.Add($"{site.Land} / {site.TSC}: manuelle Excel-/CSV-Datei fehlt.");
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
private static string ResolveDashboardSapServiceUrl(Site site, List<SourceSystemDefinition> sourceSystems)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(site.SapServiceUrl))
|
||||
@@ -114,6 +146,10 @@ public sealed class DashboardPageState
|
||||
{
|
||||
public List<DashboardRow> DashboardRows { get; set; } = [];
|
||||
public List<ConsolidatedDashboardRow> ConsolidatedRows { get; set; } = [];
|
||||
public List<string> ReadinessWarnings { get; set; } = [];
|
||||
public bool IsConsolidatedStale { get; set; }
|
||||
public DateTime? LatestSuccessfulSiteRun { get; set; }
|
||||
public DateTime? LatestConsolidatedRun { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DashboardRow
|
||||
|
||||
@@ -146,11 +146,98 @@ public class ExcelExportService : IExcelExportService
|
||||
|
||||
ws.Columns().AdjustToContents();
|
||||
if (includeFinanceHelpSheet)
|
||||
{
|
||||
AddFinanceSummarySheet(workbook, records);
|
||||
AddFinanceHelpSheet(workbook);
|
||||
}
|
||||
|
||||
workbook.SaveAs(fullPath);
|
||||
}
|
||||
|
||||
private static void AddFinanceSummarySheet(XLWorkbook workbook, List<SalesRecord> records)
|
||||
{
|
||||
var ws = workbook.Worksheets.Add("Finance Summary");
|
||||
ws.Position = 1;
|
||||
ws.Cell(1, 1).Value = "Finance Summary";
|
||||
ws.Cell(1, 1).Style.Font.Bold = true;
|
||||
ws.Cell(1, 1).Style.Font.FontSize = 14;
|
||||
ws.Cell(2, 1).Value = "Diese Summen verwenden dieselbe Finance-Sicht wie die Spalten Finance | ... im Blatt Sales.";
|
||||
|
||||
var headers = new[]
|
||||
{
|
||||
"Year",
|
||||
"Country Key",
|
||||
"Currency",
|
||||
"Included Rows",
|
||||
"Net Sales Actual",
|
||||
"Excluded Rows",
|
||||
"Hinweis"
|
||||
};
|
||||
|
||||
for (var i = 0; i < headers.Length; i++)
|
||||
{
|
||||
ws.Cell(4, i + 1).Value = headers[i];
|
||||
ws.Cell(4, i + 1).Style.Font.Bold = true;
|
||||
}
|
||||
|
||||
var italyBlankSupplierCountryRows = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var summaryRows = records
|
||||
.Select(record =>
|
||||
{
|
||||
var financeDate = ResolveFinanceDate(record);
|
||||
var countryKey = ResolveFinanceCountryKey(record.Land, record.Tsc);
|
||||
var include = ResolveFinanceInclude(record, countryKey, italyBlankSupplierCountryRows) && record.SalesPriceValue != 0m;
|
||||
return new
|
||||
{
|
||||
Year = financeDate.Year,
|
||||
CountryKey = countryKey,
|
||||
Currency = ResolveFinanceCurrency(record),
|
||||
Include = include,
|
||||
Value = include ? record.SalesPriceValue : 0m
|
||||
};
|
||||
})
|
||||
.GroupBy(row => new { row.Year, row.CountryKey, row.Currency })
|
||||
.OrderBy(group => group.Key.Year)
|
||||
.ThenBy(group => group.Key.CountryKey, StringComparer.OrdinalIgnoreCase)
|
||||
.ThenBy(group => group.Key.Currency, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(group => new
|
||||
{
|
||||
group.Key.Year,
|
||||
group.Key.CountryKey,
|
||||
group.Key.Currency,
|
||||
IncludedRows = group.Count(row => row.Include),
|
||||
NetSalesActual = group.Sum(row => row.Value),
|
||||
ExcludedRows = group.Count(row => !row.Include)
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var rowIndex = 5;
|
||||
foreach (var row in summaryRows)
|
||||
{
|
||||
ws.Cell(rowIndex, 1).Value = row.Year;
|
||||
ws.Cell(rowIndex, 2).Value = row.CountryKey;
|
||||
ws.Cell(rowIndex, 3).Value = row.Currency;
|
||||
ws.Cell(rowIndex, 4).Value = row.IncludedRows;
|
||||
ws.Cell(rowIndex, 5).Value = row.NetSalesActual;
|
||||
ws.Cell(rowIndex, 6).Value = row.ExcludedRows;
|
||||
ws.Cell(rowIndex, 7).Value = BuildFinanceSummaryHint(row.CountryKey);
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
ws.Column(5).Style.NumberFormat.Format = "#,##0.00";
|
||||
ws.Columns().AdjustToContents();
|
||||
}
|
||||
|
||||
private static string BuildFinanceSummaryHint(string countryKey)
|
||||
=> countryKey.ToUpperInvariant() switch
|
||||
{
|
||||
"DE" => "DE Alphaplan ist technisch vorbereitet; Kundenlaender/Filter fachlich noch bestaetigen.",
|
||||
"IT" => "IT: Trafag Italia ausgeschlossen; doppelte Blank-Supplier-Zeilen nur einmal.",
|
||||
"UK" => "UK: Sage/Manual Excel, Credit Notes negativ.",
|
||||
"ES" => "ES: Sage CSV/Manual Excel, REC/Credit Notes negativ.",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
private static void AddFinanceHelpSheet(XLWorkbook workbook)
|
||||
{
|
||||
var ws = workbook.Worksheets.Add("Finance Filter Hilfe");
|
||||
|
||||
@@ -96,7 +96,7 @@ public class ExportOrchestrationService
|
||||
lock (_lock)
|
||||
{
|
||||
if (_runningExports.ContainsKey(site.Id)) return null;
|
||||
_runningExports[site.Id] = "HANA Abfrage...";
|
||||
_runningExports[site.Id] = BuildInitialExportStatus(site);
|
||||
}
|
||||
NotifyChanged();
|
||||
|
||||
@@ -134,6 +134,17 @@ public class ExportOrchestrationService
|
||||
OnExportStatusChanged?.Invoke();
|
||||
}
|
||||
|
||||
private static string BuildInitialExportStatus(Site site)
|
||||
{
|
||||
var sourceSystem = (site.SourceSystem ?? string.Empty).Trim().ToUpperInvariant();
|
||||
return sourceSystem switch
|
||||
{
|
||||
"MANUAL_EXCEL" => "Manuelle Excel/CSV lesen...",
|
||||
"SAP" => "SAP OData lesen...",
|
||||
_ => "Quelldaten lesen..."
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<string?> RunConsolidatedExportAsync()
|
||||
{
|
||||
lock (_lock)
|
||||
|
||||
Reference in New Issue
Block a user