Alle Beispiele

Autokaufvertrag · Free-form-Flow mit Allgemeinen Bedingungen

Ein Autokaufvertrag im Flow-Modus. Der Browser paginiert den Fliesstext; ein CSS-Seitenumbruch startet die Allgemeinen Bedingungen auf Seite 2.

Flow Free-form /reports/contract_example/run
PDF

Was hier typisch ist

  • freeform() im Flow-Modus: keine festen Page-Blocks, nur Blade-Markup
  • Die Allgemeinen Bedingungen starten via break-before: page auf Seite 2
  • Lange Klauseln fliessen natürlich über Seitengrenzen
  • break-inside: avoid hält einzelne Klauseln zusammen
  • pdfFooter() ergänzt einen PDF-Footer mit pageNumber/totalPages
  • Derselbe Vertrag lässt sich als HTML-Vorschau und PDF ausgeben

Modul-Struktur

app/Reports/ContractExample/
├── Report.php              # freeform(), flow, browser pagination
├── Source.php              # one car purchase contract
└── views/
    ├── contract.blade.php  # page 1 + forced page break
    └── terms.blade.php     # general terms from page 2

Dateien

<?php

declare(strict_types=1);

namespace App\Reports\ContractExample;

use Guggach\Reports\Definition\PageSetup;
use Guggach\Reports\Definition\ReportBuilder;
use Guggach\Reports\Definition\ReportMode;
use Guggach\Reports\Report as BaseReport;
use Guggach\Reports\Sources\ReportSource;

/**
 * Free-form Flow demo: a car purchase contract with the general terms starting
 * on page 2 via a CSS page break. Unlike the invoice example this report does
 * not use fixed page blocks; Chromium paginates the prose.
 */
final class Report extends BaseReport
{
    public function key(): string
    {
        return 'contract_example';
    }

    public function name(): string
    {
        return 'Autokaufvertrag (Beispiel)';
    }

    public function layout(): string
    {
        return 'default';
    }

    public function source(): ReportSource
    {
        return new Source;
    }

    /**
     * The PDF footer template. Chromium/WeasyPrint replace the pageNumber and
     * totalPages spans; the HTML preview is unchanged.
     */
    public function pdfFooter(): ?string
    {
        return view('contract_example::pdf-footer', ['title' => $this->name()])->render();
    }

    public function define(ReportBuilder $r): void
    {
        $r->mode(ReportMode::Flow);
        $r->pageSetup(PageSetup::a4()->portrait()->marginsMm(24, 20, 24, 20));

        // One complete contract per record; the browser paginates the prose.
        $r->freeform(view: 'contract');
    }
}
<?php

declare(strict_types=1);

namespace App\Reports\ContractExample;

use Guggach\Reports\Sources\ReportSource;

/**
 * Demo car purchase contract with general terms. The terms are long enough to
 * show natural Flow pagination after the forced break onto page 2.
 */
final class Source extends ReportSource
{
    public function records(): iterable
    {
        return [[
            'contract_number' => 'KV-2026-0042',
            'contract_date' => '31.10.2026',
            'seller' => [
                'name' => 'Acme Garage AG',
                'street' => 'Beispielstrasse 1',
                'city' => '8000 Zürich',
                'commercial_register' => 'CHE-106.833.447 MWST',
            ],
            'buyer' => [
                'name' => 'Mara Beispiele',
                'street' => 'Seefeldstrasse 12',
                'city' => '8008 Zürich',
            ],
            'vehicle' => [
                'make' => 'Volvo',
                'model' => 'V60 Recharge T6',
                'year' => '2024',
                'vin' => 'YV1ZWK8V1P1234567',
                'mileage' => '18\'400 km',
                'colour' => 'Denim Blue',
                'plate' => 'ZH 123 456',
            ],
            'price' => 48900.00,
            'deposit' => 5000.00,
            'delivery' => '30.11.2026',
            'terms' => [
                [
                    'title' => '1. Kaufgegenstand',
                    'paragraphs' => [
                        'Die Verkäuferin verkauft dem Käufer das im Vertragskopf beschriebene Fahrzeug zu den dort genannten Bedingungen. Der Verkauf erfolgt unter Ausschluss der Weiterveräusserung von Fahrzeugdaten zu Werbezwecken.',
                        'Der Käufer bestätigt, das Fahrzeug vor Vertragsabschluss besichtigt und eine Probefahrt durchgeführt zu haben. Die Laufleistung entspricht dem bei der Übergabe abgelesenen Kilometerstand; Rundungsdifferenzen von bis zu 100 Kilometern sind zulässig.',
                    ],
                ],
                [
                    'title' => '2. Kaufpreis und Zahlung',
                    'paragraphs' => [
                        'Der Kaufpreis beträgt CHF 48\'900.00 und versteht sich inklusive der gesetzlichen Mehrwertsteuer. Eine Anzahlung von CHF 5\'000.00 ist bei Vertragsunterzeichnung fällig.',
                        'Der Restbetrag ist spätestens bei der Übergabe des Fahrzeugs ohne Abzug zu bezahlen. Zahlungen gelten erst mit Gutschrift auf dem Konto der Verkäuferin als geleistet. Bei Zahlungsverzug ist die Verkäuferin berechtigt, Verzugszinsen von 5 % pro Jahr geltend zu machen.',
                    ],
                ],
                [
                    'title' => '3. Übergabe und Nutzen',
                    'paragraphs' => [
                        'Die Übergabe erfolgt am 30.11.2026 am Geschäftssitz der Verkäuferin. Nutzen und Gefahr gehen mit der Übergabe auf den Käufer über. Der Käufer ist verpflichtet, das Fahrzeug innert 10 Tagen nach Übergabe auf seinen Namen umzumelden.',
                        'Die Verkäuferin übergibt dem Käufer bei der Übergabe sämtliche Fahrzeugdokumente, den Fahrzeugausweis, die Servicehistorie sowie zwei Fahrzeugschlüssel. Allfällige Leasing- oder Pfandrechte werden vor der Übergabe vollständig abgelöst.',
                    ],
                ],
                [
                    'title' => '4. Gewährleistung',
                    'paragraphs' => [
                        'Die Verkäuferin gewährleistet, dass das Fahrzeug zum Zeitpunkt der Übergabe frei von wesentlichen Mängeln ist und den vertraglich vereinbarten Eigenschaften entspricht. Die gesetzliche Gewährleistungsfrist beträgt zwei Jahre ab Übergabe.',
                        'Verschleissteile, Reifen, Bremsbeläge und Flüssigkeiten fallen nicht unter die Gewährleistung, soweit sie nicht bereits bei der Übergabe mangelhaft waren. Der Käufer hat Mängel unverzüglich, spätestens innert fünf Werktagen nach Entdeckung, schriftlich zu melden.',
                        'Die Verkäuferin ist berechtigt, Mängel nach ihrer Wahl durch Nachbesserung oder Ersatzlieferung zu beheben. Schlägt die Nachbesserung zweimal fehl, kann der Käufer eine angemessene Minderung des Kaufpreises verlangen.',
                    ],
                ],
                [
                    'title' => '5. Haftung',
                    'paragraphs' => [
                        'Die Haftung der Verkäuferin für leichte Fahrlässigkeit ist ausgeschlossen, soweit es sich nicht um die Verletzung von Leben, Körper oder Gesundheit oder um die Verletzung wesentlicher Vertragspflichten handelt. Die Haftung für mittelbare Schäden und entgangenen Gewinn ist ausgeschlossen.',
                        'Der Käufer haftet für Schäden, die durch unsachgemässe Nutzung des Fahrzeugs nach der Übergabe entstehen. Er stellt die Verkäuferin von Ansprüchen Dritter frei, die auf eine solche Nutzung zurückgehen.',
                    ],
                ],
                [
                    'title' => '6. Datenschutz',
                    'paragraphs' => [
                        'Die Verkäuferin bearbeitet die Personendaten des Käufers ausschliesslich zur Abwicklung des Kaufvertrags sowie zur Erfüllung gesetzlicher Pflichten. Eine Weitergabe an Dritte erfolgt nur, soweit dies für die Vertragsabwicklung oder aufgrund gesetzlicher Vorschriften erforderlich ist.',
                        'Der Käufer kann Auskunft über die zu seiner Person bearbeiteten Daten verlangen. Die Daten werden nach Ablauf der gesetzlichen Aufbewahrungsfristen gelöscht oder anonymisiert.',
                    ],
                ],
                [
                    'title' => '7. Gerichtsstand und anwendbares Recht',
                    'paragraphs' => [
                        'Auf diesen Vertrag findet ausschliesslich schweizerisches Recht Anwendung, unter Ausschluss des Übereinkommens der Vereinten Nationen über Verträge über den internationalen Warenkauf.',
                        'Ausschliesslicher Gerichtsstand für alle Streitigkeiten aus oder im Zusammenhang mit diesem Vertrag ist Zürich. Die Verkäuferin bleibt berechtigt, am Wohnsitz des Käufers zu klagen.',
                    ],
                ],
                [
                    'title' => '8. Versicherung und Zulassung',
                    'paragraphs' => [
                        'Der Käufer ist verpflichtet, das Fahrzeug ab dem Zeitpunkt der Übergabe ausreichend zu versichern. Der Nachweis einer Haftpflichtversicherung ist bei der Übergabe vorzulegen, sofern das Fahrzeug nicht bereits durch die Verkäuferin für den Käufer versichert wurde.',
                        'Die Verkäuferin unterstützt den Käufer bei der Umschreibung des Fahrzeugs, bleibt jedoch für die fristgerechte Anmeldung nicht verantwortlich. Allfällige Gebühren der Zulassungsstelle trägt der Käufer.',
                        'Bis zur vollständigen Bezahlung des Kaufpreises bleibt das Fahrzeug Eigentum der Verkäuferin. Der Käufer ist verpflichtet, das Fahrzeug in diesem Fall sorgfältig zu behandeln und die Verkäuferin über einen Wechsel des Standorts zu informieren.',
                    ],
                ],
                [
                    'title' => '9. Rücktritt und Nichterfüllung',
                    'paragraphs' => [
                        'Gerät der Käufer mit der Zahlung des Restbetrags mehr als 14 Tage in Verzug, kann die Verkäuferin nach schriftlicher Mahnung vom Vertrag zurücktreten. Bereits geleistete Zahlungen werden nach Abzug der entstandenen Kosten zurückerstattet.',
                        'Die Verkäuferin kann vom Vertrag zurücktreten, wenn das Fahrzeug vor der Übergabe durch einen nicht von ihr verschuldeten Umstand untergeht oder nicht mehr verfügbar ist. In diesem Fall werden bereits geleistete Zahlungen vollumfänglich zurückerstattet.',
                        'Weitergehende Ansprüche des Käufers, insbesondere auf Schadenersatz wegen Nichterfüllung, richten sich nach den gesetzlichen Bestimmungen und den Regelungen zur Haftung in diesem Vertrag.',
                    ],
                ],
                [
                    'title' => '10. Schlussbestimmungen',
                    'paragraphs' => [
                        'Änderungen und Ergänzungen dieses Vertrags bedürfen der Schriftform. Sollte eine Bestimmung dieses Vertrags unwirksam sein oder werden, bleibt die Wirksamkeit der übrigen Bestimmungen unberührt. An die Stelle der unwirksamen Bestimmung tritt die gesetzlich zulässige Regelung, die dem wirtschaftlichen Zweck am nächsten kommt.',
                        'Der Käufer bestätigt, den Vertrag gelesen und verstanden zu haben. Er erhält ein vollständig unterzeichnetes Exemplar dieses Vertrags. Die Allgemeinen Bedingungen sind integrierender Bestandteil des Vertrags.',
                        'Dieser Vertrag tritt mit der Unterzeichnung durch beide Parteien in Kraft. Mündliche Nebenabreden bestehen nicht.',
                    ],
                ],
            ],
        ]];
    }
}
<style>
    .contract {
        font-size: 10px;
        line-height: 1.55;
        color: #1f2937;
    }
    .contract-brand {
        display: flex;
        justify-content: space-between;
        align-items: flex-end;
        border-bottom: 3px solid #0f766e;
        padding-bottom: 4mm;
        margin-bottom: 8mm;
    }
    .contract-brand__name { font-size: 24px; font-weight: 800; color: #0f766e; letter-spacing: .02em; }
    .contract-brand__meta { text-align: right; font-size: 9px; line-height: 1.5; color: #475569; }

    .contract-title { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 7mm; }
    .contract-title h1 { margin: 0; font-size: 22px; line-height: 1.1; }
    .contract-title__meta { text-align: right; font-size: 9px; line-height: 1.5; color: #475569; }

    .contract-party-grid,
    .contract-vehicle-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 6mm 12mm;
    }
    .contract-party-grid { margin-bottom: 7mm; }
    .contract-party { border-top: 1px solid #cbd5e1; padding-top: 3mm; }
    .contract-label { margin-bottom: 1mm; font-size: 8px; text-transform: uppercase; letter-spacing: .08em; color: #64748b; }

    .contract-section-title {
        margin: 7mm 0 2mm;
        font-size: 11px;
        font-weight: 700;
        color: #0f172a;
        border-bottom: 1px solid #e2e8f0;
        padding-bottom: 1mm;
    }
    .contract-table { width: 100%; border-collapse: collapse; font-size: 9px; }
    .contract-table th,
    .contract-table td { padding: 2mm 0; border-bottom: 1px solid #e2e8f0; text-align: left; vertical-align: top; }
    .contract-table th { width: 38mm; color: #64748b; font-weight: 400; }
    .contract-price { font-size: 13px; font-weight: 700; }

    .contract-signatures { display: grid; grid-template-columns: 1fr 1fr; gap: 20mm; margin-top: 14mm; }
    .contract-signature { border-top: 1px solid #64748b; padding-top: 2mm; font-size: 8px; color: #64748b; }

    .contract-terms-head {
        display: flex;
        justify-content: space-between;
        align-items: flex-end;
        border-bottom: 2px solid #0f766e;
        padding-bottom: 3mm;
        margin-bottom: 7mm;
    }
    .contract-terms-head h2 { margin: 0; font-size: 18px; }
    .contract-terms-head__meta { text-align: right; font-size: 9px; color: #64748b; }
    .contract-clause { break-inside: avoid; page-break-inside: avoid; margin-bottom: 5mm; }
    .contract-clause h3 { margin: 0 0 1.5mm; font-size: 11px; }
    .contract-clause p { margin: 0 0 2mm; orphans: 3; widows: 3; }

    @media screen {
        /* Flow has one continuous sheet on screen; mark the forced print break. */
        .contract-page-break { border-top: 2px dashed #94a3b8; padding-top: 8mm; }
    }
</style>

<article class="contract">
    <header class="contract-brand">
        <div>
            <div class="contract-brand__name">Acme Garage AG</div>
            <div class="contract-brand__meta" style="text-align:left">Automobile · Service · Finanzierung</div>
        </div>
        <div class="contract-brand__meta">
            Beispielstrasse 1<br>
            8000 Zürich<br>
            garage@acme.example
        </div>
    </header>

    <div class="contract-title">
        <h1>Autokaufvertrag</h1>
        <div class="contract-title__meta">
            Vertrag Nr. {{ $ctx->contract_number }}<br>
            {{ $ctx->contract_date }}
        </div>
    </div>

    <div class="contract-party-grid">
        <div class="contract-party">
            <div class="contract-label">Verkäuferin</div>
            <strong>{{ $ctx->seller['name'] }}</strong><br>
            {{ $ctx->seller['street'] }}<br>
            {{ $ctx->seller['city'] }}<br>
            {{ $ctx->seller['commercial_register'] }}
        </div>
        <div class="contract-party">
            <div class="contract-label">Käufer</div>
            <strong>{{ $ctx->buyer['name'] }}</strong><br>
            {{ $ctx->buyer['street'] }}<br>
            {{ $ctx->buyer['city'] }}
        </div>
    </div>

    <h2 class="contract-section-title">1. Fahrzeug</h2>
    <table class="contract-table">
        <tr><th>Marke / Modell</th><td>{{ $ctx->vehicle['make'] }} {{ $ctx->vehicle['model'] }}</td></tr>
        <tr><th>Jahrgang</th><td>{{ $ctx->vehicle['year'] }}</td></tr>
        <tr><th>Fahrgestellnummer</th><td>{{ $ctx->vehicle['vin'] }}</td></tr>
        <tr><th>Kilometerstand</th><td>{{ $ctx->vehicle['mileage'] }}</td></tr>
        <tr><th>Farbe</th><td>{{ $ctx->vehicle['colour'] }}</td></tr>
        <tr><th>Kontrollschild</th><td>{{ $ctx->vehicle['plate'] }}</td></tr>
    </table>

    <h2 class="contract-section-title">2. Kaufpreis und Zahlung</h2>
    <table class="contract-table">
        <tr><th>Kaufpreis inkl. MWST</th><td class="contract-price">CHF {{ number_format($ctx->price, 2, '.', "'") }}</td></tr>
        <tr><th>Anzahlung bei Vertragsabschluss</th><td>CHF {{ number_format($ctx->deposit, 2, '.', "'") }}</td></tr>
        <tr><th>Restbetrag bei Übergabe</th><td>CHF {{ number_format($ctx->price - $ctx->deposit, 2, '.', "'") }}</td></tr>
        <tr><th>Übergabe</th><td>{{ $ctx->delivery }}</td></tr>
    </table>

    <h2 class="contract-section-title">3. Besondere Vereinbarungen</h2>
    <p>Das Fahrzeug wird im aktuellen Zustand verkauft. Die Verkäuferin bestätigt, dass keine offenen Leasing- oder Pfandrechte bestehen. Service und Hauptuntersuchung werden vor der Übergabe durchgeführt. Der Käufer ist mit der Übermittlung der Fahrzeugdaten an die zuständige Zulassungsstelle einverstanden.</p>

    <div class="contract-signatures">
        <div class="contract-signature">Ort, Datum / Verkäuferin</div>
        <div class="contract-signature">Ort, Datum / Käufer</div>
    </div>
</article>

<x-reports::page-break />

<section class="contract-page-break">
    <div class="contract-terms-head">
        <h2>Allgemeine Bedingungen</h2>
        <div class="contract-terms-head__meta">
            Autokaufvertrag Nr. {{ $ctx->contract_number }}<br>
            {{ $ctx->seller['name'] }} · {{ $ctx->buyer['name'] }}
        </div>
    </div>

    @include('contract_example::terms')
</section>
<div class="contract">
    @foreach ($ctx->terms as $clause)
        <section class="contract-clause">
            <h3>{{ $clause['title'] }}</h3>
            @foreach ($clause['paragraphs'] as $paragraph)
                <p>{{ $paragraph }}</p>
            @endforeach
        </section>
    @endforeach

    <p style="margin-top:8mm;font-size:8px;color:#64748b">
        Diese Allgemeinen Bedingungen sind Bestandteil des Autokaufvertrags Nr. {{ $ctx->contract_number }}.
        Es gilt das am Vertragsort vereinbarte Recht.
    </p>
</div>
<div style="width:100%; box-sizing:border-box; padding:0 20mm; font-family:sans-serif; font-size:8px; color:#64748b; display:flex; justify-content:space-between; align-items:center;">
    <span>{{ $title }} · Acme Garage AG</span>
    <span>Seite <span class="pageNumber"></span> / <span class="totalPages"></span></span>
</div>