0

I am using Rotativa to generate a single PDF file for single invoice, in Asp.Net MVC application. I am using the command --header-html with CustomSwitches of ViewAsPdf to include header for each page of an Invoice as follows,

public ActionResult GenerateSingleInvoicePDF(string invoiceId)
{    
  var invoiceViewModel = new InvoicePDFModel();
  ... // get content from database;    
  ...
  ...    
  ViewBag.InvoiceDetail = invoiceViewModel;    

  string customSwitches = string.Format("--print-media-type --allow {0} --header-html {0} --page-offset \"0\" --header-spacing \"1\" ", Url.Action("InvoiceHeader", "Order", new { invNumber =  
  invoiceViewModel.invNo, invDate = invoiceViewModel.InvoiceDateString, shippAddr = invoiceViewModel.DeliveryAddr, billingAddress = invoiceViewModel.BillingAddr }, "http"));    

  return new ViewAsPdf("~/SingleInvoiceView.cshtml")
   {
        FileName = "SingleInvoice.pdf",
        PageSize = Size.A4,
        CustomSwitches = customSwitches
    };
}

This works perfectly without any issue. Now my need is how to generate a single PDF for multiple invoice. I tried the above code for multiple invoice as follows,

public ActionResult GenerateMultipleInvoicePDF(string invoiceIds)
    {    
      var invoiceList = new List<InvoicePDFModel>
      ... // get list of content from database;    
      ...
      ...    
      ViewBag.InvoiceList = invoiceList;   
    
      string customSwitches = // don't know how to define header view for multiple invoice.
    
      return new ViewAsPdf("~/MultiInvoiceView.cshtml")
       {
            FileName = "MultiInvoice.pdf",
            PageSize = Size.A4,
            CustomSwitches = customSwitches
        };
    }

But I am stuck at the header part. Because, header content varies for each invoice. Any suggestions how to do this?

Thamarai T
  • 252
  • 1
  • 6
  • 19
  • My requirement is, in a single PDF document, I need to *generate PDF pages for the invoices one by one*. e.g., invoice 1, invoice 2 and so on. Each invoice having different header content at the same time. – Thamarai T Nov 02 '21 at 08:14

1 Answers1

0

For your specific case, taking a look at your individual invoice code

Url.Action("InvoiceHeader", "Order", new { invNumber =  
  invoiceViewModel.invNo, invDate = invoiceViewModel.InvoiceDateString, shippAddr = invoiceViewModel.DeliveryAddr, billingAddress = invoiceViewModel.BillingAddr }, "http")

Maybe it would be a good idea to take all the parameters you are sending to the view and store them inside a model. This model could keep a list or collection of classes or models, each of them with the same pack of parameters that you send for an individual invoice. Then, on the view, you might be able to determine, depending on your requirements, which parameters you must specify for each page.

Bearing in mind that Rotativa uses WkHtmlToPdf, and as you can chek in this, an other posts, the oficial documentation sets that the page number, among other parameters, is send to the header/footer.

Could be tricky, but this means you might be able to achieve what you are looking for, following these steps:

  1. Generate MVC action and asociated view, to generate the header, accepting the model you wish.

  2. Inside the view, access QueryString parameter for page number, so this way you can identify which invoice you are printing (supossing that each invoice prints no more and no less than one page).

  3. Using the collection of classes from your model, access by index the particular invoice that matches the page number from the previous step, and write the view according to the parameters that apply for the current invoice.

Dave Miller
  • 536
  • 3
  • 19
  • I am already using the first approach to include header for **single invoice**. But now I need for **multiple invoice**. – Thamarai T Nov 02 '21 at 08:10
  • Sorry @Tharamai T. I completely misunderstood your question. I changed the answer, to suit your case. Hope it helps now. – Dave Miller Nov 02 '21 at 08:21
  • For single invoice, i already added page number too. You are suggesting to pass a **collection of model** to header view, right? – Thamarai T Nov 02 '21 at 10:10
  • Yes, that's it. You can use page number to identify which invoice you are currently displaying, and then search by index, to iterate through items inside collection (as each item contais the parameters for an specific invoice), and get the parameters from the respective item. – Dave Miller Nov 03 '21 at 09:08
  • pages between invoice may vary. I mean, one invoice may have 2 pages and other may have one page. It seems tricky. – Thamarai T Nov 06 '21 at 06:11
  • Should it be possible to know the number of pages of each invoice before send them to the view? If true, you could pass one more paremeter in each model (as we said before, one model for one invoice), with the number of pages that may correspond to the specific invoice. – Dave Miller Nov 06 '21 at 17:07
  • If this is not possible, still there is an option, if you have some leeway to work on the invoice design. Maybe you could do the trick if you are able to structure the date inside the the invoice, using CSS page break and forcing to display some common data in specific pages. – Dave Miller Nov 06 '21 at 17:34
  • It could still be tricky, but I will try to give you an example. I was able to achive this some years ago in some kind of a energy comsumption and prices report. Based on my case, the first page cointained the "header" data (consumptions summary, office info...), the second page always displayed the consumptions detailed info, the third page was used for prices, the fourth and fifth pages were reserved to charts... – Dave Miller Nov 06 '21 at 17:37
  • In conclusion, structure the info inside the invoice for your case in "data sets", so you can have some control on it: depending which data sets you need to display, you can foresee the number of pages you are usign for each real invoice. The existence of this data sets could be managed using bolleans or other fields in your model. Hope this could be helpful for your case. If not, please let me know. – Dave Miller Nov 06 '21 at 17:40
  • Hi, @Tharamai T. Any luck on this approach? – Dave Miller Nov 10 '21 at 07:31
  • Tried for *finding the number of pages of each invoice before send them to the view*. But I couldn't find the solution for that. – Thamarai T Nov 12 '21 at 06:09
  • Considering your energy consumption report, it seems you had header part in first page only. But in my case, all pages have header part for each invoice. As per your suggestion, I am passing a collection of model to header view, but I couldn't bind the respective header content to each invoice. As you said, it seems a little bit tricky. – Thamarai T Nov 12 '21 at 06:15
  • I'm sorry, @Tharamai T. The use of word _header_ in my previous comment was not accurate... I meant that passage acts like a header for the current report, like a first page summary. This had nothing to do with page headers. I apologize if this served to confuse the example. in fact, I use headers in all pages. But the important thing is that the example tried to explain how to structure the content of th PDF when you have multiple passages each of them of a different nature. – Dave Miller Nov 12 '21 at 07:38
  • About your previous comment, maybe you could add and explanation about the kind of invoices you want to generate, and the expected casuistry, to the main post/question, so this way maybe we might be able to helpt you, and even provide you a basic code sample. – Dave Miller Nov 12 '21 at 07:45
  • currently I generated the PDF for each invoice **separately** due to urgent requirement for my client. I will update the explanation in the main post as soon as possible. Thanks. – Thamarai T Nov 15 '21 at 06:20