Merge pull request 'Bugfixes und Kleinigkeiten Anlagegüter' (#91) from fds2610-bot/Steuerkram:main into main
Reviewed-on: https://codeberg.org/fds2610/Steuerkram/pulls/91
This commit is contained in:
commit
44b78db210
5 changed files with 407 additions and 35 deletions
|
|
@ -18,12 +18,16 @@ class AssetController extends BaseController
|
||||||
public function index(array $params): void
|
public function index(array $params): void
|
||||||
{
|
{
|
||||||
$assets = Asset::all();
|
$assets = Asset::all();
|
||||||
|
$nurUnzugeordnet = ($_GET['filter'] ?? 'unzugeordnet') !== 'alle';
|
||||||
|
$anlageBookings = Asset::anlagekontoBookings($nurUnzugeordnet);
|
||||||
|
|
||||||
$view = new View();
|
$view = new View();
|
||||||
$view->render('layout/base.php', [
|
$view->render('layout/base.php', [
|
||||||
'pageTitle' => 'Anlagevermögen',
|
'pageTitle' => 'Anlagevermögen',
|
||||||
'content' => $this->renderView('assets/list', [
|
'content' => $this->renderView('assets/list', [
|
||||||
'assets' => $assets,
|
'assets' => $assets,
|
||||||
|
'anlageBookings' => $anlageBookings,
|
||||||
|
'nurUnzugeordnet' => $nurUnzugeordnet,
|
||||||
]),
|
]),
|
||||||
'topbarActions' => '<a href="/assets/new" class="btn btn-primary" title="Wirtschaftsgut anlegen" style="display:inline-flex;align-items:center;justify-content:center;padding:.36rem;border-radius:50%;width:1.8rem;height:1.8rem">'
|
'topbarActions' => '<a href="/assets/new" class="btn btn-primary" title="Wirtschaftsgut anlegen" style="display:inline-flex;align-items:center;justify-content:center;padding:.36rem;border-radius:50%;width:1.8rem;height:1.8rem">'
|
||||||
. '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">'
|
. '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">'
|
||||||
|
|
@ -35,11 +39,25 @@ class AssetController extends BaseController
|
||||||
|
|
||||||
public function create(array $params): void
|
public function create(array $params): void
|
||||||
{
|
{
|
||||||
|
$prefill = [];
|
||||||
|
if (!empty($_GET['bk_booking_id'])) {
|
||||||
|
$prefill['bk_booking_id'] = (int)$_GET['bk_booking_id'];
|
||||||
|
}
|
||||||
|
if (!empty($_GET['bk_account_id'])) {
|
||||||
|
$prefill['account_id'] = (int)$_GET['bk_account_id'];
|
||||||
|
}
|
||||||
|
if (!empty($_GET['bk_datum'])) {
|
||||||
|
$prefill['anschaffungsdatum'] = $_GET['bk_datum'];
|
||||||
|
}
|
||||||
|
if (isset($_GET['bk_betrag']) && $_GET['bk_betrag'] !== '') {
|
||||||
|
$prefill['anschaffungskosten'] = number_format((float)$_GET['bk_betrag'], 2, '.', '');
|
||||||
|
}
|
||||||
|
|
||||||
$view = new View();
|
$view = new View();
|
||||||
$view->render('layout/base.php', [
|
$view->render('layout/base.php', [
|
||||||
'pageTitle' => 'Wirtschaftsgut anlegen',
|
'pageTitle' => 'Wirtschaftsgut anlegen',
|
||||||
'content' => $this->renderView('assets/form', [
|
'content' => $this->renderView('assets/form', [
|
||||||
'asset' => [],
|
'asset' => $prefill,
|
||||||
'errors' => [],
|
'errors' => [],
|
||||||
'action' => '/assets',
|
'action' => '/assets',
|
||||||
'anlagearten' => Asset::anlagearten(),
|
'anlagearten' => Asset::anlagearten(),
|
||||||
|
|
@ -74,6 +92,14 @@ class AssetController extends BaseController
|
||||||
AssetDepreciation::generateAndSave($asset);
|
AssetDepreciation::generateAndSave($asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$bkBookingId = (int)($_POST['bk_booking_id'] ?? 0);
|
||||||
|
if ($bkBookingId > 0) {
|
||||||
|
\Steuerkram\Database::execute(
|
||||||
|
'UPDATE bookings SET asset_id = ? WHERE id = ? AND asset_id IS NULL',
|
||||||
|
[$id, $bkBookingId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
View::redirect('/assets/' . $id . '/edit', 'Wirtschaftsgut erfolgreich angelegt.');
|
View::redirect('/assets/' . $id . '/edit', 'Wirtschaftsgut erfolgreich angelegt.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,6 +119,8 @@ class AssetController extends BaseController
|
||||||
);
|
);
|
||||||
$previousAfaKontoId = $prevAfaKonto ? (int)$prevAfaKonto['kategorie_konto_id'] : null;
|
$previousAfaKontoId = $prevAfaKonto ? (int)$prevAfaKonto['kategorie_konto_id'] : null;
|
||||||
|
|
||||||
|
$bookingHints = $this->buildBookingHints($asset);
|
||||||
|
|
||||||
$view = new View();
|
$view = new View();
|
||||||
$view->render('layout/base.php', [
|
$view->render('layout/base.php', [
|
||||||
'pageTitle' => 'Wirtschaftsgut bearbeiten',
|
'pageTitle' => 'Wirtschaftsgut bearbeiten',
|
||||||
|
|
@ -105,10 +133,33 @@ class AssetController extends BaseController
|
||||||
'abschreibungskonten' => $abschreibungskonten,
|
'abschreibungskonten' => $abschreibungskonten,
|
||||||
'previousAfaKontoId' => $previousAfaKontoId,
|
'previousAfaKontoId' => $previousAfaKontoId,
|
||||||
'testMode' => Setting::isTestMode(),
|
'testMode' => Setting::isTestMode(),
|
||||||
|
'bookingHints' => $bookingHints,
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildBookingHints(array $asset): array
|
||||||
|
{
|
||||||
|
$hints = [];
|
||||||
|
|
||||||
|
$bkAccountId = isset($_GET['bk_account_id']) && $_GET['bk_account_id'] !== ''
|
||||||
|
? (int)$_GET['bk_account_id'] : null;
|
||||||
|
$bkDatum = $_GET['bk_datum'] ?? '';
|
||||||
|
|
||||||
|
if ($bkAccountId !== null && (int)($asset['account_id'] ?? 0) !== $bkAccountId) {
|
||||||
|
$bkAccount = Account::find($bkAccountId);
|
||||||
|
$hints['account_id'] = $bkAccount
|
||||||
|
? $bkAccount['kontonummer'] . ' – ' . $bkAccount['bezeichnung']
|
||||||
|
: 'Konto-ID ' . $bkAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bkDatum !== '' && ($asset['anschaffungsdatum'] ?? '') !== $bkDatum) {
|
||||||
|
$hints['anschaffungsdatum'] = View::formatDate($bkDatum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hints;
|
||||||
|
}
|
||||||
|
|
||||||
public function update(array $params): void
|
public function update(array $params): void
|
||||||
{
|
{
|
||||||
$id = (int)$params['id'];
|
$id = (int)$params['id'];
|
||||||
|
|
@ -151,8 +202,13 @@ class AssetController extends BaseController
|
||||||
public function destroy(array $params): void
|
public function destroy(array $params): void
|
||||||
{
|
{
|
||||||
$id = (int)$params['id'];
|
$id = (int)$params['id'];
|
||||||
AssetDepreciation::deleteByAsset($id);
|
$result = Asset::delete($id);
|
||||||
if (!Asset::delete($id)) {
|
|
||||||
|
if ($result === 'hat_buchungen') {
|
||||||
|
View::redirect('/assets', 'Das Wirtschaftsgut kann nicht gelöscht werden, da noch Buchungen damit verknüpft sind.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$result) {
|
||||||
View::redirect('/assets', 'Wirtschaftsgut konnte nicht gelöscht werden.', 'error');
|
View::redirect('/assets', 'Wirtschaftsgut konnte nicht gelöscht werden.', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -203,11 +203,54 @@ class Asset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete(int $id): bool
|
public static function anlagekontoBookings(bool $nurUnzugeordnet = true): array
|
||||||
|
{
|
||||||
|
$extraWhere = $nurUnzugeordnet ? 'AND (b.asset_id IS NULL OR a.id IS NULL)' : '';
|
||||||
|
|
||||||
|
return Database::fetchAll(
|
||||||
|
"SELECT
|
||||||
|
b.id, b.buchungs_nr, b.buchungs_datum, b.buchungstext,
|
||||||
|
b.betrag_netto, b.betrag_brutto, b.is_reversal, b.reversed_by,
|
||||||
|
b.asset_id, b.beleg_id, b.kategorie_konto_id,
|
||||||
|
ac.kontonummer AS kategorie_kontonummer,
|
||||||
|
ac.bezeichnung AS kategorie_bezeichnung,
|
||||||
|
zk.kontonummer AS zahlungs_kontonummer,
|
||||||
|
zk.bezeichnung AS zahlungs_bezeichnung,
|
||||||
|
a.bezeichnung AS asset_bezeichnung,
|
||||||
|
a.anlage_nr AS asset_anlage_nr
|
||||||
|
FROM bookings b
|
||||||
|
JOIN accounts ac ON b.kategorie_konto_id = ac.id
|
||||||
|
AND ac.kontenart = 'Anlagevermögen'
|
||||||
|
JOIN accounts zk ON b.zahlungskonto_id = zk.id
|
||||||
|
LEFT JOIN assets a ON b.asset_id = a.id
|
||||||
|
WHERE b.buchungstyp != 'AfA'
|
||||||
|
AND b.is_reversal = 0
|
||||||
|
AND b.reversed_by IS NULL
|
||||||
|
$extraWhere
|
||||||
|
ORDER BY b.buchungs_datum DESC",
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Löscht ein Wirtschaftsgut inklusive AfA-Buchungen und Abschreibungstabelle.
|
||||||
|
* Gibt 'hat_buchungen' zurück, wenn noch reguläre Buchungen verknüpft sind.
|
||||||
|
*/
|
||||||
|
public static function delete(int $id): bool|string
|
||||||
{
|
{
|
||||||
$asset = self::find($id);
|
$asset = self::find($id);
|
||||||
if (!$asset) return false;
|
if (!$asset) return false;
|
||||||
|
|
||||||
|
$linked = Database::fetchOne(
|
||||||
|
"SELECT COUNT(*) AS cnt FROM bookings WHERE asset_id = ? AND buchungstyp != 'AfA'",
|
||||||
|
[$id]
|
||||||
|
);
|
||||||
|
if ($linked && (int)$linked['cnt'] > 0) {
|
||||||
|
return 'hat_buchungen';
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::execute("DELETE FROM bookings WHERE asset_id = ? AND buchungstyp = 'AfA'", [$id]);
|
||||||
|
AssetDepreciation::deleteByAsset($id);
|
||||||
Database::execute('DELETE FROM assets WHERE id = ?', [$id]);
|
Database::execute('DELETE FROM assets WHERE id = ?', [$id]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,20 @@ $predefined = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 20, 25, 50];
|
||||||
$isCustom = $nutzung !== null && !in_array($nutzung, $predefined, true);
|
$isCustom = $nutzung !== null && !in_array($nutzung, $predefined, true);
|
||||||
$centFlag = !empty($asset['cent_im_ersten_jahr']);
|
$centFlag = !empty($asset['cent_im_ersten_jahr']);
|
||||||
$autoFlag = isset($asset['automatisch_berechnet']) ? (bool)(int)$asset['automatisch_berechnet'] : true;
|
$autoFlag = isset($asset['automatisch_berechnet']) ? (bool)(int)$asset['automatisch_berechnet'] : true;
|
||||||
|
$bkHints = $bookingHints ?? [];
|
||||||
|
|
||||||
|
$conflictBadge = function(string $field, string $label) use ($bkHints, $h): string {
|
||||||
|
if (!isset($bkHints[$field])) return '';
|
||||||
|
$val = $h($bkHints[$field]);
|
||||||
|
return '<span style="display:inline-flex;align-items:center;gap:.3rem;background:#fef2f2;color:#b91c1c;'
|
||||||
|
. 'border:1px solid #fecaca;border-radius:.35rem;font-size:.75rem;padding:.15rem .5rem;'
|
||||||
|
. 'margin-left:.5rem;font-weight:500" title="Abweichung zur verknüpften Buchung">'
|
||||||
|
. '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" '
|
||||||
|
. 'stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">'
|
||||||
|
. '<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>'
|
||||||
|
. '<line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>'
|
||||||
|
. 'Buchung: ' . $val . '</span>';
|
||||||
|
};
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="card" style="max-width:620px">
|
<div class="card" style="max-width:620px">
|
||||||
|
|
@ -16,7 +30,7 @@ $autoFlag = isset($asset['automatisch_berechnet']) ? (bool)(int)$asset['automa
|
||||||
<form method="post" action="<?= $h($action) ?>">
|
<form method="post" action="<?= $h($action) ?>">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="account_id">Anlageart (Konto)</label>
|
<label for="account_id">Anlageart (Konto)<?= $conflictBadge('account_id', 'Anlageart') ?></label>
|
||||||
<select id="account_id" name="account_id">
|
<select id="account_id" name="account_id">
|
||||||
<option value="">– bitte wählen –</option>
|
<option value="">– bitte wählen –</option>
|
||||||
<?php foreach ($anlagearten as $kto): ?>
|
<?php foreach ($anlagearten as $kto): ?>
|
||||||
|
|
@ -40,7 +54,7 @@ $autoFlag = isset($asset['automatisch_berechnet']) ? (bool)(int)$asset['automa
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="anschaffungsdatum">Anschaffungsdatum *</label>
|
<label for="anschaffungsdatum">Anschaffungsdatum *<?= $conflictBadge('anschaffungsdatum', 'Anschaffungsdatum') ?></label>
|
||||||
<input type="date" id="anschaffungsdatum" name="anschaffungsdatum"
|
<input type="date" id="anschaffungsdatum" name="anschaffungsdatum"
|
||||||
value="<?= $h($asset['anschaffungsdatum'] ?? '') ?>"
|
value="<?= $h($asset['anschaffungsdatum'] ?? '') ?>"
|
||||||
class="<?= isset($errors['anschaffungsdatum']) ? 'input-error' : '' ?>"
|
class="<?= isset($errors['anschaffungsdatum']) ? 'input-error' : '' ?>"
|
||||||
|
|
@ -133,6 +147,11 @@ $autoFlag = isset($asset['automatisch_berechnet']) ? (bool)(int)$asset['automa
|
||||||
<textarea id="notizen" name="notizen" rows="3"><?= $h($asset['notizen'] ?? '') ?></textarea>
|
<textarea id="notizen" name="notizen" rows="3"><?= $h($asset['notizen'] ?? '') ?></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Buchungs-Verknüpfung aus dem Zuordnungs-Workflow -->
|
||||||
|
<?php if (!empty($asset['bk_booking_id'])): ?>
|
||||||
|
<input type="hidden" name="bk_booking_id" value="<?= (int)$asset['bk_booking_id'] ?>">
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Automatisch-Flag (versteckt, wird per JS aktualisiert) -->
|
<!-- Automatisch-Flag (versteckt, wird per JS aktualisiert) -->
|
||||||
<input type="hidden" name="automatisch_berechnet" id="automatisch_berechnet_input"
|
<input type="hidden" name="automatisch_berechnet" id="automatisch_berechnet_input"
|
||||||
value="<?= $autoFlag ? '1' : '0' ?>">
|
value="<?= $autoFlag ? '1' : '0' ?>">
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,17 @@
|
||||||
<?php use Steuerkram\View; $h = fn($v) => View::h($v); ?>
|
<?php
|
||||||
|
use Steuerkram\View;
|
||||||
|
$h = fn($v) => View::h($v);
|
||||||
|
|
||||||
|
$assetsJson = json_encode(array_map(fn($a) => [
|
||||||
|
'id' => (int)$a['id'],
|
||||||
|
'lfd_nr' => (int)$a['lfd_nr'],
|
||||||
|
'anlage_nr' => $a['anlage_nr'],
|
||||||
|
'bezeichnung' => $a['bezeichnung'],
|
||||||
|
'anschaffungsdatum' => $a['anschaffungsdatum'],
|
||||||
|
'anschaffungskosten' => (float)$a['anschaffungskosten'],
|
||||||
|
'account_id' => $a['account_id'] !== null ? (int)$a['account_id'] : null,
|
||||||
|
], $assets), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT);
|
||||||
|
?>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
|
|
@ -67,3 +80,244 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:2rem">
|
||||||
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:.75rem">
|
||||||
|
<h2 style="font-size:1rem;font-weight:600;margin:0">Buchungen auf Anlagevermögens-Konten</h2>
|
||||||
|
<div style="display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:var(--color-muted)">
|
||||||
|
<label style="display:flex;align-items:center;gap:.35rem;cursor:pointer">
|
||||||
|
<input type="checkbox" id="filter-unzugeordnet"
|
||||||
|
<?= $nurUnzugeordnet ? 'checked' : '' ?>
|
||||||
|
onchange="location.href='/assets?filter='+(this.checked?'unzugeordnet':'alle')">
|
||||||
|
Nur nicht zugeordnete anzeigen
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width:8rem">Datum</th>
|
||||||
|
<th style="width:7rem">Beleg-Nr.</th>
|
||||||
|
<th>Konto</th>
|
||||||
|
<th>Buchungstext</th>
|
||||||
|
<th class="td-num">Betrag</th>
|
||||||
|
<th>Anlagegut</th>
|
||||||
|
<th style="width:2.5rem"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($anlageBookings as $b): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="td-muted text-sm"><?= View::formatDate($b['buchungs_datum']) ?></td>
|
||||||
|
<td class="td-mono text-sm">
|
||||||
|
<?php if ($b['beleg_id']): ?>
|
||||||
|
<a href="/belege/<?= $h($b['beleg_id']) ?>" style="color:var(--color-link)">
|
||||||
|
<?= $h($b['buchungs_nr']) ?>
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= $h($b['buchungs_nr']) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="text-sm">
|
||||||
|
<span class="td-mono"><?= $h($b['kategorie_kontonummer']) ?></span>
|
||||||
|
<span class="td-muted"> <?= $h($b['kategorie_bezeichnung']) ?></span>
|
||||||
|
</td>
|
||||||
|
<td class="text-sm"><?= $h($b['buchungstext']) ?></td>
|
||||||
|
<td class="td-num text-sm"><?= number_format((float)$b['betrag_brutto'], 2, ',', '.') ?> €</td>
|
||||||
|
<td class="text-sm">
|
||||||
|
<?php if ($b['asset_id']): ?>
|
||||||
|
<a href="/assets/<?= $h($b['asset_id']) ?>/edit" style="color:var(--color-link)">
|
||||||
|
<?= $h($b['asset_anlage_nr']) ?> <?= $h($b['asset_bezeichnung']) ?>
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">–</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:center">
|
||||||
|
<?php if (!$b['asset_id']): ?>
|
||||||
|
<button type="button"
|
||||||
|
class="anlage-assign-btn"
|
||||||
|
data-booking-id="<?= $h($b['id']) ?>"
|
||||||
|
data-account-id="<?= $h($b['kategorie_konto_id'] ?? '') ?>"
|
||||||
|
data-datum="<?= $h($b['buchungs_datum'] ?? '') ?>"
|
||||||
|
data-betrag="<?= $h($b['betrag_netto'] ?? '') ?>"
|
||||||
|
title="Anlagegut zuordnen"
|
||||||
|
style="background:none;border:none;cursor:pointer;color:var(--color-muted);padding:.2rem;line-height:1;display:inline-flex;align-items:center;justify-content:center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
||||||
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<rect x="3" y="3" width="14" height="14" rx="2"/>
|
||||||
|
<polyline points="17 8 21 12 17 16"/>
|
||||||
|
<line x1="10" y1="12" x2="21" y2="12"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($anlageBookings)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="7" class="text-center text-muted" style="padding:2rem">
|
||||||
|
<?= $nurUnzugeordnet ? 'Alle Buchungen sind bereits einem Anlagegut zugeordnet.' : 'Keine Buchungen auf Anlagevermögens-Konten vorhanden.' ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Modal: Anlagegut zuordnen ──────────────────────────────── -->
|
||||||
|
<div id="modal-anlage-assign" class="modal-overlay" role="dialog" aria-modal="true">
|
||||||
|
<div class="modal" style="max-width:640px;width:100%">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">Anlagegut zuordnen</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p style="margin-bottom:1rem">Soll ein neues Wirtschaftsgut angelegt oder ein bestehendes ausgewählt werden?</p>
|
||||||
|
|
||||||
|
<div style="display:flex;flex-direction:column;gap:.6rem;margin-bottom:1.25rem">
|
||||||
|
<label style="display:flex;align-items:center;gap:.6rem;cursor:pointer">
|
||||||
|
<input type="radio" name="assign_wahl" id="assign_radio_neu" value="neu" checked>
|
||||||
|
<span>Neues Wirtschaftsgut anlegen</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:.6rem;cursor:pointer">
|
||||||
|
<input type="radio" name="assign_wahl" id="assign_radio_vorhanden" value="vorhanden">
|
||||||
|
<span>Bestehendes Wirtschaftsgut auswählen</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="assign_liste_wrap" style="display:none">
|
||||||
|
<p id="assign_liste_leer" class="text-muted text-sm" style="display:none">
|
||||||
|
Für dieses Konto sind noch keine Wirtschaftsgüter vorhanden.
|
||||||
|
</p>
|
||||||
|
<div class="table-wrap" id="assign_liste_table_wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width:6rem">Nr.</th>
|
||||||
|
<th>Wirtschaftsgut</th>
|
||||||
|
<th>Anschaffungsdatum</th>
|
||||||
|
<th class="td-num">Anschaffungskosten</th>
|
||||||
|
<th style="width:2.5rem"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="assign_liste_tbody"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer" style="display:flex;justify-content:flex-end;gap:.75rem;padding:1rem 1.5rem;border-top:1px solid var(--color-border)">
|
||||||
|
<button type="button" class="btn btn-secondary" data-modal-close>Abbrechen</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="assign_modal_ok">Weiter</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const _anlageAssets = <?= $assetsJson ?>;
|
||||||
|
|
||||||
|
let _assignAccountId = 0;
|
||||||
|
let _assignBookingId = 0;
|
||||||
|
let _assignDatum = '';
|
||||||
|
let _assignBetrag = '';
|
||||||
|
|
||||||
|
function _fmtDate(str) {
|
||||||
|
if (!str) return '–';
|
||||||
|
const [y, m, d] = str.split('-');
|
||||||
|
return d + '.' + m + '.' + y;
|
||||||
|
}
|
||||||
|
function _fmtEur(n) {
|
||||||
|
return n.toLocaleString('de-DE', {minimumFractionDigits:2, maximumFractionDigits:2}) + ' €';
|
||||||
|
}
|
||||||
|
function _escHtml(s) {
|
||||||
|
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.anlage-assign-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
_assignAccountId = parseInt(btn.dataset.accountId, 10) || 0;
|
||||||
|
_assignBookingId = parseInt(btn.dataset.bookingId, 10) || 0;
|
||||||
|
_assignDatum = btn.dataset.datum || '';
|
||||||
|
_assignBetrag = btn.dataset.betrag || '';
|
||||||
|
|
||||||
|
document.getElementById('assign_radio_neu').checked = true;
|
||||||
|
document.getElementById('assign_liste_wrap').style.display = 'none';
|
||||||
|
document.querySelectorAll('input[name="assign_auswahl"]').forEach(r => r.checked = false);
|
||||||
|
|
||||||
|
const passend = _anlageAssets.filter(a => a.account_id === _assignAccountId);
|
||||||
|
_renderAssignListe(passend);
|
||||||
|
|
||||||
|
document.getElementById('modal-anlage-assign').classList.add('open');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function _renderAssignListe(list) {
|
||||||
|
const tbody = document.getElementById('assign_liste_tbody');
|
||||||
|
const leer = document.getElementById('assign_liste_leer');
|
||||||
|
const table = document.getElementById('assign_liste_table_wrap');
|
||||||
|
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
|
if (list.length === 0) {
|
||||||
|
leer.style.display = '';
|
||||||
|
table.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
leer.style.display = 'none';
|
||||||
|
table.style.display = '';
|
||||||
|
|
||||||
|
list.forEach(a => {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
tr.style.cursor = 'pointer';
|
||||||
|
tr.innerHTML =
|
||||||
|
'<td class="td-mono text-sm">' + _escHtml(a.anlage_nr || a.lfd_nr) + '</td>' +
|
||||||
|
'<td>' + _escHtml(a.bezeichnung) + '</td>' +
|
||||||
|
'<td class="td-muted text-sm">' + _fmtDate(a.anschaffungsdatum) + '</td>' +
|
||||||
|
'<td class="td-num">' + _fmtEur(a.anschaffungskosten) + '</td>' +
|
||||||
|
'<td><input type="radio" name="assign_auswahl" value="' + a.id + '"></td>';
|
||||||
|
tbody.appendChild(tr);
|
||||||
|
|
||||||
|
tr.addEventListener('click', () => {
|
||||||
|
const radio = tr.querySelector('input[type="radio"]');
|
||||||
|
if (radio) radio.checked = true;
|
||||||
|
tbody.querySelectorAll('tr').forEach(r => r.classList.remove('row-selected'));
|
||||||
|
tr.classList.add('row-selected');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('change', e => {
|
||||||
|
if (e.target.name !== 'assign_wahl') return;
|
||||||
|
const wrap = document.getElementById('assign_liste_wrap');
|
||||||
|
wrap.style.display = e.target.value === 'vorhanden' ? '' : 'none';
|
||||||
|
if (e.target.value === 'neu') {
|
||||||
|
document.querySelectorAll('input[name="assign_auswahl"]').forEach(r => r.checked = false);
|
||||||
|
document.querySelectorAll('#assign_liste_tbody tr').forEach(r => r.classList.remove('row-selected'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('assign_modal_ok').addEventListener('click', () => {
|
||||||
|
const wahl = document.querySelector('input[name="assign_wahl"]:checked')?.value;
|
||||||
|
const bkParams = new URLSearchParams();
|
||||||
|
if (_assignBookingId) bkParams.set('bk_booking_id', _assignBookingId);
|
||||||
|
if (_assignAccountId) bkParams.set('bk_account_id', _assignAccountId);
|
||||||
|
if (_assignDatum) bkParams.set('bk_datum', _assignDatum);
|
||||||
|
if (_assignBetrag) bkParams.set('bk_betrag', _assignBetrag);
|
||||||
|
const qs = bkParams.toString() ? '?' + bkParams.toString() : '';
|
||||||
|
|
||||||
|
if (wahl === 'vorhanden') {
|
||||||
|
const gewählt = document.querySelector('input[name="assign_auswahl"]:checked');
|
||||||
|
if (!gewählt) {
|
||||||
|
alert('Bitte ein Wirtschaftsgut aus der Liste auswählen.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.getElementById('modal-anlage-assign').classList.remove('open');
|
||||||
|
location.href = '/assets/' + gewählt.value + '/edit' + qs;
|
||||||
|
} else {
|
||||||
|
document.getElementById('modal-anlage-assign').classList.remove('open');
|
||||||
|
location.href = '/assets/new' + qs;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -142,15 +142,15 @@ $fmt = fn($v) => View::formatMoney($v);
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Anlage-ID</th>
|
<th style="white-space:normal">Anlage-ID</th>
|
||||||
<th>Bezeichnung</th>
|
<th style="white-space:normal">Bezeichnung</th>
|
||||||
<th>Anschaffungsdatum</th>
|
<th style="white-space:normal">Anschaff.-datum</th>
|
||||||
<th class="td-right">Anschaffungskosten</th>
|
<th class="td-right" style="white-space:normal">Anschaff.-kosten</th>
|
||||||
<th class="td-right">Nutzungsdauer</th>
|
<th class="td-right" style="white-space:normal">Nutzungs-dauer</th>
|
||||||
<th class="td-right">AfA Vorjahre</th>
|
<th class="td-right" style="white-space:normal">AfA Vorjahre</th>
|
||||||
<th class="td-right">Restbuchwert Vorjahr</th>
|
<th class="td-right" style="white-space:normal">Restbuch-wert Vorjahr</th>
|
||||||
<th class="td-right">AfA <?= $h($year) ?></th>
|
<th class="td-right" style="white-space:normal">AfA <?= $h($year) ?></th>
|
||||||
<th class="td-right">Restbuchwert 31.12.<?= $h($year) ?></th>
|
<th class="td-right" style="white-space:normal">Restbuch-wert 31.12.<?= $h($year) ?></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -170,17 +170,17 @@ $fmt = fn($v) => View::formatMoney($v);
|
||||||
if ($al['nutzungsdauer'] === '0' || $al['nutzungsdauer'] === 0) $nd = 'sofort';
|
if ($al['nutzungsdauer'] === '0' || $al['nutzungsdauer'] === 0) $nd = 'sofort';
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="td-mono text-sm">
|
<td class="td-mono text-sm" style="white-space:nowrap">
|
||||||
<a href="/assets/<?= (int)$al['id'] ?>/edit"><?= $h($al['anlage_nr'] ?: $al['lfd_nr']) ?></a>
|
<a href="/assets/<?= (int)$al['id'] ?>/edit"><?= $h($al['anlage_nr'] ?: $al['lfd_nr']) ?></a>
|
||||||
</td>
|
</td>
|
||||||
<td><?= $h($al['bezeichnung']) ?></td>
|
<td style="min-width:10rem;width:100%"><?= $h($al['bezeichnung']) ?></td>
|
||||||
<td class="td-muted text-sm"><?= View::formatDate($al['anschaffungsdatum']) ?></td>
|
<td class="td-muted text-sm" style="white-space:nowrap"><?= View::formatDate($al['anschaffungsdatum']) ?></td>
|
||||||
<td class="td-right td-mono"><?= $fmt($al['basis']) ?></td>
|
<td class="td-right td-mono" style="white-space:nowrap"><?= $fmt($al['basis']) ?></td>
|
||||||
<td class="td-right td-muted"><?= $h($nd) ?></td>
|
<td class="td-right td-muted" style="white-space:nowrap"><?= $h($nd) ?></td>
|
||||||
<td class="td-right td-mono"><?= $fmt($al['afa_vorjahre']) ?></td>
|
<td class="td-right td-mono" style="white-space:nowrap"><?= $fmt($al['afa_vorjahre']) ?></td>
|
||||||
<td class="td-right td-mono"><?= $fmt($al['restbuchwert_vorjahr']) ?></td>
|
<td class="td-right td-mono" style="white-space:nowrap"><?= $fmt($al['restbuchwert_vorjahr']) ?></td>
|
||||||
<td class="td-right td-mono"><?= $fmt($al['afa_jahr']) ?></td>
|
<td class="td-right td-mono" style="white-space:nowrap"><?= $fmt($al['afa_jahr']) ?></td>
|
||||||
<td class="td-right td-mono"><?= $fmt($al['restbuchwert']) ?></td>
|
<td class="td-right td-mono" style="white-space:nowrap"><?= $fmt($al['restbuchwert']) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue