From 37a175551b97b4ba0dfb027be4f7fa2b67f85d73 Mon Sep 17 00:00:00 2001 From: metacube Date: Tue, 2 Jun 2026 18:06:30 +0200 Subject: [PATCH] Document finance and mapping updates --- ...Abgrenzung_Laender_Andreas_2026-06-02.xlsx | Bin 0 -> 15819 bytes .../SageSpainFinalExportPackage.zip | Bin 2957 -> 3727 bytes .../Export-SageSpainSalesCsv.ps1 | 51 +++- .../SageSpainFinalExportPackage/README.txt | 24 +- .../Services/DatabaseSeedService.cs | 41 +-- ...NANCE_SITZUNGSPUNKTE_ANDREAS_2026-06-02.md | 251 ++++++++++++++++++ .../PRODUCT_SPARTEN_MAPPING_2026-05-27.md | 105 ++++++++ .../docs/rag/PRODUCT_MAPPING.md | 21 ++ .../scripts/Export-SageSpainSalesCsv.ps1 | 51 +++- 9 files changed, 511 insertions(+), 33 deletions(-) create mode 100644 TrafagSalesExporter/IC_Abgrenzung_Laender_Andreas_2026-06-02.xlsx create mode 100644 TrafagSalesExporter/docs/FINANCE_SITZUNGSPUNKTE_ANDREAS_2026-06-02.md diff --git a/TrafagSalesExporter/IC_Abgrenzung_Laender_Andreas_2026-06-02.xlsx b/TrafagSalesExporter/IC_Abgrenzung_Laender_Andreas_2026-06-02.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1319e9a1fa69cb5d0b342f5609594f13e052d614 GIT binary patch literal 15819 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 delta 2875 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 @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:" diff --git a/TrafagSalesExporter/SageSpainFinalExportPackage/README.txt b/TrafagSalesExporter/SageSpainFinalExportPackage/README.txt index 845ea13..6c6816f 100644 --- a/TrafagSalesExporter/SageSpainFinalExportPackage/README.txt +++ b/TrafagSalesExporter/SageSpainFinalExportPackage/README.txt @@ -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 diff --git a/TrafagSalesExporter/Services/DatabaseSeedService.cs b/TrafagSalesExporter/Services/DatabaseSeedService.cs index 5bfe819..c059320 100644 --- a/TrafagSalesExporter/Services/DatabaseSeedService.cs +++ b/TrafagSalesExporter/Services/DatabaseSeedService.cs @@ -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; diff --git a/TrafagSalesExporter/docs/FINANCE_SITZUNGSPUNKTE_ANDREAS_2026-06-02.md b/TrafagSalesExporter/docs/FINANCE_SITZUNGSPUNKTE_ANDREAS_2026-06-02.md new file mode 100644 index 0000000..0b1a6c2 --- /dev/null +++ b/TrafagSalesExporter/docs/FINANCE_SITZUNGSPUNKTE_ANDREAS_2026-06-02.md @@ -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. diff --git a/TrafagSalesExporter/docs/PRODUCT_SPARTEN_MAPPING_2026-05-27.md b/TrafagSalesExporter/docs/PRODUCT_SPARTEN_MAPPING_2026-05-27.md index daaad98..51040d3 100644 --- a/TrafagSalesExporter/docs/PRODUCT_SPARTEN_MAPPING_2026-05-27.md +++ b/TrafagSalesExporter/docs/PRODUCT_SPARTEN_MAPPING_2026-05-27.md @@ -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. diff --git a/TrafagSalesExporter/docs/rag/PRODUCT_MAPPING.md b/TrafagSalesExporter/docs/rag/PRODUCT_MAPPING.md index 83bc193..28a35c4 100644 --- a/TrafagSalesExporter/docs/rag/PRODUCT_MAPPING.md +++ b/TrafagSalesExporter/docs/rag/PRODUCT_MAPPING.md @@ -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. diff --git a/TrafagSalesExporter/scripts/Export-SageSpainSalesCsv.ps1 b/TrafagSalesExporter/scripts/Export-SageSpainSalesCsv.ps1 index 2204d88..9f7d716 100644 --- a/TrafagSalesExporter/scripts/Export-SageSpainSalesCsv.ps1 +++ b/TrafagSalesExporter/scripts/Export-SageSpainSalesCsv.ps1 @@ -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:"