Add provisional Germany Alphaplan import
This commit is contained in:
@@ -2,6 +2,49 @@
|
||||
|
||||
Stand: 2026-05-20
|
||||
|
||||
## Nachtrag 2026-05-20 DE Alphaplan-Excel provisorisch eingebaut
|
||||
|
||||
Erledigt:
|
||||
|
||||
- Deutschland wird als manueller Excel-Standort vorbereitet:
|
||||
- `TSC = TRDE`
|
||||
- `Land = Deutschland`
|
||||
- `SourceSystem = MANUAL_EXCEL`
|
||||
- neuer Standort ist standardmaessig inaktiv, damit Export-All nicht ohne Datei scheitert
|
||||
- Alphaplan-Mapping wird automatisch geseedet:
|
||||
- `NettoPreisGesamtX` -> `SalesPriceValue`
|
||||
- `Belegnummer` -> `InvoiceNumber`
|
||||
- `Position` -> `PositionOnInvoice`
|
||||
- `ArtikelNummer` -> `Material`
|
||||
- `ArtikelBezeichnung` -> `Name`
|
||||
- `Warengruppen-Bezeichnung` -> `ProductGroup`
|
||||
- `Anz. VE` -> `Quantity`
|
||||
- `Name/Land Lieferant`, `Name/Land Kunde`, `Branche`, `Versandbedingung`
|
||||
- `Belegdatum-Rechnung` -> `PostingDate` und `InvoiceDate`
|
||||
- `DocumentType = Alphaplan Excel`
|
||||
- Datei erhalten:
|
||||
|
||||
```text
|
||||
docs/2025_DataExport_DE.xlsx
|
||||
```
|
||||
|
||||
Bedienung:
|
||||
|
||||
1. App starten.
|
||||
2. `Standorte` oeffnen.
|
||||
3. Deutschland / `TRDE` oeffnen.
|
||||
4. Alphaplan-Excel hochladen oder Pfad setzen.
|
||||
5. Standort aktivieren.
|
||||
6. Standortexport fuer DE ausfuehren.
|
||||
7. Danach zentrale Excel erzeugen; DE ist dann in `CentralSalesRecords` und im Endexcel enthalten.
|
||||
|
||||
Offen fachlich:
|
||||
|
||||
- Komplette Summe `NettoPreisGesamtX`: `4'154'690.05 EUR`.
|
||||
- Nur `Land Kunde = Deutschland`: `3'455'276.64 EUR`.
|
||||
- Sollwert DE: `3'635'923.00 EUR`.
|
||||
- Finance/Munir muss bestaetigen, welche Kundenlaender oder Filter zum offiziellen DE-Ist gehoeren.
|
||||
|
||||
## Nachtrag 2026-05-20 IIS 500 aktueller Stand
|
||||
|
||||
Vollstaendige Doku:
|
||||
|
||||
@@ -13,6 +13,7 @@ public class DatabaseSeedService : IDatabaseSeedService
|
||||
EnsureSourceSystemDefinitions(db);
|
||||
EnsureCentralHanaServerRecords(db);
|
||||
EnsureSpainManualExcelSite(db);
|
||||
EnsureGermanyManualExcelSite(db);
|
||||
EnsureUkManualExcelFolder(db);
|
||||
EnsureSapODataDachSite(db);
|
||||
EnsureFinanceReferenceDefaults(db);
|
||||
@@ -288,6 +289,61 @@ public class DatabaseSeedService : IDatabaseSeedService
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
private static void EnsureGermanyManualExcelSite(AppDbContext db)
|
||||
{
|
||||
if (db.Sites.Count() <= 1)
|
||||
return;
|
||||
|
||||
var existing = db.Sites
|
||||
.OrderBy(x => x.Id)
|
||||
.FirstOrDefault(x =>
|
||||
x.TSC == "TRDE" ||
|
||||
x.Land == "Deutschland" ||
|
||||
x.Land == "Germany");
|
||||
|
||||
if (existing is null)
|
||||
{
|
||||
existing = new Site
|
||||
{
|
||||
Schema = string.Empty,
|
||||
TSC = "TRDE",
|
||||
Land = "Deutschland",
|
||||
SourceSystem = "MANUAL_EXCEL",
|
||||
IsActive = false
|
||||
};
|
||||
db.Sites.Add(existing);
|
||||
db.SaveChanges();
|
||||
}
|
||||
else
|
||||
{
|
||||
var changed = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(existing.TSC))
|
||||
{
|
||||
existing.TSC = "TRDE";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(existing.Land))
|
||||
{
|
||||
existing.Land = "Deutschland";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(existing.SourceSystem))
|
||||
{
|
||||
existing.SourceSystem = "MANUAL_EXCEL";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
if (CanSeedSiteDependentTable(db, "ManualExcelColumnMappings"))
|
||||
EnsureGermanyManualExcelMapping(db, existing.Id);
|
||||
}
|
||||
|
||||
private static void EnsureUkManualExcelFolder(AppDbContext db)
|
||||
{
|
||||
var existing = db.Sites
|
||||
@@ -411,6 +467,91 @@ public class DatabaseSeedService : IDatabaseSeedService
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
private static void EnsureGermanyManualExcelMapping(AppDbContext db, int siteId)
|
||||
{
|
||||
var mappings = new (string Target, string Source, bool Required)[]
|
||||
{
|
||||
(nameof(SalesRecord.ExtractionDate), "Export-Datum", false),
|
||||
(nameof(SalesRecord.Tsc), "=TRDE", false),
|
||||
(nameof(SalesRecord.Land), "=Deutschland", false),
|
||||
(nameof(SalesRecord.InvoiceNumber), "Belegnummer", true),
|
||||
(nameof(SalesRecord.PositionOnInvoice), "Position", false),
|
||||
(nameof(SalesRecord.Material), "ArtikelNummer", false),
|
||||
(nameof(SalesRecord.Name), "ArtikelBezeichnung", false),
|
||||
(nameof(SalesRecord.ProductGroup), "Warengruppen-Bezeichnung", false),
|
||||
(nameof(SalesRecord.Quantity), "Anz. VE", false),
|
||||
(nameof(SalesRecord.SupplierNumber), "Lieferanten Nummer", false),
|
||||
(nameof(SalesRecord.SupplierName), "Name Lieferant", false),
|
||||
(nameof(SalesRecord.SupplierCountry), "Land Lieferant", false),
|
||||
(nameof(SalesRecord.CustomerNumber), "AdressNummer-Kunde", false),
|
||||
(nameof(SalesRecord.CustomerName), "Name Kunde", false),
|
||||
(nameof(SalesRecord.CustomerCountry), "Land Kunde", false),
|
||||
(nameof(SalesRecord.CustomerIndustry), "Branche", false),
|
||||
(nameof(SalesRecord.StandardCost), "EinstandsPreis", false),
|
||||
(nameof(SalesRecord.StandardCostCurrency), "W\u00e4hrung", false),
|
||||
(nameof(SalesRecord.SalesPriceValue), "NettoPreisGesamtX", true),
|
||||
(nameof(SalesRecord.SalesCurrency), "W\u00e4hrung", false),
|
||||
(nameof(SalesRecord.DocumentCurrency), "W\u00e4hrung", false),
|
||||
(nameof(SalesRecord.CompanyCurrency), "W\u00e4hrung", false),
|
||||
(nameof(SalesRecord.Incoterms2020), "Versandbedingung", false),
|
||||
(nameof(SalesRecord.SalesResponsibleEmployee), "AdressNummer_V", false),
|
||||
(nameof(SalesRecord.PostingDate), "Belegdatum-Rechnung", false),
|
||||
(nameof(SalesRecord.InvoiceDate), "Belegdatum-Rechnung", false),
|
||||
(nameof(SalesRecord.OrderDate), "BelegDatum Auftrag", false),
|
||||
(nameof(SalesRecord.DocumentType), "=Alphaplan Excel", false)
|
||||
};
|
||||
|
||||
var changed = false;
|
||||
for (var i = 0; i < mappings.Length; i++)
|
||||
{
|
||||
var mapping = db.ManualExcelColumnMappings
|
||||
.OrderBy(x => x.Id)
|
||||
.FirstOrDefault(x => x.SiteId == siteId && x.TargetField == mappings[i].Target);
|
||||
|
||||
if (mapping is null)
|
||||
{
|
||||
db.ManualExcelColumnMappings.Add(new ManualExcelColumnMapping
|
||||
{
|
||||
SiteId = siteId,
|
||||
TargetField = mappings[i].Target,
|
||||
SourceHeader = mappings[i].Source,
|
||||
IsRequired = mappings[i].Required,
|
||||
IsActive = true,
|
||||
SortOrder = i
|
||||
});
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mapping.SourceHeader != mappings[i].Source)
|
||||
{
|
||||
mapping.SourceHeader = mappings[i].Source;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (mapping.IsRequired != mappings[i].Required)
|
||||
{
|
||||
mapping.IsRequired = mappings[i].Required;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!mapping.IsActive)
|
||||
{
|
||||
mapping.IsActive = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (mapping.SortOrder != i)
|
||||
{
|
||||
mapping.SortOrder = i;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
private static void EnsureSapODataDachSite(AppDbContext db)
|
||||
{
|
||||
if (db.Sites.Count() <= 1)
|
||||
|
||||
@@ -89,6 +89,18 @@ public class DatabaseInitializationServiceTests : IDisposable
|
||||
|
||||
Assert.Contains(db.HanaServers, x => x.SourceSystem == "BI1");
|
||||
Assert.Contains(db.HanaServers, x => x.SourceSystem == "SAGE");
|
||||
var germany = Assert.Single(db.Sites, x => x.TSC == "TRDE" && x.Land == "Deutschland");
|
||||
Assert.Equal("MANUAL_EXCEL", germany.SourceSystem);
|
||||
Assert.False(germany.IsActive);
|
||||
Assert.Contains(db.ManualExcelColumnMappings, x =>
|
||||
x.SiteId == germany.Id &&
|
||||
x.TargetField == nameof(SalesRecord.SalesPriceValue) &&
|
||||
x.SourceHeader == "NettoPreisGesamtX" &&
|
||||
x.IsRequired);
|
||||
Assert.Contains(db.ManualExcelColumnMappings, x =>
|
||||
x.SiteId == germany.Id &&
|
||||
x.TargetField == nameof(SalesRecord.DocumentType) &&
|
||||
x.SourceHeader == "=Alphaplan Excel");
|
||||
Assert.Equal(2, db.FieldTransformationRules.Count(x => x.SourceSystem == "MANUAL_EXCEL"));
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -144,6 +144,16 @@ Ob FKDAT fuer diese Quelle fachlich Buchungsdatum oder Fakturadatum ist, muss be
|
||||
|
||||
## DE
|
||||
|
||||
Aktuelle Quelle:
|
||||
|
||||
```text
|
||||
SourceSystem = MANUAL_EXCEL
|
||||
Fachlich = Alphaplan Excel
|
||||
TSC = TRDE
|
||||
Land = Deutschland
|
||||
Aktueller Datei-/Teststand = docs/2025_DataExport_DE.xlsx
|
||||
```
|
||||
|
||||
Aktueller Referenzwert:
|
||||
|
||||
```text
|
||||
@@ -151,30 +161,56 @@ FinanceReference.DE.LocalCurrencyValue = 3'635'923
|
||||
Hauswaehrung = EUR
|
||||
```
|
||||
|
||||
Formel im Vergleich:
|
||||
Provisorisches Import-Mapping:
|
||||
|
||||
```text
|
||||
Ist = gemeinsame Auswahl aus CentralSalesRecords fuer Key DE
|
||||
SalesPriceValue = NettoPreisGesamtX
|
||||
InvoiceNumber = Belegnummer
|
||||
PositionOnInvoice = Position
|
||||
Material = ArtikelNummer
|
||||
Name = ArtikelBezeichnung
|
||||
ProductGroup = Warengruppen-Bezeichnung
|
||||
Quantity = Anz. VE
|
||||
SupplierNumber = Lieferanten Nummer
|
||||
SupplierName = Name Lieferant
|
||||
SupplierCountry = Land Lieferant
|
||||
CustomerNumber = AdressNummer-Kunde
|
||||
CustomerName = Name Kunde
|
||||
CustomerCountry = Land Kunde
|
||||
CustomerIndustry = Branche
|
||||
StandardCost = EinstandsPreis
|
||||
SalesCurrency / DocumentCurrency / CompanyCurrency = Waehrung
|
||||
Incoterms2020 = Versandbedingung
|
||||
SalesResponsibleEmployee = AdressNummer_V
|
||||
PostingDate / InvoiceDate = Belegdatum-Rechnung
|
||||
OrderDate = BelegDatum Auftrag
|
||||
DocumentType = Alphaplan Excel
|
||||
```
|
||||
|
||||
Das heisst konkret:
|
||||
Technischer Ablauf:
|
||||
|
||||
```text
|
||||
bevorzugt SalesPriceValue, wenn Belegkopfwerte wiederholt aussehen
|
||||
sonst Nettofakturawert Hauswaehrung pro Position
|
||||
sonst Nettofakturawert Hauswaehrung pro Beleg dedupliziert
|
||||
sonst SalesPriceValue
|
||||
DE wird als manueller Excel-Standort vorbereitet.
|
||||
Nach Upload/Pfad setzen und Aktivieren wird die Alphaplan-Datei beim Standortexport gelesen.
|
||||
Die gelesenen Zeilen werden in CentralSalesRecords gespeichert.
|
||||
Die zentrale Excel enthaelt danach DE-Zeilen mit Finance | Country Key = DE.
|
||||
```
|
||||
|
||||
Erster Befund aus `docs/2025_DataExport_DE.xlsx`:
|
||||
|
||||
```text
|
||||
Zeilen: 6'198 Datenzeilen
|
||||
Summe NettoPreisGesamtX komplett: 4'154'690.05 EUR
|
||||
Nur Land Kunde = Deutschland: 3'455'276.64 EUR
|
||||
Deutschland + China: 3'647'592.44 EUR
|
||||
Sollwert DE: 3'635'923.00 EUR
|
||||
```
|
||||
|
||||
Offen:
|
||||
|
||||
```text
|
||||
Fuer DE ist in diesem Dokument keine bestaetigte landesspezifische Importformel dokumentiert.
|
||||
Wenn DE aus Sage kommt, muss in einer Sitzung geklaert werden:
|
||||
- welche Datei/CSV geladen wird
|
||||
- welches Betragsfeld Rhino verwendet
|
||||
- wie Gutschriften, Zuschlaege, Freight/Charges und Steuer getrennt werden
|
||||
```
|
||||
- Finance muss bestaetigen, welche Kundenlaender fuer DE zum offiziellen Ist gehoeren.
|
||||
- Manager-Input nennt Warengruppen-Codes und Versandbedingungs-Codes, im Excel sind aktuell primär Bezeichnungen/Texte sichtbar.
|
||||
- Falls nach Codes gefiltert werden soll, braucht der Export eigene Code-Spalten oder eine eindeutige Mapping-Tabelle Text -> Code.
|
||||
|
||||
## ES
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Die Logik darf nicht auf einzelne Testzahlen optimiert werden. Sie muss je Jahr
|
||||
| IT | Hauswaehrung verwenden. Intercompany separat ausweisen und weiter fachlich abgrenzen. |
|
||||
| UK | Sage/Manual-Excel. Hauswaehrung `GBP` verwenden. Netto ohne VAT; Credit Notes muessen negativ in die Summe laufen. |
|
||||
| CH / AT | SAP-ZSCHWEIZ liefert Schweiz und Oesterreich aus gleichem System; Trennung ueber Buchungskreis bzw. Reporting-Land. |
|
||||
| DE | Alphaplan-Excel; finaler Jahresfile erforderlich. Sample darf nicht als Jahres-Ist verwendet werden. |
|
||||
| DE | Alphaplan-Excel; finaler Jahresfile `docs/2025_DataExport_DE.xlsx` liegt vor. Provisorisches Mapping nutzt `NettoPreisGesamtX` als SalesPriceValue. Fachlich offen bleibt, welche Kundenlaender fuer den Sollwert eingeschlossen werden. |
|
||||
| ES | Sage-CSV. `ImporteNeto` als Nettozeile ohne VAT verwenden; Credit Notes/REC negativ; Datumsbasis ist `FechaFactura`, solange Finance nichts anderes vorgibt. |
|
||||
|
||||
## Intercompany / 2nd Party
|
||||
@@ -69,7 +69,7 @@ Ergebnis im Reporting:
|
||||
- IN: Anzeige muss fachlich `INR` zeigen, auch wenn Quellzeilen verschiedene Belegwaehrungen enthalten.
|
||||
- IT: IC-Kundenliste final bestaetigen.
|
||||
- CH / AT: echtes SAP-Buchungsdatum pruefen, falls `ZSCHWEIZ` aktuell nur Fakturadatum liefert.
|
||||
- DE: finalen Jahresfile laden.
|
||||
- DE: finaler Alphaplan-Jahresfile liegt vor und ist technisch mappbar. Rohsumme `NettoPreisGesamtX` komplett ist `4'154'690.05 EUR`; nur `Land Kunde = Deutschland` ist `3'455'276.64 EUR`; Sollwert ist `3'635'923.00 EUR`. Offene Fachfrage: welche Kundenlaender/Abgrenzungen gehoeren offiziell zu DE?
|
||||
- ES: Aktuell `3'082'320.18 EUR` gegen Soll `3'102'333.61`; Differenz `-20'013.43 EUR`. CSV nutzt `ImporteNeto`; Credit Notes/REC sind negativ. Offen bleiben Perioden-/Serienabgrenzung und ob Rhino eine andere Sage-Auswertung nutzt.
|
||||
|
||||
## Pruefstand 2026-05-11
|
||||
|
||||
@@ -1703,6 +1703,49 @@ Ergebnis:
|
||||
- Build erfolgreich.
|
||||
- 3 bestehende MudBlazor-Analyzer-Warnungen in `Logs.razor`, `Transformations.razor` und `Standorte.razor`.
|
||||
|
||||
## DE Alphaplan-Excel provisorisch vorbereitet 2026-05-20
|
||||
|
||||
Geaendert:
|
||||
|
||||
- Deutschland wird beim Start als manueller Excel-Standort vorbereitet:
|
||||
- `TSC = TRDE`
|
||||
- `Land = Deutschland`
|
||||
- `SourceSystem = MANUAL_EXCEL`
|
||||
- `IsActive = false`, damit der Gesamtexport ohne gesetzte Datei nicht scheitert.
|
||||
- Alphaplan-Mapping wird fuer Deutschland geseedet:
|
||||
- `NettoPreisGesamtX` -> `SalesPriceValue`
|
||||
- `Belegnummer`, `Position`, `ArtikelNummer`, `ArtikelBezeichnung`
|
||||
- `Warengruppen-Bezeichnung`, `Anz. VE`
|
||||
- Lieferant/Kunde/Land/Branche
|
||||
- `Waehrung`, `Versandbedingung`, `AdressNummer_V`
|
||||
- `Belegdatum-Rechnung` fuer Posting-/Invoice-Date
|
||||
- `DocumentType = Alphaplan Excel`
|
||||
- Testdatei erhalten und eingeordnet:
|
||||
- `docs/2025_DataExport_DE.xlsx`
|
||||
|
||||
Erster Befund:
|
||||
|
||||
- `NettoPreisGesamtX` komplett: `4'154'690.05 EUR`
|
||||
- `Land Kunde = Deutschland`: `3'455'276.64 EUR`
|
||||
- `Land Kunde = Deutschland + China`: `3'647'592.44 EUR`
|
||||
- Sollwert DE: `3'635'923.00 EUR`
|
||||
|
||||
Offen:
|
||||
|
||||
- Finance/Munir muss bestaetigen, welche Kundenlaender und Filter in Alphaplan fuer den offiziellen DE-Istwert gelten.
|
||||
- Manager-Input nennt Warengruppen- und Versandbedingungs-Codes; im Excel sind aktuell vor allem Bezeichnungen/Texte sichtbar.
|
||||
|
||||
Verifikation:
|
||||
|
||||
```text
|
||||
dotnet test .\TrafagSalesExporter.Tests\TrafagSalesExporter.Tests.csproj --no-restore -p:UseAppHost=false -p:OutDir=.\obj\verify_de_alphaplan\ --verbosity minimal
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- 75/75 Tests erfolgreich.
|
||||
- Bestehende Warnungen: NU1900 wegen lokaler Paket-Sicherheitsdatenabfrage, sowie bekannte MudBlazor-Analyzer-Warnungen zu `Dense`.
|
||||
|
||||
## Management Cockpit zentrale Filterkopplung 2026-05-15
|
||||
|
||||
Geaendert:
|
||||
|
||||
Reference in New Issue
Block a user