In the world of modern business and finance, the creation and management of Golang libraries for invoices and billing statements are critical tasks. These documents serve as a record of transactions, ensuring transparent communication between businesses and their clients.

With the advent of technology, the manual process of generating these documents has been largely automated, thanks to programming languages and libraries that offer convenient solutions.

In this blog post, we’ll delve into the realm of Go (Golang) programming and explore how you can utilize Golang libraries to efficiently generate PDF invoices and billing statements.

Specifically, we’ll focus on the popular Golang library options available for handling these tasks.

Understanding the Importance of Golang Libraries for Invoices and Billing Statements

In the realm of business transactions, invoices and billing statements play an integral role. An invoice is a document sent by a seller to a buyer, outlining the details of products or services provided, quantities, prices, and the total amount owed. It serves as a formal request for payment.

On the other hand, a billing statement provides a comprehensive overview of a customer’s account activity, listing multiple transactions over a specific period along with their corresponding amounts.

Both invoices and billing statements are vital for several reasons:

  • Legal and Financial Records: Invoices serve as legal records of transactions and are crucial for tax purposes. Billing statements help customers reconcile their accounts and identify any discrepancies.

  • Communication: These documents facilitate clear communication between businesses and clients. A well-designed invoice or billing statement ensures that both parties have a common understanding of the transaction details.

  • Professionalism: Professionally crafted invoices and billing statements contribute to the credibility of a business. They demonstrate attention to detail and reliability.

  • Payment Tracking: Invoices include due dates, enabling businesses to track payment timelines. Billing statements provide a holistic view of a customer’s payment history.

Introduction to Golang PDF Libraries

Go, often referred to as Golang, is an open-source programming language developed by Google. It’s known for its efficiency, simplicity, and strong support for concurrency. Golang has gained popularity for building a wide range of applications, including web services, networking tools, and command-line utilities.

Leveraging Golang for generating PDF invoices and billing statements combines the language’s simplicity with the powerful capabilities of PDF generation.

PDF libraries for Go offer developers a convenient way to create, customize, and export PDF documents programmatically. These libraries provide features to design the layout, add text, images, and tables, and manipulate the document’s structure. By utilizing Golang PDF libraries, you can automate the process of generating invoices and billing statements, reducing the risk of errors and saving valuable time.

Choosing the Right Golang PDF Library

Before diving into the implementation, it’s essential to choose the right Golang PDF library for your project. Let’s take a look at two popular options:

  • UniPDF: UniPDF is a comprehensive PDF manipulation library that supports creating, editing, and extracting content from PDFs. It provides advanced features like adding annotations, watermarks, and digital signatures. UniPDF’s capabilities make it suitable for complex scenarios, but its usage might involve a steeper learning curve.

  • gofpdf: Gofpdf is a widely used PDF generation library for Go. It allows you to create PDFs with text, images, lines, and basic shapes. It provides control over fonts, colors, and sizes. While it’s not as feature-rich as some other libraries, it’s lightweight and straightforward to use.

Both libraries have their strengths, so your choice depends on your project’s requirements. For the purpose of this blog post, we’ll focus on using the UniPDF library due to its ease of use and suitability for basic invoice and billing statement generation.

Generating PDF Invoices with Golang

Installing the Chosen Library

Before we start coding, we need to install the UniPDF library. Open your terminal and run the following command:

Installing the Chosen Library

This command fetches the library and makes it available in your Go environment.

Designing the Invoice Template

The first step in generating PDF invoices is designing the template. Decide on the layout, fonts, colors, and overall structure of the invoice. You can create a function that initializes the PDF document and sets up the template:

// Create new UniPDF creator.
c := creator.New()

// Add new page into creator.
c.NewPage()

// Initialize UniPDF invoice.
invoice := c.NewInvoice()

Populating Data into the Invoice

Next, populate the template with data from your invoice. This includes client information, itemized details, quantities, prices, and totals. You can create functions to add different sections of the invoice:

// Load and read logo.
logo, err := c.NewImageFromFile("unidoc-logo.png")
if err != nil {
	log.Fatalf("Fail: %v\n", err)
}

// Set invoice logo.
invoice.SetLogo(logo)

// Set invoice information.
invoice.SetNumber("0001")
invoice.SetDate("28/07/2016")
invoice.SetDueDate("28/07/2016")
invoice.AddInfo("Payment terms", "Due on receipt")
invoice.AddInfo("Paid", "No")

// Set invoice addresses.
invoice.SetSellerAddress(&creator.InvoiceAddress{
  Name:    "John Doe",
  Street:  "8 Elm Street",
  City:    "Cambridge",
  Zip:     "CB14DH",
  Country: "United Kingdom",
  Phone:   "xxx-xxx-xxxx",
  Email:   "[email protected]",
})

invoice.SetBuyerAddress(&creator.InvoiceAddress{
  Name:    "Jane Doe",
  Street:  "9 Elm Street",
  City:    "London",
  Zip:     "LB15FH",
  Country: "United Kingdom",
  Phone:   "xxx-xxx-xxxx",
  Email:   "[email protected]",
})

// Add invoice line items.
for i := 0; i < 75; i++ {
  invoice.AddLine(
    fmt.Sprintf("Test product #%d", i+1),
    "1",
    "$10",
    "$10",
  )
}

// Set invoice totals.
invoice.SetSubtotal("$100.00")
invoice.AddTotalLine("Tax (10%)", "$10.00")
invoice.AddTotalLine("Shipping", "$5.00")
invoice.SetTotal("$115.00")

// Set invoice content sections.
invoice.SetNotes("Notes", "Thank you for your business.")
invoice.SetTerms("Terms and conditions", "Full refund for 60 days after purchase.")

// Draw invoice into creator.
if err = c.Draw(invoice); err != nil {
  log.Fatalf("Error drawing: %v", err)
}

Exporting as PDF

Once you’ve added all the necessary data to the PDF object, it’s time to save the invoice as a PDF file:

// Write output file.
err = c.WriteToFile("invoice_simple.pdf")
if err != nil {
  log.Fatalf("Fail: %v\n", err)
}

Invoice example with UniPDF

Invoice example with UniPDF Invoice example with UniPDF Invoice example with UniPDF

Creating Billing Statements Using Golang PDF Libraries

Creating billing statements follows a similar process as generating invoices. The key difference lies in the content and structure of the document.

Structuring the Billing Statement

Billing statements typically include sections for account summary, transaction details, due amounts, and any additional notes. You can define functions to add these sections:

header.tpl

<division margin="20 50">
    <table position="relative" columns="2" column-widths="0.9 0.1">
        <table-cell indent="0" vertical-align="middle">
            <division>
                <paragraph>
                    <text-chunk font="helvetica-bold" font-size="16">{{.Statement.BankName}} Simple Business Checking</text-chunk>
                </paragraph>
                <table columns="5" column-widths="0.3 0.05 0.3 0.05 0.3" margin="8 0 0 0">
                    <table-cell indent="0">
                        <paragraph>
                            <text-chunk>Account Number: </text-chunk>
                            <text-chunk font="helvetica-bold">{{.Statement.AccountNumber}}</text-chunk>
                        </paragraph>
                    </table-cell>
                    <table-cell indent="0">
                        <paragraph text-align="center">
                            <text-chunk></text-chunk>
                        </paragraph>
                    </table-cell>
                    <table-cell indent="0">
                        <paragraph text-align="center">
                            <text-chunk>{{formatTime .Statement.DateBegin "Jan 02 2006"}} - {{formatTime .Statement.DateEnd "Jan 02 2006"}}</text-chunk>
                        </paragraph>
                    </table-cell>
                    <table-cell indent="0">
                        <paragraph text-align="center">
                            <text-chunk></text-chunk>
                        </paragraph>
                    </table-cell>
                    <table-cell indent="0">
                        <paragraph>
                            <text-chunk>Page {{.PageNum}} of {{.TotalPages}}</text-chunk>
                        </paragraph>
                    </table-cell>
                </table>
            </division>
        </table-cell>
        <table-cell indent="0" vertical-align="middle">
            <image src="path('templates/res/logo.png')" fit-mode="fill-width" margin="0 0 0 5"></image>
        </table-cell>
    </table>
    <line position="relative" fit-mode="fill-width" margin="5 0 0 0" color="#00aff5"></line>
</division>

footer.tpl

<line position="relative" fit-mode="fill-width" margin="0 50" color="#00aff5"></line>
<paragraph margin="5 0 0 50">
    <text-chunk font-size="8">© {{.Date.Year}} {{.Statement.BankName}}, N.A. All rights reserved. Member FDIC.</text-chunk>
</paragraph>

main.tpl

{{define "simple-paragraph"}}
    {{$margin := "0"}}
    {{if .Margin}} {{$margin = .Margin}} {{end}}

    {{$lineHeight := 1}}
    {{if .LineHeight}} {{$lineHeight = .LineHeight}} {{end}}

    {{$align := "left"}}
    {{if .TextAlign}} {{$align = .TextAlign}} {{end}}

    {{$font := "helvetica"}}
    {{if .Font}} {{$font = .Font}} {{end}}

    {{$fontSize := 10}}
    {{if .FontSize}} {{$fontSize = .FontSize}} {{end}}

    {{$textColor := "#000000"}}
    {{if .TextColor}} {{$textColor = .TextColor}} {{end}}

    {{$text := ""}}
    {{if .Text}} {{$text = .Text}} {{end}}

    <paragraph margin="{{$margin}}" line-height="{{$lineHeight}}" text-align="{{$align}}">
        <text-chunk font="{{$font}}" font-size="{{$fontSize}}" color="{{$textColor}}">{{$text}}</text-chunk>
    </paragraph>
{{end}}

{{define "table-cell-paragraph"}}
    {{$colspan := 1}}
    {{if .Colspan}} {{$colspan = .Colspan}} {{end}}

    {{$backgroundColor := "#ffffff"}}
    {{if .BackgroundColor}} {{$backgroundColor = .BackgroundColor}} {{end}}

    {{$align := "left"}}
    {{if .Align}} {{$align = .Align}} {{end}}

    {{$verticalAlign := "top"}}
    {{if .VerticalAlign}} {{$verticalAlign = .VerticalAlign}} {{end}}

    {{$borderColor := "#ffffff"}}
    {{if .BorderColor}} {{$borderColor = .BorderColor}} {{end}}

    {{$borderLeftSize := 0}}
    {{if .BorderLeftSize}} {{$borderLeftSize = .BorderLeftSize}} {{end}}

    {{$borderRightSize := 0}}
    {{if .BorderRightSize}} {{$borderRightSize = .BorderRightSize}} {{end}}

    {{$borderTopSize := 0}}
    {{if .BorderTopSize}} {{$borderTopSize = .BorderTopSize}} {{end}}

    {{$borderBottomSize := 0}}
    {{if .BorderBottomSize}} {{$borderBottomSize = .BorderBottomSize}} {{end}}

    {{$indent := 0}}
    {{if .Indent}} {{$indent = .Indent}} {{end}}

    <table-cell colspan="{{$colspan}}" background-color="{{$backgroundColor}}" align="{{$align}}" vertical-align="{{$verticalAlign}}" border-color="{{$borderColor}}" border-width-left="{{$borderLeftSize}}" border-width-right="{{$borderRightSize}}" border-width-top="{{$borderTopSize}}" border-width-bottom="{{$borderBottomSize}}" indent="{{$indent}}">
        {{template "simple-paragraph" .}}
    </table-cell>
{{end}}

{{define "panel-title"}}
    <background border-radius="2" border-color="#00aff5" border-size="1"></background>
    <division padding="5">
        <background border-radius="2 2 0 0" fill-color="#00aff5"></background>
        {{template "simple-paragraph" dict "Margin" "0 0 5 0" "Font" "helvetica-bold" "FontSize" 14 "TextColor" "#ffffff" "Text" .Title}}
    </division>
{{end}}

<table columns="2" column-widths="0.4 0.6" margin="0">
    <table-cell indent="0">
        <division>
            {{template "panel-title" dict "Title" "Company Information"}}
            <division margin="10 5 108 10">
                <paragraph>
                    <text-chunk font="helvetica-bold" font-size="12">{{.CompanyName}}</text-chunk>
                </paragraph>
                <paragraph margin="10 0 0 0" line-height="1.1">
                    <text-chunk>{{.CompanyAddress}}</text-chunk>
                </paragraph>
            </division>
        </division>
    </table-cell>
    <table-cell indent="0">
        <division margin="0 0 0 7">
            {{template "panel-title" dict "Title" "Questions"}}
            <division margin="10 5 10 10">
                {{template "simple-paragraph" dict "Font" "helvetica-bold" "FontSize" 12 "Text" "Contact"}}
                {{template "simple-paragraph" dict "Margin" "10 0 0 0" "LineHeight" 1.1 "Text" "Available by phone 24 hours a day, 7 days a week. Telecommunications Relay Services calls are accepted."}}
                <paragraph margin="5 0 0 0">
                    <text-chunk font="helvetica-bold" font-size="12">{{.PhoneFree}} </text-chunk>
                    <text-chunk font-size="12">({{.Phone}})</text-chunk>
                </paragraph>
                <table columns="2" column-widths="0.3 0.7" margin="10 0 0 0">
                    {{$props := dict "LineHeight" 1.1}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "TTY")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" .Phone)}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Online")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" .Online)}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Write")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" .White)}}
                </table>
            </division>
        </division>
    </table-cell>
</table>

<division margin="7 0 0 0">
    {{template "panel-title" dict "Title" "Company Information"}}
    <division>
        <table columns="2" column-widths="0.6 0.4" margin="10">
            <table-cell indent="0">
                <division margin="0 5 0 0">
                    {{template "simple-paragraph" dict "Font" "helvetica-bold" "FontSize" 12 "Text" (printf "Your business and %s" .BankName)}}
                    {{template "simple-paragraph" dict "Margin" "10 0 0 0" "LineHeight" 1.1 "Text" "The plans you establish today will shape your business far into the future. The heart of the planning process is your business plan. Take your time to build a strong foundation."}}
                    <paragraph margin="5 0 0 0">
                        <text-chunk>Find out more at </text-chunk>
                        <text-chunk color="#0000ff">{{.BusinessPlanURL}}</text-chunk>
                        <text-chunk>.</text-chunk>
                    </paragraph>
                </division>
            </table-cell>
            <table-cell indent="0">
                <division margin="0 0 0 5">
                    {{template "simple-paragraph" dict "Font" "helvetica-bold" "FontSize" 12 "Text" "Account options"}}
                    <paragraph margin="10 0 0 0">
                        <text-chunk>A check mark in the box indicates you have these convenient services with your account(s). Go to </text-chunk>
                        <text-chunk color="#0000ff">{{.AccountOptionsURL}}</text-chunk>
                        <text-chunk> or call the number above if you have questions or if you would like to add new services.</text-chunk>
                    </paragraph>
                    <table columns="2" column-widths="0.8 0.2" margin="10 0 0 0">
                        {{range $label := .AccountOptionsLabels}}
                            <table-cell indent="0" vertical-align="middle">
                                {{template "simple-paragraph" dict "TextColor" "#000000" "Text" $label}}
                            </table-cell>
                            <table-cell indent="0" align="right" vertical-align="middle">
                                {{template "simple-paragraph" dict "Margin" "-4 0 0 0" "Font" "zapf-dingbats" "FontSize" 12 "Text" "❑"}}
                            </table-cell>
                        {{end}}
                    </table>
                </division>
            </table-cell>
        </table>
    </division>
</division>

<division margin="7 0 0 0">
    {{template "panel-title" dict "Title" "Account Summary"}}
    <division margin="10">
        {{template "simple-paragraph" dict "LineHeight" 1.1 "Text" .Advt}}
    </division>
</division>

<table columns="2" column-widths="0.5 0.5" margin="7 0 0 0">
    <table-cell indent="0">
        <division>
            {{template "panel-title" dict "Title" "Company Information"}}
            <table columns="2" column-widths="0.75 0.25" margin="10">
                {{template "table-cell-paragraph" (dict "Text" (printf "Beginning balance on %s" (formatTime .DateBegin "Jan 02 2006")))}}
                {{template "table-cell-paragraph" (dict "Align" "right" "Text" (printf " $%.2f" .BeginningBalance))}}
                {{template "table-cell-paragraph" (dict "Text" "Deposits/Credits")}}
                {{template "table-cell-paragraph" (dict "Align" "right" "Text" (printf " %.2f" .Deposits))}}
                {{template "table-cell-paragraph" (dict "Text" "Withdrawals/Debits")}}
                {{template "table-cell-paragraph" (dict "Align" "right" "Text" (printf "%.2f" .Withdrawals))}}
                {{template "table-cell-paragraph" (dict "Font" "helvetica-bold" "BorderColor" "#000000" "BorderTopSize" 1 "Text" (printf "Ending balance on %s" (formatTime .DateEnd "Jan 02 2006")))}}
                {{template "table-cell-paragraph" (dict "Align" "right" "Font" "helvetica-bold" "BorderColor" "#000000" "BorderTopSize" 1 "Text" (printf " $%.2f" .EndingBalance))}}
                {{template "table-cell-paragraph" (dict "Margin" "10 0 0 0" "Text" "Average ledger balance this period")}}
                {{template "table-cell-paragraph" (dict "Align" "right" "Margin" "10 0 1 0" "Text" (printf " %.2f" .AverageBalance))}}
            </table>
        </division>
    </table-cell>
    <table-cell indent="0">
        <division margin="0 0 0 7">
            {{template "panel-title" dict "Title" "Account Info"}}
            <division margin="10">
                {{template "simple-paragraph" dict "Font" "helvetica-bold" "Text" .CompanyName}}
                {{template "simple-paragraph" dict "Margin" "2 0 0 0" "Text" "New York account terms and conditions apply."}}
                {{template "simple-paragraph" dict "Margin" "10 0 0 0" "Text" "For Direct Deposit use:"}}
                {{template "simple-paragraph" dict "Margin" "2 0 0 0" "Text" (printf "Routing Number (RTN): %s" .DepositRTN)}}
                {{template "simple-paragraph" dict "Margin" "10 0 0 0" "Text" "For Wire Transfers use:"}}
                {{template "simple-paragraph" dict "Margin" "2 0 0 0" "Text" (printf "Routing Number (RTN): %s" .WireRTN)}}
            </division>
        </division>
    </table-cell>
</table>

<division margin="7 0 0 0">
    {{template "panel-title" dict "Title" "Overdraft Protection"}}
    <division margin="10 10 20 10">
        {{template "simple-paragraph" dict "Text" "Your account is linked to the following for overdraft protection:"}}
        {{template "simple-paragraph" dict "Text" "Savings - 000001234567890"}}
    </division>
</division>

<division>
    {{template "panel-title" dict "Title" "Transaction History"}}
    <division margin="5" padding="5">
        <table columns="6" column-widths="0.075 0.1 0.405 0.14 0.14 0.14">
            {{$props := dict "BorderColor" "#000000" "BorderTopSize" 1}}
            {{template "table-cell-paragraph" (extendDict $props "BorderTopSize" 0 "Text" "Date")}}
            {{template "table-cell-paragraph" (extendDict $props "BorderTopSize" 0 "TextAlign" "right" "Text" "Check&#xA;Number")}}
            {{template "table-cell-paragraph" (extendDict $props "BorderTopSize" 0 "Indent" 5 "Text" "Description")}}
            {{template "table-cell-paragraph" (extendDict $props "BorderTopSize" 0 "TextAlign" "right" "Text" "Deposits/&#xA;Credits")}}
            {{template "table-cell-paragraph" (extendDict $props "BorderTopSize" 0 "TextAlign" "right" "Text" "Withdrawals/&#xA;Debits")}}
            {{template "table-cell-paragraph" (extendDict $props "BorderTopSize" 0 "TextAlign" "right" "Text" "Ending Daily&#xA;Balance")}}

            {{range $transaction := .Transactions}}
                {{template "table-cell-paragraph" (extendDict $props "Text" (formatTime $transaction.Date "01/02"))}}
                {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" $transaction.Check)}}
                {{template "table-cell-paragraph" (extendDict $props "Indent" 5 "Text" $transaction.Details)}}
                {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf " $%.2f" $transaction.Deposits))}}
                {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf " $%.2f" $transaction.Withdrawals))}}
                {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf " $%.2f" $transaction.EndingDailyBalance))}}
            {{end}}

            {{template "table-cell-paragraph" (extendDict $props "Colspan" 5 "Font" "helvetica-bold" "Text" (printf "Ending balance on %s" (formatTime .DateEnd "Jan 02 2006")))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Font" "helvetica-bold" "Indent" 3 "Text" (printf " $%.2f" .EndingBalance))}}

            {{template "table-cell-paragraph" (extendDict $props "Colspan" 3 "Font" "helvetica-bold" "BorderBottomSize" 0 "Text" "Totals")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Font" "helvetica-bold" "Indent" 3 "Text" (printf " $%.2f" .TransactionDeposits))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Font" "helvetica-bold" "Text" (printf " $%.2f" .TransactionWithdrawals))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Font" "helvetica-bold")}}
        </table>

        {{template "simple-paragraph" dict "Margin" "7 0 0 0" "LineHeight" 1.1 "Text" "The Ending Daily Balance does not reflect any pending withdrawals or holds on deposited funds that may have been outstanding on your account when your transaction posted. If you had insufficient available funds when a transaction posted, fees may have been assessed."}}
    </division>
</division>

<division margin="7 0 0 0">
    {{template "panel-title" dict "Title" "Service Fee Summary"}}
    <division margin="10">
        <paragraph line-height="1.1">
            <text-chunk>For a complete list of fees and detailed account information, please see the {{.BankName}} Fee and Information Schedule and Account Agreement applicable to your account or talk to a banker. Go to </text-chunk>
            <text-chunk color="#0000ff">{{.AccountOptionsURL}} </text-chunk>
            <text-chunk>to find the answers to common questions about the monthly service fee on your account.</text-chunk>
        </paragraph>

        <table columns="4" column-widths="0.45 0.26 0.26 0.03" margin="10 0 0 0">
            {{$props := dict "BorderColor" "#000000" "BorderBottomSize" 1 "Indent" 5}}
            {{template "table-cell-paragraph" (extendDict $props "Indent" 0 "Text" (printf "Fee period %s - %s" (formatTime .DateBegin "Jan 02 2006") (formatTime .DateEnd "Jan 02 2006")))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf "Standard monthly fee %.2f" .StandardServiceFee))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf "You paid %.2f" .ServiceFee))}}
            {{template "table-cell-paragraph" (extendDict $props)}}

            <table-cell indent="0" background-color="#ffffff">
                <paragraph>
                    <text-chunk font="helvetica-bold">How to reduce the monthly service fee by {{.ServiceDiscount}}&#xA;</text-chunk>
                    <text-chunk>Have </text-chunk>
                    <text-chunk font="helvetica-bold">ONE </text-chunk>
                    <text-chunk>of the following account requirements</text-chunk>
                </paragraph>
            </table-cell>
            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 0 "Text" "Minimum required")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "BorderBottomSize" 0 "Text" "This fee period")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "BorderBottomSize" 0)}}

            {{template "table-cell-paragraph" (extendDict $props "Indent" 0 "Text" "Average ledger balance")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf "$%.2f" .MinimumRequired))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf "$%.2f" .AverageBalance))}}
            {{template "table-cell-paragraph" (extendDict $props "VerticalAlign" "middle" "FontSize" 12 "Margin" "-4 0 0 0" "Font" "zapf-dingbats" "TextAlign" "right" "Text" "❑")}}
            {{template "table-cell-paragraph" (extendDict $props "Indent" 0 "Colspan" 4 "Font" "helvetica-bold" "BorderBottomSize" 0 "Text" "Monthly fee discount(s) (applied when box is checked)")}}

            {{template "table-cell-paragraph" (extendDict $props "Indent" 0 "Text" "Online only statements")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf "$%.2f" .MinimumRequired))}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" (printf "$%.2f" .AverageBalance))}}
            {{template "table-cell-paragraph" (extendDict $props "VerticalAlign" "middle" "FontSize" 12 "Margin" "-4 0 0 0" "Font" "zapf-dingbats" "TextAlign" "right" "Text" "❑")}}
        </table>

        <table columns="6" column-widths="0.3 0.1 0.1 0.1 0.2 0.2" margin="20 0 0 0">
            {{$props := dict "BorderColor" "#000000" "BorderBottomSize" 1 "Indent" 5}}
            {{template "table-cell-paragraph" (extendDict $props "Indent" 0 "Text" "Service&#xA;charge description")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" "Units&#xA;used")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" "Units&#xA;included")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" "Excess&#xA;units")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" "Service charge per&#xA;excess units ($)")}}
            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Text" "Total service charge($)")}}

            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 3 "Indent" 0 "Text" "Transactions")}}
            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 3 "TextAlign" "right" "Text" .TransactionUnits)}}
            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 3 "TextAlign" "right" "Text" .TransactionUnitsIncluded)}}
            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 3 "TextAlign" "right" "Text" (printf "%.0f" .TransactionExcessUnits))}}
            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 3 "TextAlign" "right" "Text" (printf "%.2f" .ServiceCharge))}}
            {{template "table-cell-paragraph" (extendDict $props "BorderBottomSize" 3 "TextAlign" "right" "Text" (printf "%.2f" .TotalServiceCharge))}}

            {{template "table-cell-paragraph" (extendDict $props "Colspan" 5 "Font" "helvetica-bold" "BorderBottomSize" 0 "Indent" 0 "Text" "Total service charges")}}
            {{template "table-cell-paragraph" (extendDict $props "Font" "helvetica-bold" "BorderBottomSize" 0 "TextAlign" "right" "Text" (printf "%.2f" .TotalServiceCharge))}}
        </table>

        <table columns="2" column-widths="0.03 0.97" margin="20 0 0 0">
            <table-cell indent="0" border-color="#000000" border-width-top="1">
                {{template "simple-paragraph" dict "Margin" "0" "Font" "zapf-dingbats" "FontSize" 12 "Text" "❑"}}
            </table-cell>
            <table-cell indent="0" border-color="#000000" border-width-top="1">
                <paragraph margin="6 0 0 0">
                    <text-chunk font="helvetica-bold">Your feedback matters&#xA;</text-chunk>
                    <text-chunk>Share your compliments and complaints so we can better serve you.&#xA;</text-chunk>
                    <text-chunk>Call us at {{.FeedbackPhone}} ({{.Phone}}) or visit </text-chunk>
                    <text-chunk color="#0000ff">{{.BusinessPlanURL}}</text-chunk>
                    <text-chunk>.</text-chunk>
                </paragraph>
            </table-cell>
        </table>
    </division>
</division>

<division margin="7 0 0 0">
    {{template "panel-title" dict "Title" "Policies"}}
    <division>
        <table columns="2" column-widths="0.6 0.4" margin="10">
            <table-cell indent="0">
                <paragraph>
                    <text-chunk font="helvetica-bold">Notice</text-chunk>
                    <text-chunk>: {{.BankName}}, {{.BankNameState}} may furnish information about accounts belonging to individuals, including sole proprietorships, to consumer reporting agencies. If this applies to you, you have the right to dispute the accuracy of information that we have reporting by writing to us at: {{.ReportAddress}}</text-chunk>
                </paragraph>
            </table-cell>
            <table-cell indent="2">
                {{template "simple-paragraph" dict "LineHeight" 1.1 "Text" "You must describe the specific information that is innacurate or in dispute and the basis for any dispute with supporting documentation. In the case of information that relates to an identity theft, you will need to provide us with an identity theft report."}}
            </table-cell>
        </table>
    </division>
</division>

<table columns="2" margin="7 0 0 0">
    <table-cell indent="0">
        <division>
            {{template "panel-title" dict "Title" "Instruction"}}
            <division margin="10 5 120 10">
                <table columns="2" column-widths="0.05 0.95">
                    {{$props := dict "LineHeight" 1.1 "FontSize" 7 "Indent" 0}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "1.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Use the following worksheet to calculate your overall account balance.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "2.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Go through your register and mark each check, withdrawal, ATM transaction, payment, deposit or other credit listed on your statement. Be sure that your register shows any interest paid into your account and any service charges, automatic payments or ATM transactions withdrawn from your account during this statement period.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "3.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Use the chart to the right to list any deposits, transfers to your account, outstanding checks, ATM withdrawals, ATM payments or any other withdrawals (including any from previous months) which are listed in your register but not shown on your statement.")}}
                </table>

                {{template "simple-paragraph" dict "Font" "helvetica-bold" "FontSize" 7 "Margin" "15 0 0 0" "Text" "ENTER"}}
                <table columns="4" column-widths="0.05 0.5 0.15 0.3">
                    {{template "table-cell-paragraph" (extendDict $props "Font" "helvetica-bold" "Text" "A.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 2 "Text" "The ending balance shown on your statement.")}}
                    {{template "table-cell-paragraph" (extendDict $props)}}
                    {{template "table-cell-paragraph" (extendDict $props)}}
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 2 "Text" (strRepeat ". " 40))}}
                    <table-cell>
                        <table columns="2" column-widths="0.3 0.7">
                            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Margin" "-1 0 0 0" "Text" "$ ")}}
                            <table-cell indent="0">
                                <line position="relative" fit-mode="fill-width" color="#e9e9e9" margin="8 0 0 0"></line>
                            </table-cell>
                        </table>
                    </table-cell>
                </table>

                {{template "simple-paragraph" dict "Font" "helvetica-bold" "FontSize" 7 "Margin" "7 0 0 0" "Text" "ADD"}}
                <table columns="4" column-widths="0.05 0.5 0.15 0.3">
                    {{template "table-cell-paragraph" (extendDict $props "Font" "helvetica-bold" "Text" "B.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 2 "Text" "Any deposits listed in your register or transfers into account which are not shown on your statement.")}}

                    <table-cell>
                        <table columns="2" column-widths="0.3 0.7" margin="0 0 10 0">
                            {{range $i, $unused := (loop 4)}}
                                {{$text := "$ "}}
                                {{if eq $i 3}}
                                    {{$text = "+$ "}}
                                {{end}}

                                {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Margin" "-1 0 0 0" "Text" $text)}}
                                <table-cell indent="0">
                                    <line position="relative" fit-mode="fill-width" color="#e9e9e9" margin="8 0 0 0"></line>
                                </table-cell>
                            {{end}}
                        </table>
                    </table-cell>

                    {{template "table-cell-paragraph" (extendDict $props)}}
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 2 "Text" (strRepeat ". " 40))}}
                    <table-cell>
                        <table columns="2" column-widths="0.3 0.7">
                            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Margin" "-1 0 0 0" "Text" "$ ")}}
                            <table-cell indent="0">
                                <line position="relative" fit-mode="fill-width" color="#e9e9e9" margin="8 0 0 0"></line>
                            </table-cell>
                        </table>
                    </table-cell>
                </table>

                {{template "simple-paragraph" dict "Font" "helvetica-bold" "FontSize" 7 "Margin" "7 0 0 0" "Text" "SUBTRACT"}}
                <table columns="4" column-widths="0.05 0.5 0.15 0.3">
                    {{template "table-cell-paragraph" (extendDict $props "Font" "helvetica-bold" "Text" "C.")}}
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 2 "Text" (printf "The total outstanding checks and withdrawals from the chart above. %s" (strRepeat ". " 23)))}}
                    <table-cell vertical-align="bottom">
                        <table columns="2" column-widths="0.3 0.7">
                            {{template "table-cell-paragraph" (extendDict $props "TextAlign" "right" "Margin" "-2 0 0 0" "Text" "-$ ")}}
                            <table-cell indent="0">
                                <line position="relative" fit-mode="fill-width" color="#e9e9e9" margin="7 0 0 0"></line>
                            </table-cell>
                        </table>
                    </table-cell>
                </table>

                <table columns="4" column-widths="0.05 0.5 0.15 0.3" margin="10 0 0 0">
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 4 "Font" "helvetica-bold" "Text" "CALCULATE THE ENDING BALANCE")}}
                    {{template "table-cell-paragraph" (extendDict $props "Colspan" 3 "Margin" "-3 0 0 0" "Text" (printf "(Part A + Part B + Part C)&#xA;This amount should be the same as the current balance shown in your check register. %s" (strRepeat ". " 13)))}}
                    <table-cell vertical-align="bottom">
                        <table columns="2" column-widths="0.3 0.7">
                            {{template "table-cell-paragraph" (extendDict $props "Font" "helvetica-bold" "TextAlign" "right" "Margin" "-2 0 0 0" "Text" "$ ")}}
                            <table-cell indent="0">
                                <line position="relative" fit-mode="fill-width" margin="7 0 0 0"></line>
                            </table-cell>
                        </table>
                    </table-cell>
                </table>
            </division>
        </division>
    </table-cell>
    <table-cell indent="0">
        <division margin="0 0 0 7">
            {{template "panel-title" dict "Title" "Balance calculation"}}
            <division margin="10">
                <table columns="3" column-widths="0.3 0.4 0.3">
                    {{$props = dict "TextAlign" "center" "Indent" 0 "Font" "helvetica-bold" "FontSize" 7}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Number")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Items Outstanding")}}
                    {{template "table-cell-paragraph" (extendDict $props "Text" "Amount")}}

                    {{range $unused := (loop 25)}}
                        {{$props = dict "BorderColor" "#000000" "BorderLeftSize" 1 "BorderRightSize" 1 "BorderTopSize" 1 "BorderBottomSize" 1 "Margin" "5 0" "Indent" 0}}
                        {{template "table-cell-paragraph" $props}}
                        {{template "table-cell-paragraph" $props}}
                        {{template "table-cell-paragraph" $props}}
                    {{end}}

                    {{template "table-cell-paragraph" (dict "BorderTopSize" 1 "BorderColor" "#000000")}}
                    {{template "table-cell-paragraph" (dict "VerticalAlign" "middle" "TextAlign" "right" "BorderTopSize" 1 "BorderColor" "#000000" "Font" "helvetica-bold" "FontSize" 7 "Text" "Total Amount $ ")}}
                    {{template "table-cell-paragraph" $props}}
                </table>
            </division>
        </division>
    </table-cell>
</table>

Incorporating Styling and Formatting

To give your billing statement a more visually appealing and polished look, consider adding style elements such as borders, shading, and color accents. You’ll find these options readily available within the template located in the main.tpl file. This means you don’t need to worry about manually implementing them, as the template already incorporates these design elements, making your billing statement look more professional and visually engaging.

Dynamic Data Integration

Billing statements often include dynamic data, such as a list of recent transactions. You can dynamically populate these sections by iterating through the data and adding it to the PDF:

account_statement.json

{
    "bankName": "UniPDF Bank",
    "bankNameState": "N.A.",
    "accountNumber": "1234567890",
    "dateBegin": "2020-05-26T00:00:00",
    "dateEnd": "2020-06-24T00:00:00",
    "companyName": "Sample Company",
    "companyAddress": "123 Main Street\nAnywhere NY\n12345-6789",
    "reportAddress": "Overdraft Collections and Recovery, P.O. Box 1234, Anywhere, OR 12345-6789",
    "phoneFree": "1-800-CALL-XXXXX",
    "phone": "1-234-567-8900",
    "tTY": "1-234-567-8900",
    "online": "unidoc.io",
    "white": "UniPDF Bank, N.A.\nP.O. Box 1234\nNewYork, OR\n12345-6789",
    "businessPlanURL": "unidoc.io/unipdf",
    "accountOptionsURL": "unidoc.io/pricing",
    "advt": "The UniPDF Bank Mobile App is now available in Spanish!\n\nYou can securely manage your finances virtually anytime, anywhere in Spanish.\nOnce you have downloaded the latest version of the UniPDF Bank Mobile ® App from Google Play or the Apple App Store, go to Mobile Settings and set your language preference to Spanish.",
    "beginningBalance": 550,
    "withdrawals": -1639.32,
    "deposits": 3820,
    "endingBalance": 2417.96,
    "averageBalance": 1186.58,
    "depositRTN": "123456789",
    "wireRTN": "987654321",
    "standardServiceFee": 10,
    "minimumRequired": 500,
    "serviceFee": 0,
    "serviceDiscount": 5,
    "transactionUnits": 17,
    "transactionUnitsIncluded": 50,
    "transactionExcessUnits": 0,
    "serviceCharge": 0.5,
    "totalServiceCharge": 0,
    "feedbackPhone": "1-234-XXX-CARE",
    "transactionDeposits": 5700,
    "transactionWithdrawals": 3832.04,
    "transactions": [
        {
            "date": "2020-05-26T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :677577755404",
            "deposits": 300,
            "withdrawals": 0,
            "endingDailyBalance": 850
        },
        {
            "date": "2020-05-27T00:00:00",
            "check": "",
            "details": "Purchase authorized amazon.com",
            "deposits": 0,
            "withdrawals": 178.15,
            "endingDailyBalance": 671.85
        },
        {
            "date": "2020-05-28T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :824527230250",
            "deposits": 450,
            "withdrawals": 0,
            "endingDailyBalance": 1121.85
        },
        {
            "date": "2020-05-28T00:00:00",
            "check": "",
            "details": "Purchase authorized Shoprite #4512",
            "deposits": 0,
            "withdrawals": 87.15,
            "endingDailyBalance": 1034.7
        },
        {
            "date": "2020-05-28T00:00:00",
            "check": "",
            "details": "Purchase authorized amazon.com",
            "deposits": 0,
            "withdrawals": 17.92,
            "endingDailyBalance": 1016.78
        },
        {
            "date": "2020-05-28T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :107043500279",
            "deposits": 150,
            "withdrawals": 0,
            "endingDailyBalance": 1166.78
        },
        {
            "date": "2020-06-01T00:00:00",
            "check": "",
            "details": "PayPal Transfer : Ref Number : Q4THK3mqAjKK4DJ",
            "deposits": 1000,
            "withdrawals": 0,
            "endingDailyBalance": 2166.78
        },
        {
            "date": "2020-06-02T00:00:00",
            "check": "",
            "details": "Purchase authorized Shoprite #4512",
            "deposits": 0,
            "withdrawals": 43.2,
            "endingDailyBalance": 2123.58
        },
        {
            "date": "2020-06-03T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :310455748540",
            "deposits": 200,
            "withdrawals": 0,
            "endingDailyBalance": 2323.58
        },
        {
            "date": "2020-06-03T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :511250576650",
            "deposits": 100,
            "withdrawals": 0,
            "endingDailyBalance": 2423.58
        },
        {
            "date": "2020-06-03T00:00:00",
            "check": "",
            "details": "Purchase authorized Games Inc.",
            "deposits": 0,
            "withdrawals": 399,
            "endingDailyBalance": 2024.58
        },
        {
            "date": "2020-06-03T00:00:00",
            "check": "",
            "details": "Purchase authorized amazon.com",
            "deposits": 0,
            "withdrawals": 325,
            "endingDailyBalance": 1699.58
        },
        {
            "date": "2020-06-04T00:00:00",
            "check": "1247",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 230,
            "endingDailyBalance": 1469.58
        },
        {
            "date": "2020-06-05T00:00:00",
            "check": "1248",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 193.12,
            "endingDailyBalance": 1276.46
        },
        {
            "date": "2020-06-09T00:00:00",
            "check": "1249",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 1204.1,
            "endingDailyBalance": 72.36
        },
        {
            "date": "2020-06-10T00:00:00",
            "check": "",
            "details": "Purchase authorized Sunoco Gas",
            "deposits": 0,
            "withdrawals": 45.1,
            "endingDailyBalance": 27.26
        },
        {
            "date": "2020-06-11T00:00:00",
            "check": "",
            "details": "Purchase authorized Shoprite #4512",
            "deposits": 0,
            "withdrawals": 23,
            "endingDailyBalance": 4.26
        },
        {
            "date": "2020-06-12T00:00:00",
            "check": "1251",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 0,
            "endingDailyBalance": 4.26
        },
        {
            "date": "2020-06-12T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :511250576650",
            "deposits": 350,
            "withdrawals": 0,
            "endingDailyBalance": 354.26
        },
        {
            "date": "2020-06-12T00:00:00",
            "check": "",
            "details": "Mobile Deposit : Ref Number :656808908596",
            "deposits": 700,
            "withdrawals": 0,
            "endingDailyBalance": 1054.26
        },
        {
            "date": "2020-06-12T00:00:00",
            "check": "",
            "details": "Purchase authorized Walmart",
            "deposits": 0,
            "withdrawals": 124.1,
            "endingDailyBalance": 930.16
        },
        {
            "date": "2020-06-12T00:00:00",
            "check": "",
            "details": "Purchase authorized CVS #12349",
            "deposits": 0,
            "withdrawals": 1.13,
            "endingDailyBalance": 929.03
        },
        {
            "date": "2020-06-12T00:00:00",
            "check": "",
            "details": "Purchase authorized Shoprite #4512",
            "deposits": 0,
            "withdrawals": 94.3,
            "endingDailyBalance": 834.73
        },
        {
            "date": "2020-06-18T00:00:00",
            "check": "",
            "details": "Purchase authorized Shoprite #4512",
            "deposits": 0,
            "withdrawals": 45.8,
            "endingDailyBalance": 788.93
        },
        {
            "date": "2020-06-19T00:00:00",
            "check": "1250",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 25.1,
            "endingDailyBalance": 763.83
        },
        {
            "date": "2020-06-20T00:00:00",
            "check": "1254",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 340,
            "endingDailyBalance": 423.83
        },
        {
            "date": "2020-06-21T00:00:00",
            "check": "",
            "details": "PayPal Transfer : Ref Number : s9Wb9ejIBemLrqY",
            "deposits": 1500,
            "withdrawals": 0,
            "endingDailyBalance": 1923.83
        },
        {
            "date": "2020-06-22T00:00:00",
            "check": "",
            "details": "PayPal Transfer : Ref Number : ztnneHwt28flJvp",
            "deposits": 700,
            "withdrawals": 0,
            "endingDailyBalance": 2623.83
        },
        {
            "date": "2020-06-23T00:00:00",
            "check": "",
            "details": "PayPal Transfer : Ref Number : oQ3f6fi1fp1O7tS",
            "deposits": 250,
            "withdrawals": 0,
            "endingDailyBalance": 2873.83
        },
        {
            "date": "2020-06-23T00:00:00",
            "check": "",
            "details": "Purchase authorized amazon.com",
            "deposits": 0,
            "withdrawals": 62.1,
            "endingDailyBalance": 2811.73
        },
        {
            "date": "2020-06-23T00:00:00",
            "check": "",
            "details": "Purchase authorized Walmart",
            "deposits": 0,
            "withdrawals": 23.2,
            "endingDailyBalance": 2788.53
        },
        {
            "date": "2020-06-24T00:00:00",
            "check": "",
            "details": "Purchase authorized Shoprite #4512",
            "deposits": 0,
            "withdrawals": 94.2,
            "endingDailyBalance": 2694.33
        },
        {
            "date": "2020-06-24T00:00:00",
            "check": "1255",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 125.1,
            "endingDailyBalance": 2569.23
        },
        {
            "date": "2020-06-24T00:00:00",
            "check": "1256",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 93.21,
            "endingDailyBalance": 2476.02
        },
        {
            "date": "2020-06-24T00:00:00",
            "check": "1257",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 15.13,
            "endingDailyBalance": 2460.89
        },
        {
            "date": "2020-06-24T00:00:00",
            "check": "1258",
            "details": "Check",
            "deposits": 0,
            "withdrawals": 42.93,
            "endingDailyBalance": 2417.96
        }
    ],
    "accountOptionsLabels": [
        "Business Online Banking",
        "Online Statements",
        "Business Bill Pay",
        "Business Spending Report",
        "Overdraft Protection"
    ]
}

main.go

/*
 * This example showcases the usage of creator templates by creating a sample
 * bank account statement.
 *
 * Run as: go run main.go
 */

package main

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"os"
	"strings"
	"text/template"
	"time"

	"github.com/unidoc/unipdf/v3/common"
	"github.com/unidoc/unipdf/v3/common/license"
	"github.com/unidoc/unipdf/v3/core"
	"github.com/unidoc/unipdf/v3/creator"
)

func init() {
	// Make sure to load your metered License API key prior to using the library.
	// If you need a key, you can sign up and create a free one at https://cloud.unidoc.io.
	err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
	if err != nil {
		panic(err)
	}

	common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug))
}

func main() {
	c := creator.New()
	c.SetPageMargins(50, 50, 80, 25)

	// Read main content template.
	mainTpl, err := readTemplate("templates/main.tpl")
	if err != nil {
		log.Fatal(err)
	}

	// Read account statement data.
	statement, err := readAccountStatement("account_statement.json")
	if err != nil {
		log.Fatal(err)
	}

	// Draw main content template.
	tplOpts := &creator.TemplateOptions{
		HelperFuncMap: template.FuncMap{
			"formatTime": func(val, format string) string {
				t, _ := time.Parse("2006-01-02T15:04:05", val)
				return t.Format(format)
			},
			"extendDict": func(m map[string]interface{}, params ...interface{}) (map[string]interface{}, error) {
				lenParams := len(params)
				if lenParams%2 != 0 {
					return nil, core.ErrRangeError
				}

				out := make(map[string]interface{}, len(m))
				for key, val := range m {
					out[key] = val
				}

				for i := 0; i < lenParams; i += 2 {
					key, ok := params[i].(string)
					if !ok {
						return nil, core.ErrTypeError
					}

					out[key] = params[i+1]
				}

				return out, nil
			},
			"strRepeat": strings.Repeat,
			"loop": func(size uint64) []struct{} {
				return make([]struct{}, size)
			},
		},
	}

  // Draw template with options and data from `statement`.
	if err := c.DrawTemplate(mainTpl, statement, tplOpts); err != nil {
		log.Fatal(err)
	}

	// Draw header and footer.
	drawHeader := func(tplPath string, block *creator.Block, pageNum, totalPages int) {
		// Read template.
		tpl, err := readTemplate(tplPath)
		if err != nil {
			log.Fatal(err)
		}

		// Draw template.
		data := map[string]interface{}{
			"Date":       time.Now(),
			"Statement":  statement,
			"PageNum":    pageNum,
			"TotalPages": totalPages,
		}

		if err := block.DrawTemplate(c, tpl, data, tplOpts); err != nil {
			log.Fatal(err)
		}
	}

	c.DrawHeader(func(block *creator.Block, args creator.HeaderFunctionArgs) {
		drawHeader("templates/header.tpl", block, args.PageNum, args.TotalPages)
	})
	c.DrawFooter(func(block *creator.Block, args creator.FooterFunctionArgs) {
		drawHeader("templates/footer.tpl", block, args.PageNum, args.TotalPages)
	})

	// Write output file.
	if err := c.WriteToFile("unipdf-bank-account-statement.pdf"); err != nil {
		log.Fatal(err)
	}
}

// readTemplate reads the template at the specified file path and returns it
// as an io.Reader.
func readTemplate(tplFile string) (io.Reader, error) {
	file, err := os.Open(tplFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	buf := bytes.NewBuffer(nil)
	if _, err = io.Copy(buf, file); err != nil {
		return nil, err
	}

	return buf, nil
}

// AccountStatement represents a sample account statement.
type AccountStatement struct {
	BankName                 string  `json:"bankName"`
	BankNameState            string  `json:"bankNameState"`
	AccountNumber            string  `json:"accountNumber"`
	DateBegin                string  `json:"dateBegin"`
	DateEnd                  string  `json:"dateEnd"`
	CompanyName              string  `json:"companyName"`
	CompanyAddress           string  `json:"companyAddress"`
	ReportAddress            string  `json:"reportAddress"`
	PhoneFree                string  `json:"phoneFree"`
	Phone                    string  `json:"phone"`
	Tty                      string  `json:"tTY"`
	Online                   string  `json:"online"`
	White                    string  `json:"white"`
	BusinessPlanURL          string  `json:"businessPlanURL"`
	AccountOptionsURL        string  `json:"accountOptionsURL"`
	Advt                     string  `json:"advt"`
	BeginningBalance         float64 `json:"beginningBalance"`
	Withdrawals              float64 `json:"withdrawals"`
	Deposits                 float64 `json:"deposits"`
	EndingBalance            float64 `json:"endingBalance"`
	AverageBalance           float64 `json:"averageBalance"`
	DepositRTN               string  `json:"depositRTN"`
	WireRTN                  string  `json:"wireRTN"`
	StandardServiceFee       float64 `json:"standardServiceFee"`
	MinimumRequired          float64 `json:"minimumRequired"`
	ServiceFee               float64 `json:"serviceFee"`
	ServiceDiscount          float64 `json:"serviceDiscount"`
	TransactionUnits         float64 `json:"transactionUnits"`
	TransactionUnitsIncluded float64 `json:"transactionUnitsIncluded"`
	TransactionExcessUnits   float64 `json:"transactionExcessUnits"`
	ServiceCharge            float64 `json:"serviceCharge"`
	TotalServiceCharge       float64 `json:"totalServiceCharge"`
	FeedbackPhone            string  `json:"feedbackPhone"`
	TransactionDeposits      float64 `json:"transactionDeposits"`
	TransactionWithdrawals   float64 `json:"transactionWithdrawals"`
	Transactions             []struct {
		Date               string      `json:"date"`
		Check              interface{} `json:"check"`
		Details            string      `json:"details"`
		Deposits           float64     `json:"deposits"`
		Withdrawals        float64     `json:"withdrawals"`
		EndingDailyBalance float64     `json:"endingDailyBalance"`
	} `json:"Transactions"`
	AccountOptionsLabels []string `json:"accountOptionsLabels"`
}

// readAccountStatement reads the data for an account statement from a
// specified JSON file.
func readAccountStatement(jsonFile string) (*AccountStatement, error) {
	file, err := os.Open(jsonFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	statement := &AccountStatement{}
	if err := json.NewDecoder(file).Decode(statement); err != nil {
		return nil, err
	}

	return statement, nil
}

Advanced Features and Customization

To enhance the functionality and appearance of your generated invoices and billing statements, consider implementing the following advanced features:

Adding Logos and Branding

Including your company logo and branding elements in the PDF documents can add a professional touch. You can use the Image() function in UniPDF to add images:

add-image.go

c := creator.New()
...

// Load image from file.
img, err := c.NewImageFromFile("./unidoc-logo.png")
if err != nil {
  log.Fatalf(err)
}

// Draw image into creator.
c.Draw(img)
...

Billing statement example with UniPDF

Billing statement example with UniPDF Billing statement example with UniPDF Billing statement example with UniPDF Billing statement example with UniPDF

Calculating Totals and Taxes

To calculate totals and taxes for invoices and billing statements, you can utilize the functions that are already available in your main.go file. These functions are essential for ensuring accuracy and consistency in your financial documents.

Conclusion

Golang libraries for invoices and billing statements offers an efficient way to streamline business operations and enhance communication with clients.

By harnessing the capabilities of Golang’s simplicity and the power of PDF generation libraries, you can create customized, professional-grade documents that accurately represent transaction details and account activities. Remember that the choice of library depends on your project’s requirements, with options like UniPDF and gofpdf catering to different levels of complexity.

Automating the process of generating invoices and billing statements not only reduces the risk of errors but also saves valuable time and resources. As businesses continue to rely on digital solutions, Golang’s PDF libraries provide a valuable toolset for creating clear, organized, and visually appealing documents that contribute to successful financial transactions.