Header / Footer Development

@rmehta, we will still send the $50 as originally quoted, do you have a timeline for this?

@cpurbaugh - I am not even seeing this thread :slight_smile: btw, @anand wants to experiment with some hack using <table>. I am not sure.

Its best to use pre-printed stationary if you really want to print and send. With PDF, its not necessary.

Hi all

maybe I got this wrong but wkhtmltopdf is able to be supplied with a HTML Footer
via argument --footer-html TheURL
same with header

so it might be possible to tie that in when generating a pdf, isn´t it?
wich Python or Javascript starts/generates the PDF output??
I might have a look into it as well

… we also could then set a foundation for extending the command set to wkhtmltopdf in order to
allow for other print formats by giving page dimensions.
that could be usefull for POS printers, ID card Printers or Labelsticker printers

rgds

@rmehta printed stationary is only useful when you want to print it, but when you want to send the Purchase Order to vendor directly through ERP. Because if we are using and ERP then we should think about a paperless office.

Regards
Ruchin Sharma

@spa that was our first idea, but then we would have to make the HTML generation dependent on whether the output is HTML or PDF (We still support HTML only generation)

@anand wants to try a hack around using table-head when he gets time.

@ruchin78 it should not matter in PDF if the header is not repeated on each page. Though I agree it looks nicer.

@anand
Agreed :grinning:

@rmehta
I see , thanks for the explanation, now I understand the
table thing

I was looking into this a few days back and set it up using the wkhtmltopdf method. We usually have long lists of items so need the letter head and page numbers on every page. If we switched to completely paperless, we might not need a header on each page but I think it’s just something we’re used to doing so prefer it that way.

In frappe/frappe/templates/pages/print.py the download_pdf method. I added the following options.

options = {}

options.update({
    'header-left':'Something here'
    'header-spacing' : '0',
    'footer-right': 'Page [page] of [toPage]'
})
frappe.local.response.filecontent = get_pdf(html,options)

Adding the letter head itself requires using the header-html option instead and creating an html file with contents from the letterhead which you can get by looking at the get_letter_head method. Yes its quite hacky and you have to play with the margins options but it works for now. I’m open to other ideas.

Hope it helps.

2 Likes

HI @Kar_M

that looks like a workaround…
do you know where to alter the PDF rendering´s margin??..
I noticed that playing with the css class .print-format I´m able to adjust the HTML view to my needs in terms of the format.
But when it comes to rendering the PDF seems to have its own margins for the content as it ads
my css `ed margins to its defaults.
So I think working with a full PDF page and adjusting the HTML´s CSS to be rendered might do the trick
I would appreciate a hint

thanks n rgds

Ah yes I forgot to mention that. It’s under frappe/frappe/utils/pdf.py. Default margins are 15mm.
The header-spacing option also helps a bit if you use header-html. If you wanted to you could keep all the options in pdf.py. I decided to keep it in print.py because I wanted easier access to methods like get_letter_head to get the default letter head and use it with header-html.

Regards

@Kar_M Nice! Can you add these as settings in Print Settings and send a pull request. Will be happy to add this in the product :smile:

I could give it a shot. Could you give me an idea of what settings are most useful? I figure values for margins, checkbox to enable page numbers maybe. I believe pdfkit has options for the font of the header and footer. It should probably match with erpnext defaults.

As for using the letterhead itself, I’ve hit a few road blocks. If the letterhead checkbox is enabled I get two showing on the first page. I thought I narrowed it down to frappe/public/js/frappe/form/print.js. From what I’ve gathered, the pdf button opens a new window to /api/method/frappe.templates.pages.print.download_pdf passing in arguments for doctype, name, format and no_letterhead. I’m not sure if this is the right direction to go in but so far changing these values hasn’t done much.

Any help is appreciated.

@Kar_M here is my solution

Part I

  1. In print settings, we can have html that will go in header and footer
  2. We set a print option like use_print_letterhead head
  3. If this is set, set no_letterhead as true,

Part II

While we are at it, we need to create a new print setting for a new printer. So print setting has to be changed from a single type DocType to a table. And then in the print options, we also need to pass on the Printer

Can you start this? Will be happy to help

Edit: If you can build and test Part I, I can do Part II

Step 3 is where I’m getting stuck at. Modifying no_letterhead in print.js doesn’t seem to change anything.

this.wrapper.find(".btn-download-pdf").click(function() {

		if(!me.is_old_style()) {
			this.print_letterhead.is(":checked") ? 1 : 0;
			var w = window.open("/api/method/frappe.templates.pages.print.download_pdf?"
				+"doctype="+encodeURIComponent(me.frm.doc.doctype)
				+"&name="+encodeURIComponent(me.frm.doc.name)
				+"&format="+me.selected_format()
				+"&no_letterhead="+(me.with_letterhead() ? "0" : "1"));
			if(!w) {
				msgprint(__("Please enable pop-ups")); return;
			}
		}
	});
1 Like

@Kar_M can we discuss this over a pull-request?

1 Like

Any updates on this? I’m ready to sponsor as well.

Back from the break. I’ll be getting back to work on migrating to erpnext. Might take some time still.

1 Like

Hi,

I just saw this topic while searching for a solution to the same problem. The actual issue I’m facing is regarding invoices that have multiple pages. When an invoice here has multiple pages it’s required to have all the things below repeated in every single page.

  1. Publisher company’s info
  2. Customer company information
  3. Original or Copy
  4. Current page number and total pages.

So basically only the item list should be changing in all pages.

Inspired by @Kar_M here’s what I’m thinking in a simple way for my case but I’d like some tips in how to properly implement this as a generic solution if at all possible since I’m really new at this.

  1. I’d like to first create two extra fields in the Print Format doctype called Header HTML and Footer HTML

  2. Then I’d like to modify the function download_pdf with something like below

    def download_pdf(doctype, name, format=None):
    html = frappe.get_print(doctype, name, format)
    frappe.local.response.filename = “{name}.pdf”.format(name=name.replace(" “, “-”).replace(”/", “-”))
    options = {}
    header_html = ‘code that will get the header_html value for the corresponding print format from the DB’ or ‘’
    footer_html = ‘code that will get the footer_html value for the corresponding print format from the DB’ or ‘’
    options.update({
    ‘header-html’: header_html,
    ‘footer-html’: footer_html,
    ‘header-spacing’ : ‘0’,
    })
    frappe.local.response.filecontent = get_pdf(html,options)
    frappe.local.response.type = “download”
    where header_html and footer_html would be the html read from the custom fields in the database. Then in the custom fields I can add variables that only exist in the current form like, for sales invoice the customer_name for example as well as the page numbering that wkhtmltopdf defines with javascript

    Footers And Headers:
    Headers and footers can be added to the document by the --header-* and
    –footer* arguments respectfully. In header and footer text string supplied
    to e.g. --header-left, the following variables will be substituted.

    * [page]       Replaced by the number of the pages currently being printed
    * [frompage]   Replaced by the number of the first page to be printed
    * [topage]     Replaced by the number of the last page to be printed
    * [webpage]    Replaced by the URL of the page being printed
    * [section]    Replaced by the name of the current section
    * [subsection] Replaced by the name of the current subsection
    * [date]       Replaced by the current date in system local format
    * [isodate]    Replaced by the current date in ISO 8601 extended format
    * [time]       Replaced by the current time in system local format
    * [title]      Replaced by the title of the of the current page object
    * [doctitle]   Replaced by the title of the output document
    * [sitepage]   Replaced by the number of the page in the current site being converted
    * [sitepages]  Replaced by the number of pages in the current site being converted
    

    As an example specifying --header-right “Page [page] of [toPage]”, will result
    in the text “Page x of y” where x is the number of the current page and y is
    the number of the last page, to appear in the upper left corner in the
    document.

    Headers and footers can also be supplied with HTML documents. As an example
    one could specify --header-html header.html, and use the following content in
    header.html:

    Page of

Would it be possible to do this in your opinion and do you know of anything I could read to help me implement this? And sorry for the long post

@gabtzi thanks for taking this up. Can we discuss this over a pull-request, it will be so much easier to understand what you are proposing

@rmehta Sure but to actually present some starting code in a pull request I’d like to know how I can add a field to the print format doctype and how to then access it from the DB.

Also, this code part belongs to frappe/frappe but where is the print format doctype defined? I didn’t see any way to alter the print format doctype from inside ERPNext so my guess is I have to alter the original doctype definition for it.

Could someone give some hints for those two things?