C#/Java 动态生成电子发票

2022-10-17,,,,

电子发票是电商时代的产物,pdf发票是最常见的电子发票之一。在这篇文章中,我将给大家分享一个免费的动态生成pdf电子发票的c#方案,并在文章末尾附上java解决方案。

典型的发票包含客户和供应商的名称和地址、发票编号、购买物品的描述、付款金额等信息。为了动态地生成发票,我使用ms word创建了一个模板,在该模板中设计好想要呈现的大部分内容及文档样式,然后通过代码替换文本和插入新内容,最后保存为pdf文档。用代码操作word文档的部分需要使用免费版的spire.doc for .net7.1

创建模板
如图1所示,发票模板由两个表组成。表1用于显示买卖双方的信息和订单信息,表2用于陈列卖方向买方提供的产品或服务列表。我们需要做的是替换表1中以#开头的文本,并将客户的购物清单填充至第二个表格。

为了能自动计算总金额,需要在某些单元格添加公式域。例如,单元格e2包含公式“=c2*d2”,该公式将计算单元格b2中商品的总价。当买家购买超过一件商品时,我们需要在表格添加更多行并动态更新一些单元格的公式。

图1 发票模板

如何替换文本
spire.doc 有一个ibodyregion.replace(string given, string replace, bool casesensitive, bool wholeword)方法,可以用于替换文档中的指定字符串。例如,将“#ordernum”替换成“2516595027”,我们可以直接使用下面的代码,代码中doc是document对象。

doc.replace("#ordernum", "2516595027", true, true);

如何更新表格二

现在,让我们看看如何向现有表格添加行,如何将数据填充至表格,以及如何动态地更新公式。为了使逻辑更清晰,我创建了三个方法,并制作了图2,来展示它们的具体含义以及它们之间的调用关系。

图2 自定义方法的含义及调用关系

下面,看一下这三个方法的代码片段:

1. addrows()

此方法实际上复制了现有表格的第二行,将复制行依次添加到第二行的下面。新行继承了第二行的单元格格式、字体样式和公式。因此,我们需要依次更新新行中的公式,以及下面随行数增加而变化的公式。

private static void addrows(table table, int rownum)
{
 
    for (int i = 0; i < rownum; i++)
    {
        //将指定个数的第二行的复制行依次添加到第二行下面
        table.rows.insert(2 + i, table.rows[1].clone());
 
        //更新“金额”所对应单元格的公式
        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;
        }
 
    }
 
    //更新“折扣金额”对应的单元格的公式
    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;
    }
 
    //更新“总计”对应的单元格的公式
    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()

此方法仅用于将sting[][]类型数据从表格的第二行开始写入表格。

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++)
         {
             //将数据从表格的第二行开始写入表格
             table.rows[r + 1].cells[c].paragraphs[0].text = data[r][c];
         }
     }
 }

 

3. writedatatodocument()

由于发票模板已经有一行(第二行)用于显示一项商品,因此我们需要判断是否需要添加更多行。如果客户只购买一项商品,模板文档就可以容纳商品信息并输出结果;否则,我们需要添加行来容纳更多的项目,并动态更新公式以获得正确的总金额。

private static void writedatatodocument(document doc, string[][] purhcasedata)
{
    //获取word模板中的第二个表格
    table table = doc.sections[0].tables[1] as table;
 
    //若购买商品多于一项,则添加purhcasedata.length - 1个行
    if (purhcasedata.length > 1)
    {
        addrows(table, purhcasedata.length - 1);
    }
 
    //将购买数据填充至表格
    filltablewithdata(table, purhcasedata);
}

writedatatodocument()方法的参数之一是sting[][]对象,该对象存储了客户的购买信息,它的每个元素都是一个字符串数组,可以这样设置:

string[] product = new string[] { "1023", "华为 p30 pro (8g+128g)全网通", "1", "4288" };

string[][]的长度则是商品的项数,如果长度大于1,则需要添加[长度 - 1]个新行。

生成发票

以下是main函数中用于生成pdf发票的代码。

using spire.doc;
using spire.doc.fields;
 
namespace createpdfinvoice
{
    class program
    {
        static void main(string[] args)
        {
            //加载word模板文档
            document doc = new document();
            doc.loadfromfile("invoice-template.docx");
 
            //替换文档中以#开头的文本
            doc.replace("#customername", "小伟", true, true);
            doc.replace("#contactnum", "13601234567", true, true);
            doc.replace("#shippingadd", "北京市海淀区幸福小区1幢2单元3号", true, true);
            doc.replace("#orderdate", "2019-05-30", true, true);
            doc.replace("#ordernum", "2516595027", true, true);
 
            //定义客户购买数据
            string[][] purchasedata = {
 
                                  new string[]{"1023","华为 p30 pro (8g+128g)全网通","1","4288"},
                                  new string[]{"1429","华为watch gt运动版","2","1288"},
                                  new string[]{"1268","华为无线耳机 freebuds 2pro","2","799"},
                                  new string[]{"1281","华为 matebook 14 (i5 8g 512g)","1","5999"},
                              };
 
            //将购买数据写入模板文档的第二个表格
            writedatatodocument(doc, purchasedata);
 
            //更新域
            doc.isupdatefields = true;
 
            //保存为pdf格式文档
            doc.savetofile("invoice.pdf", fileformat.pdf);
            system.diagnostics.process.start("invoice.pdf");
        }
    }
}

生成的结果文档如下:

图 3 多项目pdf发票

 

如果你输入购买数据只有一行,那么你将得到如图4所示的结果文档。

string[][] purchasedata = {new string[]{"1023","华为 p30 pro (8g+128g)全网通","1","4288"},};

图4 单项目pdf发票

 

工程下载

c#工程(含dll和模板文档)  https://pan.baidu.com/s/1jci1j5j08hgregie0zzosa  提取码:zp6n
java 工程(含jar和模板文档)  https://pan.baidu.com/s/1bthb3gnd0b0jqyzwzdwmva   提取码:ciey

 

 

 

注:

免费版 spire.doc能加载和生成的word文档不能超过500个段落或25个表格,将word文档保存为pdf时仅支持前3页。绝大多数发票只有1页或2页,所以该方案适用于大多数情况。

————————————————
版权声明:本文为csdn博主「ssw_jack」的原创文章。
原文链接:https://blog.csdn.net/ssw_jack/article/details/91379486

《C#/Java 动态生成电子发票.doc》

下载本文的Word格式文档,以方便收藏与打印。