Merge pull request 'Feature: Bank-Zuordnung zeigt Ausgangsrechnungen inkl. Rechnungen ohne Beleg' (#72) from fds2610-bot/Steuerkram:main into main
Reviewed-on: https://codeberg.org/fds2610/Steuerkram/pulls/72
This commit is contained in:
commit
a30221ff53
5 changed files with 103 additions and 17 deletions
|
|
@ -72,6 +72,7 @@ $router->post('/bank/upload/confirm', fn($p) => (new BankController())->up
|
|||
$router->get('/bank/{id}', fn($p) => (new BankController())->show($p));
|
||||
$router->post('/bank/{id}/status', fn($p) => (new BankController())->updateStatus($p));
|
||||
$router->post('/bank/{id}/link', fn($p) => (new BankController())->linkBeleg($p));
|
||||
$router->post('/bank/{id}/link-invoice', fn($p) => (new BankController())->linkInvoice($p));
|
||||
$router->post('/bank/{id}/unlink', fn($p) => (new BankController())->unlinkBeleg($p));
|
||||
$router->post('/bank/{id}/beleg', fn($p) => (new BankController())->uploadBeleg($p));
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Steuerkram\Controllers;
|
|||
|
||||
use Steuerkram\Models\BankImportFormat;
|
||||
use Steuerkram\Models\BankTransaction;
|
||||
use Steuerkram\Controllers\InvoiceController;
|
||||
use Steuerkram\Database;
|
||||
use Steuerkram\Models\Beleg;
|
||||
use Steuerkram\Models\Invoice;
|
||||
use Steuerkram\Services\BankImportParser;
|
||||
use Steuerkram\View;
|
||||
|
||||
|
|
@ -161,7 +163,7 @@ class BankController
|
|||
|
||||
$linkedBelege = BankTransaction::getLinkedBelege($id);
|
||||
$remainingBetrag = BankTransaction::getRemainingBetrag($id);
|
||||
$offeneBelege = Beleg::all(['booked' => '0'], 1, 200);
|
||||
$offeneBelege = Beleg::getOffeneFuerBankzuordnung();
|
||||
|
||||
$view = new View();
|
||||
$view->render('layout/base.php', [
|
||||
|
|
@ -170,7 +172,7 @@ class BankController
|
|||
'transaction' => $transaction,
|
||||
'linkedBelege' => $linkedBelege,
|
||||
'remainingBetrag' => $remainingBetrag,
|
||||
'offeneBelege' => $offeneBelege['rows'],
|
||||
'offeneBelege' => $offeneBelege,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
|
@ -205,6 +207,36 @@ class BankController
|
|||
View::redirect("/belege/$belegId?bank_tx=$id&alloc_betrag=$betrag");
|
||||
}
|
||||
|
||||
public function linkInvoice(array $params): void
|
||||
{
|
||||
$id = (int)($params['id'] ?? 0);
|
||||
$invoiceId = (int)($_POST['invoice_id'] ?? 0);
|
||||
$betrag = round((float)str_replace(',', '.', $_POST['alloc_betrag'] ?? ''), 2);
|
||||
|
||||
if (!$invoiceId) {
|
||||
View::redirect("/bank/$id", 'Keine Rechnung ausgewählt.', 'error');
|
||||
}
|
||||
|
||||
$invoice = Invoice::find($invoiceId);
|
||||
if (!$invoice) {
|
||||
View::redirect("/bank/$id", 'Rechnung nicht gefunden.', 'error');
|
||||
}
|
||||
|
||||
try {
|
||||
InvoiceController::createBeleg($invoice);
|
||||
$invoice = Invoice::find($invoiceId);
|
||||
} catch (\Exception $e) {
|
||||
View::redirect("/bank/$id", 'Beleg konnte nicht erstellt werden: ' . $e->getMessage(), 'error');
|
||||
}
|
||||
|
||||
$belegId = (int)($invoice['beleg_id'] ?? 0);
|
||||
if (!$belegId) {
|
||||
View::redirect("/bank/$id", 'Beleg-Erstellung fehlgeschlagen.', 'error');
|
||||
}
|
||||
|
||||
View::redirect("/belege/$belegId?bank_tx=$id&alloc_betrag=$betrag");
|
||||
}
|
||||
|
||||
public function unlinkBeleg(array $params): void
|
||||
{
|
||||
$id = (int)($params['id'] ?? 0);
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ class InvoiceController
|
|||
\Steuerkram\Database::beginTransaction();
|
||||
$nr = Invoice::finalize($id);
|
||||
$invoice = Invoice::find($id);
|
||||
$belegNr = $this->createBeleg($invoice);
|
||||
$belegNr = self::createBeleg($invoice);
|
||||
\Steuerkram\Database::commit();
|
||||
View::redirect("/invoices/{$id}", "Rechnung {$nr} wurde finalisiert (Beleg {$belegNr}). Bitte Zahlungseingang erfassen.");
|
||||
} catch (\PDOException $e) {
|
||||
|
|
@ -478,7 +478,7 @@ class InvoiceController
|
|||
}
|
||||
}
|
||||
|
||||
private function createBeleg(array $invoice): string
|
||||
public static function createBeleg(array $invoice): string
|
||||
{
|
||||
$id = (int)$invoice['id'];
|
||||
$lines = Invoice::lines($id);
|
||||
|
|
@ -550,7 +550,7 @@ class InvoiceController
|
|||
$stornoId = Invoice::createCancellation((int)$params['id']);
|
||||
$storno = Invoice::find($stornoId);
|
||||
if ($storno) {
|
||||
$this->createBeleg($storno);
|
||||
self::createBeleg($storno);
|
||||
}
|
||||
View::redirect('/invoices/' . $stornoId, 'Stornorechnung erstellt.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,50 @@ class Beleg
|
|||
return ['rows' => $rows, 'total' => $total, 'pages' => (int)ceil($total / $perPage)];
|
||||
}
|
||||
|
||||
public static function getOffeneFuerBankzuordnung(): array
|
||||
{
|
||||
$belege = Database::fetchAll(
|
||||
'SELECT b.*,
|
||||
COALESCE(
|
||||
(SELECT SUM(bk.betrag_brutto) FROM bookings bk
|
||||
WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL),
|
||||
b.betrag_brutto
|
||||
) AS betrag_brutto,
|
||||
fy.year as fiscal_year_nr,
|
||||
s.name as supplier_name
|
||||
FROM belege b
|
||||
LEFT JOIN fiscal_years fy ON b.fiscal_year_id = fy.id
|
||||
LEFT JOIN suppliers s ON b.supplier_id = s.id
|
||||
WHERE (
|
||||
(b.belegtyp = \'Eingangsrechnung\'
|
||||
AND NOT EXISTS (SELECT 1 FROM bookings bk2 WHERE bk2.beleg_id = b.id))
|
||||
OR
|
||||
(b.belegtyp = \'Ausgangsrechnung\'
|
||||
AND NOT EXISTS (SELECT 1 FROM bank_transaction_belege btb WHERE btb.beleg_id = b.id))
|
||||
)',
|
||||
[]
|
||||
);
|
||||
|
||||
$rechnungenOhneBeleg = Database::fetchAll(
|
||||
'SELECT NULL AS id,
|
||||
i.id AS invoice_id,
|
||||
i.rechnungs_nr AS beleg_nr,
|
||||
i.rechnungs_datum AS beleg_datum,
|
||||
\'Ausgangsrechnung\' AS belegtyp,
|
||||
i.betrag_brutto,
|
||||
COALESCE(NULLIF(TRIM(c.firma), \'\'), CONCAT(TRIM(c.vorname), \' \', TRIM(c.nachname))) AS supplier_name
|
||||
FROM invoices i
|
||||
JOIN customers c ON c.id = i.customer_id
|
||||
WHERE i.status IN (\'Finalisiert\', \'Gesendet\')
|
||||
AND i.beleg_id IS NULL',
|
||||
[]
|
||||
);
|
||||
|
||||
$alle = array_merge($belege, $rechnungenOhneBeleg);
|
||||
usort($alle, fn($a, $b) => strcmp($b['beleg_datum'] ?? '', $a['beleg_datum'] ?? ''));
|
||||
return $alle;
|
||||
}
|
||||
|
||||
public static function find(int $id): array|false
|
||||
{
|
||||
return Database::fetchOne(
|
||||
|
|
|
|||
|
|
@ -222,18 +222,22 @@ $restFormatted = number_format($remaining, 2, ',', '.');
|
|||
<th>Typ</th>
|
||||
<th>Lieferant</th>
|
||||
<th class="td-right">Brutto</th>
|
||||
<th class="td-right" style="width:130px">Zuzuordnen (€)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($offeneBelege as $b): ?>
|
||||
<?php $hatBeleg = $b['id'] !== null; ?>
|
||||
<tr class="beleg-row"
|
||||
data-beleg-id="<?= (int)$b['id'] ?>"
|
||||
style="cursor:pointer"
|
||||
title="Klicken zum Vorschau anzeigen">
|
||||
style="cursor:<?= $hatBeleg ? 'pointer' : 'default' ?>"
|
||||
<?= $hatBeleg ? 'title="Klicken zum Vorschau anzeigen"' : '' ?>>
|
||||
<td class="td-mono" onclick="event.stopPropagation()">
|
||||
<?php if ($hatBeleg): ?>
|
||||
<a href="/belege/<?= (int)$b['id'] ?>" target="_blank"><?= $h($b['beleg_nr']) ?></a>
|
||||
<?php else: ?>
|
||||
<a href="/invoices/<?= (int)$b['invoice_id'] ?>" target="_blank"><?= $h($b['beleg_nr']) ?></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="td-mono"><?= $h(View::formatDate($b['beleg_datum'])) ?></td>
|
||||
<td><span class="badge badge-gray"><?= $h($b['belegtyp']) ?></span></td>
|
||||
|
|
@ -243,17 +247,22 @@ $restFormatted = number_format($remaining, 2, ',', '.');
|
|||
<td class="td-right td-mono">
|
||||
<?= $b['betrag_brutto'] ? $fmt($b['betrag_brutto']) . ' €' : '<span class="text-muted">–</span>' ?>
|
||||
</td>
|
||||
<td class="td-right" onclick="event.stopPropagation()">
|
||||
<form method="post" action="/bank/<?= (int)$transaction['id'] ?>/link"
|
||||
style="display:flex;gap:.4rem;align-items:center;justify-content:flex-end">
|
||||
<td onclick="event.stopPropagation()">
|
||||
<?php if ($hatBeleg): ?>
|
||||
<form method="post" action="/bank/<?= (int)$transaction['id'] ?>/link">
|
||||
<input type="hidden" name="beleg_id" value="<?= (int)$b['id'] ?>">
|
||||
<input type="number" name="alloc_betrag"
|
||||
value="<?= $h(number_format($remaining, 2, '.', '')) ?>"
|
||||
min="0.01" step="0.01"
|
||||
style="width:90px;text-align:right"
|
||||
required>
|
||||
<input type="hidden" name="alloc_betrag"
|
||||
value="<?= $h(number_format($remaining, 2, '.', '')) ?>">
|
||||
<button type="submit" class="btn btn-primary btn-sm">Verknüpfen</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<form method="post" action="/bank/<?= (int)$transaction['id'] ?>/link-invoice">
|
||||
<input type="hidden" name="invoice_id" value="<?= (int)$b['invoice_id'] ?>">
|
||||
<input type="hidden" name="alloc_betrag"
|
||||
value="<?= $h(number_format($remaining, 2, '.', '')) ?>">
|
||||
<button type="submit" class="btn btn-primary btn-sm">Verknüpfen</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue