Document finance and mapping updates

This commit is contained in:
2026-06-02 18:06:30 +02:00
parent 6470cb8751
commit 37a175551b
9 changed files with 511 additions and 33 deletions
Binary file not shown.
@@ -1,9 +1,15 @@
param(
[string]$ServerInstance = "localhost",
[string]$Database = "Sage",
[ValidateSet("Full", "Range")]
[string]$ExportMode = "Full",
[ValidateSet("InvoiceDate", "LineRegistrationDate")]
[string]$DateFilter = "InvoiceDate",
[int]$Year = 2025,
[datetime]$FromDate = "2025-01-01",
[datetime]$ToDate = "2026-01-01",
[string]$OutputDirectory = (Join-Path $env:USERPROFILE "Desktop")
[string]$OutputDirectory = (Join-Path $env:USERPROFILE "Desktop"),
[string]$OutputFileName = ""
)
$ErrorActionPreference = "Stop"
@@ -97,12 +103,41 @@ function Export-QueryToCsv {
}
}
if ($ExportMode -eq "Full") {
$FromDate = [datetime]::new($Year, 1, 1)
$ToDate = $FromDate.AddYears(1)
}
else {
if (-not $PSBoundParameters.ContainsKey("ToDate")) {
throw "Range export requires -ToDate. Example: -ExportMode Range -FromDate '2025-05-01' -ToDate '2025-06-01'"
}
}
if ($ToDate.Date -le $FromDate.Date) {
throw "ToDate must be later than FromDate. FromDate=$($FromDate.ToString("yyyy-MM-dd")), ToDate=$($ToDate.ToString("yyyy-MM-dd"))"
}
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$runDirectory = Join-Path $OutputDirectory "Sage_Spain_Sales_Export_$timestamp"
New-Item -ItemType Directory -Path $runDirectory -Force | Out-Null
$csvPath = Join-Path $runDirectory "Spain_Sales_2025.csv"
$summaryPath = Join-Path $runDirectory "Spain_Sales_2025_summary.txt"
if ([string]::IsNullOrWhiteSpace($OutputFileName)) {
$fromToken = $FromDate.ToString("yyyyMMdd")
$toToken = $ToDate.Date.AddDays(-1).ToString("yyyyMMdd")
$kindToken = $ExportMode.ToLowerInvariant()
$OutputFileName = "Spain_Sales_${kindToken}_${fromToken}_to_${toToken}.csv"
}
$csvPath = Join-Path $runDirectory $OutputFileName
$summaryPath = Join-Path $runDirectory ([System.IO.Path]::GetFileNameWithoutExtension($OutputFileName) + "_summary.txt")
$datePredicate = if ($DateFilter -eq "LineRegistrationDate") {
"COALESCE(l.FechaRegistro, c.FechaFactura) >= @FromDate
AND COALESCE(l.FechaRegistro, c.FechaFactura) < @ToDate"
} else {
"c.FechaFactura >= @FromDate
AND c.FechaFactura < @ToDate"
}
$sql = @"
SELECT
@@ -170,8 +205,7 @@ JOIN dbo.LineasAlbaranCliente l
AND l.EjercicioAlbaran = c.EjercicioAlbaran
AND l.SerieAlbaran = c.SerieAlbaran
AND l.NumeroAlbaran = c.NumeroAlbaran
WHERE c.FechaFactura >= @FromDate
AND c.FechaFactura < @ToDate
WHERE $datePredicate
ORDER BY
c.FechaFactura,
c.SerieFactura,
@@ -188,6 +222,8 @@ Sage Spain Sales CSV export
Created: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
Server instance: $ServerInstance
Database: $Database
Export mode: $ExportMode
Date filter mode: $DateFilter
From date: $($FromDate.ToString("yyyy-MM-dd"))
To date: $($ToDate.ToString("yyyy-MM-dd"))
@@ -204,14 +240,15 @@ Source:
dbo.CabeceraAlbaranCliente joined with dbo.LineasAlbaranCliente
Filter:
CabeceraAlbaranCliente.FechaFactura >= FromDate
CabeceraAlbaranCliente.FechaFactura < ToDate
$datePredicate
Notes:
- Currency is set to EUR because Sage exports EnEuros_=-1 and CodigoDivisa is empty in the analysed rows.
- SalesPriceValue uses LineasAlbaranCliente.ImporteNeto; credit notes are forced negative.
- DocumentNetAmount uses CabeceraAlbaranCliente.BaseImponible; credit notes are forced negative.
- Credit notes are marked when TipoNuevaFra=2, SerieFactura='REC', or StatusAbono is non-zero.
- Full exports use the complete selected year.
- Range exports use the explicit FromDate/ToDate window.
"@ | Set-Content -LiteralPath $summaryPath -Encoding UTF8
Write-Host "Created:"
@@ -8,14 +8,27 @@ PowerShell commands:
Set-ExecutionPolicy -Scope Process Bypass
.\Export-SageSpainSalesCsv.ps1
Full export, default year 2025:
.\Export-SageSpainSalesCsv.ps1 -ExportMode Full -Year 2025
Range export, explicit window:
.\Export-SageSpainSalesCsv.ps1 -ExportMode Range -FromDate "2025-05-01" -ToDate "2025-06-01"
Range export by registration date, useful for new/changed records registered in a period:
.\Export-SageSpainSalesCsv.ps1 -ExportMode Range -DateFilter LineRegistrationDate -FromDate "2025-05-01" -ToDate "2025-06-01"
Output folder on Desktop:
Sage_Spain_Sales_Export_YYYYMMDD_HHMMSS
Files created:
- Spain_Sales_2025.csv
- Spain_Sales_2025_summary.txt
- Spain_Sales_full_YYYY0101_to_YYYY1231.csv for full export
- Spain_Sales_range_YYYYMMDD_to_YYYYMMDD.csv for range export
- Matching *_summary.txt file
The script only reads SQL Server data. It does not change Sage or SQL Server.
@@ -24,9 +37,12 @@ Default source:
- Database: Sage
- Header: dbo.CabeceraAlbaranCliente
- Lines: dbo.LineasAlbaranCliente
- Date filter: CabeceraAlbaranCliente.FechaFactura from 2025-01-01 to 2026-01-01
- Full export date filter: CabeceraAlbaranCliente.FechaFactura from YYYY-01-01 to next YYYY-01-01
- Range export date filter: explicit FromDate/ToDate
- DateFilter InvoiceDate uses CabeceraAlbaranCliente.FechaFactura
- DateFilter LineRegistrationDate uses LineasAlbaranCliente.FechaRegistro, with fallback to FechaFactura
- Sales value: LineasAlbaranCliente.ImporteNeto
If the SQL instance or database name differs:
.\Export-SageSpainSalesCsv.ps1 -ServerInstance "localhost" -Database "Sage"
.\Export-SageSpainSalesCsv.ps1 -ServerInstance "localhost" -Database "Sage" -ExportMode Full -Year 2025
@@ -932,27 +932,38 @@ public class DatabaseSeedService : IDatabaseSeedService
private static void EnsureBudgetExchangeRateDefaults(AppDbContext db)
{
var defaults = new (string From, string To, decimal Rate)[]
var defaults = new (int Year, string From, string To, decimal Rate)[]
{
("CHF", "CHF", 1m),
("USD", "CHF", 0.85m),
("EUR", "CHF", 0.95m),
("GBP", "CHF", 1.13m),
("CNY", "CHF", 1m / 8.50m),
("INR", "CHF", 1m / 90.91m),
("CZK", "CHF", 1m / 25.64m),
("PLN", "CHF", 0.22m),
("JPY", "CHF", 1m / 156.25m)
(2025, "CHF", "CHF", 1m),
(2025, "USD", "CHF", 0.85m),
(2025, "EUR", "CHF", 0.95m),
(2025, "GBP", "CHF", 1.13m),
(2025, "CNY", "CHF", 1m / 8.50m),
(2025, "INR", "CHF", 1m / 90.91m),
(2025, "CZK", "CHF", 1m / 25.64m),
(2025, "PLN", "CHF", 0.22m),
(2025, "JPY", "CHF", 1m / 156.25m),
(2026, "CHF", "CHF", 1m),
(2026, "USD", "CHF", 0.80m),
(2026, "EUR", "CHF", 0.94m),
(2026, "GBP", "CHF", 1.09m),
(2026, "CNY", "CHF", 1m / 8.50m),
(2026, "INR", "CHF", 1m / 110m),
(2026, "CZK", "CHF", 1m / 26m),
(2026, "PLN", "CHF", 0.22m),
(2026, "JPY", "CHF", 1m / 175m)
};
var changed = false;
foreach (var item in defaults)
{
var validFrom = new DateTime(item.Year, 1, 1);
var notes = $"Budget {item.Year}";
var exists = db.CurrencyExchangeRates.Any(x =>
x.FromCurrency == item.From &&
x.ToCurrency == item.To &&
x.ValidFrom == new DateTime(2025, 1, 1) &&
x.Notes == "Budget 2025");
x.ValidFrom == validFrom &&
x.Notes == notes);
if (exists)
continue;
@@ -961,9 +972,9 @@ public class DatabaseSeedService : IDatabaseSeedService
FromCurrency = item.From,
ToCurrency = item.To,
Rate = item.Rate,
ValidFrom = new DateTime(2025, 1, 1),
ValidTo = new DateTime(2025, 12, 31),
Notes = "Budget 2025",
ValidFrom = validFrom,
ValidTo = new DateTime(item.Year, 12, 31),
Notes = notes,
IsActive = true
});
changed = true;
@@ -0,0 +1,251 @@
# Finance Sitzungspunkte Andreas
Stand: 2026-06-02
Zweck: Kompakte Zusammenfassung der letzten Finance-/Andreas-Punkte und was davon bereits umgesetzt bzw. noch offen ist.
## Kurzfazit
- Das Finance Dashboard bleibt technisch produktiv nutzbar.
- Fuehrende Sicht fuer Soll/Ist bleibt `Finance Summary`.
- `Management Analyse` bleibt Diagnose: Laender, IC/2nd-party, Rohdaten, Abweichungen, Spartenanalyse.
- IC wird nicht automatisch aus dem Standard-Ist entfernt.
- Budgetkurse 2026 sind im Programm und auf dem Server eingespielt.
- Spanien-Sage-Serverexport kann jetzt Full oder Range exportieren.
## Letzte Sitzungspunkte
| Thema | Punkt von Andreas / Finance | Stand |
| --- | --- | --- |
| Intercompany | Pro Land klaeren, ob IC bereits in Quelle/Sollwert herausgerechnet ist. | Teilweise geklaert: FR, IN, US passen ohne IC-Abgrenzung; IT braucht Sonderabgrenzung; DE, UK, CH, AT bleiben offen. |
| Spanien Sollwert | ES hat keine echte Ist-Abweichung; alter Sollwert war falsch. | Fachlich dokumentiert: ES-Ist und korrigierter Sollwert `3'082'320.18 EUR`. |
| Spanien Export | Nicht jedes Mal Volljahr exportieren, wenn bereits Basisexport vorhanden ist. | Sage-Server-Script unterstuetzt jetzt `-ExportMode Full` und `-ExportMode Range`. |
| Wechselkurse | Offizieller Kurstyp und Kursdatum klaeren. | Budgetkurse 2026 wurden als Budgetkurse eingetragen. Kursdatum bleibt in Settings konfigurierbar. |
| Spartenanalyse | >90% nicht zugeordnet ist fachlich unplausibel. | Aktuelle Daten zeigen: Spartenfelder sind fast nur bei CH und teilweise AT gefuellt. Viele Laender haben keine Produktspartenfelder in `CentralSalesRecords`; deshalb ist es ein Mapping-/Referenzproblem, nicht fachlich "nur 10% Umsatz mit Sparte". |
| DE | Welche Kundenlaender / Filter gehoeren offiziell zum deutschen Ist? | Offen. Nicht einfach IC abziehen; Hauptfrage sind Kundenlaender/Filter. |
| UK | Sage-Differenz klaeren. | Offen: Exportvollstaendigkeit, Discounts, Freight/Charges und 2nd-party/IC pruefen. |
| IT | Neue IT-Abgrenzung pruefen. | IT ist Sonderfall: `Trafag Italia` aus externem IT-Ist ausschliessen; doppelte Einzelpositionen mit leerem Supplier country nur einmal zaehlen. |
| CH / AT | `FKDAT` als Perioden-/Buchungsdatum bestaetigen. | Offen. |
| Kosten | Entscheiden, ob Kosten/Marge Teil des Dashboards werden. | Offen; weiterhin nicht in Umsatzfreigabe mischen. |
## IC-Stand je Land
| Land | Aussage | Filter / Abgrenzung |
| --- | --- | --- |
| FR | Ohne IC-Abgrenzung stimmt der Soll/Ist-Vergleich. | IC-Filter ignorieren; B1 Positions-Netto verwenden. |
| IN | Ohne IC-Abgrenzung stimmt der Soll/Ist-Vergleich. | IC-Filter ignorieren; INR-Hauswaehrung verwenden. |
| US | Ohne IC-Abgrenzung stimmt der Soll/Ist-Vergleich. | IC-Filter ignorieren; B1 Positions-Netto verwenden. |
| IT | Ohne Abgrenzung stimmt es nicht sauber. | IT-Sonderabgrenzung anwenden: `Trafag Italia` aus externem Ist ausschliessen; Duplikate mit leerem `Supplier country` nur einmal zaehlen. |
| ES | IC ist aktuell nicht der relevante Punkt. | Sage `ImporteNeto`; Credit Notes/REC negativ; korrigierter Sollwert `3'082'320.18 EUR`. |
| DE | Nicht final beurteilbar. | Kundenlaender/Kundenfilter offen; nicht einfach IC abziehen. |
| UK | Nicht final beurteilbar. | Sage-Export, Discounts/Freight/Charges und 2nd-party/IC pruefen. |
| CH | Nicht beurteilbar. | Kein Sollwert im Seed. |
| AT | Abweichung vorhanden, Ursache unklar. | IC nicht automatisch abziehen; Filter/Datum weiter pruefen. |
## Spanien Sage Server Export
Relevant ist das Paket:
```text
SageSpainFinalExportPackage.zip
```
Wichtige Datei im Paket:
```text
Export-SageSpainSalesCsv.ps1
```
Full Export:
```powershell
.\Export-SageSpainSalesCsv.ps1 -ExportMode Full -Year 2025
```
Range Export:
```powershell
.\Export-SageSpainSalesCsv.ps1 -ExportMode Range -FromDate "2025-05-01" -ToDate "2025-06-01"
```
Range nach Registrierungsdatum:
```powershell
.\Export-SageSpainSalesCsv.ps1 -ExportMode Range -DateFilter LineRegistrationDate -FromDate "2025-05-01" -ToDate "2025-06-01"
```
Hinweis:
- `ToDate` ist exklusiv.
- Wenn der alte Vollbestand bereits vorhanden ist, braucht Spanien fuer Folgeupdates nur noch Range-Dateien fuer den neuen oder korrigierten Zeitraum.
- Das Sage-Script liest nur Daten aus SQL Server und aendert nichts in Sage.
- Unser Importprozess wird danach separat entschieden; der Serverexport ist jetzt nur die Dateierzeugung.
## Spartenanalyse / Produktmapping
### Warum nur rund 10% Abdeckung?
Die Spartenanalyse zaehlt Umsatz nur als sauber zugeordnet, wenn eine Materialnummer gegen die zentrale TR-AG-/SAP-Referenz gematcht wird und dort eine gueltige Produktsparte vorhanden ist.
Aktueller Befund aus der lokalen Datenbank:
| Kennzahl | Wert |
| --- | ---: |
| `CentralSalesRecords` total | `75'089` |
| Zeilen 2025 nach Invoice/Extraction | `54'682` |
| Zeilen mit Produktsparte-Code | `36'847` |
| Zeilen mit gueltigem Assigned-Flag | `27'047` |
| Zeilen mit gueltiger Produktsparte | `27'047` |
| Zeilen `UNASS` | `9'800` |
| Zeilen ohne Materialnummer | `59` |
Laenderbefund:
| Land | Zeilen | Gueltig zugeordnet | `UNASS` | Keine Produktfelder |
| --- | ---: | ---: | ---: | ---: |
| CH | `38'838` | `26'337` | `9'187` | `3'314` |
| AT | `1'454` | `710` | `613` | `131` |
| Italien | `16'850` | `0` | `0` | `16'850` |
| Indien | `5'515` | `0` | `0` | `5'515` |
| Deutschland | `4'548` | `0` | `0` | `4'548` |
| Spanien | `4'341` | `0` | `0` | `4'341` |
| Frankreich | `2'285` | `0` | `0` | `2'285` |
| USA | `1'256` | `0` | `0` | `1'256` |
| England | `2` | `0` | `0` | `2` |
Interpretation:
- Die niedrige Abdeckung ist nicht als fachliche Umsatzverteilung zu lesen.
- Sie zeigt, dass das zentrale Produktmapping aktuell nur fuer CH und teilweise AT in den Daten ankommt.
- Bei IT, IN, DE, ES, FR, US und UK sind die Produktspartenfelder aktuell leer.
- Wahrscheinliche Ursachen: lokale Materialnummern passen nicht direkt zu TR-AG `MATNR`, fehlende Referenzdaten in `ProductDivisionRefSet`, Join trifft nicht oder Produktfelder werden bei diesen Laendern nicht befuellt.
### Prozessfluss vom Holen bis Anwenden
```text
1. SAP/TR-AG stellt zentrale Produktreferenz bereit
EntitySet: ProductDivisionRefSet
Felder: Matnr, Paph1, Paph1Text, Wwpfa, WwpfaText, Wwpsp, WwpspText, IsAssigned
2. Webprogramm holt beim SAP-Standort zwei Quellen
Z = FinanzdataSchweizOeSet
P = ProductDivisionRefSet
3. Join im Web-Exporter
Z.Matnr = P.Matnr
JoinType = Left
4. Mapping ins interne SalesRecord-Modell
Z.Matnr -> Material
Z.Prodh -> ProductGroup
P.Paph1 -> ProductHierarchyCode
P.Paph1Text -> ProductHierarchyText
P.Wwpfa -> ProductFamilyCode
P.WwpfaText -> ProductFamilyText
P.Wwpsp -> ProductDivisionCode
P.WwpspText -> ProductDivisionText
P.IsAssigned -> ProductMappingAssigned
5. Speicherung in CentralSalesRecords
Die Produktfelder werden mit jeder Umsatzzeile gespeichert.
6. Management Analyse > Spartenanalyse
Statuslogik:
- Material leer -> Material fehlt
- kein Treffer in zentraler Referenz -> Nicht im TR-AG-Stamm
- Treffer, aber IsAssigned nicht wahr oder Division = UNASS -> Nicht zugeordnet
- Treffer, IsAssigned wahr und Division nicht UNASS -> Zugeordnet
7. Sparten-Finanzanalyse
Nur Status Zugeordnet geht in Umsatz nach Produktsparte / Produktfamilie / PAPH1.
```
### SAP-Objektnamen und Code-Stand
| Objekt | Name |
| --- | --- |
| SAP Gateway Service | `ZPOWERBI_EINKAUF_SRV` |
| Sales EntitySet | `FinanzdataSchweizOeSet` |
| Sales Gateway-Methode | `FINANZDATASCHWEI_GET_ENTITYSET` |
| Produktsparten EntitySet | `ProductDivisionRefSet` |
| Produktsparten Gateway-Methode | `PRODUCTDIVISIONR_GET_ENTITYSET` |
| Provider-Klasse | `ZCL_PRODSPARTE_PROVIDER` |
| Mapping-Aufbau-Report | `Z_PRODSPARTE_MAP_BUILD` |
| Test-/ALV-Report | `Z_PRODSPARTE_REPORT` |
| Mapping-Tabelle | `ZPRODSPARTE_MAP` |
| DDIC-Struktur | `ZSTR_PRODSPARTE_OUT` |
Vorhandener Code im Repo:
- `docs/abap/ZCL_PRODSPARTE_PROVIDER.abap`
- `docs/abap/Z_PRODSPARTE_MAP_BUILD.abap`
- `docs/abap/Z_PRODSPARTE_REPORT.abap`
Nicht als vollstaendiger Code im Repo vorhanden:
- `FINANZDATASCHWEI_GET_ENTITYSET`
- `PRODUCTDIVISIONR_GET_ENTITYSET`
Diese beiden Gateway-Methoden sind in den MDs beschrieben, aber der komplette DPC_EXT-Methodencode muss aus SAP geholt oder neu formuliert werden.
## Budgetkurse
### Budget 2026
Budget 2026 wurde eingetragen und deployed:
| Von | Nach | Rate |
| --- | --- | ---: |
| CHF | CHF | 1 |
| USD | CHF | 0.80 |
| EUR | CHF | 0.94 |
| GBP | CHF | 1.09 |
| CNY | CHF | 0.11764706 |
| INR | CHF | 0.00909091 |
| CZK | CHF | 0.03846154 |
| PLN | CHF | 0.22 |
| JPY | CHF | 0.00571429 |
Technische Ablage:
```text
CurrencyExchangeRates
Notes = Budget 2026
ValidFrom = 2026-01-01
ValidTo = 2026-12-31
```
### Budget 2025
Andreas hat neue Budget-2025-Werte geliefert. Noch nicht final eingetragen, weil CNY noch fehlt:
| Waehrung | Rate nach CHF |
| --- | ---: |
| EUR | 0.937034700 |
| GBP | 1.093822350 |
| INR | 0.009532034 |
| PLN | 0.221032130 |
| RUB | 0.009958327 |
| CZK | 0.037963103 |
| JPY | 0.005553195 |
| USD | 0.830651790 |
| CNY | offen |
## Deploy-Stand
Deploy wurde am 2026-06-02 ausgefuehrt:
- Publish nach `\\trch-webapp-bidashboard.trafagch.local\BiDashboard$\`
- `BiDashboard.dll` Zeitstempel nach Deploy: `2026-06-02 15:15:20`
- Server-DB enthaelt `9` Budget-2026-Kurse.
- Testlauf vor Deploy: `82/82` Tests gruen.
## Naechste klare To-dos
1. CNY Budget 2025 von Andreas nachliefern lassen.
2. Budget 2025 Seedwerte danach gesammelt aktualisieren und deployen.
3. DE: offizielle Kundenlaender/Kundenfilter bestaetigen.
4. UK: Sage-Exportvollstaendigkeit und Discounts/Freight/Charges pruefen.
5. CH/AT: `FKDAT` als fachliches Periodendatum bestaetigen.
6. Spartenmapping weiter pruefen: Gateway-Methodencode `PRODUCTDIVISIONR_GET_ENTITYSET` aus SAP holen oder sauber neu formulieren; danach pruefen, warum Produktfelder nur bei CH/AT gefuellt sind.
7. Entscheiden, ob CHF-Sicht nur Reporting bleibt oder offizieller Vergleichswert wird.
@@ -508,3 +508,108 @@ Deploy:
- `ProductRows = 36'847`
- `TR-AG Referenzmaterialien = 6'805`
- `P ProductDivisionRefSet` aktiv.
## Nachtrag 2026-06-02 Prozessfluss Und Offene Gateway-Codes
### Prozess Vom Holen Bis Anwenden
```text
SAP/TR-AG
|
| ProductDivisionRefSet
| Matnr, Paph1, Paph1Text, Wwpfa, WwpfaText, Wwpsp, WwpspText, IsAssigned
v
Webprogramm / SAP-Komposition
|
| Quelle Z = FinanzdataSchweizOeSet
| Quelle P = ProductDivisionRefSet
| Join = Z.Matnr = P.Matnr, Left Join
v
SalesRecord
|
| ProductHierarchyCode/Text
| ProductFamilyCode/Text
| ProductDivisionCode/Text
| ProductMappingAssigned
v
CentralSalesRecords
|
v
Management Analyse > Spartenanalyse
|
| Zugeordnet / Nicht zugeordnet / Nicht im TR-AG-Stamm / Material fehlt
v
Sparten-Finanzanalyse
|
| Umsatz nach Produktsparte nur fuer Status Zugeordnet
```
### Technische Objektliste
| Rolle | Name |
| --- | --- |
| Gateway Service | `ZPOWERBI_EINKAUF_SRV` |
| Sales EntitySet | `FinanzdataSchweizOeSet` |
| Sales Gateway-Methode | `FINANZDATASCHWEI_GET_ENTITYSET` |
| Produktsparten EntitySet | `ProductDivisionRefSet` |
| Produktsparten Gateway-Methode | `PRODUCTDIVISIONR_GET_ENTITYSET` |
| Produktsparten Provider | `ZCL_PRODSPARTE_PROVIDER` |
| Mapping-Aufbau | `Z_PRODSPARTE_MAP_BUILD` |
| ALV-Test | `Z_PRODSPARTE_REPORT` |
| Persistente Mapping-Tabelle | `ZPRODSPARTE_MAP` |
| Gateway/DDIC-Struktur | `ZSTR_PRODSPARTE_OUT` |
### Code-Stand Im Repository
Vollstaendig als ABAP-Dateien vorhanden:
- `docs/abap/ZCL_PRODSPARTE_PROVIDER.abap`
- `docs/abap/Z_PRODSPARTE_MAP_BUILD.abap`
- `docs/abap/Z_PRODSPARTE_REPORT.abap`
Nur dokumentiert, aber nicht als kompletter Gateway-Methodencode vorhanden:
- `FINANZDATASCHWEI_GET_ENTITYSET`
- `PRODUCTDIVISIONR_GET_ENTITYSET`
Fachlich gilt:
- `FINANZDATASCHWEI_GET_ENTITYSET` muss den bestehenden Sales-Select aus `ZSCHWEIZ` behalten.
- Produktspartenlogik gehoert in `PRODUCTDIVISIONR_GET_ENTITYSET`.
- `PRODUCTDIVISIONR_GET_ENTITYSET` soll die flache Referenz fuer `ProductDivisionRefSet` liefern, idealerweise ueber `ZCL_PRODSPARTE_PROVIDER->GET_DATA( )`.
### Befund Zur Niedrigen Abdeckung
Die Sparten-Finanzanalyse zeigt aktuell nur eine niedrige zugeordnete Umsatzabdeckung. Das ist nicht als fachliche Aussage "nur 10% des Umsatzes hat eine Sparte" zu lesen, sondern als Mapping-/Referenzbefund.
Lokaler DB-Stand 2026-06-02:
| Kennzahl | Wert |
| --- | ---: |
| `CentralSalesRecords` total | `75'089` |
| Zeilen mit Produktsparte-Code | `36'847` |
| Zeilen mit gueltigem Assigned-Flag | `27'047` |
| Zeilen mit gueltiger Produktsparte | `27'047` |
| Zeilen `UNASS` | `9'800` |
| Zeilen ohne Materialnummer | `59` |
Laenderdetail:
| Land | Zeilen | Gueltig zugeordnet | `UNASS` | Keine Produktfelder |
| --- | ---: | ---: | ---: | ---: |
| CH | `38'838` | `26'337` | `9'187` | `3'314` |
| AT | `1'454` | `710` | `613` | `131` |
| Italien | `16'850` | `0` | `0` | `16'850` |
| Indien | `5'515` | `0` | `0` | `5'515` |
| Deutschland | `4'548` | `0` | `0` | `4'548` |
| Spanien | `4'341` | `0` | `0` | `4'341` |
| Frankreich | `2'285` | `0` | `0` | `2'285` |
| USA | `1'256` | `0` | `0` | `1'256` |
| England | `2` | `0` | `0` | `2` |
Naechste Pruefpunkte:
- Gateway-Methodencode `PRODUCTDIVISIONR_GET_ENTITYSET` aus SAP sichern oder im Repo nachbauen.
- Pruefen, ob `ProductDivisionRefSet` vollstaendig genug ist.
- Pruefen, warum Produktfelder bei IT, IN, DE, ES, FR, US und UK leer bleiben.
- Klaeren, ob fuer lokale Materialnummern eine zusaetzliche Cross-Reference gegen TR-AG-Materialnummern notwendig ist.
@@ -100,6 +100,27 @@ Stand: 2026-05-29
- UNASS -> `HelpOutline`
- sonst -> `Category`
- Finance-Schulung hat einen neuen Tab `Spartenanalyse`.
## Stand 2026-06-02
- Niedrige Spartenabdeckung ist als Mapping-/Referenzproblem zu lesen, nicht als fachliche Umsatzverteilung.
- Lokaler DB-Befund: `75'089` CentralSalesRecords, davon `27'047` mit gueltiger zugeordneter Produktsparte und `9'800` mit `UNASS`.
- Produktfelder sind aktuell fast nur bei CH und teilweise AT gefuellt; IT, IN, DE, ES, FR, US und UK haben in den Daten keine Produktspartenfelder.
- Prozessfluss:
- SAP Service `ZPOWERBI_EINKAUF_SRV`
- Sales EntitySet `FinanzdataSchweizOeSet`
- Produktmapping EntitySet `ProductDivisionRefSet`
- Web-Join `Z.Matnr = P.Matnr`
- Speicherung in `CentralSalesRecords`
- Anwendung in `Management Analyse > Spartenanalyse`
- Vollstaendige ABAP-Dateien im Repo:
- `docs/abap/ZCL_PRODSPARTE_PROVIDER.abap`
- `docs/abap/Z_PRODSPARTE_MAP_BUILD.abap`
- `docs/abap/Z_PRODSPARTE_REPORT.abap`
- Nicht als kompletter Gateway-Methodencode im Repo vorhanden:
- `FINANZDATASCHWEI_GET_ENTITYSET`
- `PRODUCTDIVISIONR_GET_ENTITYSET`
- Naechster Schritt: Gateway-Methodencode aus SAP sichern oder `PRODUCTDIVISIONR_GET_ENTITYSET` sauber neu formulieren.
- Browser-Favicon wurde ergaenzt: `wwwroot/favicon.svg`.
- Letzter dokumentierter Deploy: 2026-05-29 13:47, Tests `80/80` gruen.
@@ -1,9 +1,15 @@
param(
[string]$ServerInstance = "localhost",
[string]$Database = "Sage",
[ValidateSet("Full", "Range")]
[string]$ExportMode = "Full",
[ValidateSet("InvoiceDate", "LineRegistrationDate")]
[string]$DateFilter = "InvoiceDate",
[int]$Year = 2025,
[datetime]$FromDate = "2025-01-01",
[datetime]$ToDate = "2026-01-01",
[string]$OutputDirectory = (Join-Path $env:USERPROFILE "Desktop")
[string]$OutputDirectory = (Join-Path $env:USERPROFILE "Desktop"),
[string]$OutputFileName = ""
)
$ErrorActionPreference = "Stop"
@@ -97,12 +103,41 @@ function Export-QueryToCsv {
}
}
if ($ExportMode -eq "Full") {
$FromDate = [datetime]::new($Year, 1, 1)
$ToDate = $FromDate.AddYears(1)
}
else {
if (-not $PSBoundParameters.ContainsKey("ToDate")) {
throw "Range export requires -ToDate. Example: -ExportMode Range -FromDate '2025-05-01' -ToDate '2025-06-01'"
}
}
if ($ToDate.Date -le $FromDate.Date) {
throw "ToDate must be later than FromDate. FromDate=$($FromDate.ToString("yyyy-MM-dd")), ToDate=$($ToDate.ToString("yyyy-MM-dd"))"
}
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$runDirectory = Join-Path $OutputDirectory "Sage_Spain_Sales_Export_$timestamp"
New-Item -ItemType Directory -Path $runDirectory -Force | Out-Null
$csvPath = Join-Path $runDirectory "Spain_Sales_2025.csv"
$summaryPath = Join-Path $runDirectory "Spain_Sales_2025_summary.txt"
if ([string]::IsNullOrWhiteSpace($OutputFileName)) {
$fromToken = $FromDate.ToString("yyyyMMdd")
$toToken = $ToDate.Date.AddDays(-1).ToString("yyyyMMdd")
$kindToken = $ExportMode.ToLowerInvariant()
$OutputFileName = "Spain_Sales_${kindToken}_${fromToken}_to_${toToken}.csv"
}
$csvPath = Join-Path $runDirectory $OutputFileName
$summaryPath = Join-Path $runDirectory ([System.IO.Path]::GetFileNameWithoutExtension($OutputFileName) + "_summary.txt")
$datePredicate = if ($DateFilter -eq "LineRegistrationDate") {
"COALESCE(l.FechaRegistro, c.FechaFactura) >= @FromDate
AND COALESCE(l.FechaRegistro, c.FechaFactura) < @ToDate"
} else {
"c.FechaFactura >= @FromDate
AND c.FechaFactura < @ToDate"
}
$sql = @"
SELECT
@@ -170,8 +205,7 @@ JOIN dbo.LineasAlbaranCliente l
AND l.EjercicioAlbaran = c.EjercicioAlbaran
AND l.SerieAlbaran = c.SerieAlbaran
AND l.NumeroAlbaran = c.NumeroAlbaran
WHERE c.FechaFactura >= @FromDate
AND c.FechaFactura < @ToDate
WHERE $datePredicate
ORDER BY
c.FechaFactura,
c.SerieFactura,
@@ -188,6 +222,8 @@ Sage Spain Sales CSV export
Created: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
Server instance: $ServerInstance
Database: $Database
Export mode: $ExportMode
Date filter mode: $DateFilter
From date: $($FromDate.ToString("yyyy-MM-dd"))
To date: $($ToDate.ToString("yyyy-MM-dd"))
@@ -204,14 +240,15 @@ Source:
dbo.CabeceraAlbaranCliente joined with dbo.LineasAlbaranCliente
Filter:
CabeceraAlbaranCliente.FechaFactura >= FromDate
CabeceraAlbaranCliente.FechaFactura < ToDate
$datePredicate
Notes:
- Currency is set to EUR because Sage exports EnEuros_=-1 and CodigoDivisa is empty in the analysed rows.
- SalesPriceValue uses LineasAlbaranCliente.ImporteNeto; credit notes are forced negative.
- DocumentNetAmount uses CabeceraAlbaranCliente.BaseImponible; credit notes are forced negative.
- Credit notes are marked when TipoNuevaFra=2, SerieFactura='REC', or StatusAbono is non-zero.
- Full exports use the complete selected year.
- Range exports use the explicit FromDate/ToDate window.
"@ | Set-Content -LiteralPath $summaryPath -Encoding UTF8
Write-Host "Created:"