Teilnahmerechnungen erstellen
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Admin\Controllers;
|
||||
|
||||
use App\Models\DocumentAsset;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class DocumentAssetDeleteController extends CommonController
|
||||
{
|
||||
public function __invoke(string $name): JsonResponse
|
||||
{
|
||||
$asset = DocumentAsset::where('name', $name)->first();
|
||||
|
||||
// Durchweg 200 mit Status im Body -- wie die übrigen Admin-Endpunkte, damit der Grund im Frontend
|
||||
// ankommt (der Ajax-Helfer verwirft den Body bei Fehler-Statuscodes).
|
||||
if ($asset === null) {
|
||||
return response()->json(['status' => 'error', 'message' => 'Das Bild existiert nicht.']);
|
||||
}
|
||||
|
||||
// Ein noch referenziertes Bild zu löschen würde stillschweigend eine Lücke in jede künftige
|
||||
// Rechnung reißen -- der Platzhalter löst dann zu einem Leerstring auf.
|
||||
if ($this->isReferenced($asset->name)) {
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => sprintf('Das Bild wird noch als {asset:%s} in der Vorlage verwendet.', $asset->name),
|
||||
]);
|
||||
}
|
||||
|
||||
$asset->delete();
|
||||
|
||||
return response()->json(['status' => 'success', 'message' => 'Das Bild wurde gelöscht.']);
|
||||
}
|
||||
|
||||
private function isReferenced(string $name): bool
|
||||
{
|
||||
return DocumentTemplate::query()
|
||||
->where('content', 'like', '%{asset:' . $name . '}%')
|
||||
->exists();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Admin\Controllers;
|
||||
|
||||
use App\Domains\Admin\Actions\UpdateDocumentAsset\UpdateDocumentAssetAction;
|
||||
use App\Domains\Admin\Actions\UpdateDocumentAsset\UpdateDocumentAssetRequest;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DocumentAssetUpdateController extends CommonController
|
||||
{
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
$action = new UpdateDocumentAssetAction(new UpdateDocumentAssetRequest(
|
||||
name: (string) $request->input('name'),
|
||||
label: $request->input('label'),
|
||||
file: $request->file('file'),
|
||||
));
|
||||
|
||||
$response = $action->execute();
|
||||
|
||||
return response()->json([
|
||||
'status' => $response->success ? 'success' : 'error',
|
||||
'message' => $response->message,
|
||||
'token' => $response->asset !== null ? '{asset:' . $response->asset->name . '}' : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Admin\Controllers;
|
||||
|
||||
use App\Domains\ParticipantInvoice\ParticipantInvoiceTokens;
|
||||
use App\Models\DocumentAsset;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class DocumentTemplatesGetController extends CommonController
|
||||
{
|
||||
/** Blöcke, die Layout-HTML bzw. CSS enthalten und deshalb im Quelltext-Editor gepflegt werden. */
|
||||
private const array SOURCE_BLOCKS = [
|
||||
DocumentTemplate::BLOCK_LAYOUT,
|
||||
DocumentTemplate::BLOCK_STYLE,
|
||||
];
|
||||
|
||||
private const array BLOCK_LABELS = [
|
||||
DocumentTemplate::BLOCK_LAYOUT => 'Seitengerüst',
|
||||
DocumentTemplate::BLOCK_STYLE => 'Gestaltung (CSS)',
|
||||
'header_sender_return' => 'Rücksendezeile',
|
||||
'header_recipient' => 'Empfängeranschrift',
|
||||
'emblem' => 'Emblem',
|
||||
'logo' => 'Logo',
|
||||
'sender_data' => 'Absenderangaben',
|
||||
'subject' => 'Betreff und Referenzdaten',
|
||||
DocumentTemplate::BLOCK_BODY => 'Rechnungsinhalt',
|
||||
'footer' => 'Grußformel und Fußnote',
|
||||
];
|
||||
|
||||
public function __invoke(): JsonResponse
|
||||
{
|
||||
$blocks = DocumentTemplate::forType(DocumentTemplate::TYPE_PARTICIPANT_INVOICE)
|
||||
->values()
|
||||
->map(fn(DocumentTemplate $block): array => [
|
||||
'block' => $block->block,
|
||||
'label' => self::BLOCK_LABELS[$block->block] ?? $block->block,
|
||||
'content' => (string) $block->content,
|
||||
'editable' => $block->editable,
|
||||
'source' => in_array($block->block, self::SOURCE_BLOCKS, true),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'blocks' => $blocks,
|
||||
'assets' => DocumentAsset::orderBy('name')->get()->map(fn(DocumentAsset $asset): array => [
|
||||
'name' => $asset->name,
|
||||
'label' => $asset->label,
|
||||
'mime' => $asset->mime,
|
||||
'token' => '{asset:' . $asset->name . '}',
|
||||
'preview' => $asset->toDataUri(),
|
||||
]),
|
||||
'tokenGroups' => ParticipantInvoiceTokens::groups(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Admin\Controllers;
|
||||
|
||||
use App\Providers\InertiaProvider;
|
||||
use App\Scopes\CommonController;
|
||||
use Inertia\Response;
|
||||
|
||||
class DocumentTemplatesPageController extends CommonController
|
||||
{
|
||||
public function __invoke(): Response
|
||||
{
|
||||
return new InertiaProvider('Admin/DocumentTemplates', [])->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Admin\Controllers;
|
||||
|
||||
use App\Domains\ParticipantInvoice\ParticipantInvoiceTokens;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Providers\DocumentTemplateRenderProvider;
|
||||
use App\Providers\PdfGenerateAndDownloadProvider;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
/**
|
||||
* Rendert die Vorlage mit Beispieldaten, ohne sie zu speichern -- damit niemand blind HTML editiert.
|
||||
*/
|
||||
class DocumentTemplatesPreviewController extends CommonController
|
||||
{
|
||||
public function __invoke(Request $request): Response
|
||||
{
|
||||
$html = new DocumentTemplateRenderProvider(
|
||||
DocumentTemplate::TYPE_PARTICIPANT_INVOICE,
|
||||
(array) $request->input('blocks', []),
|
||||
)->render(ParticipantInvoiceTokens::sample());
|
||||
|
||||
return response(PdfGenerateAndDownloadProvider::fromHtml($html, 'portrait'), 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => 'inline; filename="vorschau.pdf"',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Admin\Controllers;
|
||||
|
||||
use App\Domains\Admin\Actions\UpdateDocumentTemplate\UpdateDocumentTemplateAction;
|
||||
use App\Domains\Admin\Actions\UpdateDocumentTemplate\UpdateDocumentTemplateRequest;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DocumentTemplatesUpdateController extends CommonController
|
||||
{
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
$action = new UpdateDocumentTemplateAction(new UpdateDocumentTemplateRequest(
|
||||
documentType: DocumentTemplate::TYPE_PARTICIPANT_INVOICE,
|
||||
blocks: (array) $request->input('blocks', []),
|
||||
));
|
||||
|
||||
$response = $action->execute();
|
||||
|
||||
return response()->json([
|
||||
'status' => $response->success ? 'success' : 'error',
|
||||
'message' => $response->message,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,13 @@ class ManagedTenantContactGetController extends CommonController
|
||||
return response()->json([
|
||||
'email' => $tenant->email,
|
||||
'email_finance' => $tenant->email_finance,
|
||||
'invoice_sender_name' => $tenant->invoice_sender_name,
|
||||
// Als Platzhalter im Formular: so heisst der Absender, solange nichts eingetragen ist.
|
||||
'name' => $tenant->name,
|
||||
'phone' => $tenant->phone,
|
||||
'address_1' => $tenant->address_1,
|
||||
'address_2' => $tenant->address_2,
|
||||
'address_3' => $tenant->address_3,
|
||||
'postcode' => $tenant->postcode,
|
||||
'city' => $tenant->city,
|
||||
'saveEndpoint' => '/api/v1/admin/tenants/' . $slug . '/contact',
|
||||
|
||||
@@ -20,6 +20,11 @@ class ManagedTenantContactUpdateController extends CommonController
|
||||
emailFinance: $request->input('email_finance'),
|
||||
postcode: $request->input('postcode'),
|
||||
city: $request->input('city'),
|
||||
invoiceSenderName: $request->input('invoice_sender_name'),
|
||||
address1: $request->input('address_1'),
|
||||
address2: $request->input('address_2'),
|
||||
address3: $request->input('address_3'),
|
||||
phone: $request->input('phone'),
|
||||
));
|
||||
|
||||
$response = $action->execute();
|
||||
|
||||
@@ -20,6 +20,11 @@ class ManagedTenantTaxGetController extends CommonController
|
||||
'tax_exemption_reason' => $tenant->tax_exemption_reason,
|
||||
'tax_exemption_note' => $tenant->tax_exemption_note,
|
||||
'vat_pricing_mode' => $tenant->vat_pricing_mode,
|
||||
'tax_number' => $tenant->tax_number,
|
||||
'vat_id' => $tenant->vat_id,
|
||||
'invoice_prefix' => $tenant->invoice_prefix,
|
||||
// In der Mandanten-Verwaltung ist der Nummernkreis änderbar.
|
||||
'can_edit_invoice_prefix' => true,
|
||||
'exemption_reasons' => TaxExemptionReason::options(),
|
||||
'pricing_modes' => VatPricingMode::options(),
|
||||
'saveEndpoint' => '/api/v1/admin/tenants/' . $slug . '/tax',
|
||||
|
||||
@@ -23,6 +23,9 @@ class ManagedTenantTaxUpdateController extends CommonController
|
||||
exemptionReason: TaxExemptionReason::where('slug', $request->input('tax_exemption_reason'))->first(),
|
||||
exemptionNote: $request->input('tax_exemption_note'),
|
||||
vatPricingMode: VatPricingMode::tryFrom((string) $request->input('vat_pricing_mode', 'inclusive')) ?? VatPricingMode::Inclusive,
|
||||
taxNumber: $request->input('tax_number'),
|
||||
vatId: $request->input('vat_id'),
|
||||
invoicePrefix: $request->input('invoice_prefix'),
|
||||
));
|
||||
|
||||
$response = $action->execute();
|
||||
|
||||
@@ -13,6 +13,13 @@ class TenantContactGetController extends CommonController
|
||||
return response()->json([
|
||||
'email' => $this->tenant->email,
|
||||
'email_finance' => $this->tenant->email_finance,
|
||||
'invoice_sender_name' => $this->tenant->invoice_sender_name,
|
||||
// Als Platzhalter im Formular: so heisst der Absender, solange nichts eingetragen ist.
|
||||
'name' => $this->tenant->name,
|
||||
'phone' => $this->tenant->phone,
|
||||
'address_1' => $this->tenant->address_1,
|
||||
'address_2' => $this->tenant->address_2,
|
||||
'address_3' => $this->tenant->address_3,
|
||||
'postcode' => $this->tenant->postcode,
|
||||
'city' => $this->tenant->city,
|
||||
'saveEndpoint' => '/api/v1/admin/tenant/contact',
|
||||
|
||||
@@ -18,6 +18,11 @@ class TenantContactUpdateController extends CommonController
|
||||
emailFinance: $request->input('email_finance'),
|
||||
postcode: $request->input('postcode'),
|
||||
city: $request->input('city'),
|
||||
invoiceSenderName: $request->input('invoice_sender_name'),
|
||||
address1: $request->input('address_1'),
|
||||
address2: $request->input('address_2'),
|
||||
address3: $request->input('address_3'),
|
||||
phone: $request->input('phone'),
|
||||
));
|
||||
|
||||
$response = $action->execute();
|
||||
|
||||
@@ -18,6 +18,11 @@ class TenantTaxGetController extends CommonController
|
||||
'tax_exemption_reason' => $this->tenant->tax_exemption_reason,
|
||||
'tax_exemption_note' => $this->tenant->tax_exemption_note,
|
||||
'vat_pricing_mode' => $this->tenant->vat_pricing_mode,
|
||||
'tax_number' => $this->tenant->tax_number,
|
||||
'vat_id' => $this->tenant->vat_id,
|
||||
'invoice_prefix' => $this->tenant->invoice_prefix,
|
||||
// Im Self-Service nicht änderbar: das Präfix bestimmt den Nummernkreis.
|
||||
'can_edit_invoice_prefix' => false,
|
||||
'exemption_reasons' => TaxExemptionReason::options(),
|
||||
'pricing_modes' => VatPricingMode::options(),
|
||||
'saveEndpoint' => '/api/v1/admin/tenant/tax',
|
||||
|
||||
@@ -21,6 +21,10 @@ class TenantTaxUpdateController extends CommonController
|
||||
exemptionReason: TaxExemptionReason::where('slug', $request->input('tax_exemption_reason'))->first(),
|
||||
exemptionNote: $request->input('tax_exemption_note'),
|
||||
vatPricingMode: VatPricingMode::tryFrom((string) $request->input('vat_pricing_mode', 'inclusive')) ?? VatPricingMode::Inclusive,
|
||||
taxNumber: $request->input('tax_number'),
|
||||
vatId: $request->input('vat_id'),
|
||||
// invoice_prefix wird hier bewusst nicht durchgereicht -- der Nummernkreis ist nur in der
|
||||
// Mandanten-Verwaltung änderbar.
|
||||
));
|
||||
|
||||
$response = $action->execute();
|
||||
|
||||
Reference in New Issue
Block a user