Export | Rechnung

Export um eine einfache Rechnung anhand der Daten eines bestätigten Angebots zu erstellen.

Vorschau

Preprozessor

return {
    ...ctx,
    events: ctx.events.map(e => {

        // nur das 1. bestätigte Angebot
        const confirmedOffer = e?.offersOnEvent?.find(o => o.offerStatus === "CONFIRMED")
        let netTotalByVat
        if(confirmedOffer){
            netTotalByVat = Object.entries(confirmedOffer?.netTotalByVat).map(([vat,_netTotal]) => {
                const netTotal = confirmedOffer.discount ? _netTotal - (_netTotal * (confirmedOffer.discount/100)) : _netTotal
                const vatTotal = Math.floor(netTotal * (0 + vat / 100))
                return {
                    netTotal,
                    vatTotal,
                    vat
                }
            })
        }
        
        return {
            ...e,
            confirmedOffer: {
                ...confirmedOffer,
                netTotalByVat
            }
        }
    })
}

Template

<style>
    @page {
        size: A4;
        margin: 1cm 2cm 0.5cm;
    }

    .logo {
        width: auto;
        height: 4cm;
    }

    .page-container-table {
        width: 100%;
    }

    .page-footer {
        position: fixed;
        bottom: 1cm;
        width: 17cm;

    }

    .page-footer table {
        width: 100%;
        font-size: 0.7em;
    }

    .page-header {
        position: fixed;
        top: 1cm;
        right: 1cm;
    }

    .page-header,
    .page-header-space {
        height: 3cm;
    }

    .page-footer,
    .page-footer-space {
        height: 2cm;
        display: flex;
        align-content: end;
    }

    @media print {
        .page-header {
            top: 0 !important;
            right: 0 !important;
        }

        .page-footer {
            bottom: 0 !important;
        }
    }

    .alert {
        background-color: yellow;
        font-size: 1.5em;
    }

    h1 {
        font-family: Ubuntu;
        text-decoration: none;
    }

    body {
        position: relative;
        margin: 0;
        padding: 0;
    }

    body,
    h2,
    h3,
    h4,
    p,
    th,
    td {
        font-family: Ubuntu;
    }

    .page {
        margin-top: 2cm;
        padding-bottom: 2cm;
        page-break-after: auto;
    }

    .page table {
        width: 100%;
        border-spacing: 0px;
        border-collapse: separate;
    }

    .page td,
    .page th {
        text-align: left;
        border-bottom: 1px solid black;
        padding: 5px 10px;
        vertical-align: top;
        page-break-inside: avoid;
    }

    .smallText {
        font-size: 0.7rem;
    }

    .numeric {
        text-align: right;
        white-space: nowrap;
    }

    .noWrap {
        text-align: right;
        white-space: nowrap;
    }
</style>

<div class="page-header">
    {{#if baseData.images.[0].sizes}}
    <img class="logo" src="{{lookup baseData.images.[0].sizes '640'}}" />
    {{else}}
    <div class="alert">
        Kein Logo in Stammdaten hochgeladen
    </div>
    {{/if}}
</div>

<div class="page-footer">
    <table>
        <tbody>
            <tr>
                <td class="smallText">
                    {{baseData.name}}<br />
                    {{ baseData.web }}
                </td>
                <td class="smallText">
                    {{baseData.addresses.[0].address.street}}<br />
                    {{baseData.addresses.[0].address.zip}} {{baseData.addresses.[0].address.city}}
                </td>
                <td class="smallText">
                    Tel: {{ baseData.phone }} <br />
                    E-Mail: {{ baseData.email }} <br />
                </td>
            </tr>
        </tbody>
    </table>
</div>

<table class="page-container-table">
    <thead>
        <tr>
            <td>
                <!--place holder for the fixed-position header-->
                <div class="page-header-space"></div>
            </td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>

                {{#each events}}

                <div class="page">

                    {{ assign 'ansprechpartner' (contactByRole this.contacts "Ansprechpartner:in") }}
                    {{ assign 'mieter' (contactByRole this.contacts "Mieter:in") }}
                    {{ assign 'rechnungsnr' (eventInformationByName this.eventInformations "RE-Nr.") }}
                    {{ assign 'zahlungsziel' (eventInformationByName this.eventInformations "RE-Zahlungsziel") }}

                    {{#unless rechnungsnr}}
                    <div class="alert">
                        Keine Rechnungs-Nr. (Benutzerfeld: RE:Nr.) angegeben
                    </div>
                    {{/unless}}

                    {{#unless zahlungsziel}}
                    <div class="alert">
                        Kein Zahlungsziel (Benutzerfeld: RE:Zahlungsziel) angegeben
                    </div>
                    {{/unless}}

                    {{#unless mieter}}
                    <div class="alert">
                        Kontakt mit Rolle "Mieter:in" nicht angegeben
                    </div>
                    {{/unless}}

                    {{#unless ansprechpartner}}
                    <div class="alert">
                        Kontakt mit Rolle "Ansprechpartner:in" nicht angegeben
                    </div>
                    {{/unless}}

                    {{#unless this.confirmedOffer}}
                    <div class="alert">
                        Kein bestätigtes Angebot hinterlegt
                    </div>
                    {{/unless}}

                    <div>

                        <div class="smallText">
                            {{baseData.name}} &middot;
                            {{baseData.addresses.[0].address.street}} &middot;
                            {{baseData.addresses.[0].address.zip}} {{baseData.addresses.[0].address.city}}
                        </div>

                        {{#if mieter }}
                        {{ mieter.displayName }}<br />
                        {{ansprechpartner.firstName}} {{ansprechpartner.lastName}}<br />
                        {{ mieter.address.street }}<br />
                        {{ mieter.address.zip }} {{ mieter.address.city }}
                        {{/if}}
                    </div>


                    <div style="margin-top: 1cm; text-align: right;">Datum: {{ currentDate "P" }}</div>

                    <div>

                        <h2>Rechnung {{rechnungsnr}} </h2>

                        <p>Für Ihre Veranstaltung <b>{{this.displayNames.eventTitleWithArtists}}</b> stellen wir
                            folgende Kosten in Rechnung:</p>
                    </div>

                    {{assign 'anyLineItemHasDiscount' (add (sumBy this.roomsOnOffer 'discount') (sumBy
                    this.resourcesOnOffer 'discount'))}}

                    <table>
                        <thead>
                            <tr>
                                <th>Anz.</th>
                                <th>Einheit</th>
                                <th>Posten</th>
                                <th class="numeric">Einzelpreis</th>{{!-- Notiz: Hier keinen Umbruch einfügen --}}{{#if
                                anyLineItemHasDiscount}}<th class="numeric">Rabatt</th>{{/if}}
                                <th class="noWrap">Ust. %</th>
                                <th class="numeric">Gesamt</th>
                            </tr>
                        </thead>
                        <tbody>
                            {{#each this.confirmedOffer.roomsOnOffer}}
                            <tr>
                                <td class="numeric">-</td>
                                <td>Pauschal</td>
                                <td>{{this.room}}{{#if this.description}}<br /><em>{{this.description}}</em>{{/if}}</td>
                                <td class="numeric">{{formatEuro this.price}}</td>{{!-- Notiz: Hier keinen Umbruch
                                einfügen --}}{{#if anyLineItemHasDiscount}}<td class="numeric">{{#if
                                    this.discount}}{{this.discount}} %{{else}}-{{/if}}</td>{{/if}}
                                <td class="numeric">{{ this.vat }}</td>
                                <td class="numeric">{{formatEuro this.netTotal}}</td>
                            </tr>
                            {{/each}}
                            {{#each this.confirmedOffer.resourcesOnOffer}}
                            <tr>
                                <td class="numeric">{{this.amount}}</td>
                                <td>{{#if (isEqual this.unit 'PIECE')}}Stück{{/if}}{{#if (isEqual this.unit
                                    'DAY')}}Tag{{/if}}{{#if (isEqual this.unit 'HOUR')}}Stunde{{/if}}</td>
                                <td>{{this.resource}}{{#if this.description}}<br />{{this.description}}{{/if}}</td>
                                <td class="numeric">{{formatEuro this.price}}</td>{{!-- Notiz: Hier keinen Umbruch
                                einfügen --}}{{#if anyLineItemHasDiscount}}<td class="numeric">{{#if
                                    this.discount}}{{this.discount}} %{{else}}-{{/if}}</td>{{/if}}
                                <td class="numeric">{{ this.vat }}</td>
                                <td class="numeric">{{formatEuro this.netTotal}}</td>
                            </tr>
                            {{/each}}
                            {{#if this.confirmedOffer.discount}}
                            <tr>
                                <td colspan="{{#if anyLineItemHasDiscount}}6{{else}}5{{/if}}">abzgl.
                                    {{this.confirmedOffer.discount}}% Rabatt</td>
                                <td class="numeric">-{{formatEuro (multiply this.confirmedOffer.netTotal (divide
                                    this.confirmedOffer.discount 100))}}</td>
                            </tr>
                            {{/if}}
                            <tr>
                                <th colspan="{{#if anyLineItemHasDiscount}}6{{else}}5{{/if}}">Gesamt netto</th>
                                <th class="numeric">{{formatEuro this.confirmedOffer.netTotal}}</th>
                            </tr>
                            {{#each this.confirmedOffer.netTotalByVat}}
                            <tr>
                                <td colspan="{{#if anyLineItemHasDiscount}}6{{else}}5{{/if}}">zzgl. {{this.vat}}% MWSt.
                                    von {{ formatEuro this.netTotal}}</td>
                                <td class="numeric">{{formatEuro this.vatTotal}}</td>
                            </tr>
                            {{/each}}
                            <tr>
                                <th colspan="{{#if anyLineItemHasDiscount}}6{{else}}5{{/if}}">Gesamt brutto</th>
                                <td class="numeric"><strong>{{formatEuro this.confirmedOffer.grossTotal}}<strong></td>
                            </tr>
                            </tfoot>
                    </table>

                    Wir bitten Sie den Rechnungsbetrag von {{formatEuro confirmedOffer.grossTotal}} bis zum
                    {{this.zahlungsziel}}
                    auf das u.a. Konto, mit dem Verwendungszweck "{{this.rechnungsnr}}", zu überweisen.<br /><br />
                    Wir danken für das entgegengebrachte Vertrauen und begrüßen Sie gerne wieder bei uns.

                    <h3>Bankverbindung</h3>
                    IBAN: DE12 7016 9356 0000 1234 12<br />
                    BIC: GENODEV1EDR

                </div>

                {{/each}}
            </td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td>
                <!--place holder for the fixed-position footer-->
                <div class="page-footer-space"></div>
            </td>
        </tr>
    </tfoot>
</table>