257 lines
9.6 KiB
PHP
257 lines
9.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Steuerkram\Models;
|
|
|
|
use Steuerkram\Database;
|
|
|
|
class Asset
|
|
{
|
|
/**
|
|
* Anlageliste für die EÜR: alle Assets, die im gegebenen Jahr aktiv sind,
|
|
* mit kumulierten AfA-Buchungen aus Vorjahren und dem laufenden Jahr.
|
|
*/
|
|
public static function anlageliste(int $year): array
|
|
{
|
|
$rows = Database::fetchAll(
|
|
"SELECT
|
|
a.*,
|
|
ac.kontonummer AS anlageart_kontonummer,
|
|
ac.bezeichnung AS anlageart_bezeichnung,
|
|
COALESCE(bk_prev.afa_vorjahre, 0) AS afa_vorjahre,
|
|
COALESCE(bk_curr.afa_jahr, 0) AS afa_jahr
|
|
FROM assets a
|
|
LEFT JOIN accounts ac ON a.account_id = ac.id
|
|
LEFT JOIN (
|
|
SELECT asset_id, SUM(betrag_netto) AS afa_vorjahre
|
|
FROM bookings
|
|
WHERE buchungstyp = 'AfA' AND afa_jahr < ?
|
|
GROUP BY asset_id
|
|
) bk_prev ON bk_prev.asset_id = a.id
|
|
LEFT JOIN (
|
|
SELECT asset_id, SUM(betrag_netto) AS afa_jahr
|
|
FROM bookings
|
|
WHERE buchungstyp = 'AfA' AND afa_jahr = ?
|
|
GROUP BY asset_id
|
|
) bk_curr ON bk_curr.asset_id = a.id
|
|
WHERE YEAR(a.anschaffungsdatum) <= ?
|
|
ORDER BY a.lfd_nr ASC, a.id ASC",
|
|
[$year, $year, $year]
|
|
);
|
|
|
|
$result = [];
|
|
foreach ($rows as $row) {
|
|
$basis = (float)$row['anschaffungskosten'] + (float)$row['zugaenge'] - (float)$row['abgaenge'];
|
|
$afaVorjahre = (float)$row['afa_vorjahre'];
|
|
$afaJahr = (float)$row['afa_jahr'];
|
|
$restbuchwertVorjahr = round($basis - $afaVorjahre, 2);
|
|
$restbuchwert = round($restbuchwertVorjahr - $afaJahr, 2);
|
|
|
|
$result[] = array_merge($row, [
|
|
'basis' => $basis,
|
|
'afa_vorjahre' => $afaVorjahre,
|
|
'afa_jahr' => $afaJahr,
|
|
'restbuchwert_vorjahr' => $restbuchwertVorjahr,
|
|
'restbuchwert' => $restbuchwert,
|
|
]);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public static function all(?int $fiscalYearId = null): array
|
|
{
|
|
$where = '1=1';
|
|
$params = [];
|
|
|
|
if ($fiscalYearId !== null) {
|
|
$where = 'a.fiscal_year_id = ?';
|
|
$params[] = $fiscalYearId;
|
|
}
|
|
|
|
return Database::fetchAll(
|
|
"SELECT a.*, ac.kontonummer AS anlageart_kontonummer, ac.bezeichnung AS anlageart_bezeichnung
|
|
FROM assets a
|
|
LEFT JOIN accounts ac ON a.account_id = ac.id
|
|
WHERE $where
|
|
ORDER BY a.lfd_nr ASC, a.id ASC",
|
|
$params
|
|
);
|
|
}
|
|
|
|
public static function find(int $id): array|false
|
|
{
|
|
return Database::fetchOne(
|
|
'SELECT a.*, ac.kontonummer AS anlageart_kontonummer, ac.bezeichnung AS anlageart_bezeichnung
|
|
FROM assets a
|
|
LEFT JOIN accounts ac ON a.account_id = ac.id
|
|
WHERE a.id = ?',
|
|
[$id]
|
|
);
|
|
}
|
|
|
|
public static function anlagearten(): array
|
|
{
|
|
return Database::fetchAll(
|
|
"SELECT id, kontonummer, bezeichnung FROM accounts
|
|
WHERE kontenart = 'Anlagevermögen'
|
|
ORDER BY kontonummer ASC"
|
|
);
|
|
}
|
|
|
|
public static function nextLfdNr(): int
|
|
{
|
|
$row = Database::fetchOne('SELECT COALESCE(MAX(lfd_nr), 0) + 1 AS next FROM assets');
|
|
return (int)($row['next'] ?? 1);
|
|
}
|
|
|
|
public static function generateAnlageNr(): string
|
|
{
|
|
$settings = Database::fetchOne(
|
|
'SELECT anlage_nr_prefix, anlage_nr_next FROM company_settings WHERE id=1'
|
|
);
|
|
$prefix = $settings['anlage_nr_prefix'] ?? 'ANL';
|
|
$next = (int)($settings['anlage_nr_next'] ?? 1);
|
|
$year = date('Y');
|
|
$nr = sprintf('%s-%s-%04d', $prefix, $year, $next);
|
|
|
|
Database::execute(
|
|
'UPDATE company_settings SET anlage_nr_next = anlage_nr_next + 1 WHERE id=1'
|
|
);
|
|
|
|
return $nr;
|
|
}
|
|
|
|
public static function create(array $data): int
|
|
{
|
|
$fyId = null;
|
|
if (!empty($data['anschaffungsdatum'])) {
|
|
$year = (int)date('Y', strtotime($data['anschaffungsdatum']));
|
|
$fy = FiscalYear::findOrCreateByYear($year);
|
|
$fyId = $fy['id'];
|
|
}
|
|
|
|
$anlageNr = $data['anlage_nr'] ?? self::generateAnlageNr();
|
|
|
|
Database::execute(
|
|
'INSERT INTO assets
|
|
(lfd_nr, anlage_nr, bezeichnung, account_id, anschaffungsdatum, anschaffungskosten,
|
|
zugaenge, abgaenge, abschreibung_jahr, nutzungsdauer, automatisch_berechnet,
|
|
cent_im_ersten_jahr, notizen, fiscal_year_id)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
|
[
|
|
$data['lfd_nr'] ?? self::nextLfdNr(),
|
|
$anlageNr,
|
|
$data['bezeichnung'],
|
|
isset($data['account_id']) && $data['account_id'] !== '' ? (int)$data['account_id'] : null,
|
|
$data['anschaffungsdatum'],
|
|
$data['anschaffungskosten'] ?? 0,
|
|
$data['zugaenge'] ?? 0,
|
|
$data['abgaenge'] ?? 0,
|
|
$data['abschreibung_jahr'] ?? 0,
|
|
isset($data['nutzungsdauer']) && $data['nutzungsdauer'] !== '' ? (int)$data['nutzungsdauer'] : null,
|
|
isset($data['automatisch_berechnet']) ? (int)(bool)$data['automatisch_berechnet'] : 1,
|
|
isset($data['cent_im_ersten_jahr']) ? (int)(bool)$data['cent_im_ersten_jahr'] : 0,
|
|
$data['notizen'] ?? null,
|
|
$fyId,
|
|
]
|
|
);
|
|
return (int)Database::lastInsertId();
|
|
}
|
|
|
|
public static function update(int $id, array $data): void
|
|
{
|
|
$fyId = null;
|
|
if (!empty($data['anschaffungsdatum'])) {
|
|
$year = (int)date('Y', strtotime($data['anschaffungsdatum']));
|
|
$fy = FiscalYear::findOrCreateByYear($year);
|
|
$fyId = $fy['id'];
|
|
}
|
|
|
|
Database::execute(
|
|
'UPDATE assets SET
|
|
bezeichnung = ?,
|
|
account_id = ?,
|
|
anschaffungsdatum = ?,
|
|
anschaffungskosten = ?,
|
|
zugaenge = ?,
|
|
abgaenge = ?,
|
|
abschreibung_jahr = ?,
|
|
nutzungsdauer = ?,
|
|
automatisch_berechnet = ?,
|
|
cent_im_ersten_jahr = ?,
|
|
notizen = ?,
|
|
fiscal_year_id = COALESCE(?, fiscal_year_id),
|
|
updated_at = NOW()
|
|
WHERE id = ?',
|
|
[
|
|
$data['bezeichnung'],
|
|
isset($data['account_id']) && $data['account_id'] !== '' ? (int)$data['account_id'] : null,
|
|
$data['anschaffungsdatum'],
|
|
$data['anschaffungskosten'] ?? 0,
|
|
$data['zugaenge'] ?? 0,
|
|
$data['abgaenge'] ?? 0,
|
|
$data['abschreibung_jahr'] ?? 0,
|
|
isset($data['nutzungsdauer']) && $data['nutzungsdauer'] !== '' ? (int)$data['nutzungsdauer'] : null,
|
|
isset($data['automatisch_berechnet']) ? (int)(bool)$data['automatisch_berechnet'] : 1,
|
|
isset($data['cent_im_ersten_jahr']) ? (int)(bool)$data['cent_im_ersten_jahr'] : 0,
|
|
$data['notizen'] ?? null,
|
|
$fyId,
|
|
$id,
|
|
]
|
|
);
|
|
}
|
|
|
|
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);
|
|
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]);
|
|
return true;
|
|
}
|
|
}
|