105 lines
3.3 KiB
PHP
105 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Domains\Admin\Actions\UpdateTenantTax;
|
|
|
|
use App\Enumerations\VatPricingMode;
|
|
use App\Models\Tenant;
|
|
use App\Support\Text;
|
|
|
|
class UpdateTenantTaxAction
|
|
{
|
|
public function __construct(private UpdateTenantTaxRequest $request)
|
|
{
|
|
}
|
|
|
|
public function execute(): UpdateTenantTaxResponse
|
|
{
|
|
$response = new UpdateTenantTaxResponse();
|
|
|
|
// Präfixe sind großgeschrieben; null heißt "nicht mitgeschickt" und damit "unverändert".
|
|
$prefix = Text::nullIfBlank(strtoupper((string) $this->request->invoicePrefix));
|
|
|
|
if ($prefix !== null && $this->prefixTakenByAnotherTenant($prefix)) {
|
|
$response->message = sprintf('Das Rechnungs-Präfix "%s" wird bereits von einem anderen Mandanten genutzt.', $prefix);
|
|
|
|
return $response;
|
|
}
|
|
|
|
if ($this->request->taxLiable) {
|
|
$this->request->tenant->update($this->withInvoiceDetails([
|
|
'tax_liable' => true,
|
|
'vat_rate' => $this->clampVatRate($this->request->vatRate),
|
|
'vat_pricing_mode' => $this->request->vatPricingMode->value,
|
|
'tax_exemption_reason' => null,
|
|
'tax_exemption_note' => null,
|
|
], $prefix));
|
|
|
|
$response->success = true;
|
|
$response->message = 'Steuerinformationen wurden gespeichert.';
|
|
|
|
return $response;
|
|
}
|
|
|
|
$reason = $this->request->exemptionReason;
|
|
|
|
if ($reason === null) {
|
|
$response->message = 'Bitte einen gültigen Befreiungsgrund auswählen.';
|
|
|
|
return $response;
|
|
}
|
|
|
|
$note = trim((string)$this->request->exemptionNote);
|
|
|
|
if ($reason->requires_note && $note === '') {
|
|
$response->message = 'Bitte einen Text für den Befreiungsgrund angeben.';
|
|
|
|
return $response;
|
|
}
|
|
|
|
$this->request->tenant->update($this->withInvoiceDetails([
|
|
'tax_liable' => false,
|
|
'vat_rate' => 0,
|
|
'vat_pricing_mode' => VatPricingMode::Inclusive->value,
|
|
'tax_exemption_reason' => $reason->slug,
|
|
'tax_exemption_note' => $reason->requires_note ? $note : null,
|
|
], $prefix));
|
|
|
|
$response->success = true;
|
|
$response->message = 'Steuerinformationen wurden gespeichert.';
|
|
|
|
return $response;
|
|
}
|
|
|
|
private function clampVatRate(int $vatRate): int
|
|
{
|
|
return max(0, min(100, $vatRate));
|
|
}
|
|
|
|
/**
|
|
* Ergänzt die Rechnungsstellerangaben. Sie gelten unabhängig davon, ob Steuerpflicht besteht -- eine
|
|
* Steuernummer gehört auch auf eine steuerfreie Rechnung.
|
|
*
|
|
* @param array<string, mixed> $attributes
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function withInvoiceDetails(array $attributes, ?string $prefix): array
|
|
{
|
|
$attributes['tax_number'] = Text::nullIfBlank($this->request->taxNumber);
|
|
$attributes['vat_id'] = Text::nullIfBlank($this->request->vatId);
|
|
|
|
// Nicht mitgeschickt heißt "unverändert", nicht "leeren".
|
|
if ($prefix !== null) {
|
|
$attributes['invoice_prefix'] = $prefix;
|
|
}
|
|
|
|
return $attributes;
|
|
}
|
|
|
|
private function prefixTakenByAnotherTenant(string $prefix): bool
|
|
{
|
|
return Tenant::where('invoice_prefix', $prefix)
|
|
->where('id', '!=', $this->request->tenant->id)
|
|
->exists();
|
|
}
|
|
}
|