Electronic invoice is the product of e-commerce era. PDF invoice is one of the most common electronic invoices. In this article, I will share a free C # solution for dynamically generating PDF electronic invoices, and attach a Java solution at the end of the article.
Typical invoices contain the names and addresses of customers and suppliers, invoice numbers, descriptions of purchases, payment amounts, etc. To generate invoices dynamically, I used MS Word to create a template in which I designed most of the content and document style I wanted to present, then replaced the text with code and inserted new content, and finally saved it as a PDF document. Using code to manipulate parts of a Word document requires the use of Free version of Spire. Doc for. NET 7.1.
Creating Templates
As shown in Figure 1, the invoice template consists of two tables. Table 1 is used to display information of buyers and sellers and order information, and Table 2 is used to display a list of products or services provided by sellers to buyers. What we need to do is replace the text in Table 1 that begins with # and fill the customer's shopping list into the second table.
In order to automatically calculate the total amount, formula fields need to be added to some cells. For example, cell E2 contains a formula "= C2*D2", which calculates the total price of the goods in cell B2. When a buyer purchases more than one item, we need to add more rows to the table and update the formulas of some cells dynamically.
Figure 1 Invoice template
How to Replace Text
Spire.Doc has an IBodyRegion. Replace (string given, string replaced, bool case Sensitive, bool wholeWord) method that can be used to replace the specified string in the document. For example, by replacing "orderNum" with "2516595027", we can directly use the following code, in which doc is a Document object.
doc.Replace("#orderNum", "2516595027", true, true);
How to update Table 2
Now let's see how to add rows to existing tables, how to populate data into tables, and how to update formulas dynamically. To make the logic clearer, I created three methods and produced Figure 2 to show their specific meanings and their invocation relationships.
Figure 2 The meaning and invocation relationship of the custom method
Next, take a look at the code snippets of these three methods:
1. AddRows()
This method actually duplicates the second row of the existing table and adds the duplicate rows to the bottom of the second row in turn. The new line inherits the cell format, font style and formula of the second line. Therefore, we need to update the formulas in the new rows in turn, and the following formulas as the number of rows increases.
private static void AddRows(Table table, int rowNum) { for (int i = 0; i < rowNum; i++) { //Add the second row of the specified number of replicated rows to the bottom of the second row in turn table.Rows.Insert(2 + i, table.Rows[1].Clone()); //Update the formula of the cell corresponding to the "amount" foreach (var item in table.Rows[2 + i].Cells[4].Paragraphs[0].ChildObjects) { if (item is Field) { Field field = item as Field; field.Code = string.Format("=C{0}*D{0}\\# \"0.00\"", 3 + i); } break; } } //Update the formula of the cell corresponding to the "discount amount" foreach (var item in table.Rows[4 + rowNum].Cells[4].Paragraphs[0].ChildObjects) { if (item is Field) { Field field = item as Field; field.Code = string.Format("=E{0}*0.05\\# \"0.00\"", 3 + rowNum); } break; } //Update the formula for the cell corresponding to the "total" foreach (var item in table.Rows[5 + rowNum].Cells[4].Paragraphs[0].ChildObjects) { if (item is Field) { Field field = item as Field; field.Code = string.Format("=E{0}-E{1}\\# \"¥#,##0.00\"", 3 + rowNum, 5 + rowNum); } break; } }
2. FillTableWithData()
This method is only used to write sting [][] type data from the second row of the table.
private static void FillTableWithData(Table table, string[][] data) { for (int r = 0; r < data.Length; r++) { for (int c = 0; c < data[r].Length; c++) { //Write data to the table from the second row of the table table.Rows[r + 1].Cells[c].Paragraphs[0].Text = data[r][c]; } } }
3. WriteDataToDocument()
Since the invoice template already has one line (the second line) for displaying an item, we need to determine whether more lines need to be added. If the customer purchases only one item, the template document can contain the product information and output the results; otherwise, we need to add rows to accommodate more items and update the formula dynamically to get the correct total amount.
private static void WriteDataToDocument(Document doc, string[][] purhcaseData) { //Obtain Word The second table in the template Table table = doc.Sections[0].Tables[1] as Table; //If more than one item is purchased, add purhcaseData.Length - 1 Row if (purhcaseData.Length > 1) { AddRows(table, purhcaseData.Length - 1); } //Fill in the purchase data into the form FillTableWithData(table, purhcaseData); }
One of the parameters of the WriteDataToDocument() method is the sting [][] object, which stores the customer's purchase information. Each element of the object is an array of strings, which can be set as follows:
string[] product = new string[] { "1023", "HUAWEI P30 Pro (8G+128G)A phone fit all kinds of networks", "1", "4288" };
The length of string [][] is the number of items in the commodity. If the length is greater than 1, a new line [length - 1] needs to be added.
Generation of invoices
The following is the code in the Main function for generating PDF invoices.
using Spire.Doc; using Spire.Doc.Fields; namespace CreatePdfInvoice { class Program { static void Main(string[] args) { //Load Word Template document Document doc = new Document(); doc.LoadFromFile("Invoice-Template.docx"); //Replace the document with#Beginning Text doc.Replace("#customerName", "Wei Wei", true, true); doc.Replace("#contactNum", "13601234567", true, true); doc.Replace("#shippingAdd", "Unit 3, Unit 2, Building 1, Happy Community, Haidian District, Beijing", true, true); doc.Replace("#orderDate", "2019-05-30", true, true); doc.Replace("#orderNum", "2516595027", true, true); //Define customer purchase data string[][] purchaseData = { new string[]{"1023","HUAWEI P30 Pro (8G+128G)A phone fit all kinds of networks","1","4288"}, new string[]{"1429","HUAWEI Watch GT Sports Edition","2","1288"}, new string[]{"1268","Huawei Wireless Headphones FreeBuds 2Pro","2","799"}, new string[]{"1281","HUAWEI MateBook 14 (i5 8G 512G)","1","5999"}, }; //Write the purchase data to the second table of the template document WriteDataToDocument(doc, purchaseData); //Update domain doc.IsUpdateFields = true; //Save as PDF Format document doc.SaveToFile("Invoice.pdf", FileFormat.PDF); System.Diagnostics.Process.Start("Invoice.pdf"); } } }
The resulting document is as follows:
Figure 3 PDF invoices for more than one item
If you enter only one line of purchase data, you will get the result document as shown in Figure 4.
string[][] purchaseData = {new string[]{"1023","HUAWEI P30 Pro (8G+128G)A phone fit all kinds of networks","1","4288"},};
Figure 4 Single item PDF invoice
Engineering Download
C# Project (including DLL and template documents) | https://pan.baidu.com/s/1jCI1J5J08hGReGIe0ZzOsA | Extraction code: zp6n |
Java engineering (including Jar and template documents) | https://pan.baidu.com/s/1bthB3gnd0B0JQYzwZDWmVA | Extraction code: ciey |
Note:
The free version of Spire.Doc can load and generate no more than 500 paragraphs or 25 tables of Word documents. Only the first three pages are supported when the Word documents are saved as PDF. Most invoices have only one or two pages, so this scheme is applicable in most cases.
--------
Copyright Statement: This is an original article by CSDN blogger "ssw_jack".
Original link: https://blog.csdn.net/ssw_jack/article/details/91379486