Odoo rendert im Standard den Header und Footer von allen PDF-Reports in einem externen Template (external_layout). Header und Footer werden auf allen Seiten ganz oben und ganz unten angezeigt. Die Abstände kannst du im Papierformat festlegen.
Wenn du einen ausführlichen Footer-Block hast, ist das nicht ideal. Denn er nimmt dir auf jeder Seite Platz weg, und du möchtest den Footer vielleicht als Abschluss in einem schön gestalteten Angebot anzeigen. Dasselbe gilt für den Header: Wenn du Logo und Firmeninformationen auf jeder Seite wieder oben anzeigst, verlierst du unnötig viel Platz, und es kann die Optik eines Angebots negativ beeinflussen.
Gerade bei Angeboten für Immobilien oder Innenarchitektur ist das nicht gut.
Doch warum können wir in Odoo PDF-Reports den Footer nicht einfach nur auf der letzten Seite darstellen? Kurz gesagt:
Wenn du einen Report generierst, rendert Odoo aus dem Template zuerst den Report-Body. Das ist eine HTML-Seite, die genau wie dein Report aussieht. Dieses HTML übergibt Odoo an das interne Tool „wkhtmltopdf“. Dieses rendert aus dem HTML das PDF. Erst wenn das PDF gerendert wurde, weiss Odoo, wie viele Seiten das PDF genau hat.
Die Position des Footers bestimmst du in deinem Report-Template. Odoo weiss aber erst, wie die Seitenstruktur aussieht, sobald das Template gerendert wurde. Genau deshalb kannst du im Report-Template die Position des Footers nicht so einfach bestimmen.
Wie können wir nun dennoch Header nur auf der ersten und Footer nur auf der letzten Seite platzieren?
Wir nutzen dazu einen einfachen Workaround. Wir definieren einen Helper-Report und rendern ihn innerhalb des Main-Reports, um die Seitenzahl zu bestimmen. Mit dieser Angabe positionieren wir den Footer absolut im Main-Report.
Hinweis: Diese Methode funktioniert nur mit Odoo.sh oder On Premise.
Nachfolgend zeige ich dir das Konzept und die Struktur für die Anpassung. Für die genaue Umsetzung kannst du gerne mit mir Kontakt aufnehmen. In meinen anderen Blogbeiträgen findest du Anleitungen, wie du Odoo PDF-Report-Templates anpassen und strukturieren kannst. Das kann dir bei der Umsetzung auch helfen.
Schritt 1: Finde das korrekte Template für den Header und Footer. Prüfe dazu als Erstes, welches Dokumentenlayout du in den Firmeneinstellungen eingestellt hast (DIN5008, striped, boxed etc.). Suche danach nach dem korrekten external_layout unter Einstellungen / Technisch / Benutzerschnittstelle / Ansichten. Odoo hat für jedes Dokumentenlayout ein separates Header- und Footer-Layout, deshalb ist es wichtig, das richtige zu finden.
Schritt 2: Setze den CSS-Style "display: none;" für den Header und Footer im external_layout. Hinweis: Im nachfolgenden Screenshot habe ich zur Demo den Style direkt im Odoo-Default-Template hinzugefügt. Beim nächsten Update des Web-Moduls würde dieser wieder überschrieben werden. Wie du mit XPath bleibende Änderungen machst, zeige ich dir in diesem Blogbeitrag ->.
Schritt 3: Erstelle ein neues Papierformat mit den verkleinerten Header- und Footer-Seitenabständen. Hinterlege das neue Papierformat bei den Firmeneinstellungen. Wenn du das Papierformat beibehältst, ist der Header und Footer zwar weg, du wirst stattdessen aber einen weissen Leerraum haben.
Schritt 4: Füge deinen Custom-Header direkt im entsprechenden Report-Template hinzu (ganz oben im <page>-Div).
Schritt 5: Füge deinem Report-Model (z. B. sale.order, account.move) in einem Custom-Modul folgende Methode hinzu:
from odoo import api, fields, models
import io
try:
from PyPDF2 import PdfReader
class SaleOrder(models.Model):
_inherit = 'sale.order'
def get_report_page_count(self, report_name):
"""
This method is used to render a helper report inside the sale quotation report and returns its page count for dynamic positioning of the footer.
"""
self.ensure_one()
report_action = self.env.ref(report_name)
pdf_content, content_type = self.env['ir.actions.report']._render_qweb_pdf(report_action.id, [self.id])
pdf_stream = io.BytesIO(pdf_content)
pdf_reader = PdfReader(pdf_stream)
return len(pdf_reader.pages)
Schritt 6: Erstelle einen neuen, eigenständigen Report, der eine genaue Kopie deines eigentlichen Report-Templates verwendet. Diesen Report brauchen wir, um die Seitenanzahl vorherzusagen. Wenn du den Report im Code erstellst, hast du bereits eine externe ID. Wenn du ihn im User-Interface erstellst, exportiere den Report, um die externe ID zu generieren. Füge anschliessend dieses Snippet in dein Main-Report-Template ein. Es erstellt dir einen dynamischen Header-Abstand vom Seitenanfang, basierend auf den Seitenzahlen.
Im folgenden Snippet sind beispielhafte Millimeterwerte für die Seitenhöhe eingetragen. Passe page_height nach Belieben an.
<t t-set="page_count" t-value="o.get_report_page_count('set_here_your_external_id') or 1"/>
<t t-set="page_height" t-value="378.0"/>
<t t-set="footer_top" t-value="page_count * page_height"/>
Schritt 7: Nutze die Variable footer_top, um deinen Footer dynamisch zu positionieren.
Fertig! Nun kannst du deinen Footer dynamisch am Ende der letzten Seite platzieren :-)
Wenn du Fragen hast, kontaktiere mich gerne oder schreibe einen Kommentar.
Nate