Kostenarten und geschützte Standkosten umsetzen

This commit is contained in:
gitea_admin committed 2026-09-20 12:16:31 +02:00
1 parent 313475afec
commit 3a0cb81a97
7 files changed
+200 -17

No files matched your search

+98 -14
View File
@@ -89,6 +89,60 @@ function market_management_create_municipality(PDO $pdo, string $name): array
return (array) $stmt->fetch();
}
function market_management_list_cost_types(PDO $pdo): array
{
return $pdo->query(
'SELECT id, code, name, is_system, is_active
FROM market_cost_type
WHERE is_active = TRUE
ORDER BY is_system DESC, name ASC, id ASC'
)->fetchAll() ?: [];
}
function market_management_get_cost_type(PDO $pdo, int $costTypeId): ?array
{
$stmt = $pdo->prepare(
'SELECT id, code, name, is_system, is_active
FROM market_cost_type WHERE id = :id AND is_active = TRUE'
);
$stmt->execute([':id' => $costTypeId]);
$type = $stmt->fetch();
return is_array($type) ? $type : null;
}
function market_management_get_cost_type_id(PDO $pdo, string $code): int
{
$stmt = $pdo->prepare('SELECT id FROM market_cost_type WHERE code = :code AND is_active = TRUE');
$stmt->execute([':code' => $code]);
$id = $stmt->fetchColumn();
if ($id === false) {
throw new RuntimeException('Standard-Kostenart fehlt.');
}
return (int) $id;
}
function market_management_create_cost_type(PDO $pdo, string $name, ?string $code = null): array
{
$name = trim($name);
$code = trim((string) ($code ?? ''));
if ($name === '') {
throw new InvalidArgumentException('Kostenartenname fehlt.');
}
if ($code === '') {
$code = strtolower(trim((string) preg_replace('/[^a-z0-9]+/i', '_', $name), '_'));
}
if ($code === '') {
throw new InvalidArgumentException('Code der Kostenart fehlt.');
}
$stmt = $pdo->prepare(
'INSERT INTO market_cost_type (code, name)
VALUES (:code, :name)
RETURNING id, code, name, is_system, is_active'
);
$stmt->execute([':code' => $code, ':name' => $name]);
return (array) $stmt->fetch();
}
function market_management_require_positive_id(mixed $value, string $field): int
{
if (!is_int($value) && !ctype_digit((string) $value)) {
@@ -724,6 +778,13 @@ function market_management_create_occurrence(PDO $pdo, array $input): array
'contact_email' => null,
'contact_phone' => null,
]);
market_management_create_cost_item($pdo, [
'occurrence_id' => (int) $occurrence['id'],
'cost_type_id' => market_management_get_cost_type_id($pdo, 'stand_fee'),
'gross_amount' => 0,
'tax_status' => 'taxable',
'tax_rate' => 8.10,
]);
if ($startedTransaction) {
$pdo->commit();
}
@@ -865,8 +926,14 @@ function market_management_get_occurrence(PDO $pdo, int $occurrenceId, bool $inc
'last_name' => '',
'party_name' => '',
]],
'cost_types' => market_management_list_cost_types($pdo),
];
$costs = $pdo->prepare('SELECT * FROM market_occurrence_cost_item WHERE occurrence_id = :occurrence_id ORDER BY id ASC');
$costs = $pdo->prepare(
'SELECT item.*, type.code AS cost_type_code, type.name AS cost_type
FROM market_occurrence_cost_item item
INNER JOIN market_cost_type type ON type.id = item.cost_type_id
WHERE item.occurrence_id = :occurrence_id ORDER BY item.id ASC'
);
$costs->execute([':occurrence_id' => $occurrenceId]);
$occurrence['cost_items'] = $costs->fetchAll();
$costSummary = $pdo->prepare(
@@ -1195,35 +1262,51 @@ function market_management_set_occurrence_contact(PDO $pdo, array $input): array
function market_management_create_cost_item(PDO $pdo, array $input): array
{
$occurrenceId = market_management_require_positive_id($input['occurrence_id'] ?? null, 'occurrence_id');
$costType = trim((string) ($input['cost_type'] ?? ''));
$costTypeId = market_management_require_positive_id($input['cost_type_id'] ?? null, 'cost_type_id');
$grossAmount = market_management_optional_number($input, 'gross_amount');
$taxStatus = trim((string) ($input['tax_status'] ?? ''));
$taxRate = market_management_optional_number($input, 'tax_rate') ?? '0.00';
if ($costType === '' || $grossAmount === null || !in_array($taxStatus, ['tax_free', 'taxable'], true)) {
throw new InvalidArgumentException('cost_type, gross_amount und tax_status sind erforderlich.');
if ($grossAmount === null || !in_array($taxStatus, ['tax_free', 'taxable'], true)) {
throw new InvalidArgumentException('cost_type_id, gross_amount und tax_status sind erforderlich.');
}
if (($taxStatus === 'tax_free' && $taxRate !== '0.00') || ($taxStatus === 'taxable' && (float) $taxRate <= 0)) {
throw new InvalidArgumentException('tax_rate passt nicht zu tax_status.');
}
$stmt = $pdo->prepare(
'INSERT INTO market_occurrence_cost_item
(occurrence_id, cost_type, description, gross_amount, tax_status, tax_rate)
VALUES (:occurrence_id, :cost_type, :description, :gross_amount, :tax_status, :tax_rate)
(occurrence_id, cost_type_id, description, gross_amount, tax_status, tax_rate)
VALUES (:occurrence_id, :cost_type_id, :description, :gross_amount, :tax_status, :tax_rate)
RETURNING *'
);
if (market_management_get_cost_type($pdo, $costTypeId) === null) {
throw new InvalidArgumentException('Kostenart nicht gefunden oder inaktiv.');
}
$stmt->execute([
':occurrence_id' => $occurrenceId,
':cost_type' => $costType,
':cost_type_id' => $costTypeId,
':description' => market_management_optional_string($input, 'description'),
':gross_amount' => $grossAmount,
':tax_status' => $taxStatus,
':tax_rate' => $taxRate,
]);
return (array) $stmt->fetch();
$item = (array) $stmt->fetch();
$item['cost_type'] = market_management_get_cost_type($pdo, $costTypeId)['name'];
return $item;
}
function market_management_delete_cost_item(PDO $pdo, int $costItemId): array
{
$stmt = $pdo->prepare('SELECT id, occurrence_id FROM market_occurrence_cost_item WHERE id = :id');
$stmt->execute([':id' => $costItemId]);
$item = $stmt->fetch();
if (!is_array($item)) {
throw new RuntimeException('Kostenposition nicht gefunden.');
}
$first = $pdo->prepare('SELECT MIN(id) FROM market_occurrence_cost_item WHERE occurrence_id = :occurrence_id');
$first->execute([':occurrence_id' => $item['occurrence_id']]);
if ((int) $first->fetchColumn() === $costItemId) {
throw new InvalidArgumentException('Die erste Standkostenposition darf nicht gelöscht werden.');
}
$stmt = $pdo->prepare('DELETE FROM market_occurrence_cost_item WHERE id = :id RETURNING id, occurrence_id');
$stmt->execute([':id' => $costItemId]);
$item = $stmt->fetch();
@@ -1237,13 +1320,13 @@ function market_management_update_cost_item(PDO $pdo, int $costItemId, array $in
{
$sets = [];
$params = [':id' => $costItemId];
if (array_key_exists('cost_type', $input)) {
$costType = trim((string) $input['cost_type']);
if ($costType === '') {
throw new InvalidArgumentException('cost_type darf nicht leer sein.');
if (array_key_exists('cost_type_id', $input)) {
$costTypeId = market_management_require_positive_id($input['cost_type_id'], 'cost_type_id');
if (market_management_get_cost_type($pdo, $costTypeId) === null) {
throw new InvalidArgumentException('Kostenart nicht gefunden oder inaktiv.');
}
$sets[] = 'cost_type = :cost_type';
$params[':cost_type'] = $costType;
$sets[] = 'cost_type_id = :cost_type_id';
$params[':cost_type_id'] = $costTypeId;
}
foreach (['description' => 'string', 'gross_amount' => 'number', 'tax_status' => 'string', 'tax_rate' => 'number'] as $field => $type) {
if (!array_key_exists($field, $input)) {
@@ -1269,5 +1352,6 @@ function market_management_update_cost_item(PDO $pdo, int $costItemId, array $in
if (!is_array($item)) {
throw new RuntimeException('Kostenposition nicht gefunden.');
}
$item['cost_type'] = market_management_get_cost_type($pdo, (int) $item['cost_type_id'])['name'];
return $item;
}