Teilnahmerechnungen erstellen
This commit is contained in:
1 parent
a61344395a
commit
9c4c28e566
79 files changed
+4303
-75
No files matched your search
@@ -1,20 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Setzt den Standard-Befreiungsgrund neuer Tenants auf Jugendhilfe (§ 4 Nr. 25 Buchst. a). Der Wert
|
||||
* existiert in tax_exemption_reasons, der FK bleibt gültig. Bestehende Zeilen bleiben unverändert.
|
||||
*
|
||||
* Über `change()` statt rohem `ALTER TABLE ... SET DEFAULT`, weil sqlite das nicht kennt und die
|
||||
* Testsuite auf sqlite läuft.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
DB::statement("ALTER TABLE tenants ALTER COLUMN tax_exemption_reason SET DEFAULT 'ustg_4_25a'");
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->string('tax_exemption_reason')->nullable()->default('ustg_4_25a')->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::statement('ALTER TABLE tenants ALTER COLUMN tax_exemption_reason DROP DEFAULT');
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->string('tax_exemption_reason')->nullable()->default(null)->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Ergänzt die für eine Rechnung nach § 14 Abs. 4 UStG fehlenden Angaben des Rechnungsstellers
|
||||
* (vollständige Anschrift, Steuernummer bzw. USt-IdNr.) sowie das Kürzel für den Nummernkreis.
|
||||
*
|
||||
* Die Adressfelder heißen wie die des Teilnehmers (`event_participants.address_1/2`), damit
|
||||
* Absender- und Empfängerblock der Rechnungsvorlage gleich aufgebaut sind.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->string('address_1')->nullable()->after('name');
|
||||
$table->string('address_2')->nullable()->after('address_1');
|
||||
$table->string('address_3')->nullable()->after('address_2');
|
||||
$table->string('phone')->nullable()->after('email_finance');
|
||||
$table->string('tax_number')->nullable()->after('vat_pricing_mode');
|
||||
$table->string('vat_id')->nullable()->after('tax_number');
|
||||
$table->string('invoice_prefix')->nullable()->after('vat_id');
|
||||
});
|
||||
|
||||
// Bestands-Tenants bekommen den großgeschriebenen Slug als Default-Präfix (wm -> WM).
|
||||
foreach (DB::table('tenants')->select('id', 'slug')->get() as $tenant) {
|
||||
DB::table('tenants')
|
||||
->where('id', $tenant->id)
|
||||
->update(['invoice_prefix' => strtoupper($tenant->slug)]);
|
||||
}
|
||||
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->unique('invoice_prefix');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropUnique(['invoice_prefix']);
|
||||
$table->dropColumn([
|
||||
'address_1',
|
||||
'address_2',
|
||||
'address_3',
|
||||
'phone',
|
||||
'tax_number',
|
||||
'vat_id',
|
||||
'invoice_prefix',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Friert bei Event-Anlage den Rechnungssteller und den Event-Teil der Rechnungsnummer ein -- analog zur
|
||||
* bereits bestehenden USt-Grundlage (`2026_08_06_160010_add_tax_snapshot_to_events`).
|
||||
*
|
||||
* ACHTUNG: Das hier erzeugte Format ist überholt -- `2026_09_02_140030_compact_invoice_key_format`
|
||||
* entfernt die Trenner zwischen Jahr, Monat und Veranstaltungsnummer (`WM-V-20260701`). Diese
|
||||
* Migration bleibt unverändert, weil sie den damaligen Stand abbildet.
|
||||
*
|
||||
* `invoice_key` hat die Form `WM-V-2026-07-01` (Tenant-Präfix, Dokumentart, Jahr, Monat, laufende Nummer
|
||||
* der Veranstaltung dieses Tenants im Monat). Er muss eingefroren werden, weil Tenant-Präfix und
|
||||
* `start_date` später änderbar sind -- eine bereits herausgegebene Rechnung würde sonst zu einer anderen
|
||||
* Nummer gehören.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->string('invoice_key')->nullable()->unique();
|
||||
|
||||
$table->string('invoice_sender_name')->nullable();
|
||||
$table->string('invoice_sender_address_1')->nullable();
|
||||
$table->string('invoice_sender_address_2')->nullable();
|
||||
$table->string('invoice_sender_address_3')->nullable();
|
||||
$table->string('invoice_sender_postcode')->nullable();
|
||||
$table->string('invoice_sender_city')->nullable();
|
||||
$table->string('invoice_sender_email')->nullable();
|
||||
$table->string('invoice_sender_phone')->nullable();
|
||||
$table->string('invoice_sender_tax_number')->nullable();
|
||||
$table->string('invoice_sender_vat_id')->nullable();
|
||||
});
|
||||
|
||||
$this->backfill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bestandsevents nachträglich bestücken: Absenderdaten aus dem heutigen Tenant, `invoice_key` je
|
||||
* Tenant und Monat nach `start_date`, dann `id` durchnummeriert.
|
||||
*/
|
||||
private function backfill(): void
|
||||
{
|
||||
$tenants = DB::table('tenants')->get()->keyBy('slug');
|
||||
$counters = [];
|
||||
|
||||
$events = DB::table('events')
|
||||
->select('id', 'tenant', 'start_date')
|
||||
->orderBy('start_date')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
foreach ($events as $event) {
|
||||
$tenant = $tenants->get($event->tenant);
|
||||
if ($tenant === null || $event->start_date === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$month = date('Y-m', strtotime($event->start_date));
|
||||
$bucket = $event->tenant . '|' . $month;
|
||||
$counters[$bucket] = ($counters[$bucket] ?? 0) + 1;
|
||||
|
||||
DB::table('events')->where('id', $event->id)->update([
|
||||
// $month ist bereits "2026-07" -> ergibt "WM-V-2026-07-01"
|
||||
'invoice_key' => sprintf(
|
||||
'%s-V-%s-%s',
|
||||
$tenant->invoice_prefix,
|
||||
$month,
|
||||
str_pad((string) $counters[$bucket], 2, '0', STR_PAD_LEFT)
|
||||
),
|
||||
'invoice_sender_name' => $tenant->name,
|
||||
'invoice_sender_address_1' => $tenant->address_1,
|
||||
'invoice_sender_address_2' => $tenant->address_2,
|
||||
'invoice_sender_address_3' => $tenant->address_3,
|
||||
'invoice_sender_postcode' => $tenant->postcode,
|
||||
'invoice_sender_city' => $tenant->city,
|
||||
'invoice_sender_email' => $tenant->email,
|
||||
'invoice_sender_phone' => $tenant->phone,
|
||||
'invoice_sender_tax_number' => $tenant->tax_number,
|
||||
'invoice_sender_vat_id' => $tenant->vat_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->dropUnique(['invoice_key']);
|
||||
$table->dropColumn([
|
||||
'invoice_key',
|
||||
'invoice_sender_name',
|
||||
'invoice_sender_address_1',
|
||||
'invoice_sender_address_2',
|
||||
'invoice_sender_address_3',
|
||||
'invoice_sender_postcode',
|
||||
'invoice_sender_city',
|
||||
'invoice_sender_email',
|
||||
'invoice_sender_phone',
|
||||
'invoice_sender_tax_number',
|
||||
'invoice_sender_vat_id',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Drei Angaben, die für die Anmelde-Rechnung gebraucht werden:
|
||||
*
|
||||
* - `invoice_sequence` -- die Position des Teilis in der Veranstaltung, bildet den letzten Block der
|
||||
* Rechnungsnummer. Wird persistiert und nicht zur Laufzeit gezählt, damit die Nummer stabil bleibt,
|
||||
* wenn sich jemand abmeldet.
|
||||
* - `fee_type` / `sibling_reduction` -- flossen bisher in den Preis ein, ohne gespeichert zu werden.
|
||||
* Ohne sie ließe sich der ausgewiesene Tagessatz nicht korrekt darstellen (siehe
|
||||
* CreateParticipantInvoiceCommand).
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('event_participants', function (Blueprint $table) {
|
||||
$table->unsignedInteger('invoice_sequence')->nullable()->after('identifier');
|
||||
$table->string('fee_type')->nullable()->after('participation_type');
|
||||
$table->boolean('sibling_reduction')->default(false)->after('fee_type');
|
||||
});
|
||||
|
||||
$this->backfillSequences();
|
||||
|
||||
Schema::table('event_participants', function (Blueprint $table) {
|
||||
$table->unique(['event_id', 'invoice_sequence']);
|
||||
});
|
||||
}
|
||||
|
||||
/** Bestandsanmeldungen je Event nach `id` durchnummerieren. */
|
||||
private function backfillSequences(): void
|
||||
{
|
||||
$counters = [];
|
||||
|
||||
$participants = DB::table('event_participants')
|
||||
->select('id', 'event_id')
|
||||
->orderBy('event_id')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
foreach ($participants as $participant) {
|
||||
$counters[$participant->event_id] = ($counters[$participant->event_id] ?? 0) + 1;
|
||||
|
||||
DB::table('event_participants')
|
||||
->where('id', $participant->id)
|
||||
->update(['invoice_sequence' => $counters[$participant->event_id]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('event_participants', function (Blueprint $table) {
|
||||
$table->dropUnique(['event_id', 'invoice_sequence']);
|
||||
$table->dropColumn(['invoice_sequence', 'fee_type', 'sibling_reduction']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Vorlage für generierte Dokumente (aktuell: Anmelde-Rechnung), zerlegt in einzeln pflegbare Blöcke.
|
||||
*
|
||||
* Bewusst app-weit und ohne Tenant-Spalte (Model erbt `CommonModel`, also kein `SiteScope`) -- es gibt
|
||||
* eine Vorlage für alle Tenants, tenant-spezifisch sind nur die eingesetzten Werte. Vorbild ist
|
||||
* `page_texts`.
|
||||
*
|
||||
* Der Inhalt liegt in der Datenbank statt im Blade, damit ein Release ihn nicht überschreibt.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('document_templates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('document_type');
|
||||
$table->string('block');
|
||||
$table->longText('content')->nullable();
|
||||
$table->integer('sort_order')->default(1);
|
||||
$table->boolean('editable')->default(true);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['document_type', 'block']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('document_templates');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Bilder für die Dokumentvorlagen (Logo, Emblem, ...), referenziert als `{asset:name}`.
|
||||
*
|
||||
* Die Bilder liegen in der Datenbank und nicht im Dateisystem: ein Release ist ein `git checkout`,
|
||||
* alles unter `public/` und `resources/` wird dabei überschrieben. Die Datenbank fasst ein Release
|
||||
* nicht an, und die Bilder wandern automatisch mit jedem Dump mit. Für das PDF werden sie ohnehin als
|
||||
* Data-URI eingebettet, `data` wird also direkt so verwendet, wie es gespeichert ist.
|
||||
*
|
||||
* Die Namen vergibt die verwaltende Person selbst -- es gibt keine fachlich vorbelegten Slots.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('document_assets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name')->unique();
|
||||
$table->string('label')->nullable();
|
||||
$table->string('mime');
|
||||
$table->longText('data');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('document_assets');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Eigener Absendername für Rechnungen.
|
||||
*
|
||||
* `tenants.name` ist ein internes Kürzel ("Wilde Möhre", "Landesunmittelbare Mitglieder"). Auf einer
|
||||
* Rechnung muss dagegen die vollständige Bezeichnung des Rechnungsstellers stehen, üblicherweise
|
||||
* inklusive Rechtsform. Bleibt das Feld leer, wird weiterhin `name` verwendet.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->string('invoice_sender_name')->nullable()->after('name');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn('invoice_sender_name');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Nimmt den Absender-Snapshot vom Event zurück.
|
||||
*
|
||||
* Der Absender einer Rechnung ist der Mandant, nicht die Veranstaltung. Eingefroren gehörten diese
|
||||
* Angaben nie: eine Korrektur am Absendernamen oder an der Anschrift hätte sonst auf keiner
|
||||
* bestehenden Veranstaltung gewirkt -- und damit auf keiner Rechnung, die zu ihr erzeugt wird.
|
||||
*
|
||||
* Eingefroren bleibt, was tatsächlich historisch ist: `events.invoice_key` (der Nummernkreis) und
|
||||
* die Steuergrundlage (`tax_liable`, `vat_rate`, `vat_pricing_mode`, `tax_exemption_*`) -- sie
|
||||
* beschreibt, wie der Preis zustande kam, und darf sich rückwirkend nicht ändern.
|
||||
*
|
||||
* Angelegt wurden die Spalten in `2026_08_27_140020_add_invoice_snapshot_to_events`; die bleibt
|
||||
* unangetastet, weil sie zusätzlich `invoice_key` anlegt.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
/** @var array<int, string> */
|
||||
private const array COLUMNS = [
|
||||
'invoice_sender_name',
|
||||
'invoice_sender_address_1',
|
||||
'invoice_sender_address_2',
|
||||
'invoice_sender_address_3',
|
||||
'invoice_sender_postcode',
|
||||
'invoice_sender_city',
|
||||
'invoice_sender_email',
|
||||
'invoice_sender_phone',
|
||||
'invoice_sender_tax_number',
|
||||
'invoice_sender_vat_id',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->dropColumn(self::COLUMNS);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
foreach (self::COLUMNS as $column) {
|
||||
$table->string($column)->nullable();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Entfernt die Trenner zwischen Jahr, Monat und Veranstaltungsnummer im Rechnungsschlüssel.
|
||||
*
|
||||
* vorher WM-V-2026-07-01 -> Rechnungsnummer WM-V-2026-07-01-0005
|
||||
* nachher WM-V-20260701 -> Rechnungsnummer WM-V-20260701-0005
|
||||
*
|
||||
* Die Rechnungsnummer selbst wird nirgends gespeichert, sondern bei jedem Abruf aus `invoice_key`
|
||||
* und `event_participants.invoice_sequence` zusammengesetzt. Die Umstellung hier wirkt daher
|
||||
* unmittelbar auf alle Rechnungen; alte und neue Veranstaltungen bleiben im selben Format.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
$this->rewrite('/^(.*-V-)(\d{4})-(\d{2})-(\d{2})$/', '$1$2$3$4');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->rewrite('/^(.*-V-)(\d{4})(\d{2})(\d{2})$/', '$1$2-$3-$4');
|
||||
}
|
||||
|
||||
private function rewrite(string $pattern, string $replacement): void
|
||||
{
|
||||
$events = DB::table('events')
|
||||
->select('id', 'invoice_key')
|
||||
->whereNotNull('invoice_key')
|
||||
->get();
|
||||
|
||||
foreach ($events as $event) {
|
||||
$rewritten = preg_replace($pattern, $replacement, (string) $event->invoice_key);
|
||||
|
||||
if ($rewritten !== null && $rewritten !== $event->invoice_key) {
|
||||
DB::table('events')->where('id', $event->id)->update(['invoice_key' => $rewritten]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
-- Standard-Vorlage für die Teilnehmer-Rechnung.
|
||||
--
|
||||
-- Bewusst ein manuelles Skript und keine Migration: der Vorlageninhalt wird über die Admin-Oberfläche
|
||||
-- gepflegt und soll von einem Release nicht überschrieben werden. Einspielen also nur bei der
|
||||
-- Erstinstallation oder wenn die Vorlage bewusst zurückgesetzt werden soll.
|
||||
--
|
||||
-- docker exec -i mareike-mareike-db mysql -u<user> -p<pass> <db> < database/seed-scripts/participant-invoice-template.sql
|
||||
--
|
||||
-- Die Bilder liegen als base64 in der Datenbank, damit ein Release sie nicht überschreibt und sie mit
|
||||
-- jedem Dump mitwandern. Referenziert werden sie in der Vorlage als {asset:name}.
|
||||
--
|
||||
-- Zum Asset "edge": der gelbe Randstreifen mit Knick aus dem BdP-Erscheinungsbild. Mit GD gezeichnet
|
||||
-- (16 mm breit, volle Seitenhöhe, Innenkante von 10 mm oben auf 3 mm bei 198 mm, dann auf 16 mm
|
||||
-- auslaufend). Als PNG und nicht als SVG, weil ohne svg-lib von dompdf kommentarlos ignoriert.
|
||||
|
||||
DELETE FROM document_templates WHERE document_type = 'participant_invoice';
|
||||
|
||||
INSERT INTO document_templates (document_type, block, content, sort_order, editable, created_at, updated_at) VALUES
|
||||
('participant_invoice', 'layout', '<img class="edge" src="{asset:edge}" alt="" />
|
||||
|
||||
<div class="page">
|
||||
|
||||
<table class="header-table">
|
||||
<tr>
|
||||
<td style="width: 45%; padding-top: 4mm;">
|
||||
{block:header_sender_return}
|
||||
{block:header_recipient}
|
||||
</td>
|
||||
<td style="width: 9%; vertical-align: middle; padding-top: 4mm; padding-right: 6mm;">
|
||||
{block:emblem}
|
||||
</td>
|
||||
<td style="width: 46%; vertical-align: top; padding-top: 2mm;">
|
||||
{block:logo}
|
||||
{block:sender_data}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{block:subject}
|
||||
{block:body}
|
||||
{block:footer}
|
||||
|
||||
</div>', 10, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'style', '@page { size: A4 portrait; margin: 0; }
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: \'DejaVu Sans\', sans-serif; font-size: 9.5pt; color: #1a1a1a; background: white; }
|
||||
|
||||
.page { padding: 10mm 18mm 20mm 22mm; }
|
||||
|
||||
/* Kopfbereich */
|
||||
.header-table { width: 100%; border-collapse: collapse; margin-bottom: 6mm; }
|
||||
.header-table td { vertical-align: top; padding: 0; }
|
||||
.absender-rueck { font-size: 6pt; color: #555; border-bottom: 0.3pt solid #888; padding-bottom: 1.5mm; margin-bottom: 3.5mm; }
|
||||
.empfaenger { font-size: 10pt; line-height: 1.65; }
|
||||
.empfaenger-bold { font-weight: bold; }
|
||||
.logo-img { width: 36mm; display: block; margin-bottom: 4mm; }
|
||||
.emblem-img { width: 22mm; display: block; margin: 0 auto; }
|
||||
.absender-block { font-size: 7.5pt; color: #1a4799; line-height: 1.7; }
|
||||
.absender-name { font-weight: bold; font-size: 8pt; }
|
||||
|
||||
/* Betreff und Referenzdaten */
|
||||
.betreff { font-size: 14pt; color: #1a4799; margin-bottom: 5mm; }
|
||||
.ref-table { border-collapse: collapse; font-size: 8.5pt; margin-bottom: 7mm; }
|
||||
.ref-table td { padding: 0.9mm 7mm 0.9mm 0; vertical-align: top; }
|
||||
.ref-key { color: #666; white-space: nowrap; }
|
||||
|
||||
/* Anrede und Einleitung */
|
||||
.salutation { font-size: 9.5pt; margin-bottom: 3mm; }
|
||||
.intro-text { font-size: 9pt; line-height: 1.6; margin-bottom: 7mm; color: #333; }
|
||||
|
||||
/* Positionstabelle */
|
||||
.pos-table { width: 100%; border-collapse: collapse; font-size: 8.5pt; }
|
||||
.pos-table th { background-color: #1a4799; color: white; padding: 2.5mm 3mm; text-align: left; font-size: 7.5pt; letter-spacing: 0.03em; }
|
||||
.pos-table th.r, .pos-table td.r { text-align: right; }
|
||||
.pos-table td { padding: 2mm 3mm; border-bottom: 0.3pt solid #d8dde6; vertical-align: top; }
|
||||
.pos-table tr:nth-child(even) td { background-color: #f7f8fb; }
|
||||
.pos-table tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* Summen */
|
||||
.sum-outer { width: 100%; border-collapse: collapse; margin-top: 1mm; margin-bottom: 5mm; }
|
||||
.sum-outer td { padding: 0; }
|
||||
.sum-spacer { width: 55%; }
|
||||
.sum-inner { width: 100%; border-collapse: collapse; font-size: 8.5pt; }
|
||||
.sum-inner td { padding: 1.2mm 0; }
|
||||
.sum-key { color: #555; padding-right: 6mm; white-space: nowrap; }
|
||||
.sum-val { text-align: right; white-space: nowrap; }
|
||||
.sum-line td { border-top: 0.4pt solid #bbb; padding-top: 2mm; }
|
||||
.sum-total td { font-weight: bold; font-size: 11pt; color: #1a4799; border-top: 1.5pt solid #1a4799; padding-top: 2mm; }
|
||||
|
||||
/* Pflichthinweis bei Steuerbefreiung */
|
||||
.tax-note { font-size: 8pt; color: #555; line-height: 1.5; margin-bottom: 5mm; }
|
||||
|
||||
/* Zahlungshinweis -- der gelbe Streifen */
|
||||
.payment-box { border-left: 3pt solid #f5c400; padding: 3mm 5mm; background-color: #fffef5; font-size: 8.5pt; line-height: 1.6; margin-bottom: 6mm; }
|
||||
.payment-head { font-size: 7pt; font-weight: bold; color: #888; text-transform: uppercase; letter-spacing: 0.07em; margin-bottom: 2mm; }
|
||||
|
||||
/* Grußformel und Fußnote */
|
||||
.closing { font-size: 9.5pt; line-height: 1.5; }
|
||||
.gut-pfad { font-size: 13pt; color: #1a4799; margin-top: 1mm; margin-bottom: 1mm; }
|
||||
.footer-note { margin-top: 4mm; font-size: 7.5pt; color: #888; }
|
||||
|
||||
/* Gelber Randstreifen mit Knick -- position:fixed, damit er auf jeder Seite steht. */
|
||||
.edge { position: fixed; top: 0; left: 0; width: 16mm; height: 297mm; }', 20, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'header_sender_return', '<div class="absender-rueck">{sender_name}{if:sender_address_1} · {sender_address_1}{/if:sender_address_1} · {sender_postcode} {sender_city}</div>', 30, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'header_recipient', '<div class="empfaenger">
|
||||
<div class="empfaenger-bold">{recipient_name}</div>
|
||||
<div>{recipient_address_1}</div>
|
||||
{if:recipient_address_2}<div>{recipient_address_2}</div>{/if:recipient_address_2}
|
||||
<div>{recipient_postcode} {recipient_city}</div>
|
||||
</div>', 40, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'emblem', '<img src="{asset:emblem}" class="emblem-img" alt="" />', 50, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'logo', '<img src="{asset:logo}" class="logo-img" alt="" />', 60, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'sender_data', '<div class="absender-block">
|
||||
<div class="absender-name">{sender_name}</div>
|
||||
{if:sender_address_2}<div>{sender_address_2}</div>{/if:sender_address_2}
|
||||
{if:sender_address_3}<div>{sender_address_3}</div>{/if:sender_address_3}
|
||||
{if:sender_address_1}<div style="margin-top:2.5mm;">{sender_address_1}</div>{/if:sender_address_1}
|
||||
<div>{sender_postcode} {sender_city}</div>
|
||||
{if:sender_email}<div style="margin-top:2.5mm;">{sender_email}</div>{/if:sender_email}
|
||||
{if:sender_phone}<div>{sender_phone}</div>{/if:sender_phone}
|
||||
{if:sender_tax_number}<div style="margin-top:2.5mm;">Steuernummer: {sender_tax_number}</div>{/if:sender_tax_number}
|
||||
{if:sender_vat_id}<div>USt-IdNr.: {sender_vat_id}</div>{/if:sender_vat_id}
|
||||
</div>', 70, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'subject', '<div class="betreff">Rechnung Nr. {invoice_number}</div>
|
||||
|
||||
<table class="ref-table">
|
||||
<tr>
|
||||
<td class="ref-key">Rechnungsdatum:</td>
|
||||
<td>{invoice_date}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ref-key">Leistungszeitraum:</td>
|
||||
<td>{service_period}</td>
|
||||
</tr>
|
||||
</table>', 80, 1, NOW(), NOW()),
|
||||
('participant_invoice', 'body', '<div class="salutation">Hallo {recipient_name},</div>
|
||||
<div class="intro-text">anbei erhältst du die Rechnung über deinen Teilnahmebeitrag.</div>
|
||||
|
||||
{positions_table}
|
||||
{summary_table}
|
||||
|
||||
<div class="payment-box">
|
||||
<div class="payment-head">Zahlung</div>
|
||||
{closing_statement}
|
||||
</div>', 90, 0, NOW(), NOW()),
|
||||
('participant_invoice', 'footer', '<div class="closing">
|
||||
<div class="gut-pfad">Herzlichst Gut Pfad,</div>
|
||||
<div>{sender_name}</div>
|
||||
<div class="footer-note">Diese Rechnung wurde maschinell erstellt und ist auch ohne Unterschrift gültig.</div>
|
||||
</div>', 100, 1, NOW(), NOW());
|
||||
|
||||
DELETE FROM document_assets WHERE name = 'edge';
|
||||
INSERT INTO document_assets (name, label, mime, data, created_at, updated_at) VALUES ('edge', 'Gelber Randstreifen mit Knick (BdP-Anschnitt)', 'image/png', 'iVBORw0KGgoAAAANSUhEUgAAAMAAAA3sCAYAAABDZciKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAElEQVR42u3dS2okW5ZAUa/qGgjXBIRrAsLVN4Rr5HJE9OVoAjI0gSgCXruqlZAkrzLfJz7S2WvNII7F5ppdN9n9r9++7P53x2SPy7o7G8Pv+28jQAAgAIb6HyMQQNay7i6mIAAQAAgABAACAAEMZwtUAGm2QAUAAgABgABAACCAAtugAkh7MQIBgABAACAAEAAIAAQw27MRCAAEAAIAAYAAQAAggMGcCyAAEAAIAAQAAgABgABmOxuBAEAAIAAQAAgABAACmO3JCAQAAgABgABAACAAEMBsr0YggDIH5AkABAACAAGAAEAABRcjEEDWstoGFQAIAAQAAgABgADGswUqgDRboAIAAYAAQAAgABBAwWYEAih7MwIBgABAACAAEAAIIODdCARQthmBAEAAIAAQAAgABBCwGYEAspZVAAIAAYAAQAAgABDAeJsRCEAACAAEAAIAAYAAQACzOR1GAGkvRiAAEAAIAAQAAgABBHwzAgGUXYxAACAAEAAIAAQAAgjwNqgAupbVNqgAQAAgABAACAAEAAKY7GwEAgABgABAACAAEAAIYLYnIxAACAAEAAIAAYAAQACzPRuBAEAAIAAQAAgABAACGGxZ/VG8AEAAIAAQAAgABAACmMzRSAJIczieAEAAIAAQAAgABFBgG1QAaV+NQAAgABAACAAEAAIIeDUCAZR5G1QAIAAQAAgABAACKNiMQABZyyoAAYAAQAAgABAACGC8zQgEIAAEAAIAAYAAQAAggNk2IxBA2ZsRCAAEAAIAAYAAQAAB70YggLLNCAQAAgABgABAACCAAKfDCKBrWXcXUxAACAAEAAIAAYAAhrMFKoA0W6ACAAGAAEAAIAAQQIFtUAGkvRiBAEAAIAAQAAgABAACmO3ZCAQAAgABgABAACAAEMBgy7o7m4IAQAAgABAACAAEAAKY62wEAgABgABAACAAEAAIYLYnIxAACAAEAAIAAYAAQACzvRqBAMockCcAEAAIAAQAAgABFFyMQABZy2obVAAgABAACAAEAAIYzxaoANJsgQoABAACAAGAAEAABZsRCKDszQgEAAIAAYAAQAAggIB3IxBA2WYEAgABgABAACAAEEDAZgQCyFpWAQgABAACAAGAAEAA421GIAABIAAQAAgABAACAAHM5nQYAaS9GIEAQAAgABAACAAEEPDNCARQdjECAYAAQAAgABAACCDA26AC6FpW26ACAAGAAEAAIAAQAAhgsrMRCAAEAAIAAYAAQAAggNmejEAAIAAQAAgABAACAAHM9mwEAgABgABAACAAEAAIYLBl9UfxAgABgABAACAAEAAIYDJHIwkgzeF4AgABgABAACAAEECBbVABpH01AgGAAEAAIAAQAAgg4NUIBFDmbVABgABAACAAEAAIoGAzAgFkLasABAACAAGAAEAAIIDxNiMQgAAQAAgABAACAAGAAGbbjEAAZW9GIAAQAAgABAACAAEEvBuBAMo2IxAACAAEAAIAAYAAApwOI4CuZd1dTEEAIAAQAAgABAACGM4WqADSbIEKAAQAAgABgABAAAW2QQWQ9mIEAgABgABAACAAEAAIYLZnIxAACAAEAAIAAYAAQACDLevubAoCAAGAAEAAIAAQAAhgrrMRCAAEAAIAAYAAQAAggNmejEAAIAAQAAgABAACAAHM9moEAihzQJ4AQAAgABAACAAEUHAxAgFkLattUAGAAEAAIAAQAAhgPFugAkizBSoAEAAIAAQAAgABFGxGIICyNyMQAAgABAACAAGAAALejUAAZZsRCAAEAAIAAYAAQAABmxEIIGtZBSAAEAAIAAQAAgABjLcZgQAEgABAACAAEAAIAAQwm9NhBJD2YgQCAAGAAEAAIAAQQMA3IxBA2cUIBAACAAGAAEAAIIAAb4MKoGtZbYMKAAQAAgABgABAACCAyc5GIAAQAAgABAACAAGAAGZ7MgIBgABAACAAEAAIAAQw27MRCAAEAAIAAYAAQAAggMGW1R/FCwAEAAIAAYAAQAAggMkcjSSANIfjCQAEAAIAAYAAQAAFtkEFkPbVCAQAAgABgABAACCAgFcjEECZt0EFAAIAAYAAQAAggILNCASQtawCEAAIAAQAAgABgADG24xAAAJAACAAEAAIAAQAAphtMwIBlL0ZgQBAACAAEAAIAAQQ8G4EAijbjEAAIAAQAAgABAACCHA6jAC6lnV3MQUBgABAACAAEAAIYDhboAJIswUqABAACAAEAAIAARTYBhVA2osRCAAEAAIAAYAAQAAggNmejUAAIAAQAAgABAACAAEMtqy7sykIAAQAAgABgABAACCAuc5GIAAQAAgABAACAAGAAGZ7MgIBgABAACAAEAAIAAQw26sRCKDMAXkCAAGAAEAAIAAQQMHFCASQtay2QQUAAgABgABAACCA8WyBCiDNFqgAQAAgABAACAAEULAZgQDK3oxAACAAEAAIAAQAAgh4NwIBlG1GIAAQAAgABAACAAEEbEYggKxlFYAAQAAgABAACAAEMN5mBAIQAAIAAYAAQAAgABDAbE6HEUDaixEIAAQAAgABgABAAAHfjEAAZRcjEAAIAAQAAgABgAACvA0qgK5ltQ0qABAACAAEAAIAAYAAJjsbgQBAACAAEAAIAAQAApjtyQgEAAIAAYAAQAAgABDAbM9GIAAQAAgABAACAAGAAAZbVn8ULwAQAAgABAACAAGAACZzNJIA0hyOJwAQAAgABAACAAEU2AYVQNpXIxAACAAEAAIAAYAAAl6NQABl3gYVAAgABAACAAGAAAo2IxBA1rIKQAAgABAACAAEAAIYbzMCAQgAAYAAQAAgABAACGC2zQgEUPZmBAIAAYAAQAAgABBAwLsRCKBsMwIBgABAACAAEAAIIMDpMALoWtbdxRQEAAIAAYAAQAAggOFsgQogzRaoAEAAIAAQAAgABFBgG1QAaS9GIAAQAAgABAACAAGAAGZ7NgIBgABAACAAEAAIAAQw2LLuzqYgABAACAAEAAIAAYAA5jobgQBAACAAEAAIAAQAApjtyQgEAAIAAYAAQAAgABDAbK9GIIAyB+QJAAQAAgABgABAAAUXIxBA1rLaBhUACAAEAAIAAYAAxrMFKoA0W6ACAAGAAEAAIAAQQMFmBAIoezMCAYAAQAAgABAACCDg3QgEULYZgQBAACAAEAAIAAQQsBmBALKWVQACAAGAAEAAIAAQwHibEQhAAAgABAACAAGAAEAAszkdRgBpL0YgABAACAAEAAIAAQR8MwIBlF2MQAAgABAACAAEAAII8DaoALqW1TaoAEAAIAAQAAgABAACmOxsBAIAAYAAQAAgABAACGC2JyMQAAgABAACAAGAAEAAsz0bgQBAACAAEAAIAAQAAhhsWf1RvABAACAAEAAIAAQAApjM0UgCSHM4ngBAACAAEAAIAARQYBtUAGlfjUAAIAAQAAgABAACCHg1AgGUeRtUACAAEAAIAAQAAijYjEAAWcsqAAGAAEAAIAAQAAhgvM0IBCAABAACAAGAAEAAIIDZNiMQQNmbEQgABAACAAGAAEAAAe9GIICyzQgEAAIAAYAAQAAggACnwwiga1l3F1MQAAgABAACAAGAAIazBSqANFugAgABgABAACAAEECBbVABpL0YgQBAACAAEAAIAAQAApjt2QgEAAIAAYAAQAAgABDAYMu6O5uCAEAAIAAQAAgABAACmOtsBAIAAYAAQAAgABAACGC2JyMQAAgABAACAAGAAEAAs70agQDKHJAnABAACAAEAAIAARRcjEAAWctqG1QAIAAQAAgABAACGM8WqADSbIEKAAQAAgABgABAAAWbEQig7M0IBAACAAGAAEAAIICAdyMQQNlmBAIAAYAAQAAgABBAwGYEAshaVgEIAAQAAgABgABAAONtRiAAASAAEAAIAAQAAgABzOZ0GAGkvRiBAEAAIAAQAAgABBDwzQgEUHYxAgGAAEAAIAAQAAggwNugAuhaVtugAgABgABAACAAEAAIYLKzEQgABAACAAGAAEAAIIDZnoxAACAAEAAIAAQAAgABzPZsBAIAAYAAQAAgABAACGCwZfVH8QIAAYAAQAAgABAACGAyRyMJIM3heAIAAYAAQAAgABBAgW1QAaR9NQIBgABAACAAEAAIIODVCARQ5m1QAYAAQAAgABAACKBgMwIBZC2rAAQAAgABgABAACCA8TYjEIAAEAAIAAQAAgABgABm24xAAGVvRiAAEAAIAAQAAgABBLwbgQDKNiMQAAgABAACAAGAAAKcDiOArmXdXUxBACAAEAAIAAQAAhjOFqgA0myBCgAEAAIAAYAAQAAFtkEFkPZiBAIAAYAAQAAgABAACGC2ZyMQAAgABAACAAGAAEAAgy3r7mwKAgABgABAACAAEAAIYK6zEQgABAACAAGAAEAAIIDZnoxAACAAEAAIAAQAAgABzPZqBAIoc0CeAEAAIAAQAAgABFBwMQIBZC2rbVABgABAACAAEAAIYDxboAJIswUqABAACAAEAAIAARRsRiCAsjcjEAAIAAQAAgABgAAC3o1AAGWbEQgABAACAAGAAEAAAZsRCCBrWQUgABAACAAEAAIAAYy3GYEABIAAQAAgABAACAAEMJvTYQSQ9mIEAgABgABAACAAEEDANyMQQNnFCAQAAgABgABAACCAAG+DCqBrWW2DCgAEAAIAAYAAQAAggMnORiAAEAAIAAQAAgABgABmezICAYAAQAAgABAACAAEMNuzEQgABAACAAGAAEAAIIDBltLine truncated
|
||||
|
||||
DELETE FROM document_assets WHERE name = 'emblem';
|
||||
INSERT INTO document_assets (name, label, mime, data, created_at, updated_at) VALUES ('emblem', 'Emblem zwischen Empfänger und Absender', 'image/png', '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 truncated
|
||||
|
||||
DELETE FROM document_assets WHERE name = 'logo';
|
||||
INSERT INTO document_assets (name, label, mime, data, created_at, updated_at) VALUES ('logo', 'Logo im Briefkopf', 'image/png', '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 truncated
|
||||
|
||||
Reference in new issue
Block a user