mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-05 19:30:30 +08:00
Merge branch 'v3' into render.v3.hungarian
This commit is contained in:
commit
8015b712d5
@ -672,6 +672,14 @@ func (c *Creator) NewSubchapter(ch *Chapter, title string) *Subchapter {
|
|||||||
return newSubchapter(ch, title, c.NewTextStyle())
|
return newSubchapter(ch, title, c.NewTextStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInvoice returns an instance of an empty invoice.
|
||||||
|
func (c *Creator) NewInvoice() *Invoice {
|
||||||
|
headingStyle := c.NewTextStyle()
|
||||||
|
headingStyle.Font = c.defaultFontBold
|
||||||
|
|
||||||
|
return newInvoice(c.NewTextStyle(), headingStyle)
|
||||||
|
}
|
||||||
|
|
||||||
// NewRectangle creates a new Rectangle with default parameters
|
// NewRectangle creates a new Rectangle with default parameters
|
||||||
// with left corner at (x,y) and width, height as specified.
|
// with left corner at (x,y) and width, height as specified.
|
||||||
func (c *Creator) NewRectangle(x, y, width, height float64) *Rectangle {
|
func (c *Creator) NewRectangle(x, y, width, height float64) *Rectangle {
|
||||||
|
@ -80,6 +80,10 @@ func (div *Division) Height() float64 {
|
|||||||
p := t
|
p := t
|
||||||
compWidth += p.margins.left + p.margins.right
|
compWidth += p.margins.left + p.margins.right
|
||||||
compHeight += p.margins.top + p.margins.bottom
|
compHeight += p.margins.top + p.margins.bottom
|
||||||
|
case *StyledParagraph:
|
||||||
|
p := t
|
||||||
|
compWidth += p.margins.left + p.margins.right
|
||||||
|
compHeight += p.margins.top + p.margins.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical stacking.
|
// Vertical stacking.
|
||||||
|
863
pdf/creator/invoice.go
Normal file
863
pdf/creator/invoice.go
Normal file
@ -0,0 +1,863 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions defined in
|
||||||
|
* file 'LICENSE.md', which is part of this source code package.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package creator
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// InvoiceAddress contains contact information that can be displayed
|
||||||
|
// in an invoice. It is used for the seller and buyer information in the
|
||||||
|
// invoice template.
|
||||||
|
type InvoiceAddress struct {
|
||||||
|
Name string
|
||||||
|
Street string
|
||||||
|
Zip string
|
||||||
|
City string
|
||||||
|
Country string
|
||||||
|
Phone string
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvoiceCellProps holds all style properties for an invoice cell.
|
||||||
|
type InvoiceCellProps struct {
|
||||||
|
TextStyle TextStyle
|
||||||
|
Alignment CellHorizontalAlignment
|
||||||
|
BackgroundColor Color
|
||||||
|
|
||||||
|
BorderColor Color
|
||||||
|
BorderWidth float64
|
||||||
|
BorderSides []CellBorderSide
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvoiceCell represents any cell belonging to a table from the invoice
|
||||||
|
// template. The main tables are the invoice information table, the line
|
||||||
|
// items table and totals table. Contains the text value of the cell and
|
||||||
|
// the style properties of the cell.
|
||||||
|
type InvoiceCell struct {
|
||||||
|
InvoiceCellProps
|
||||||
|
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoice represents a configurable invoice template.
|
||||||
|
type Invoice struct {
|
||||||
|
// Invoice title.
|
||||||
|
title string
|
||||||
|
|
||||||
|
// Invoice logo.
|
||||||
|
logo *Image
|
||||||
|
|
||||||
|
// Invoice addresses.
|
||||||
|
buyerAddress *InvoiceAddress
|
||||||
|
sellerAddress *InvoiceAddress
|
||||||
|
|
||||||
|
// Invoice information.
|
||||||
|
number [2]*InvoiceCell
|
||||||
|
date [2]*InvoiceCell
|
||||||
|
dueDate [2]*InvoiceCell
|
||||||
|
info [][2]*InvoiceCell
|
||||||
|
|
||||||
|
// Invoice lines.
|
||||||
|
columns []*InvoiceCell
|
||||||
|
lines [][]*InvoiceCell
|
||||||
|
|
||||||
|
// Invoice totals.
|
||||||
|
subtotal [2]*InvoiceCell
|
||||||
|
total [2]*InvoiceCell
|
||||||
|
totals [][2]*InvoiceCell
|
||||||
|
|
||||||
|
// Invoice note sections.
|
||||||
|
notes [2]string
|
||||||
|
terms [2]string
|
||||||
|
sections [][2]string
|
||||||
|
|
||||||
|
// Invoice styles.
|
||||||
|
defaultStyle TextStyle
|
||||||
|
headingStyle TextStyle
|
||||||
|
titleStyle TextStyle
|
||||||
|
|
||||||
|
addressStyle TextStyle
|
||||||
|
addressHeadingStyle TextStyle
|
||||||
|
|
||||||
|
noteStyle TextStyle
|
||||||
|
noteHeadingStyle TextStyle
|
||||||
|
|
||||||
|
// Invoice style properties.
|
||||||
|
infoProps InvoiceCellProps
|
||||||
|
colProps InvoiceCellProps
|
||||||
|
itemProps InvoiceCellProps
|
||||||
|
totalProps InvoiceCellProps
|
||||||
|
|
||||||
|
// Positioning: relative/absolute.
|
||||||
|
positioning positioning
|
||||||
|
}
|
||||||
|
|
||||||
|
// newInvoice returns an instance of an empty invoice.
|
||||||
|
func newInvoice(defaultStyle, headingStyle TextStyle) *Invoice {
|
||||||
|
i := &Invoice{
|
||||||
|
// Title.
|
||||||
|
title: "INVOICE",
|
||||||
|
|
||||||
|
// Addresses.
|
||||||
|
sellerAddress: &InvoiceAddress{},
|
||||||
|
buyerAddress: &InvoiceAddress{},
|
||||||
|
|
||||||
|
// Styles.
|
||||||
|
defaultStyle: defaultStyle,
|
||||||
|
headingStyle: headingStyle,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default colors.
|
||||||
|
lightGrey := ColorRGBFrom8bit(245, 245, 245)
|
||||||
|
mediumGrey := ColorRGBFrom8bit(155, 155, 155)
|
||||||
|
|
||||||
|
// Default title style.
|
||||||
|
i.titleStyle = headingStyle
|
||||||
|
i.titleStyle.Color = mediumGrey
|
||||||
|
i.titleStyle.FontSize = 20
|
||||||
|
|
||||||
|
// Default address styles.
|
||||||
|
i.addressStyle = defaultStyle
|
||||||
|
i.addressHeadingStyle = headingStyle
|
||||||
|
|
||||||
|
// Default note styles.
|
||||||
|
i.noteStyle = defaultStyle
|
||||||
|
i.noteHeadingStyle = headingStyle
|
||||||
|
|
||||||
|
// Invoice information default properties.
|
||||||
|
i.infoProps = i.NewCellProps()
|
||||||
|
i.infoProps.BackgroundColor = lightGrey
|
||||||
|
i.infoProps.TextStyle = headingStyle
|
||||||
|
|
||||||
|
// Invoice line items default properties.
|
||||||
|
i.colProps = i.NewCellProps()
|
||||||
|
i.colProps.TextStyle = headingStyle
|
||||||
|
i.colProps.BackgroundColor = lightGrey
|
||||||
|
i.colProps.BorderColor = lightGrey
|
||||||
|
|
||||||
|
i.itemProps = i.NewCellProps()
|
||||||
|
i.itemProps.BorderColor = lightGrey
|
||||||
|
i.itemProps.BorderSides = []CellBorderSide{CellBorderSideBottom}
|
||||||
|
i.itemProps.Alignment = CellHorizontalAlignmentRight
|
||||||
|
|
||||||
|
// Invoice totals default properties.
|
||||||
|
i.totalProps = i.NewCellProps()
|
||||||
|
i.totalProps.Alignment = CellHorizontalAlignmentRight
|
||||||
|
|
||||||
|
// Invoice information fields.
|
||||||
|
i.number = [2]*InvoiceCell{
|
||||||
|
i.newCell("Invoice number", i.infoProps),
|
||||||
|
i.newCell("", i.infoProps),
|
||||||
|
}
|
||||||
|
|
||||||
|
i.date = [2]*InvoiceCell{
|
||||||
|
i.newCell("Date", i.infoProps),
|
||||||
|
i.newCell("", i.infoProps),
|
||||||
|
}
|
||||||
|
|
||||||
|
i.dueDate = [2]*InvoiceCell{
|
||||||
|
i.newCell("Date", i.infoProps),
|
||||||
|
i.newCell("", i.infoProps),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoice totals fields.
|
||||||
|
i.subtotal = [2]*InvoiceCell{
|
||||||
|
i.newCell("Subtotal", i.totalProps),
|
||||||
|
i.newCell("", i.totalProps),
|
||||||
|
}
|
||||||
|
|
||||||
|
totalProps := i.totalProps
|
||||||
|
totalProps.TextStyle = headingStyle
|
||||||
|
totalProps.BackgroundColor = lightGrey
|
||||||
|
totalProps.BorderColor = lightGrey
|
||||||
|
|
||||||
|
i.total = [2]*InvoiceCell{
|
||||||
|
i.newCell("Total", totalProps),
|
||||||
|
i.newCell("", totalProps),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoice notes fields.
|
||||||
|
i.notes = [2]string{"Notes", ""}
|
||||||
|
i.terms = [2]string{"Terms and conditions", ""}
|
||||||
|
|
||||||
|
// Default item columns.
|
||||||
|
i.columns = []*InvoiceCell{
|
||||||
|
i.newColumn("Description", CellHorizontalAlignmentLeft),
|
||||||
|
i.newColumn("Quantity", CellHorizontalAlignmentRight),
|
||||||
|
i.newColumn("Unit price", CellHorizontalAlignmentRight),
|
||||||
|
i.newColumn("Amount", CellHorizontalAlignmentRight),
|
||||||
|
}
|
||||||
|
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Title returns the title of the invoice.
|
||||||
|
func (i *Invoice) Title() string {
|
||||||
|
return i.title
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTitle sets the title of the invoice.
|
||||||
|
func (i *Invoice) SetTitle(title string) {
|
||||||
|
i.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logo returns the logo of the invoice.
|
||||||
|
func (i *Invoice) Logo() *Image {
|
||||||
|
return i.logo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogo sets the logo of the invoice.
|
||||||
|
func (i *Invoice) SetLogo(logo *Image) {
|
||||||
|
i.logo = logo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SellerAddress returns the seller address used in the invoice template.
|
||||||
|
func (i *Invoice) SellerAddress() *InvoiceAddress {
|
||||||
|
return i.sellerAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSellerAddress sets the seller address of the invoice.
|
||||||
|
func (i *Invoice) SetSellerAddress(address *InvoiceAddress) {
|
||||||
|
i.sellerAddress = address
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuyerAddress returns the buyer address used in the invoice template.
|
||||||
|
func (i *Invoice) BuyerAddress() *InvoiceAddress {
|
||||||
|
return i.buyerAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBuyerAddress sets the buyer address of the invoice.
|
||||||
|
func (i *Invoice) SetBuyerAddress(address *InvoiceAddress) {
|
||||||
|
i.buyerAddress = address
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number returns the invoice number description and value cells.
|
||||||
|
// The returned values can be used to customize the styles of the cells.
|
||||||
|
func (i *Invoice) Number() (*InvoiceCell, *InvoiceCell) {
|
||||||
|
return i.number[0], i.number[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNumber sets the number of the invoice.
|
||||||
|
func (i *Invoice) SetNumber(number string) (*InvoiceCell, *InvoiceCell) {
|
||||||
|
i.number[1].Value = number
|
||||||
|
return i.number[0], i.number[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date returns the invoice date description and value cells.
|
||||||
|
// The returned values can be used to customize the styles of the cells.
|
||||||
|
func (i *Invoice) Date() (*InvoiceCell, *InvoiceCell) {
|
||||||
|
return i.date[0], i.date[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDate sets the date of the invoice.
|
||||||
|
func (i *Invoice) SetDate(date string) (*InvoiceCell, *InvoiceCell) {
|
||||||
|
i.date[1].Value = date
|
||||||
|
return i.date[0], i.date[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// DueDate returns the invoice due date description and value cells.
|
||||||
|
// The returned values can be used to customize the styles of the cells.
|
||||||
|
func (i *Invoice) DueDate() (*InvoiceCell, *InvoiceCell) {
|
||||||
|
return i.dueDate[0], i.dueDate[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDueDate sets the due date of the invoice.
|
||||||
|
func (i *Invoice) SetDueDate(dueDate string) (*InvoiceCell, *InvoiceCell) {
|
||||||
|
i.dueDate[1].Value = dueDate
|
||||||
|
return i.dueDate[0], i.dueDate[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// InfoLines returns all the rows in the invoice information table as
|
||||||
|
// description-value cell pairs.
|
||||||
|
func (i *Invoice) InfoLines() [][2]*InvoiceCell {
|
||||||
|
info := [][2]*InvoiceCell{
|
||||||
|
i.number,
|
||||||
|
i.date,
|
||||||
|
i.dueDate,
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(info, i.info...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInfo is used to append a piece of invoice information in the template
|
||||||
|
// information table.
|
||||||
|
func (i *Invoice) AddInfo(description, value string) (*InvoiceCell, *InvoiceCell) {
|
||||||
|
info := [2]*InvoiceCell{
|
||||||
|
i.newCell(description, i.infoProps),
|
||||||
|
i.newCell(value, i.infoProps),
|
||||||
|
}
|
||||||
|
|
||||||
|
i.info = append(i.info, info)
|
||||||
|
return info[0], info[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns returns all the columns in the invoice line items table.
|
||||||
|
func (i *Invoice) Columns() []*InvoiceCell {
|
||||||
|
return i.columns
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendColumn appends a column to the line items table.
|
||||||
|
func (i *Invoice) AppendColumn(description string) *InvoiceCell {
|
||||||
|
col := i.NewColumn(description)
|
||||||
|
i.columns = append(i.columns, col)
|
||||||
|
return col
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertColumn inserts a column in the line items table at the specified index.
|
||||||
|
func (i *Invoice) InsertColumn(index uint, description string) *InvoiceCell {
|
||||||
|
l := uint(len(i.columns))
|
||||||
|
if index > l {
|
||||||
|
index = l
|
||||||
|
}
|
||||||
|
|
||||||
|
col := i.NewColumn(description)
|
||||||
|
i.columns = append(i.columns[:index], append([]*InvoiceCell{col}, i.columns[index:]...)...)
|
||||||
|
return col
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lines returns all the rows of the invoice line items table.
|
||||||
|
func (i *Invoice) Lines() [][]*InvoiceCell {
|
||||||
|
return i.lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLine appends a new line to the invoice line items table.
|
||||||
|
func (i *Invoice) AddLine(values ...string) []*InvoiceCell {
|
||||||
|
lenCols := len(i.columns)
|
||||||
|
|
||||||
|
var line []*InvoiceCell
|
||||||
|
for j, value := range values {
|
||||||
|
itemCell := i.newCell(value, i.itemProps)
|
||||||
|
if j < lenCols {
|
||||||
|
itemCell.Alignment = i.columns[j].Alignment
|
||||||
|
}
|
||||||
|
|
||||||
|
line = append(line, itemCell)
|
||||||
|
}
|
||||||
|
|
||||||
|
i.lines = append(i.lines, line)
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtotal returns the invoice subtotal description and value cells.
|
||||||
|
// The returned values can be used to customize the styles of the cells.
|
||||||
|
func (i *Invoice) Subtotal() (*InvoiceCell, *InvoiceCell) {
|
||||||
|
return i.subtotal[0], i.subtotal[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSubtotal sets the subtotal of the invoice.
|
||||||
|
func (i *Invoice) SetSubtotal(value string) {
|
||||||
|
i.subtotal[1].Value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total returns the invoice total description and value cells.
|
||||||
|
// The returned values can be used to customize the styles of the cells.
|
||||||
|
func (i *Invoice) Total() (*InvoiceCell, *InvoiceCell) {
|
||||||
|
return i.total[0], i.total[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTotal sets the total of the invoice.
|
||||||
|
func (i *Invoice) SetTotal(value string) {
|
||||||
|
i.total[1].Value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalLines returns all the rows in the invoice totals table as
|
||||||
|
// description-value cell pairs.
|
||||||
|
func (i *Invoice) TotalLines() [][2]*InvoiceCell {
|
||||||
|
totals := [][2]*InvoiceCell{i.subtotal}
|
||||||
|
totals = append(totals, i.totals...)
|
||||||
|
return append(totals, i.total)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTotalLine adds a new line in the invoice totals table.
|
||||||
|
func (i *Invoice) AddTotalLine(desc, value string) (*InvoiceCell, *InvoiceCell) {
|
||||||
|
descCell := &InvoiceCell{
|
||||||
|
i.totalProps,
|
||||||
|
desc,
|
||||||
|
}
|
||||||
|
valueCell := &InvoiceCell{
|
||||||
|
i.totalProps,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
|
||||||
|
i.totals = append(i.totals, [2]*InvoiceCell{descCell, valueCell})
|
||||||
|
return descCell, valueCell
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notes returns the notes section of the invoice as a title-content pair.
|
||||||
|
func (i *Invoice) Notes() (string, string) {
|
||||||
|
return i.notes[0], i.notes[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNotes sets the notes section of the invoice.
|
||||||
|
func (i *Invoice) SetNotes(title, content string) {
|
||||||
|
i.notes = [2]string{
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terms returns the terms and conditions section of the invoice as a
|
||||||
|
// title-content pair.
|
||||||
|
func (i *Invoice) Terms() (string, string) {
|
||||||
|
return i.terms[0], i.terms[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTerms sets the terms and conditions section of the invoice.
|
||||||
|
func (i *Invoice) SetTerms(title, content string) {
|
||||||
|
i.terms = [2]string{
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sections returns the custom content sections of the invoice as
|
||||||
|
// title-content pairs.
|
||||||
|
func (i *Invoice) Sections() [][2]string {
|
||||||
|
return i.sections
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSection adds a new content section at the end of the invoice.
|
||||||
|
func (i *Invoice) AddSection(title, content string) {
|
||||||
|
i.sections = append(i.sections, [2]string{
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TitleStyle returns the style properties used to render the invoice title.
|
||||||
|
func (i *Invoice) TitleStyle() TextStyle {
|
||||||
|
return i.titleStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTitleStyle sets the style properties of the invoice title.
|
||||||
|
func (i *Invoice) SetTitleStyle(style TextStyle) {
|
||||||
|
i.titleStyle = style
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddressStyle returns the style properties used to render the content of
|
||||||
|
// the invoice address sections.
|
||||||
|
func (i *Invoice) AddressStyle() TextStyle {
|
||||||
|
return i.addressStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAddressStyle sets the style properties used to render the content of
|
||||||
|
// the invoice address sections.
|
||||||
|
func (i *Invoice) SetAddressStyle(style TextStyle) {
|
||||||
|
i.addressStyle = style
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddressHeadingStyle returns the style properties used to render the
|
||||||
|
// heading of the invoice address sections.
|
||||||
|
func (i *Invoice) AddressHeadingStyle() TextStyle {
|
||||||
|
return i.headingStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAddressHeadingStyle sets the style properties used to render the
|
||||||
|
// heading of the invoice address sections.
|
||||||
|
func (i *Invoice) SetAddressHeadingStyle(style TextStyle) {
|
||||||
|
i.addressHeadingStyle = style
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoteStyle returns the style properties used to render the content of the
|
||||||
|
// invoice note sections.
|
||||||
|
func (i *Invoice) NoteStyle() TextStyle {
|
||||||
|
return i.noteStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNoteStyle sets the style properties used to render the content of the
|
||||||
|
// invoice note sections.
|
||||||
|
func (i *Invoice) SetNoteStyle(style TextStyle) {
|
||||||
|
i.noteStyle = style
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoteHeadingStyle returns the style properties used to render the heading of
|
||||||
|
// the invoice note sections.
|
||||||
|
func (i *Invoice) NoteHeadingStyle() TextStyle {
|
||||||
|
return i.noteHeadingStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNoteHeadingStyle sets the style properties used to render the heading
|
||||||
|
// of the invoice note sections.
|
||||||
|
func (i *Invoice) SetNoteHeadingStyle(style TextStyle) {
|
||||||
|
i.noteHeadingStyle = style
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCellProps returns the default properties of an invoice cell.
|
||||||
|
func (i *Invoice) NewCellProps() InvoiceCellProps {
|
||||||
|
white := ColorRGBFrom8bit(255, 255, 255)
|
||||||
|
|
||||||
|
return InvoiceCellProps{
|
||||||
|
TextStyle: i.defaultStyle,
|
||||||
|
Alignment: CellHorizontalAlignmentLeft,
|
||||||
|
BackgroundColor: white,
|
||||||
|
BorderColor: white,
|
||||||
|
BorderWidth: 1,
|
||||||
|
BorderSides: []CellBorderSide{CellBorderSideAll},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCell returns a new invoice table cell.
|
||||||
|
func (i *Invoice) NewCell(value string) *InvoiceCell {
|
||||||
|
return i.newCell(value, i.NewCellProps())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) newCell(value string, props InvoiceCellProps) *InvoiceCell {
|
||||||
|
return &InvoiceCell{
|
||||||
|
props,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewColumn returns a new column for the line items invoice table.
|
||||||
|
func (i *Invoice) NewColumn(description string) *InvoiceCell {
|
||||||
|
return i.newColumn(description, CellHorizontalAlignmentLeft)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) newColumn(description string, alignment CellHorizontalAlignment) *InvoiceCell {
|
||||||
|
col := &InvoiceCell{i.colProps, description}
|
||||||
|
col.Alignment = alignment
|
||||||
|
|
||||||
|
return col
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) setCellBorder(cell *TableCell, invoiceCell *InvoiceCell) {
|
||||||
|
for _, side := range invoiceCell.BorderSides {
|
||||||
|
cell.SetBorder(side, CellBorderStyleSingle, invoiceCell.BorderWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.SetBorderColor(invoiceCell.BorderColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) drawAddress(title, name string, addr *InvoiceAddress) []*StyledParagraph {
|
||||||
|
var paragraphs []*StyledParagraph
|
||||||
|
|
||||||
|
// Address title.
|
||||||
|
if title != "" {
|
||||||
|
titleParagraph := newStyledParagraph(i.addressHeadingStyle)
|
||||||
|
titleParagraph.SetMargins(0, 0, 0, 7)
|
||||||
|
titleParagraph.Append(title)
|
||||||
|
|
||||||
|
paragraphs = append(paragraphs, titleParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address information.
|
||||||
|
addressParagraph := newStyledParagraph(i.addressStyle)
|
||||||
|
addressParagraph.SetLineHeight(1.2)
|
||||||
|
|
||||||
|
city := addr.City
|
||||||
|
if addr.Zip != "" {
|
||||||
|
if city != "" {
|
||||||
|
city += ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
city += addr.Zip
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
addressParagraph.Append(addr.Name + "\n")
|
||||||
|
}
|
||||||
|
if addr.Street != "" {
|
||||||
|
addressParagraph.Append(addr.Street + "\n")
|
||||||
|
}
|
||||||
|
if city != "" {
|
||||||
|
addressParagraph.Append(city + "\n")
|
||||||
|
}
|
||||||
|
if addr.Country != "" {
|
||||||
|
addressParagraph.Append(addr.Country + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contact information.
|
||||||
|
contactParagraph := newStyledParagraph(i.addressStyle)
|
||||||
|
contactParagraph.SetLineHeight(1.2)
|
||||||
|
contactParagraph.SetMargins(0, 0, 7, 0)
|
||||||
|
|
||||||
|
if addr.Phone != "" {
|
||||||
|
contactParagraph.Append(fmt.Sprintf("Phone: %s\n", addr.Phone))
|
||||||
|
}
|
||||||
|
if addr.Email != "" {
|
||||||
|
contactParagraph.Append(fmt.Sprintf("Email: %s\n", addr.Email))
|
||||||
|
}
|
||||||
|
|
||||||
|
paragraphs = append(paragraphs, addressParagraph, contactParagraph)
|
||||||
|
return paragraphs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) drawSection(title, content string) []*StyledParagraph {
|
||||||
|
var paragraphs []*StyledParagraph
|
||||||
|
|
||||||
|
// Title paragraph.
|
||||||
|
if title != "" {
|
||||||
|
titleParagraph := newStyledParagraph(i.noteHeadingStyle)
|
||||||
|
titleParagraph.SetMargins(0, 0, 0, 5)
|
||||||
|
titleParagraph.Append(title)
|
||||||
|
|
||||||
|
paragraphs = append(paragraphs, titleParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content paragraph.
|
||||||
|
if content != "" {
|
||||||
|
contentParagraph := newStyledParagraph(i.noteStyle)
|
||||||
|
contentParagraph.Append(content)
|
||||||
|
|
||||||
|
paragraphs = append(paragraphs, contentParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
return paragraphs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) drawInformation() *Table {
|
||||||
|
table := newTable(2)
|
||||||
|
|
||||||
|
info := append([][2]*InvoiceCell{
|
||||||
|
i.number,
|
||||||
|
i.date,
|
||||||
|
i.dueDate,
|
||||||
|
}, i.info...)
|
||||||
|
|
||||||
|
for _, v := range info {
|
||||||
|
description, value := v[0], v[1]
|
||||||
|
if value.Value == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add description.
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetBackgroundColor(description.BackgroundColor)
|
||||||
|
i.setCellBorder(cell, description)
|
||||||
|
|
||||||
|
p := newStyledParagraph(description.TextStyle)
|
||||||
|
p.Append(description.Value)
|
||||||
|
p.SetMargins(0, 0, 2, 1)
|
||||||
|
cell.SetContent(p)
|
||||||
|
|
||||||
|
// Add value.
|
||||||
|
cell = table.NewCell()
|
||||||
|
cell.SetBackgroundColor(value.BackgroundColor)
|
||||||
|
i.setCellBorder(cell, value)
|
||||||
|
|
||||||
|
p = newStyledParagraph(value.TextStyle)
|
||||||
|
p.Append(value.Value)
|
||||||
|
p.SetMargins(0, 0, 2, 1)
|
||||||
|
cell.SetContent(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) drawTotals() *Table {
|
||||||
|
table := newTable(2)
|
||||||
|
|
||||||
|
totals := [][2]*InvoiceCell{i.subtotal}
|
||||||
|
totals = append(totals, i.totals...)
|
||||||
|
totals = append(totals, i.total)
|
||||||
|
|
||||||
|
for _, total := range totals {
|
||||||
|
description, value := total[0], total[1]
|
||||||
|
if value.Value == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add description.
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetBackgroundColor(description.BackgroundColor)
|
||||||
|
cell.SetHorizontalAlignment(value.Alignment)
|
||||||
|
i.setCellBorder(cell, description)
|
||||||
|
|
||||||
|
p := newStyledParagraph(description.TextStyle)
|
||||||
|
p.SetMargins(0, 0, 2, 1)
|
||||||
|
p.Append(description.Value)
|
||||||
|
cell.SetContent(p)
|
||||||
|
|
||||||
|
// Add value.
|
||||||
|
cell = table.NewCell()
|
||||||
|
cell.SetBackgroundColor(value.BackgroundColor)
|
||||||
|
cell.SetHorizontalAlignment(value.Alignment)
|
||||||
|
i.setCellBorder(cell, description)
|
||||||
|
|
||||||
|
p = newStyledParagraph(value.TextStyle)
|
||||||
|
p.SetMargins(0, 0, 2, 1)
|
||||||
|
p.Append(value.Value)
|
||||||
|
cell.SetContent(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateHeaderBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
// Create title paragraph.
|
||||||
|
titleParagraph := newStyledParagraph(i.titleStyle)
|
||||||
|
titleParagraph.SetEnableWrap(true)
|
||||||
|
titleParagraph.Append(i.title)
|
||||||
|
|
||||||
|
// Add invoice logo.
|
||||||
|
table := newTable(2)
|
||||||
|
|
||||||
|
if i.logo != nil {
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetHorizontalAlignment(CellHorizontalAlignmentLeft)
|
||||||
|
cell.SetVerticalAlignment(CellVerticalAlignmentMiddle)
|
||||||
|
cell.SetContent(i.logo)
|
||||||
|
|
||||||
|
i.logo.ScaleToHeight(titleParagraph.Height() + 20)
|
||||||
|
} else {
|
||||||
|
table.SkipCells(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add invoice title.
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetHorizontalAlignment(CellHorizontalAlignmentRight)
|
||||||
|
cell.SetVerticalAlignment(CellVerticalAlignmentMiddle)
|
||||||
|
cell.SetContent(titleParagraph)
|
||||||
|
|
||||||
|
// Generate blocks.
|
||||||
|
return table.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateInformationBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
// Draw addresses.
|
||||||
|
separatorParagraph := newStyledParagraph(i.defaultStyle)
|
||||||
|
separatorParagraph.SetMargins(0, 0, 0, 20)
|
||||||
|
|
||||||
|
addrParagraphs := i.drawAddress(i.sellerAddress.Name, "", i.sellerAddress)
|
||||||
|
addrParagraphs = append(addrParagraphs, separatorParagraph)
|
||||||
|
addrParagraphs = append(addrParagraphs,
|
||||||
|
i.drawAddress("Bill to", i.buyerAddress.Name, i.buyerAddress)...)
|
||||||
|
|
||||||
|
addrDivision := newDivision()
|
||||||
|
for _, addrParagraph := range addrParagraphs {
|
||||||
|
addrDivision.Add(addrParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw invoice information.
|
||||||
|
information := i.drawInformation()
|
||||||
|
|
||||||
|
// Generate blocks.
|
||||||
|
table := newTable(2)
|
||||||
|
table.SetMargins(0, 0, 25, 0)
|
||||||
|
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetContent(addrDivision)
|
||||||
|
|
||||||
|
cell = table.NewCell()
|
||||||
|
cell.SetContent(information)
|
||||||
|
|
||||||
|
return table.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateLineBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
table := newTable(len(i.columns))
|
||||||
|
table.SetMargins(0, 0, 25, 0)
|
||||||
|
|
||||||
|
// Draw item columns.
|
||||||
|
for _, col := range i.columns {
|
||||||
|
paragraph := newStyledParagraph(col.TextStyle)
|
||||||
|
paragraph.SetMargins(0, 0, 1, 0)
|
||||||
|
paragraph.Append(col.Value)
|
||||||
|
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetHorizontalAlignment(col.Alignment)
|
||||||
|
cell.SetBackgroundColor(col.BackgroundColor)
|
||||||
|
i.setCellBorder(cell, col)
|
||||||
|
cell.SetContent(paragraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw item lines.
|
||||||
|
for _, line := range i.lines {
|
||||||
|
for _, itemCell := range line {
|
||||||
|
paragraph := newStyledParagraph(itemCell.TextStyle)
|
||||||
|
paragraph.SetMargins(0, 0, 3, 2)
|
||||||
|
paragraph.Append(itemCell.Value)
|
||||||
|
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetHorizontalAlignment(itemCell.Alignment)
|
||||||
|
cell.SetBackgroundColor(itemCell.BackgroundColor)
|
||||||
|
i.setCellBorder(cell, itemCell)
|
||||||
|
cell.SetContent(paragraph)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return table.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateTotalBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
table := newTable(2)
|
||||||
|
table.SetMargins(0, 0, 5, 40)
|
||||||
|
table.SkipCells(1)
|
||||||
|
|
||||||
|
totalsTable := i.drawTotals()
|
||||||
|
totalsTable.SetMargins(0, 0, 5, 0)
|
||||||
|
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetContent(totalsTable)
|
||||||
|
|
||||||
|
return table.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateNoteBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
division := newDivision()
|
||||||
|
|
||||||
|
sections := append([][2]string{
|
||||||
|
i.notes,
|
||||||
|
i.terms,
|
||||||
|
}, i.sections...)
|
||||||
|
|
||||||
|
for _, section := range sections {
|
||||||
|
if section[1] != "" {
|
||||||
|
paragraphs := i.drawSection(section[0], section[1])
|
||||||
|
for _, paragraph := range paragraphs {
|
||||||
|
division.Add(paragraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
sepParagraph := newStyledParagraph(i.defaultStyle)
|
||||||
|
sepParagraph.SetMargins(0, 0, 10, 0)
|
||||||
|
division.Add(sepParagraph)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return division.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated
|
||||||
|
// if the contents wrap over multiple pages.
|
||||||
|
func (i *Invoice) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
origCtx := ctx
|
||||||
|
|
||||||
|
blockFuncs := []func(ctx DrawContext) ([]*Block, DrawContext, error){
|
||||||
|
i.generateHeaderBlocks,
|
||||||
|
i.generateInformationBlocks,
|
||||||
|
i.generateLineBlocks,
|
||||||
|
i.generateTotalBlocks,
|
||||||
|
i.generateNoteBlocks,
|
||||||
|
}
|
||||||
|
|
||||||
|
var blocks []*Block
|
||||||
|
for _, blockFunc := range blockFuncs {
|
||||||
|
newBlocks, c, err := blockFunc(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return blocks, ctx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(blocks) == 0 {
|
||||||
|
blocks = newBlocks
|
||||||
|
} else if len(newBlocks) > 0 {
|
||||||
|
blocks[len(blocks)-1].mergeBlocks(newBlocks[0])
|
||||||
|
blocks = append(blocks, newBlocks[1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = c
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.positioning.isRelative() {
|
||||||
|
// Move back X to same start of line.
|
||||||
|
ctx.X = origCtx.X
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.positioning.isAbsolute() {
|
||||||
|
// If absolute: return original context.
|
||||||
|
return blocks, origCtx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks, ctx, nil
|
||||||
|
}
|
227
pdf/creator/invoice_test.go
Normal file
227
pdf/creator/invoice_test.go
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
package creator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInvoiceSimple(t *testing.T) {
|
||||||
|
c := New()
|
||||||
|
c.NewPage()
|
||||||
|
|
||||||
|
logo, err := c.NewImageFromFile(testImageFile1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Fail: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
invoice := c.NewInvoice()
|
||||||
|
|
||||||
|
// 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(&InvoiceAddress{
|
||||||
|
Name: "John Doe",
|
||||||
|
Street: "8 Elm Street",
|
||||||
|
City: "Cambridge",
|
||||||
|
Zip: "CB14DH",
|
||||||
|
Country: "United Kingdom",
|
||||||
|
Phone: "xxx-xxx-xxxx",
|
||||||
|
Email: "johndoe@email.com",
|
||||||
|
})
|
||||||
|
|
||||||
|
invoice.SetBuyerAddress(&InvoiceAddress{
|
||||||
|
Name: "Jane Doe",
|
||||||
|
Street: "9 Elm Street",
|
||||||
|
City: "London",
|
||||||
|
Zip: "LB15FH",
|
||||||
|
Country: "United Kingdom",
|
||||||
|
Phone: "xxx-xxx-xxxx",
|
||||||
|
Email: "janedoe@email.com",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add invoice line items.
|
||||||
|
for i := 0; i < 10; 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.")
|
||||||
|
|
||||||
|
if err = c.Draw(invoice); err != nil {
|
||||||
|
t.Fatalf("Error drawing: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write output file.
|
||||||
|
err = c.WriteToFile("/tmp/invoice_simple.pdf")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Fail: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvoiceAdvanced(t *testing.T) {
|
||||||
|
fontHelvetica := model.NewStandard14FontMustCompile(model.Helvetica)
|
||||||
|
|
||||||
|
c := New()
|
||||||
|
c.NewPage()
|
||||||
|
|
||||||
|
logo, err := c.NewImageFromFile(testImageFile1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Fail: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
white := ColorRGBFrom8bit(255, 255, 255)
|
||||||
|
lightBlue := ColorRGBFrom8bit(217, 240, 250)
|
||||||
|
blue := ColorRGBFrom8bit(2, 136, 209)
|
||||||
|
|
||||||
|
invoice := c.NewInvoice()
|
||||||
|
|
||||||
|
// Set invoice title.
|
||||||
|
invoice.SetTitle("Unidoc Invoice")
|
||||||
|
|
||||||
|
// Customize invoice title style.
|
||||||
|
titleStyle := invoice.TitleStyle()
|
||||||
|
titleStyle.Color = blue
|
||||||
|
titleStyle.Font = fontHelvetica
|
||||||
|
titleStyle.FontSize = 30
|
||||||
|
|
||||||
|
invoice.SetTitleStyle(titleStyle)
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
|
||||||
|
// Customize invoice information styles.
|
||||||
|
for _, info := range invoice.InfoLines() {
|
||||||
|
descCell, contentCell := info[0], info[1]
|
||||||
|
descCell.BackgroundColor = lightBlue
|
||||||
|
contentCell.TextStyle.Font = fontHelvetica
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set invoice addresses.
|
||||||
|
invoice.SetSellerAddress(&InvoiceAddress{
|
||||||
|
Name: "John Doe",
|
||||||
|
Street: "8 Elm Street",
|
||||||
|
City: "Cambridge",
|
||||||
|
Zip: "CB14DH",
|
||||||
|
Country: "United Kingdom",
|
||||||
|
Phone: "xxx-xxx-xxxx",
|
||||||
|
Email: "johndoe@email.com",
|
||||||
|
})
|
||||||
|
|
||||||
|
invoice.SetBuyerAddress(&InvoiceAddress{
|
||||||
|
Name: "Jane Doe",
|
||||||
|
Street: "9 Elm Street",
|
||||||
|
City: "London",
|
||||||
|
Zip: "LB15FH",
|
||||||
|
Country: "United Kingdom",
|
||||||
|
Phone: "xxx-xxx-xxxx",
|
||||||
|
Email: "janedoe@email.com",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Customize address styles.
|
||||||
|
addressStyle := invoice.AddressStyle()
|
||||||
|
addressStyle.Font = fontHelvetica
|
||||||
|
addressStyle.FontSize = 9
|
||||||
|
|
||||||
|
addressHeadingStyle := invoice.AddressHeadingStyle()
|
||||||
|
addressHeadingStyle.Color = blue
|
||||||
|
addressHeadingStyle.Font = fontHelvetica
|
||||||
|
addressHeadingStyle.FontSize = 16
|
||||||
|
|
||||||
|
invoice.SetAddressStyle(addressStyle)
|
||||||
|
invoice.SetAddressHeadingStyle(addressHeadingStyle)
|
||||||
|
|
||||||
|
// Insert new column.
|
||||||
|
col := invoice.InsertColumn(2, "Discount")
|
||||||
|
col.Alignment = CellHorizontalAlignmentRight
|
||||||
|
|
||||||
|
// Customize column styles.
|
||||||
|
for _, column := range invoice.Columns() {
|
||||||
|
column.BackgroundColor = lightBlue
|
||||||
|
column.BorderColor = lightBlue
|
||||||
|
column.TextStyle.FontSize = 9
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 7; i++ {
|
||||||
|
cells := invoice.AddLine(
|
||||||
|
fmt.Sprintf("Test product #%d", i+1),
|
||||||
|
"1",
|
||||||
|
"0%",
|
||||||
|
"$10",
|
||||||
|
"$10",
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, cell := range cells {
|
||||||
|
cell.BorderColor = white
|
||||||
|
cell.TextStyle.FontSize = 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customize total line styles.
|
||||||
|
titleCell, contentCell := invoice.Total()
|
||||||
|
titleCell.BackgroundColor = lightBlue
|
||||||
|
titleCell.BorderColor = lightBlue
|
||||||
|
contentCell.BackgroundColor = lightBlue
|
||||||
|
contentCell.BorderColor = lightBlue
|
||||||
|
|
||||||
|
invoice.SetSubtotal("$100.00")
|
||||||
|
invoice.AddTotalLine("Tax (10%)", "$10.00")
|
||||||
|
invoice.AddTotalLine("Shipping", "$5.00")
|
||||||
|
invoice.SetTotal("$85.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.")
|
||||||
|
invoice.AddSection("Custom section", "This is a custom section.")
|
||||||
|
|
||||||
|
// Customize note styles.
|
||||||
|
noteStyle := invoice.AddressStyle()
|
||||||
|
noteStyle.Font = fontHelvetica
|
||||||
|
noteStyle.FontSize = 12
|
||||||
|
|
||||||
|
noteHeadingStyle := invoice.AddressHeadingStyle()
|
||||||
|
noteHeadingStyle.Color = blue
|
||||||
|
noteHeadingStyle.Font = fontHelvetica
|
||||||
|
noteHeadingStyle.FontSize = 14
|
||||||
|
|
||||||
|
invoice.SetNoteStyle(noteStyle)
|
||||||
|
invoice.SetNoteHeadingStyle(noteHeadingStyle)
|
||||||
|
|
||||||
|
if err = c.Draw(invoice); err != nil {
|
||||||
|
t.Fatalf("Error drawing: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write output file.
|
||||||
|
err = c.WriteToFile("/tmp/invoice_advanced.pdf")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Fail: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
@ -119,6 +119,12 @@ func (p *StyledParagraph) Reset() {
|
|||||||
p.chunks = []*TextChunk{}
|
p.chunks = []*TextChunk{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetText replaces all the text of the paragraph with the specified one.
|
||||||
|
func (p *StyledParagraph) SetText(text string) *TextChunk {
|
||||||
|
p.Reset()
|
||||||
|
return p.Append(text)
|
||||||
|
}
|
||||||
|
|
||||||
// SetTextAlignment sets the horizontal alignment of the text within the space provided.
|
// SetTextAlignment sets the horizontal alignment of the text within the space provided.
|
||||||
func (p *StyledParagraph) SetTextAlignment(align TextAlignment) {
|
func (p *StyledParagraph) SetTextAlignment(align TextAlignment) {
|
||||||
p.alignment = align
|
p.alignment = align
|
||||||
|
@ -97,6 +97,12 @@ func (table *Table) Height() float64 {
|
|||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Width is not used. Not used as a Table element is designed to fill into
|
||||||
|
// available width depending on the context. Returns 0.
|
||||||
|
func (table *Table) Width() float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// SetMargins sets the Table's left, right, top, bottom margins.
|
// SetMargins sets the Table's left, right, top, bottom margins.
|
||||||
func (table *Table) SetMargins(left, right, top, bottom float64) {
|
func (table *Table) SetMargins(left, right, top, bottom float64) {
|
||||||
table.margins.left = left
|
table.margins.left = left
|
||||||
@ -235,6 +241,14 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
// Add diff to last row.
|
// Add diff to last row.
|
||||||
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
||||||
}
|
}
|
||||||
|
case *Table:
|
||||||
|
tbl := t
|
||||||
|
newh := tbl.Height() + tbl.margins.top + tbl.margins.bottom
|
||||||
|
if newh > h {
|
||||||
|
diffh := newh - h
|
||||||
|
// Add diff to last row.
|
||||||
|
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
||||||
|
}
|
||||||
case *Division:
|
case *Division:
|
||||||
div := t
|
div := t
|
||||||
|
|
||||||
@ -373,6 +387,8 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
if t.enableWrap {
|
if t.enableWrap {
|
||||||
cw = t.getMaxLineWidth() / 1000.0
|
cw = t.getMaxLineWidth() / 1000.0
|
||||||
}
|
}
|
||||||
|
case *Table:
|
||||||
|
cw = w
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account for horizontal alignment:
|
// Account for horizontal alignment:
|
||||||
@ -724,6 +740,8 @@ func (cell *TableCell) SetContent(vd VectorDrawable) error {
|
|||||||
cell.content = vd
|
cell.content = vd
|
||||||
case *Image:
|
case *Image:
|
||||||
cell.content = vd
|
cell.content = vd
|
||||||
|
case *Table:
|
||||||
|
cell.content = vd
|
||||||
case *Division:
|
case *Division:
|
||||||
cell.content = vd
|
cell.content = vd
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user