cockpit vorbereitung
This commit is contained in:
@@ -33,6 +33,37 @@
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Class="pa-4 mb-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-3">Zentrale Roh-Auswertung</MudText>
|
||||
<MudAlert Severity="Severity.Info" Dense Variant="Variant.Outlined" Class="mb-3">
|
||||
Diese Sicht arbeitet direkt auf `CentralSalesRecords` und zeigt nur fachlich neutrale Rohkennzahlen. Kein Intercompany-Filter, keine CHF-Umrechnung, kein Budget, keine Spartenlogik.
|
||||
</MudAlert>
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudSelect T="int" @bind-Value="_selectedCentralYear" Label="Jahr" Dense>
|
||||
@foreach (var year in _centralYears)
|
||||
{
|
||||
<MudSelectItem Value="@year">@year</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudSelect T="int?" @bind-Value="_selectedCentralMonth" Label="Monat (optional)" Dense Clearable>
|
||||
@foreach (var month in Enumerable.Range(1, 12))
|
||||
{
|
||||
<MudSelectItem Value="@((int?)month)">@($"{month:D2}")</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="AnalyzeCentral"
|
||||
StartIcon="@Icons.Material.Filled.QueryStats" Disabled="_analyzingCentral || _selectedCentralYear == 0">
|
||||
@(_analyzingCentral ? "Analysiere..." : "Zentrale Auswertung laden")
|
||||
</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
@if (_result is not null)
|
||||
{
|
||||
<MudGrid Class="mb-4">
|
||||
@@ -91,16 +122,147 @@
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
@if (_centralResult is not null)
|
||||
{
|
||||
<MudGrid Class="mb-4">
|
||||
<MudItem xs="12" md="2"><MudPaper Class="pa-4"><MudText Typo="Typo.caption">Zeilen</MudText><MudText Typo="Typo.h6">@_centralResult.Summary.RowCount.ToString("N0")</MudText></MudPaper></MudItem>
|
||||
<MudItem xs="12" md="2"><MudPaper Class="pa-4"><MudText Typo="Typo.caption">Rechnungen</MudText><MudText Typo="Typo.h6">@_centralResult.Summary.InvoiceCount.ToString("N0")</MudText></MudPaper></MudItem>
|
||||
<MudItem xs="12" md="2"><MudPaper Class="pa-4"><MudText Typo="Typo.caption">Standorte</MudText><MudText Typo="Typo.h6">@_centralResult.Summary.SiteCount.ToString("N0")</MudText></MudPaper></MudItem>
|
||||
<MudItem xs="12" md="2"><MudPaper Class="pa-4"><MudText Typo="Typo.caption">Länder</MudText><MudText Typo="Typo.h6">@_centralResult.Summary.CountryCount.ToString("N0")</MudText></MudPaper></MudItem>
|
||||
<MudItem xs="12" md="2"><MudPaper Class="pa-4"><MudText Typo="Typo.caption">Währungen</MudText><MudText Typo="Typo.h6">@_centralResult.Summary.CurrencyCount.ToString("N0")</MudText></MudPaper></MudItem>
|
||||
<MudItem xs="12" md="2"><MudPaper Class="pa-4"><MudText Typo="Typo.caption">Periode</MudText><MudText Typo="Typo.h6">@BuildPeriodLabel(_centralResult)</MudText></MudPaper></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudPaper Class="pa-4 mb-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">Hinweise</MudText>
|
||||
@foreach (var notice in _centralResult.Notices)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Dense Variant="Variant.Outlined" Class="mb-2">@notice</MudAlert>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
<MudGrid Class="mb-4">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">Jahresumsatz 2025/2026</MudText>
|
||||
<MudTable Items="_centralResult.YearlyTotals" Dense Hover Striped>
|
||||
<HeaderContent>
|
||||
<MudTh>Jahr</MudTh>
|
||||
<MudTh>Währung</MudTh>
|
||||
<MudTh>Umsatz</MudTh>
|
||||
<MudTh>Zeilen</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Year</MudTd>
|
||||
<MudTd>@context.Currency</MudTd>
|
||||
<MudTd>@context.SalesValue.ToString("N2")</MudTd>
|
||||
<MudTd>@context.RowCount.ToString("N0")</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">Monatsumsatz</MudText>
|
||||
<MudTable Items="_centralResult.MonthlyTotals" Dense Hover Striped>
|
||||
<HeaderContent>
|
||||
<MudTh>Monat</MudTh>
|
||||
<MudTh>Währung</MudTh>
|
||||
<MudTh>Umsatz</MudTh>
|
||||
<MudTh>Zeilen</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Label</MudTd>
|
||||
<MudTd>@context.Currency</MudTd>
|
||||
<MudTd>@context.SalesValue.ToString("N2")</MudTd>
|
||||
<MudTd>@context.RowCount.ToString("N0")</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Class="mb-4">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">Tagesumsatz im ausgewählten Monat</MudText>
|
||||
<MudTable Items="_centralResult.DailyTotals" Dense Hover Striped>
|
||||
<HeaderContent>
|
||||
<MudTh>Tag</MudTh>
|
||||
<MudTh>Währung</MudTh>
|
||||
<MudTh>Umsatz</MudTh>
|
||||
<MudTh>Zeilen</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Label</MudTd>
|
||||
<MudTd>@context.Currency</MudTd>
|
||||
<MudTd>@context.SalesValue.ToString("N2")</MudTd>
|
||||
<MudTd>@context.RowCount.ToString("N0")</MudTd>
|
||||
</RowTemplate>
|
||||
<NoRecordsContent>
|
||||
<MudText Typo="Typo.caption">Für die Tagessicht bitte zusätzlich einen Monat wählen.</MudText>
|
||||
</NoRecordsContent>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">Umsatz nach Quelle</MudText>
|
||||
<MudTable Items="_centralResult.SourceSystemTotals" Dense Hover Striped>
|
||||
<HeaderContent>
|
||||
<MudTh>Quelle</MudTh>
|
||||
<MudTh>Währung</MudTh>
|
||||
<MudTh>Umsatz</MudTh>
|
||||
<MudTh>Rechnungen</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Label</MudTd>
|
||||
<MudTd>@context.Currency</MudTd>
|
||||
<MudTd>@context.SalesValue.ToString("N2")</MudTd>
|
||||
<MudTd>@context.InvoiceCount.ToString("N0")</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudPaper Class="pa-4" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">Umsatz nach Land</MudText>
|
||||
<MudTable Items="_centralResult.CountryTotals" Dense Hover Striped>
|
||||
<HeaderContent>
|
||||
<MudTh>Land</MudTh>
|
||||
<MudTh>Währung</MudTh>
|
||||
<MudTh>Umsatz</MudTh>
|
||||
<MudTh>Rechnungen</MudTh>
|
||||
<MudTh>Zeilen</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Label</MudTd>
|
||||
<MudTd>@context.Currency</MudTd>
|
||||
<MudTd>@context.SalesValue.ToString("N2")</MudTd>
|
||||
<MudTd>@context.InvoiceCount.ToString("N0")</MudTd>
|
||||
<MudTd>@context.RowCount.ToString("N0")</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<ManagementCockpitFileOption> _files = [];
|
||||
private List<int> _centralYears = [];
|
||||
private string? _selectedFilePath;
|
||||
private ManagementCockpitResult? _result;
|
||||
private ManagementCockpitCentralResult? _centralResult;
|
||||
private int _selectedCentralYear;
|
||||
private int? _selectedCentralMonth;
|
||||
private bool _loadingFiles;
|
||||
private bool _analyzing;
|
||||
private bool _analyzingCentral;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await ReloadFiles();
|
||||
await ReloadCentralYears();
|
||||
}
|
||||
|
||||
private async Task ReloadFiles()
|
||||
@@ -117,6 +279,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReloadCentralYears()
|
||||
{
|
||||
_centralYears = await CockpitService.GetAvailableCentralYearsAsync();
|
||||
if (_selectedCentralYear == 0)
|
||||
_selectedCentralYear = _centralYears.LastOrDefault();
|
||||
}
|
||||
|
||||
private async Task Analyze()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_selectedFilePath))
|
||||
@@ -137,10 +306,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AnalyzeCentral()
|
||||
{
|
||||
if (_selectedCentralYear == 0)
|
||||
return;
|
||||
|
||||
_analyzingCentral = true;
|
||||
try
|
||||
{
|
||||
_centralResult = await CockpitService.AnalyzeCentralAsync(_selectedCentralYear, _selectedCentralMonth);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Zentrale Auswertung konnte nicht erzeugt werden: {ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_analyzingCentral = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Severity MapSeverity(string severity) => severity switch
|
||||
{
|
||||
"Warning" => Severity.Warning,
|
||||
"Error" => Severity.Error,
|
||||
_ => Severity.Info
|
||||
};
|
||||
|
||||
private static string BuildPeriodLabel(ManagementCockpitCentralResult result)
|
||||
{
|
||||
if (result.Summary.PeriodStart is null || result.Summary.PeriodEnd is null)
|
||||
return "-";
|
||||
|
||||
return $"{result.Summary.PeriodStart.Value:dd.MM.yyyy} - {result.Summary.PeriodEnd.Value:dd.MM.yyyy}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,13 +497,35 @@
|
||||
|
||||
if (result != true) return;
|
||||
|
||||
try
|
||||
{
|
||||
using var db = await DbFactory.CreateDbContextAsync();
|
||||
var linkedSites = await db.Sites
|
||||
.Where(s => s.HanaServerId == server.Id)
|
||||
.OrderBy(s => s.Land)
|
||||
.Select(s => $"{s.Land} ({s.TSC})")
|
||||
.ToListAsync();
|
||||
|
||||
if (linkedSites.Count > 0)
|
||||
{
|
||||
Snackbar.Add(
|
||||
$"Server kann nicht gelöscht werden. Noch verknüpfte Standorte: {string.Join(", ", linkedSites)}",
|
||||
Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = await db.HanaServers.FindAsync(server.Id);
|
||||
if (entity is not null)
|
||||
{
|
||||
db.HanaServers.Remove(entity);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Server konnte nicht gelöscht werden: {ex.Message}", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
await LoadDataAsync();
|
||||
Snackbar.Add("Server gelöscht", Severity.Info);
|
||||
|
||||
@@ -48,3 +48,52 @@ public class ManagementCockpitResult
|
||||
public List<ManagementCockpitTopItem> TopSalesEmployees { get; set; } = [];
|
||||
public Dictionary<string, int> DataQualityCounts { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public class ManagementCockpitCentralFilter
|
||||
{
|
||||
public int Year { get; set; }
|
||||
public int? Month { get; set; }
|
||||
}
|
||||
|
||||
public class ManagementCockpitCentralSummary
|
||||
{
|
||||
public int RowCount { get; set; }
|
||||
public int InvoiceCount { get; set; }
|
||||
public int SiteCount { get; set; }
|
||||
public int CountryCount { get; set; }
|
||||
public int CurrencyCount { get; set; }
|
||||
public DateTime? PeriodStart { get; set; }
|
||||
public DateTime? PeriodEnd { get; set; }
|
||||
}
|
||||
|
||||
public class ManagementCockpitTimeValueRow
|
||||
{
|
||||
public string Label { get; set; } = string.Empty;
|
||||
public int? Year { get; set; }
|
||||
public int? Month { get; set; }
|
||||
public int? Day { get; set; }
|
||||
public string Currency { get; set; } = string.Empty;
|
||||
public decimal SalesValue { get; set; }
|
||||
public int RowCount { get; set; }
|
||||
}
|
||||
|
||||
public class ManagementCockpitDimensionValueRow
|
||||
{
|
||||
public string Label { get; set; } = string.Empty;
|
||||
public string Currency { get; set; } = string.Empty;
|
||||
public decimal SalesValue { get; set; }
|
||||
public int RowCount { get; set; }
|
||||
public int InvoiceCount { get; set; }
|
||||
}
|
||||
|
||||
public class ManagementCockpitCentralResult
|
||||
{
|
||||
public ManagementCockpitCentralFilter Filter { get; set; } = new();
|
||||
public ManagementCockpitCentralSummary Summary { get; set; } = new();
|
||||
public List<string> Notices { get; set; } = [];
|
||||
public List<ManagementCockpitTimeValueRow> YearlyTotals { get; set; } = [];
|
||||
public List<ManagementCockpitTimeValueRow> MonthlyTotals { get; set; } = [];
|
||||
public List<ManagementCockpitTimeValueRow> DailyTotals { get; set; } = [];
|
||||
public List<ManagementCockpitDimensionValueRow> SourceSystemTotals { get; set; } = [];
|
||||
public List<ManagementCockpitDimensionValueRow> CountryTotals { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -6,4 +6,6 @@ public interface IManagementCockpitService
|
||||
{
|
||||
Task<List<ManagementCockpitFileOption>> GetAvailableFilesAsync();
|
||||
Task<ManagementCockpitResult> AnalyzeAsync(string filePath);
|
||||
Task<List<int>> GetAvailableCentralYearsAsync();
|
||||
Task<ManagementCockpitCentralResult> AnalyzeCentralAsync(int year, int? month);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,152 @@ public class ManagementCockpitService : IManagementCockpitService
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public async Task<List<int>> GetAvailableCentralYearsAsync()
|
||||
{
|
||||
using var db = await _dbFactory.CreateDbContextAsync();
|
||||
var years = await db.CentralSalesRecords
|
||||
.Select(r => r.InvoiceDate.HasValue ? r.InvoiceDate.Value.Year : r.ExtractionDate.Year)
|
||||
.Distinct()
|
||||
.OrderBy(x => x)
|
||||
.ToListAsync();
|
||||
|
||||
return years;
|
||||
}
|
||||
|
||||
public async Task<ManagementCockpitCentralResult> AnalyzeCentralAsync(int year, int? month)
|
||||
{
|
||||
using var db = await _dbFactory.CreateDbContextAsync();
|
||||
var baseRows = await db.CentralSalesRecords
|
||||
.Select(r => new CentralCockpitRow
|
||||
{
|
||||
SourceSystem = r.SourceSystem,
|
||||
Land = r.Land,
|
||||
Tsc = r.Tsc,
|
||||
InvoiceNumber = r.InvoiceNumber,
|
||||
SalesCurrency = string.IsNullOrWhiteSpace(r.SalesCurrency) ? "-" : r.SalesCurrency,
|
||||
SalesValue = r.SalesPriceValue,
|
||||
PeriodDate = r.InvoiceDate ?? r.ExtractionDate
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
if (baseRows.Count == 0)
|
||||
throw new InvalidOperationException("Die zentrale Tabelle enthält noch keine Datensätze.");
|
||||
|
||||
var selectedRows = baseRows
|
||||
.Where(r => r.PeriodDate.Year == year && (!month.HasValue || r.PeriodDate.Month == month.Value))
|
||||
.ToList();
|
||||
|
||||
if (selectedRows.Count == 0)
|
||||
throw new InvalidOperationException("Für den gewählten Zeitraum gibt es keine Datensätze in der zentralen Tabelle.");
|
||||
|
||||
var yearlyRows = baseRows
|
||||
.Where(r => r.PeriodDate.Year == 2025 || r.PeriodDate.Year == 2026)
|
||||
.ToList();
|
||||
|
||||
var dailyBaseRows = selectedRows
|
||||
.Where(r => month.HasValue)
|
||||
.ToList();
|
||||
|
||||
return new ManagementCockpitCentralResult
|
||||
{
|
||||
Filter = new ManagementCockpitCentralFilter
|
||||
{
|
||||
Year = year,
|
||||
Month = month
|
||||
},
|
||||
Summary = new ManagementCockpitCentralSummary
|
||||
{
|
||||
RowCount = selectedRows.Count,
|
||||
InvoiceCount = selectedRows.Select(x => x.InvoiceNumber).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase).Count(),
|
||||
SiteCount = selectedRows.Select(x => x.Tsc).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase).Count(),
|
||||
CountryCount = selectedRows.Select(x => x.Land).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase).Count(),
|
||||
CurrencyCount = selectedRows.Select(x => x.SalesCurrency).Distinct(StringComparer.OrdinalIgnoreCase).Count(),
|
||||
PeriodStart = selectedRows.Min(x => x.PeriodDate),
|
||||
PeriodEnd = selectedRows.Max(x => x.PeriodDate)
|
||||
},
|
||||
Notices =
|
||||
[
|
||||
"Roh-Auswertung aus CentralSalesRecords.",
|
||||
"Keine Intercompany-Bereinigung angewendet.",
|
||||
"Keine CHF-Umrechnung angewendet. Umsatz bleibt in Sales Currency.",
|
||||
"Kein Budget- und kein Spartemapping angewendet.",
|
||||
"Periodenlogik basiert auf Invoice Date, falls vorhanden, sonst auf Extraction Date."
|
||||
],
|
||||
YearlyTotals = yearlyRows
|
||||
.GroupBy(x => new { x.PeriodDate.Year, x.SalesCurrency })
|
||||
.OrderBy(g => g.Key.Year)
|
||||
.ThenBy(g => g.Key.SalesCurrency, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => new ManagementCockpitTimeValueRow
|
||||
{
|
||||
Label = g.Key.Year.ToString(),
|
||||
Year = g.Key.Year,
|
||||
Currency = g.Key.SalesCurrency,
|
||||
SalesValue = g.Sum(x => x.SalesValue),
|
||||
RowCount = g.Count()
|
||||
})
|
||||
.ToList(),
|
||||
MonthlyTotals = selectedRows
|
||||
.GroupBy(x => new { x.PeriodDate.Year, x.PeriodDate.Month, x.SalesCurrency })
|
||||
.OrderBy(g => g.Key.Year)
|
||||
.ThenBy(g => g.Key.Month)
|
||||
.ThenBy(g => g.Key.SalesCurrency, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => new ManagementCockpitTimeValueRow
|
||||
{
|
||||
Label = $"{g.Key.Year:D4}-{g.Key.Month:D2}",
|
||||
Year = g.Key.Year,
|
||||
Month = g.Key.Month,
|
||||
Currency = g.Key.SalesCurrency,
|
||||
SalesValue = g.Sum(x => x.SalesValue),
|
||||
RowCount = g.Count()
|
||||
})
|
||||
.ToList(),
|
||||
DailyTotals = dailyBaseRows
|
||||
.GroupBy(x => new { x.PeriodDate.Year, x.PeriodDate.Month, x.PeriodDate.Day, x.SalesCurrency })
|
||||
.OrderBy(g => g.Key.Year)
|
||||
.ThenBy(g => g.Key.Month)
|
||||
.ThenBy(g => g.Key.Day)
|
||||
.ThenBy(g => g.Key.SalesCurrency, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => new ManagementCockpitTimeValueRow
|
||||
{
|
||||
Label = $"{g.Key.Year:D4}-{g.Key.Month:D2}-{g.Key.Day:D2}",
|
||||
Year = g.Key.Year,
|
||||
Month = g.Key.Month,
|
||||
Day = g.Key.Day,
|
||||
Currency = g.Key.SalesCurrency,
|
||||
SalesValue = g.Sum(x => x.SalesValue),
|
||||
RowCount = g.Count()
|
||||
})
|
||||
.ToList(),
|
||||
SourceSystemTotals = selectedRows
|
||||
.GroupBy(x => new { x.SourceSystem, x.SalesCurrency })
|
||||
.OrderBy(g => g.Key.SourceSystem, StringComparer.OrdinalIgnoreCase)
|
||||
.ThenBy(g => g.Key.SalesCurrency, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => new ManagementCockpitDimensionValueRow
|
||||
{
|
||||
Label = g.Key.SourceSystem,
|
||||
Currency = g.Key.SalesCurrency,
|
||||
SalesValue = g.Sum(x => x.SalesValue),
|
||||
RowCount = g.Count(),
|
||||
InvoiceCount = g.Select(x => x.InvoiceNumber).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase).Count()
|
||||
})
|
||||
.ToList(),
|
||||
CountryTotals = selectedRows
|
||||
.GroupBy(x => new { x.Land, x.SalesCurrency })
|
||||
.OrderByDescending(g => g.Sum(x => x.SalesValue))
|
||||
.ThenBy(g => g.Key.Land, StringComparer.OrdinalIgnoreCase)
|
||||
.ThenBy(g => g.Key.SalesCurrency, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => new ManagementCockpitDimensionValueRow
|
||||
{
|
||||
Label = g.Key.Land,
|
||||
Currency = g.Key.SalesCurrency,
|
||||
SalesValue = g.Sum(x => x.SalesValue),
|
||||
RowCount = g.Count(),
|
||||
InvoiceCount = g.Select(x => x.InvoiceNumber).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase).Count()
|
||||
})
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetCandidateDirectories(ExportSettings settings)
|
||||
{
|
||||
yield return Path.Combine(AppContext.BaseDirectory, "output");
|
||||
@@ -384,4 +530,15 @@ public class ManagementCockpitService : IManagementCockpitService
|
||||
public decimal EstimatedCostTotal { get; set; }
|
||||
public decimal EstimatedMarginTotal { get; set; }
|
||||
}
|
||||
|
||||
private class CentralCockpitRow
|
||||
{
|
||||
public string SourceSystem { get; set; } = string.Empty;
|
||||
public string Land { get; set; } = string.Empty;
|
||||
public string Tsc { get; set; } = string.Empty;
|
||||
public string InvoiceNumber { get; set; } = string.Empty;
|
||||
public string SalesCurrency { get; set; } = string.Empty;
|
||||
public decimal SalesValue { get; set; }
|
||||
public DateTime PeriodDate { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user