Steuerstatus und Steuersatz in Kostenkarte wiederherstellen
This commit is contained in:
1 parent
bae293ad94
commit
af235987ea
5 files changed
+39
-22
No files matched your search
@@ -187,8 +187,11 @@ Weitere mögliche Tagesfelder sind `stand_start_time`, `stand_end_time`,
|
|||||||
`contact_email` und `contact_phone` ändern.
|
`contact_email` und `contact_phone` ändern.
|
||||||
- Kosten werden bei `market_management.create_occurrence` automatisch mit einer
|
- Kosten werden bei `market_management.create_occurrence` automatisch mit einer
|
||||||
`Standkosten`-Position (`stand_fee`) und dem Standardsteuersatz 8.1 % angelegt.
|
`Standkosten`-Position (`stand_fee`) und dem Standardsteuersatz 8.1 % angelegt.
|
||||||
- `market_management.update_occurrence` ändert Kosten über `gross_cost` sowie die
|
- `market_management.update_occurrence` ändert Kosten über `gross_cost`,
|
||||||
optionale mehrzeilige Freitext-Aufschlüsselung `cost_items_text`.
|
`tax_status`, `tax_rate` sowie die optionale mehrzeilige Freitext-Aufschlüsselung
|
||||||
|
`cost_items_text`.
|
||||||
|
- `tax_status` ist `taxable` oder `tax_free`; bei `tax_free` ist der Steuersatz
|
||||||
|
`0.00`.
|
||||||
- `gross_cost` darf `0.00` sein; einzelne Kostenpositionen und Kostenarten werden
|
- `gross_cost` darf `0.00` sein; einzelne Kostenpositionen und Kostenarten werden
|
||||||
nicht separat über MCP verwaltet.
|
nicht separat über MCP verwaltet.
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function market_management_mcp_tools(): array
|
|||||||
'payment_status' => ['type' => ['string', 'null'], 'enum' => ['paid', 'unpaid']],
|
'payment_status' => ['type' => ['string', 'null'], 'enum' => ['paid', 'unpaid']],
|
||||||
'payment_date' => ['type' => ['string', 'null'], 'format' => 'date'], 'paid_amount' => ['type' => ['number', 'null']],
|
'payment_date' => ['type' => ['string', 'null'], 'format' => 'date'], 'paid_amount' => ['type' => ['number', 'null']],
|
||||||
'payment_method_code' => ['type' => ['string', 'null']], 'stand_size' => ['type' => ['string', 'null']],
|
'payment_method_code' => ['type' => ['string', 'null']], 'stand_size' => ['type' => ['string', 'null']],
|
||||||
'gross_cost' => ['type' => ['number', 'null'], 'minimum' => 0], 'cost_items_text' => ['type' => ['string', 'null']],
|
'gross_cost' => ['type' => ['number', 'null'], 'minimum' => 0], 'tax_status' => ['type' => ['string', 'null'], 'enum' => ['tax_free', 'taxable']], 'tax_rate' => ['type' => ['number', 'null'], 'minimum' => 0], 'cost_items_text' => ['type' => ['string', 'null']],
|
||||||
'table_available' => ['type' => ['boolean', 'null']], 'table_rentable' => ['type' => ['boolean', 'null']],
|
'table_available' => ['type' => ['boolean', 'null']], 'table_rentable' => ['type' => ['boolean', 'null']],
|
||||||
'own_table_required' => ['type' => ['boolean', 'null']], 'shelter_available' => ['type' => ['boolean', 'null']],
|
'own_table_required' => ['type' => ['boolean', 'null']], 'shelter_available' => ['type' => ['boolean', 'null']],
|
||||||
'power_available' => ['type' => ['boolean', 'null']], 'water_available' => ['type' => ['boolean', 'null']],
|
'power_available' => ['type' => ['boolean', 'null']], 'water_available' => ['type' => ['boolean', 'null']],
|
||||||
@@ -216,7 +216,7 @@ function market_management_mcp_get_market(PDO $pdo, int $marketId, bool $include
|
|||||||
function market_management_mcp_update_occurrence(PDO $pdo, int $occurrenceId, array $input): array
|
function market_management_mcp_update_occurrence(PDO $pdo, int $occurrenceId, array $input): array
|
||||||
{
|
{
|
||||||
$simpleCostFields = [];
|
$simpleCostFields = [];
|
||||||
foreach (['gross_cost', 'cost_items_text'] as $field) {
|
foreach (['gross_cost', 'cost_items_text', 'tax_status', 'tax_rate'] as $field) {
|
||||||
if (array_key_exists($field, $input)) {
|
if (array_key_exists($field, $input)) {
|
||||||
$simpleCostFields[$field] = $input[$field];
|
$simpleCostFields[$field] = $input[$field];
|
||||||
unset($input[$field]);
|
unset($input[$field]);
|
||||||
|
|||||||
@@ -1358,34 +1358,45 @@ function market_management_update_cost_item(PDO $pdo, int $costItemId, array $in
|
|||||||
|
|
||||||
function market_management_update_occurrence_simple_costs(PDO $pdo, int $occurrenceId, array $input): array
|
function market_management_update_occurrence_simple_costs(PDO $pdo, int $occurrenceId, array $input): array
|
||||||
{
|
{
|
||||||
$grossAmount = market_management_optional_number($input, 'gross_cost');
|
|
||||||
if ($grossAmount === null) {
|
|
||||||
throw new InvalidArgumentException('Gesamtkosten sind erforderlich.');
|
|
||||||
}
|
|
||||||
$itemStmt = $pdo->prepare(
|
$itemStmt = $pdo->prepare(
|
||||||
'SELECT id FROM market_occurrence_cost_item
|
'SELECT id, gross_amount, tax_status, tax_rate, description FROM market_occurrence_cost_item
|
||||||
WHERE occurrence_id = :occurrence_id
|
WHERE occurrence_id = :occurrence_id
|
||||||
ORDER BY id ASC LIMIT 1'
|
ORDER BY id ASC LIMIT 1'
|
||||||
);
|
);
|
||||||
$itemStmt->execute([':occurrence_id' => $occurrenceId]);
|
$itemStmt->execute([':occurrence_id' => $occurrenceId]);
|
||||||
$itemId = $itemStmt->fetchColumn();
|
$existingItem = $itemStmt->fetch();
|
||||||
$description = array_key_exists('cost_items_text', $input)
|
if (!is_array($existingItem)) {
|
||||||
? market_management_optional_string($input, 'cost_items_text')
|
$grossAmount = market_management_optional_number($input, 'gross_cost') ?? '0.00';
|
||||||
: null;
|
$taxStatus = trim((string) ($input['tax_status'] ?? 'taxable'));
|
||||||
if ($itemId === false) {
|
$taxRate = market_management_optional_number($input, 'tax_rate') ?? ($taxStatus === 'tax_free' ? '0.00' : '8.10');
|
||||||
$item = market_management_create_cost_item($pdo, [
|
$item = market_management_create_cost_item($pdo, [
|
||||||
'occurrence_id' => $occurrenceId,
|
'occurrence_id' => $occurrenceId,
|
||||||
'cost_type_id' => market_management_get_cost_type_id($pdo, 'stand_fee'),
|
'cost_type_id' => market_management_get_cost_type_id($pdo, 'stand_fee'),
|
||||||
'description' => $description,
|
'description' => array_key_exists('cost_items_text', $input) ? market_management_optional_string($input, 'cost_items_text') : null,
|
||||||
'gross_amount' => $grossAmount,
|
'gross_amount' => $grossAmount,
|
||||||
'tax_status' => 'taxable',
|
'tax_status' => $taxStatus,
|
||||||
'tax_rate' => 8.10,
|
'tax_rate' => $taxRate,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$item = market_management_update_cost_item($pdo, (int) $itemId, [
|
$costFields = [];
|
||||||
'description' => $description,
|
if (array_key_exists('gross_cost', $input)) {
|
||||||
'gross_amount' => $grossAmount,
|
$costFields['gross_amount'] = market_management_optional_number($input, 'gross_cost');
|
||||||
]);
|
}
|
||||||
|
if (array_key_exists('cost_items_text', $input)) {
|
||||||
|
$costFields['description'] = market_management_optional_string($input, 'cost_items_text');
|
||||||
|
}
|
||||||
|
if (array_key_exists('tax_status', $input)) {
|
||||||
|
$costFields['tax_status'] = trim((string) $input['tax_status']);
|
||||||
|
if ($costFields['tax_status'] === 'tax_free' && !array_key_exists('tax_rate', $input)) {
|
||||||
|
$costFields['tax_rate'] = '0.00';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('tax_rate', $input)) {
|
||||||
|
$costFields['tax_rate'] = market_management_optional_number($input, 'tax_rate');
|
||||||
|
}
|
||||||
|
$item = $costFields === []
|
||||||
|
? (array) $existingItem
|
||||||
|
: market_management_update_cost_item($pdo, (int) $existingItem['id'], $costFields);
|
||||||
}
|
}
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
@@ -1200,6 +1200,9 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $otcM
|
|||||||
echo " const marketOccurrenceFieldObserver = new MutationObserver(() => normalizeOccurrenceOverviewForm(contentRoot)); marketOccurrenceFieldObserver.observe(contentRoot, { childList: true, subtree: true });";
|
echo " const marketOccurrenceFieldObserver = new MutationObserver(() => normalizeOccurrenceOverviewForm(contentRoot)); marketOccurrenceFieldObserver.observe(contentRoot, { childList: true, subtree: true });";
|
||||||
echo " const normalizeMarketSimpleCostFields = (root) => { root.querySelectorAll('[data-market-edit-form][data-market-edit-scope=participation]').forEach((form) => { if (form.dataset.marketSimpleCostsNormalized === 'true') { return; } const drawer = getMarketDrawer(); let payload = {}; try { payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : {}; } catch (error) {} const item = Array.isArray(payload.occurrence?.cost_items) ? payload.occurrence.cost_items[0] : null; const total = form.querySelector('[name=gross_cost]'); const text = form.querySelector('[name=cost_items_text]'); const totalLabel = total?.closest('.sg-labeled-input-row')?.querySelector('.sg-label'); const textLabel = text?.closest('.sg-labeled-input-row')?.querySelector('.sg-label'); if (total) { total.disabled = false; total.removeAttribute('disabled'); total.type = 'number'; total.step = '0.01'; total.min = '0'; total.required = true; total.classList.remove('sg-input-single-line--disabled', 'sg-form-disabled'); total.value = payload.occurrence?.cost_summary?.gross_amount ?? item?.gross_amount ?? ''; } if (text) { text.disabled = false; text.removeAttribute('disabled'); text.classList.remove('sg-form-disabled'); text.value = item?.description || ''; } if (totalLabel) { totalLabel.textContent = 'Gesamtkosten'; } if (textLabel) { textLabel.textContent = 'Kostenpositionen'; } form.dataset.marketSimpleCostsNormalized = 'true'; }); };";
|
echo " const normalizeMarketSimpleCostFields = (root) => { root.querySelectorAll('[data-market-edit-form][data-market-edit-scope=participation]').forEach((form) => { if (form.dataset.marketSimpleCostsNormalized === 'true') { return; } const drawer = getMarketDrawer(); let payload = {}; try { payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : {}; } catch (error) {} const item = Array.isArray(payload.occurrence?.cost_items) ? payload.occurrence.cost_items[0] : null; const total = form.querySelector('[name=gross_cost]'); const text = form.querySelector('[name=cost_items_text]'); const totalLabel = total?.closest('.sg-labeled-input-row')?.querySelector('.sg-label'); const textLabel = text?.closest('.sg-labeled-input-row')?.querySelector('.sg-label'); if (total) { total.disabled = false; total.removeAttribute('disabled'); total.type = 'number'; total.step = '0.01'; total.min = '0'; total.required = true; total.classList.remove('sg-input-single-line--disabled', 'sg-form-disabled'); total.value = payload.occurrence?.cost_summary?.gross_amount ?? item?.gross_amount ?? ''; } if (text) { text.disabled = false; text.removeAttribute('disabled'); text.classList.remove('sg-form-disabled'); text.value = item?.description || ''; } if (totalLabel) { totalLabel.textContent = 'Gesamtkosten'; } if (textLabel) { textLabel.textContent = 'Kostenpositionen'; } form.dataset.marketSimpleCostsNormalized = 'true'; }); };";
|
||||||
echo " const marketSimpleCostFieldsObserver = new MutationObserver(() => normalizeMarketSimpleCostFields(contentRoot)); marketSimpleCostFieldsObserver.observe(contentRoot, { childList: true, subtree: true }); normalizeMarketSimpleCostFields(contentRoot);";
|
echo " const marketSimpleCostFieldsObserver = new MutationObserver(() => normalizeMarketSimpleCostFields(contentRoot)); marketSimpleCostFieldsObserver.observe(contentRoot, { childList: true, subtree: true }); normalizeMarketSimpleCostFields(contentRoot);";
|
||||||
|
echo " const normalizeMarketTaxFields = (root) => { root.querySelectorAll('[data-market-edit-form][data-market-edit-scope=participation]').forEach((form) => { if (form.dataset.marketTaxFieldsNormalized === 'true') { return; } const total = form.querySelector('[name=gross_cost]'); const totalGroup = total?.closest('.sg-form-sections-card__field-group'); if (!totalGroup) { return; } const drawer = getMarketDrawer(); let payload = {}; try { payload = drawer?.dataset.marketPayload ? JSON.parse(drawer.dataset.marketPayload) : {}; } catch (error) {} const item = Array.isArray(payload.occurrence?.cost_items) ? payload.occurrence.cost_items[0] : null; const taxStatusGroup = document.createElement('div'); taxStatusGroup.className = 'sg-form-sections-card__field-group'; taxStatusGroup.innerHTML = marketEditField('tax_status', 'Steuerstatus', 'select', item?.tax_status || 'taxable', [['taxable', 'Steuerpflichtig'], ['tax_free', 'Steuerfrei']], true); const taxRateGroup = document.createElement('div'); taxRateGroup.className = 'sg-form-sections-card__field-group'; taxRateGroup.innerHTML = marketEditField('tax_rate', 'Steuersatz', 'number', item?.tax_rate ?? '8.10', [], true); totalGroup.after(taxStatusGroup, taxRateGroup); const taxStatus = taxStatusGroup.querySelector('[name=tax_status]'); const taxRate = taxRateGroup.querySelector('[name=tax_rate]'); const sync = () => { const taxFree = taxStatus?.value === 'tax_free'; if (taxFree && taxRate) { taxRate.value = '0.00'; } if (taxRate) { taxRate.disabled = taxFree; taxRate.setAttribute('aria-disabled', String(taxFree)); } }; taxStatus?.addEventListener('change', sync); sync(); form.dataset.marketTaxFieldsNormalized = 'true'; }); };";
|
||||||
|
echo " const marketTaxFieldsObserver = new MutationObserver(() => normalizeMarketTaxFields(contentRoot)); marketTaxFieldsObserver.observe(contentRoot, { childList: true, subtree: true }); normalizeMarketTaxFields(contentRoot);";
|
||||||
|
echo " const marketTaxRateAttributesObserver = new MutationObserver(() => { contentRoot.querySelectorAll('[data-market-edit-form][data-market-edit-scope=participation] [name=tax_rate]').forEach((input) => { input.step = '0.01'; input.min = '0'; }); }); marketTaxRateAttributesObserver.observe(contentRoot, { childList: true, subtree: true });";
|
||||||
echo " bindTable();";
|
echo " bindTable();";
|
||||||
echo "}";
|
echo "}";
|
||||||
echo "function initMarketDefinitionsBindings() {";
|
echo "function initMarketDefinitionsBindings() {";
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ if ($requestMethod === 'POST') {
|
|||||||
}
|
}
|
||||||
if ($fields !== []) {
|
if ($fields !== []) {
|
||||||
$simpleCostFields = [];
|
$simpleCostFields = [];
|
||||||
foreach (['gross_cost', 'cost_items_text'] as $costField) {
|
foreach (['gross_cost', 'cost_items_text', 'tax_status', 'tax_rate'] as $costField) {
|
||||||
if (array_key_exists($costField, $fields)) {
|
if (array_key_exists($costField, $fields)) {
|
||||||
$simpleCostFields[$costField] = $fields[$costField];
|
$simpleCostFields[$costField] = $fields[$costField];
|
||||||
unset($fields[$costField]);
|
unset($fields[$costField]);
|
||||||
|
|||||||
Reference in new issue
Block a user