Add purchasing ideas tab and SAP table test
This commit is contained in:
@@ -185,6 +185,88 @@
|
|||||||
DetailRows="@SupplierDetailRows" />
|
DetailRows="@SupplierDetailRows" />
|
||||||
</MudTabPanel>
|
</MudTabPanel>
|
||||||
|
|
||||||
|
<MudTabPanel Text="@T("Ideen", "Ideas")" Icon="@Icons.Material.Filled.Lightbulb">
|
||||||
|
<MudGrid Spacing="2">
|
||||||
|
<MudItem xs="12" lg="8">
|
||||||
|
<MudPaper Class="pa-3 purchasing-overview-panel" Outlined="true">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="mb-3">
|
||||||
|
<div>
|
||||||
|
<MudText Typo="Typo.h6">@T("Weitere Einkaufsanalysen", "Additional purchasing analytics")</MudText>
|
||||||
|
<MudText Typo="Typo.body2" Class="purchasing-muted">
|
||||||
|
@T("Analysen, die dem Einkauf neben PowerBI mehr Steuerung, Risiko- und Sparpotenzial zeigen.",
|
||||||
|
"Analytics that give purchasing more steering, risk and savings potential beyond Power BI.")
|
||||||
|
</MudText>
|
||||||
|
</div>
|
||||||
|
<MudChip T="string" Color="Color.Info" Variant="Variant.Outlined">
|
||||||
|
@T("Roadmap", "Roadmap")
|
||||||
|
</MudChip>
|
||||||
|
</MudStack>
|
||||||
|
<div class="purchasing-idea-grid">
|
||||||
|
@foreach (var idea in PurchasingIdeas)
|
||||||
|
{
|
||||||
|
<div class="purchasing-idea-card">
|
||||||
|
<div class="purchasing-idea-icon">
|
||||||
|
<MudIcon Icon="@idea.Icon" Color="@idea.Color" />
|
||||||
|
</div>
|
||||||
|
<div class="purchasing-idea-content">
|
||||||
|
<div class="purchasing-idea-title">
|
||||||
|
<strong>@T(idea.TitleDe, idea.TitleEn)</strong>
|
||||||
|
<MudChip T="string" Size="Size.Small" Color="@idea.Color" Variant="Variant.Outlined">@T(idea.StatusDe, idea.StatusEn)</MudChip>
|
||||||
|
</div>
|
||||||
|
<span>@T(idea.DescriptionDe, idea.DescriptionEn)</span>
|
||||||
|
<div class="purchasing-idea-meta">
|
||||||
|
<code>@idea.RequiredData</code>
|
||||||
|
<span>@T("Nutzen", "Value"): @T(idea.ValueDe, idea.ValueEn)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</MudPaper>
|
||||||
|
</MudItem>
|
||||||
|
<MudItem xs="12" lg="4">
|
||||||
|
<MudPaper Class="pa-3 purchasing-overview-panel" Outlined="true">
|
||||||
|
<MudText Typo="Typo.h6" Class="mb-2">@T("Prioritaet", "Priority")</MudText>
|
||||||
|
<div class="purchasing-priority-stack">
|
||||||
|
@foreach (var priority in PurchasingIdeaPriorities)
|
||||||
|
{
|
||||||
|
<div class="purchasing-priority-row">
|
||||||
|
<MudIcon Icon="@priority.Icon" Color="@priority.Color" Size="Size.Small" />
|
||||||
|
<div>
|
||||||
|
<strong>@T(priority.TitleDe, priority.TitleEn)</strong>
|
||||||
|
<span>@T(priority.DetailDe, priority.DetailEn)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</MudPaper>
|
||||||
|
</MudItem>
|
||||||
|
<MudItem xs="12">
|
||||||
|
<MudPaper Class="pa-3 purchasing-overview-panel" Outlined="true">
|
||||||
|
<MudText Typo="Typo.h6" Class="mb-2">@T("Kennzahlen-Katalog fuer den naechsten Ausbau", "KPI catalogue for the next build-out")</MudText>
|
||||||
|
<MudTable Items="@PurchasingIdeaKpis" Dense="true" Hover="true" Striped="true">
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>@T("Analyse", "Analysis")</MudTh>
|
||||||
|
<MudTh>@T("Kennzahl", "KPI")</MudTh>
|
||||||
|
<MudTh>@T("Dimension", "Dimension")</MudTh>
|
||||||
|
<MudTh>@T("Datenbasis", "Data basis")</MudTh>
|
||||||
|
<MudTh>@T("Status", "Status")</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd>@T(context.AnalysisDe, context.AnalysisEn)</MudTd>
|
||||||
|
<MudTd><strong>@T(context.KpiDe, context.KpiEn)</strong></MudTd>
|
||||||
|
<MudTd>@context.Dimension</MudTd>
|
||||||
|
<MudTd><code>@context.Source</code></MudTd>
|
||||||
|
<MudTd>
|
||||||
|
<MudChip T="string" Size="Size.Small" Color="@context.Color" Variant="Variant.Outlined">@T(context.StatusDe, context.StatusEn)</MudChip>
|
||||||
|
</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
</MudTable>
|
||||||
|
</MudPaper>
|
||||||
|
</MudItem>
|
||||||
|
</MudGrid>
|
||||||
|
</MudTabPanel>
|
||||||
|
|
||||||
<MudTabPanel Text="@T("PBIX Vorlage", "PBIX template")" Icon="@Icons.Material.Filled.InsertChart">
|
<MudTabPanel Text="@T("PBIX Vorlage", "PBIX template")" Icon="@Icons.Material.Filled.InsertChart">
|
||||||
<MudPaper Class="pa-3" Outlined="true">
|
<MudPaper Class="pa-3" Outlined="true">
|
||||||
<MudText Typo="Typo.h6" Class="mb-2">@T("Aus x.pbix uebernommene Seiten", "Pages derived from x.pbix")</MudText>
|
<MudText Typo="Typo.h6" Class="mb-2">@T("Aus x.pbix uebernommene Seiten", "Pages derived from x.pbix")</MudText>
|
||||||
@@ -391,6 +473,34 @@
|
|||||||
new("Matrix Vol./WG", "Pivot, Slicer", "Sum(EKPOSet.Netwr CHF)", "Warengruppe, Lieferant, Artikel")
|
new("Matrix Vol./WG", "Pivot, Slicer", "Sum(EKPOSet.Netwr CHF)", "Warengruppe, Lieferant, Artikel")
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private IReadOnlyList<PurchasingIdea> PurchasingIdeas =>
|
||||||
|
[
|
||||||
|
new("Lieferantenrisiko", "Supplier risk", "Kombiniert Abhaengigkeit, Single-Source-Anteil, offene Bestellungen und Lieferperformance zu einem Risiko-Score.", "Combines dependency, single-source share, open orders and delivery performance into one risk score.", "EKKO, EKPO, EKET, LFA1", "Engpaesse und Lieferantenabhaengigkeit frueh sehen", "see shortages and supplier dependency early", _liveState.EkpoLoaded && _liveState.EketLoaded ? "berechenbar" : "wartet auf EKPO/EKET", _liveState.EkpoLoaded && _liveState.EketLoaded ? "calculable" : "waiting for EKPO/EKET", Icons.Material.Filled.WarningAmber, _liveState.EkpoLoaded && _liveState.EketLoaded ? Color.Success : Color.Warning),
|
||||||
|
new("Preisabweichung", "Price variance", "Zeigt Preissteigerungen pro Artikel/Lieferant gegen Vorjahr, Budget oder letzten Einkaufspreis.", "Shows price increases by article/supplier against prior year, budget or last purchase price.", "EKPO, EKKO, FX", "Sparpotenziale und Ausreisser direkt sichtbar", "savings potential and outliers visible immediately", _liveState.EkpoLoaded ? "berechenbar" : "wartet auf EKPO", _liveState.EkpoLoaded ? "calculable" : "waiting for EKPO", Icons.Material.Filled.TrendingUp, _liveState.EkpoLoaded ? Color.Success : Color.Warning),
|
||||||
|
new("Maverick Buying", "Maverick buying", "Findet Bestellungen ausserhalb bevorzugter Lieferanten, Rahmenvertraege oder Warengruppenregeln.", "Finds orders outside preferred suppliers, contracts or material-group rules.", "EKKO, EKPO, Kontrakte", "Compliance und Buendelung verbessern", "improve compliance and bundling", "Konzept", "concept", Icons.Material.Filled.Policy, Color.Info),
|
||||||
|
new("Rahmenvertragsnutzung", "Contract utilisation", "Zeigt Kontraktmenge, Abrufmenge, Restmenge, Laufzeit und drohenden Verfall.", "Shows contract quantity, call-off quantity, remaining quantity, term and expiry risk.", "EKKO, EKPO, EKET", "Restverpflichtungen aktiv steuern", "actively manage remaining commitments", _liveState.EketLoaded ? "teilweise" : "wartet auf EKET", _liveState.EketLoaded ? "partial" : "waiting for EKET", Icons.Material.Filled.AssignmentTurnedIn, _liveState.EketLoaded ? Color.Success : Color.Warning),
|
||||||
|
new("Working Capital", "Working capital", "Verbindet offene Bestellungen, Liefertermine und Zahlungs-/Bestandswirkung zu Cash-Ausblick.", "Connects open orders, delivery dates and payment/inventory impact into a cash outlook.", "EKPO, EKET, FI/AP", "Cashbedarf aus Einkauf vorhersagen", "forecast purchasing cash needs", "Konzept", "concept", Icons.Material.Filled.AccountBalanceWallet, Color.Info),
|
||||||
|
new("Datenqualitaet", "Data quality", "Prueft fehlende Lieferanten, Warengruppen, Artikeltexte, Waehrung, Preisbasis und Dubletten.", "Checks missing suppliers, material groups, article texts, currency, price basis and duplicates.", "EKKO, EKPO, Mapping", "Vertrauen in Kennzahlen sichern", "secure trust in KPIs", _liveState.EkkoLoaded ? "startklar" : "wartet", _liveState.EkkoLoaded ? "ready" : "waiting", Icons.Material.Filled.FactCheck, _liveState.EkkoLoaded ? Color.Success : Color.Warning)
|
||||||
|
];
|
||||||
|
|
||||||
|
private IReadOnlyList<PurchasingIdeaPriority> PurchasingIdeaPriorities =>
|
||||||
|
[
|
||||||
|
new("1. EKPO/EKET Daten reparieren", "1. Repair EKPO/EKET data", "Ohne Positionen fehlen echte Spend-, Artikel-, Warengruppen- und Termindaten.", "Without item rows, real spend, article, material-group and schedule data are missing.", Icons.Material.Filled.BuildCircle, Color.Warning),
|
||||||
|
new("2. Preisabweichung aktivieren", "2. Activate price variance", "Sehr hoher Managementnutzen, sobald EKPO Werte liefert.", "Very high management value as soon as EKPO provides values.", Icons.Material.Filled.TrendingUp, Color.Info),
|
||||||
|
new("3. Lieferantenrisiko aufbauen", "3. Build supplier risk", "Kombiniert Performance, offene Werte und Abhaengigkeit.", "Combines performance, open values and dependency.", Icons.Material.Filled.Security, Color.Info),
|
||||||
|
new("4. Contract Cockpit ausbauen", "4. Extend contract cockpit", "Mengenkontrakte und Restverpflichtungen brauchen EKET/EKPO.", "Quantity contracts and remaining commitments need EKET/EKPO.", Icons.Material.Filled.Assignment, Color.Info)
|
||||||
|
];
|
||||||
|
|
||||||
|
private IReadOnlyList<PurchasingIdeaKpi> PurchasingIdeaKpis =>
|
||||||
|
[
|
||||||
|
new("Lieferantenrisiko", "Supplier risk", "Risiko-Score 0-100", "Risk score 0-100", "Lieferant / Warengruppe / Artikel", "EKKO+EKPO+EKET", _liveState.EkpoLoaded && _liveState.EketLoaded ? "bereit" : "wartet auf Tabellen", _liveState.EkpoLoaded && _liveState.EketLoaded ? "ready" : "waiting for tables", _liveState.EkpoLoaded && _liveState.EketLoaded ? Color.Success : Color.Warning),
|
||||||
|
new("Preisabweichung", "Price variance", "Preisdelta % / CHF", "price delta % / CHF", "Artikel / Lieferant / Jahr", "EKPO", _liveState.EkpoLoaded ? "bereit" : "wartet auf EKPO", _liveState.EkpoLoaded ? "ready" : "waiting for EKPO", _liveState.EkpoLoaded ? Color.Success : Color.Warning),
|
||||||
|
new("Maverick Buying", "Maverick buying", "Anteil ausserhalb Vertrag", "share outside contract", "Einkaeufer / Lieferant / Warengruppe", "EKKO+EKPO+Kontrakt", "Konzept", "concept", Color.Info),
|
||||||
|
new("Rahmenvertragsnutzung", "Contract utilisation", "Abrufquote %", "consumption rate %", "Kontrakt / Lieferant / Artikel", "EKPO+EKET", _liveState.EketLoaded ? "teilweise" : "wartet auf EKET", _liveState.EketLoaded ? "partial" : "waiting for EKET", _liveState.EketLoaded ? Color.Success : Color.Warning),
|
||||||
|
new("Working Capital", "Working capital", "Cash Forecast CHF", "cash forecast CHF", "Monat / Lieferant / Warengruppe", "EKPO+EKET+FI", "Konzept", "concept", Color.Info),
|
||||||
|
new("Datenqualitaet", "Data quality", "Mapping-Abdeckung %", "mapping coverage %", "Tabelle / Feld / Land", "EKKO+EKPO+Mapping", _liveState.EkkoLoaded ? "startklar" : "wartet", _liveState.EkkoLoaded ? "ready" : "waiting", _liveState.EkkoLoaded ? Color.Success : Color.Warning)
|
||||||
|
];
|
||||||
|
|
||||||
private readonly List<Purchasing3dIndicator> Purchasing3dIndicators =
|
private readonly List<Purchasing3dIndicator> Purchasing3dIndicators =
|
||||||
[
|
[
|
||||||
new("spend", "Spend CHF", "Spend CHF", "CHF"),
|
new("spend", "Spend CHF", "Spend CHF", "CHF"),
|
||||||
@@ -661,6 +771,9 @@
|
|||||||
private sealed record PurchasingSource(string Name, string Description);
|
private sealed record PurchasingSource(string Name, string Description);
|
||||||
private sealed record PurchasingPipelineStep(string TitleDe, string TitleEn, string Value, string DetailDe, string DetailEn, string Icon, bool IsReady, Color Color);
|
private sealed record PurchasingPipelineStep(string TitleDe, string TitleEn, string Value, string DetailDe, string DetailEn, string Icon, bool IsReady, Color Color);
|
||||||
private sealed record PowerBiPageInfo(string Page, string Visuals, string Measure, string Dimensions);
|
private sealed record PowerBiPageInfo(string Page, string Visuals, string Measure, string Dimensions);
|
||||||
|
private sealed record PurchasingIdea(string TitleDe, string TitleEn, string DescriptionDe, string DescriptionEn, string RequiredData, string ValueDe, string ValueEn, string StatusDe, string StatusEn, string Icon, Color Color);
|
||||||
|
private sealed record PurchasingIdeaPriority(string TitleDe, string TitleEn, string DetailDe, string DetailEn, string Icon, Color Color);
|
||||||
|
private sealed record PurchasingIdeaKpi(string AnalysisDe, string AnalysisEn, string KpiDe, string KpiEn, string Dimension, string Source, string StatusDe, string StatusEn, Color Color);
|
||||||
private sealed record Purchasing3dIndicator(string Key, string TitleDe, string TitleEn, string Unit);
|
private sealed record Purchasing3dIndicator(string Key, string TitleDe, string TitleEn, string Unit);
|
||||||
private sealed record Purchasing3dBaseRow(string Axis, int Year, double Spend, double OpenValue, double OpenQuantity, double ContractValue, double SupplierScore);
|
private sealed record Purchasing3dBaseRow(string Axis, int Year, double Spend, double OpenValue, double OpenQuantity, double ContractValue, double SupplierScore);
|
||||||
}
|
}
|
||||||
@@ -933,6 +1046,87 @@
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(260px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-card {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 46px minmax(0, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px solid var(--mud-palette-lines-default);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--mud-palette-surface);
|
||||||
|
min-height: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-icon {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(21,101,192,.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 9px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-content > span,
|
||||||
|
.purchasing-idea-meta span,
|
||||||
|
.purchasing-priority-row span {
|
||||||
|
color: var(--mud-palette-text-secondary);
|
||||||
|
font-size: .88rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-meta {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-idea-meta code {
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-priority-stack {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-priority-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 28px minmax(0, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
align-items: start;
|
||||||
|
padding: 11px 0;
|
||||||
|
border-bottom: 1px solid var(--mud-palette-lines-default);
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-priority-row:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchasing-priority-row strong {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.purchasing-source-row {
|
.purchasing-source-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 26px minmax(0, 1fr);
|
grid-template-columns: 26px minmax(0, 1fr);
|
||||||
@@ -965,6 +1159,7 @@
|
|||||||
.purchasing-hero-metrics,
|
.purchasing-hero-metrics,
|
||||||
.purchasing-pipeline,
|
.purchasing-pipeline,
|
||||||
.purchasing-axis-grid,
|
.purchasing-axis-grid,
|
||||||
|
.purchasing-idea-grid,
|
||||||
.purchasing-mini-donut-wrap {
|
.purchasing-mini-donut-wrap {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
REPORT ztest_powerbi_ekpo_eket.
|
||||||
|
|
||||||
|
" Kleines Diagnoseprogramm fuer die SAP Einkaufs-OData-Tabellen.
|
||||||
|
" Ziel:
|
||||||
|
" - Pruefen, ob EKKO, EKPO und EKET direkt in SAP Daten liefern.
|
||||||
|
" - Pruefen, ob zu einem EKKO-Beleg passende EKPO/EKET-Zeilen existieren.
|
||||||
|
" - Ausgabe per WRITE, damit sie einfach kopiert werden kann.
|
||||||
|
|
||||||
|
PARAMETERS:
|
||||||
|
p_ebeln TYPE ekko-ebeln,
|
||||||
|
p_bedat TYPE ekko-bedat DEFAULT '20260101',
|
||||||
|
p_max TYPE i DEFAULT 20.
|
||||||
|
|
||||||
|
DATA:
|
||||||
|
lv_ebeln TYPE ekko-ebeln,
|
||||||
|
lv_ekko_count TYPE i,
|
||||||
|
lv_ekpo_count TYPE i,
|
||||||
|
lv_eket_count TYPE i,
|
||||||
|
lt_ekko TYPE STANDARD TABLE OF ekko,
|
||||||
|
lt_ekpo TYPE STANDARD TABLE OF ekpo,
|
||||||
|
lt_eket TYPE STANDARD TABLE OF eket.
|
||||||
|
|
||||||
|
START-OF-SELECTION.
|
||||||
|
|
||||||
|
lv_ebeln = p_ebeln.
|
||||||
|
IF lv_ebeln IS NOT INITIAL.
|
||||||
|
lv_ebeln = |{ lv_ebeln ALPHA = IN }|.
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
WRITE: / '=== Einkaufsdaten Test EKKO / EKPO / EKET ==='.
|
||||||
|
WRITE: / 'Input EBELN:', p_ebeln, 'ALPHA:', lv_ebeln.
|
||||||
|
WRITE: / 'Input BEDAT ab:', p_bedat.
|
||||||
|
WRITE: / 'Max Zeilen:', p_max.
|
||||||
|
ULINE.
|
||||||
|
|
||||||
|
" 1) Grundzaehlung ohne Join
|
||||||
|
SELECT COUNT( * )
|
||||||
|
FROM ekko
|
||||||
|
INTO @lv_ekko_count
|
||||||
|
WHERE bedat >= @p_bedat.
|
||||||
|
|
||||||
|
SELECT COUNT( * )
|
||||||
|
FROM ekpo
|
||||||
|
INTO @lv_ekpo_count.
|
||||||
|
|
||||||
|
SELECT COUNT( * )
|
||||||
|
FROM eket
|
||||||
|
INTO @lv_eket_count.
|
||||||
|
|
||||||
|
WRITE: / 'COUNT EKKO ab BEDAT:', lv_ekko_count.
|
||||||
|
WRITE: / 'COUNT EKPO gesamt :', lv_ekpo_count.
|
||||||
|
WRITE: / 'COUNT EKET gesamt :', lv_eket_count.
|
||||||
|
ULINE.
|
||||||
|
|
||||||
|
" 2) Beispiel-EKKO suchen, falls kein Beleg mitgegeben wurde
|
||||||
|
IF lv_ebeln IS INITIAL.
|
||||||
|
SELECT *
|
||||||
|
FROM ekko
|
||||||
|
WHERE bedat >= @p_bedat
|
||||||
|
ORDER BY bedat DESCENDING, ebeln DESCENDING
|
||||||
|
INTO TABLE @lt_ekko
|
||||||
|
UP TO 1 ROWS.
|
||||||
|
|
||||||
|
READ TABLE lt_ekko INDEX 1 INTO DATA(ls_first_ekko).
|
||||||
|
IF sy-subrc = 0.
|
||||||
|
lv_ebeln = ls_first_ekko-ebeln.
|
||||||
|
WRITE: / 'Kein EBELN mitgegeben, verwende ersten EKKO-Beleg:', lv_ebeln.
|
||||||
|
ELSE.
|
||||||
|
WRITE: / 'Kein EKKO-Beleg ab BEDAT gefunden.'.
|
||||||
|
RETURN.
|
||||||
|
ENDIF.
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
ULINE.
|
||||||
|
WRITE: / '=== Detailtest fuer EBELN ===', lv_ebeln.
|
||||||
|
|
||||||
|
" 3) EKKO Detail
|
||||||
|
CLEAR lt_ekko.
|
||||||
|
SELECT *
|
||||||
|
FROM ekko
|
||||||
|
WHERE ebeln = @lv_ebeln
|
||||||
|
INTO TABLE @lt_ekko
|
||||||
|
UP TO @p_max ROWS.
|
||||||
|
|
||||||
|
WRITE: / 'EKKO Zeilen fuer EBELN:', lines( lt_ekko ).
|
||||||
|
LOOP AT lt_ekko INTO DATA(ls_ekko).
|
||||||
|
WRITE: / 'EKKO',
|
||||||
|
'EBELN=', ls_ekko-ebeln,
|
||||||
|
'BEDAT=', ls_ekko-bedat,
|
||||||
|
'AEDAT=', ls_ekko-aedat,
|
||||||
|
'LIFNR=', ls_ekko-lifnr,
|
||||||
|
'BUKRS=', ls_ekko-bukrs,
|
||||||
|
'BSART=', ls_ekko-bsart.
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
ULINE.
|
||||||
|
|
||||||
|
" 4) EKPO Detail
|
||||||
|
CLEAR lt_ekpo.
|
||||||
|
SELECT *
|
||||||
|
FROM ekpo
|
||||||
|
WHERE ebeln = @lv_ebeln
|
||||||
|
ORDER BY ebeln, ebelp
|
||||||
|
INTO TABLE @lt_ekpo
|
||||||
|
UP TO @p_max ROWS.
|
||||||
|
|
||||||
|
WRITE: / 'EKPO Zeilen fuer EBELN:', lines( lt_ekpo ).
|
||||||
|
LOOP AT lt_ekpo INTO DATA(ls_ekpo).
|
||||||
|
WRITE: / 'EKPO',
|
||||||
|
'EBELN=', ls_ekpo-ebeln,
|
||||||
|
'EBELP=', ls_ekpo-ebelp,
|
||||||
|
'MATNR=', ls_ekpo-matnr,
|
||||||
|
'MATKL=', ls_ekpo-matkl,
|
||||||
|
'MENGE=', ls_ekpo-menge,
|
||||||
|
'MEINS=', ls_ekpo-meins,
|
||||||
|
'NETWR=', ls_ekpo-netwr,
|
||||||
|
'LOEKZ=', ls_ekpo-loekz.
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
ULINE.
|
||||||
|
|
||||||
|
" 5) EKET Detail
|
||||||
|
CLEAR lt_eket.
|
||||||
|
SELECT *
|
||||||
|
FROM eket
|
||||||
|
WHERE ebeln = @lv_ebeln
|
||||||
|
ORDER BY ebeln, ebelp, etenr
|
||||||
|
INTO TABLE @lt_eket
|
||||||
|
UP TO @p_max ROWS.
|
||||||
|
|
||||||
|
WRITE: / 'EKET Zeilen fuer EBELN:', lines( lt_eket ).
|
||||||
|
LOOP AT lt_eket INTO DATA(ls_eket).
|
||||||
|
WRITE: / 'EKET',
|
||||||
|
'EBELN=', ls_eket-ebeln,
|
||||||
|
'EBELP=', ls_eket-ebelp,
|
||||||
|
'ETENR=', ls_eket-etenr,
|
||||||
|
'EINDT=', ls_eket-eindt,
|
||||||
|
'MENGE=', ls_eket-menge,
|
||||||
|
'WEMNG=', ls_eket-wemng.
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
ULINE.
|
||||||
|
|
||||||
|
" 6) Join-Pruefung: existieren EKPO/EKET zu den aktuellen EKKO-Belegen?
|
||||||
|
SELECT COUNT( * )
|
||||||
|
FROM ekko AS h
|
||||||
|
INNER JOIN ekpo AS p
|
||||||
|
ON p~ebeln = h~ebeln
|
||||||
|
INTO @lv_ekpo_count
|
||||||
|
WHERE h~bedat >= @p_bedat.
|
||||||
|
|
||||||
|
SELECT COUNT( * )
|
||||||
|
FROM ekko AS h
|
||||||
|
INNER JOIN eket AS e
|
||||||
|
ON e~ebeln = h~ebeln
|
||||||
|
INTO @lv_eket_count
|
||||||
|
WHERE h~bedat >= @p_bedat.
|
||||||
|
|
||||||
|
WRITE: / 'JOIN EKKO->EKPO ab BEDAT:', lv_ekpo_count.
|
||||||
|
WRITE: / 'JOIN EKKO->EKET ab BEDAT:', lv_eket_count.
|
||||||
|
|
||||||
|
ULINE.
|
||||||
|
WRITE: / 'Interpretation:'.
|
||||||
|
WRITE: / '- Wenn EKPO/EKET gesamt > 0, aber fuer EBELN 0: Beleg hat keine Positionen/Termine oder falscher Beleg.'.
|
||||||
|
WRITE: / '- Wenn JOIN ab BEDAT > 0, dann muss OData EKPO/EKET mit korrektem SELECT auch Daten liefern.'.
|
||||||
|
WRITE: / '- Wenn JOIN ab BEDAT = 0, dann gibt es fuer aktuelle EKKO-Belege keine EKPO/EKET-Zuordnung im getesteten Zeitraum.'.
|
||||||
Reference in New Issue
Block a user