Jahresfilterung für ROI hinzugefügt

This commit is contained in:
2026-06-22 13:03:26 +02:00
parent 542cbfdcd8
commit 23b1768be7
2 changed files with 93 additions and 1 deletions
+1
View File
@@ -1,3 +1,4 @@
config.php config.php
.vscode .vscode
sftp.json sftp.json
.claude
+91
View File
@@ -16,6 +16,26 @@ use PhpOffice\PhpSpreadsheet\Cell\DataType;
$Epi = new Epirent(); $Epi = new Epirent();
/* =========================
Filter (Jahres-Range)
ROI wird nur ausgeführt, wenn der User einen Zeitraum gewählt hat
oder explizit "Alles" anfordert. Das spart bei großen Datenbeständen
teure API-Calls.
========================= */
$filterMode = strtolower((string)($_GET['mode'] ?? ''));
$filterFrom = isset($_GET['from']) ? (int)$_GET['from'] : 0;
$filterTo = isset($_GET['to']) ? (int)$_GET['to'] : 0;
if ($filterFrom > 0 && $filterTo > 0 && $filterTo < $filterFrom) {
[$filterFrom, $filterTo] = [$filterTo, $filterFrom];
}
$computeRoi = in_array($filterMode, ['range', 'all'], true);
if ($filterMode === 'range' && ($filterFrom <= 0 || $filterTo <= 0)) {
$computeRoi = false;
$filterMode = '';
}
/* ========================= /* =========================
Helpers Helpers
========================= */ ========================= */
@@ -706,6 +726,14 @@ function processLineItem(
1) Invoices holen + Daten sammeln 1) Invoices holen + Daten sammeln
========================= */ ========================= */
// Defaults für die HTML-Ausgabe, wenn keine Berechnung läuft
$years = [];
$pivotRows = [];
$excelFileName = '';
$excelDownloadUrl = '';
if ($computeRoi) {
$slotItemsDirect = []; // productPk => list of intervals $slotItemsDirect = []; // productPk => list of intervals
$slotItemsIncl = []; // productPk => list of intervals $slotItemsIncl = []; // productPk => list of intervals
@@ -716,6 +744,15 @@ foreach ($invoiceList as $inv) {
$invoicePk = (int)($inv->primary_key ?? 0); $invoicePk = (int)($inv->primary_key ?? 0);
if ($invoicePk <= 0) continue; if ($invoicePk <= 0) continue;
// Vorab-Filter: wenn das Listen-Item bereits invoice_date hat, sparen wir den teuren Detail-Call
if ($filterMode === 'range') {
$listYear = yearFromDate((string)($inv->invoice_date ?? '')) ?? 0;
if ($listYear > 0) {
if ($filterFrom > 0 && $listYear < $filterFrom) continue;
if ($filterTo > 0 && $listYear > $filterTo) continue;
}
}
$invRes = apiJsonDecode($Epi->requestEpiApi('/v1/invoice/' . $invoicePk . '?cl=' . Epirent_Mandant)); $invRes = apiJsonDecode($Epi->requestEpiApi('/v1/invoice/' . $invoicePk . '?cl=' . Epirent_Mandant));
$invObj = ($invRes && ($invRes->success ?? false) && !empty($invRes->payload[0])) ? $invRes->payload[0] : null; $invObj = ($invRes && ($invRes->success ?? false) && !empty($invRes->payload[0])) ? $invRes->payload[0] : null;
if (!$invObj) continue; if (!$invObj) continue;
@@ -725,6 +762,13 @@ foreach ($invoiceList as $inv) {
$invoiceNo = (int)($invObj->invoice_no ?? 0); $invoiceNo = (int)($invObj->invoice_no ?? 0);
$orderPk = (int)($invObj->order_pk ?? 0); $orderPk = (int)($invObj->order_pk ?? 0);
// Endgültiger Year-Filter (falls Listen-Antwort kein Datum hatte)
if ($filterMode === 'range') {
if ($invoiceYear <= 0) continue;
if ($filterFrom > 0 && $invoiceYear < $filterFrom) continue;
if ($filterTo > 0 && $invoiceYear > $filterTo) continue;
}
// Storno-Erkennung (Credit Note): sum_net < 0 // Storno-Erkennung (Credit Note): sum_net < 0
$invoiceIsCredit = ((float)($invObj->sum_net ?? 0.0)) < 0.0; $invoiceIsCredit = ((float)($invObj->sum_net ?? 0.0)) < 0.0;
@@ -966,6 +1010,8 @@ $sheet->freezePane("A" . ($headerRow + 1));
$writer = new Xlsx($spreadsheet); $writer = new Xlsx($spreadsheet);
$writer->save($excelFilePath); $writer->save($excelFilePath);
} // end if ($computeRoi)
/* ========================= /* =========================
5) HTML Ausgabe 5) HTML Ausgabe
========================= */ ========================= */
@@ -1035,6 +1081,49 @@ function slotsToDisplay(array $slotMap): array {
<li class="breadcrumb-item active">Umsatz / Peak / Histogramm pro Artikel</li> <li class="breadcrumb-item active">Umsatz / Peak / Histogramm pro Artikel</li>
</ol> </ol>
<!-- Zeitraum-Filter -->
<div class="card mb-4">
<div class="card-header"><i class="fas fa-filter mr-1"></i> Zeitraum wählen</div>
<div class="card-body">
<form method="get" class="form-row align-items-end">
<div class="form-group col-md-3 mb-2">
<label for="from">Startjahr</label>
<input type="number" name="from" id="from" class="form-control" min="2000" max="2100"
value="<?php echo $filterFrom > 0 ? (int)$filterFrom : ((int)date('Y') - 2); ?>">
</div>
<div class="form-group col-md-3 mb-2">
<label for="to">Endjahr</label>
<input type="number" name="to" id="to" class="form-control" min="2000" max="2100"
value="<?php echo $filterTo > 0 ? (int)$filterTo : (int)date('Y'); ?>">
</div>
<div class="form-group col-md-3 mb-2">
<button type="submit" name="mode" value="range" class="btn btn-primary btn-block">
<i class="fas fa-play"></i> Zeitraum berechnen
</button>
</div>
<div class="form-group col-md-3 mb-2">
<button type="submit" name="mode" value="all" class="btn btn-secondary btn-block">
<i class="fas fa-infinity"></i> Alles berechnen
</button>
</div>
</form>
<small class="text-muted">
<?php if ($computeRoi && $filterMode === 'range'): ?>
<br><b>Aktuell:</b> <?php echo (int)$filterFrom; ?>&nbsp;&nbsp;<?php echo (int)$filterTo; ?>
<?php elseif ($computeRoi && $filterMode === 'all'): ?>
<br><b>Aktuell:</b> alle Jahre
<?php endif; ?>
</small>
</div>
</div>
<?php if (!$computeRoi): ?>
<div class="alert alert-info">
Bitte oben einen Zeitraum auswählen und auf <b>Zeitraum berechnen</b> klicken,
oder <b>Alles berechnen</b> für die vollständige Auswertung.
</div>
<?php else: ?>
<div class="card mb-4"> <div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
<div><i class="fas fa-table mr-1"></i> Pivot: Artikel × Rechnungsjahr</div> <div><i class="fas fa-table mr-1"></i> Pivot: Artikel × Rechnungsjahr</div>
@@ -1224,6 +1313,8 @@ function slotsToDisplay(array $slotMap): array {
</div> </div>
</div> </div>
<?php endif; // $computeRoi ?>
</div> </div>
</main> </main>
<div id="footerholder"></div> <div id="footerholder"></div>