Druckformate nach DIN 5008

Hallo allerseits!

Wir haben heute unsere ERPNext-Druckformate nach DIN 5008 veröffentlicht. Diese findet ihr hier:

Ihr könnt unsere Vorlage gerne nach Belieben anpassen und kostenlos verwenden. Pull Requests mit Verbesserungsvorschlägen sind natürlich immer willkommen.

Viele Grüße
Raffael

8 Likes

@rmeyer Wir sind gerade dabei ERPNext bei uns einzuführen und sind mega glücklich, dass es auch für das Thema Dokumente so super Vorlagen gibt. Wir haben aber aktuell 3 Themen:

  1. Leider bekomme ich es nicht hin, dass der Footer mit den hier verlinkten Druckformaten vollständig angezeigt wird. Da meine Programmierkenntnisse sehr begrenzt sind, habe ich auch schon ChatGPT zu Rate gezogen, aber der Footer bewegt sich nicht. Es bleiben nur die oberen zwei Zeilen sichtbar. Nur die Seitenzahlen lassen sich verschieben.
  2. Die Seitenzahlen: Die werden bei uns nicht angezeigt.
  3. Beim Drucken habe ich immer eine weitere leere Seite?!

Wir sind bereits auf Version 15. Ich habe die Daten manuell in neu erstellte Vorlagen kopiert.

In den Druckformaten (.jinja-Datei) ist oben ein kleiner CSS-Schnipsel, der den Platz an den Rändern definiert. Damit sollte es möglich sein, mehr Platz zu schaffen.

Vermutlich sind da noch irgendwo unsichtbare Seiten- oder Zeilenumbrüche bzw. leere HTML-Element im Dokument. Das kann bei Jinja-Templates schnell passieren.

Wenn du die Vorlagen nicht im Original verwendest, ist es schwierig zu erraten, wo das Problem liegen könnte. Poste am besten immer auch deinen Code :wink:

Also ich habe es mir nochmal angeschaut und ein bisschen probiert. Ich bekomme es nicht :pensive:

Das einzige was sich bewegt sind die Seitenzahlen.

Hier der Code aus dem Druckformat:

<style>
    .print-format {
        margin-left: 0mm;
        margin-right: 0mm;
        margin-top: 10mm;
        margin-bottom: 0mm;
        font-size: 10pt;
    }
</style>

{% set company = frappe.get_doc("Company", doc.company) %}
{% set cmp_addr = frappe.get_doc("Address", doc.billing_address) if doc.billing_address else None %}
{% set pay_addr = frappe.get_doc("Address", doc.supplier_address) if doc.supplier_address else None %}

<!-- HEAD -->
<div id="header">
    <div class="letter-head">
        {{ letter_head }}
    </div>
</div>

<div class="contact-row">
    <div id="address">
        {% if cmp_addr %}
        <div id="sender">
            <p><u>{{ cmp_addr.address_title }} &#183; {{ cmp_addr.address_line1 }} &#183;
            {% if cmp_addr.address_line2 %}{{ cmp_addr.address_line2 }}<br>{% endif %}
            {{ cmp_addr.pincode }} {{ cmp_addr.city }}
            {% if pay_addr and (cmp_addr.country != pay_addr.country) -%}
                    &#183; {{ cmp_addr.country | upper }}
            {%- endif %}
            </u></p>
        </div>
        {% endif %}
        {{ doc.supplier }}<br />
        {{ doc.address_display or "" }}
    </div>

    <div id="contact">
        <table class="w-100 text-small">
            {% if company.phone_no %}
            <tr>
                <td class="text-right">{{ _("Phone") }}:</td>
                <td class="text-right">{{ company.phone_no }}</td>
            </tr>
            {% endif %}

            {% if company.email %}
            <tr>
                <td class="text-right">{{ _("Email") }}:</td>
                <td class="text-right">{{ company.email }}</td>
            </tr>
            {% endif %}
            <tr>
                <td class="text-right">{{ _("Date") }}:</td>
                <td class="text-right">{{ frappe.utils.formatdate(doc.transaction_date, "long") }}</td>
            </tr>
        </table>
    </div>
</div>

<div id="faltmarke-1" class="din-mark"></div>
<div id="lochmarke" class="din-mark"></div>
<div id="faltmarke-2" class="din-mark"></div>

<!-- CONTENT -->
<div id="text">
    <div id="subject">
        <strong>{{ _("Purchase Order") }} {{ doc.name }}</strong>
    </div>

    <table class="w-100 text-small">
        <thead class="black-border">
            <tr>
                <th style="width: 10%">{{ _("Sr") }}</th>
                <th style="width: 30%">{{ _("Description") }}</th>
                <th style="width: 10%">{{ _("Unit") if not print_settings.print_uom_after_quantity else '&nbsp;'}}</th>
                <th style="width: 10%">{{ _("Qty") }}</th>
                <th style="width: 12%">{{ _("Price") }}</th>
                <!-- <th style="width: 15%">{{ _("Discount") }}</th> -->
                <th style="width: 18%" class="text-right">{{ _("Amount") }}</th>
            </tr>
        </thead>

        <tbody>
            {% for n in doc.items %}
                <tr>
                    <td>{{ loop.index }}</td>
                    <td><b>{{ _(n.item_name) }}</b></td>
                    <td>{{ _(n.uom) if not print_settings.print_uom_after_quantity else '&nbsp;'}}</td>
                    <td>
                        {{ n.get_formatted("qty") }}
                        {% if print_settings.print_uom_after_quantity %}
                            {{ _(n.uom) }}
                        {% endif %}
                    </td>
                    <td>{{ n.get_formatted("rate") }}</td>
                    <!-- <td>{{ n.get_formatted("discount_amount") }}</td> -->
                    <td class="text-right">{{ n.get_formatted("amount") }}</td>
                </tr>
                <tr>
                    <td></td>
                    <td colspan="4">{{ n.description }}</td>
                    <td></td>
                </tr>
            {% endfor %}
        </tbody>

        <tfoot class="black-border">
            {% if doc.discount_amount %}
                <tr>
                    <td></td>
                    <td>{{ _("Total") }}</td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td class="text-right">{{ doc.get_formatted("total") }}</td>
                </tr>
                <tr>
                    <td></td>
                    <td>{{ _("Discount") }}</td>
                    <td></td>
                    <td></td>
                    <td>
                        {% if doc.additional_discount_percentage %}
                            {{ doc.get_formatted("additional_discount_percentage") }} &percnt;
                        {% endif %}
                    </td>
                    <td class="text-right">
                        {{ doc.get_formatted("discount_amount") }}
                    </td>
                </tr>
            {% endif %}
            <tr>
                <td></td>
                <td>{{ _("Net Total") }}</td>
                <td></td>
                <td></td>
                <td></td>
                <td class="text-right">{{ doc.get_formatted("net_total") }}</td>
            </tr>
            {% if doc.tax_category == "Reverse Charge" -%}
                <tr>
                    <td></td>
                    <td>Steuerschuldnerschaft des Leistungsempfängers / The recipient of the supply is liable for tax</td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td class="text-right"></td>
                </tr>
            {% else %}
                {% for tax_row in doc.taxes -%}
                    {% if tax_row.tax_amount or print_settings.print_taxes_with_zero_amount %}
                        <tr>
                            <td></td>
                            <td>
                            {{ tax_row.description }}
                            </td>
                            <td></td>
                            <td></td>
                            <td></td>
                            <td class="text-right">
                                {{ tax_row.get_formatted("tax_amount") }}
                            </td>
                        </tr>
                    {% endif %}
                {%- endfor %}
            {%- endif %}
            <tr>
                <td></td>
                <td>
                    <strong>{{ _("Grand Total") }}</strong>
                </td>
                <td></td>
                <td></td>
                <td></td>
                <td class="text-right">
                    <strong>{{ doc.get_formatted("grand_total") }}</strong>
                </td>
            </tr>
        </tfoot>
    </table>

    <br>
    <div>
        {% if doc.shipping_address_display %}
        <p>
            {{ _("Shipping Address:") }} <br>
            {{ doc.shipping_address_display }}
        </p>
        <br>
        {% endif %}
        <p>{{ _("Please deliver by: {0}").format(doc.get_formatted("schedule_date")) }}</p>
    </div>

    {% if doc.terms and (doc.terms | striptags) %}
        <br>
        {{ doc.terms }}
    {% endif %}
</div>

<!-- FOOTER -->
<div id="footer-html" class="visible-pdf">
    <p id="pagenum">
        {{ _("Page {0} of {1}").format('<span class="page"></span>', '<span class="topage"></span>') }}
    </p>
    <div class="print-format-footer">
        {{ footer }}
    </div>
</div>

Dazu die CSS:

.print-format {
    padding: 0;
    position: relative;

    #header {
        width: 100%;
        /* ( 45 mm - 10 mm margin ) */
        height: 25mm;
        /* Overwrite empty header inserted by frappe */
        margin-top: 0mm;
        overflow: hidden;
        position: relative;
        margin-left: 20mm;
        margin-right: 20mm;
    }

    .contact-row {
        position: relative;
        overflow: hidden;
        left: 20mm;
        height: 45mm;
        /* müsste eigentlich 180mm sein, sieht mit 170 aber besser aus. */
        width: 170mm;
    }

    #sender {
        position: relative;
        font-size: 60%;
        height: 17.7mm;
        display: table-cell;
        vertical-align: middle;
    }

    #sender p {
        position: absolute;
        width: 85mm;
    }

    #address {
        float: left;
        width: 85mm;
        padding-left: 5mm;
    }

    #contact {
        float: right;
        width: 60mm;
        margin-top: 5mm;
    }

    #contact td {
        padding: 1.5px !important;
    }

    #subject {
        margin-bottom: 2em;
    }

    .din-mark {
        height: 1pt;
        background-color: black;
        position: absolute;
    }

    #faltmarke-1 {
        /* ( 105 mm - 10 mm margin ) */
        top: 95mm;
        width: 12mm;
    }

    #lochmarke {
        /* ( 148.5 mm - 10 mm margin ) */
        top: 138.5mm;
        width: 7mm;
    }

    #faltmarke-2 {
        /* ( 210 mm - 10 mm margin ) */
        top: 200mm;
        width: 12mm;
    }

    #text {
        margin-top: 8.46mm;
        margin-left: 25mm;
        margin-right: 20mm;
    }

    .text-right {
        text-align: right;
    }

    .text-small {
        font-size: 8pt;
    }

    .black-border {
        border-top: solid black 1px;
        border-bottom: solid black 1px;
    }

    .w-100 {
        width: 100%;
    }

    table {
        /* --- Nice page breaks for tables --- */
        page-break-inside: auto;
        table-layout: fixed;

        tr {
            page-break-inside: avoid;
            page-break-after: auto;
        }
    
        thead {
            display: table-header-group;
        }
    
        tfoot {
            display: table-row-group;
        }
    }

    .ql-editor {
        line-height: 1.42857143;
        font-family: Inter, "Helvetica Neue", Helvetica, Arial, "Open Sans", sans-serif; // use `var(--font-stack)` for v16+
        overflow: hidden;

        p {
            margin: unset;
        }
    }
}

.print-format-footer {
    margin-top: 5mm; /* Add this line to move the footer up by 20mm */
    margin-left: 25mm;
    padding-right: 20mm;
}

#pagenum {
    text-align: right;
    margin-right: 20mm;
    margin-top: 4.23mm;
    margin-bottom: 4.23mm;
}

body, html {
    padding: 0;
    margin: 0;
    width: 100%;
    height: 100%;
}

@rmeyer ich glaube ich habe das Problem gefunden: Ich habe den ersten Block im css-file wie folgt geändert. Damit wird das Dokument jetzt ordentlich formatiert und reagiert auf alle Formateingaben:

.print-format {
    padding: 0;
    position: relative;
}
1 Like

@morsecon was genau hast du geändert? Die CSS-Angaben waren ja im Beispiel oben auch schon enthalten.

Ich habe direkt nach dem ersten Block die geschweifte Klammer zu gesetzt, die sonst die gesamten Nachfolgenden Definitionen einschließt.