mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-02 22:17:06 +08:00
Add totals and notes sections
This commit is contained in:
parent
b98f1fe6ce
commit
e7a6b1825f
@ -51,6 +51,7 @@ type Invoice struct {
|
|||||||
infoValProps InvoiceCellProps
|
infoValProps InvoiceCellProps
|
||||||
colProps InvoiceCellProps
|
colProps InvoiceCellProps
|
||||||
itemProps InvoiceCellProps
|
itemProps InvoiceCellProps
|
||||||
|
totalProps InvoiceCellProps
|
||||||
|
|
||||||
// The title of the invoice.
|
// The title of the invoice.
|
||||||
title string
|
title string
|
||||||
@ -79,7 +80,13 @@ type Invoice struct {
|
|||||||
lines [][]*InvoiceCell
|
lines [][]*InvoiceCell
|
||||||
|
|
||||||
// Invoice totals.
|
// Invoice totals.
|
||||||
totals [][2]*InvoiceCell
|
subtotal *InvoiceCell
|
||||||
|
total *InvoiceCell
|
||||||
|
totals [][2]*InvoiceCell
|
||||||
|
|
||||||
|
// Invoice notes.
|
||||||
|
notes string
|
||||||
|
terms string
|
||||||
|
|
||||||
// Positioning: relative/absolute.
|
// Positioning: relative/absolute.
|
||||||
positioning positioning
|
positioning positioning
|
||||||
@ -121,9 +128,23 @@ func newInvoice(defaultStyle, headingStyle TextStyle) *Invoice {
|
|||||||
|
|
||||||
i.colProps = i.newCellProps()
|
i.colProps = i.newCellProps()
|
||||||
i.colProps.BackgroundColor = lightBlue
|
i.colProps.BackgroundColor = lightBlue
|
||||||
|
i.colProps.BorderColor = lightBlue
|
||||||
i.colProps.Style = headingStyle
|
i.colProps.Style = headingStyle
|
||||||
|
|
||||||
i.itemProps = i.newCellProps()
|
i.itemProps = i.newCellProps()
|
||||||
|
i.itemProps.Alignment = CellHorizontalAlignmentRight
|
||||||
|
|
||||||
|
i.totalProps = i.newCellProps()
|
||||||
|
i.totalProps.Alignment = CellHorizontalAlignmentRight
|
||||||
|
|
||||||
|
i.subtotal = i.NewCell("")
|
||||||
|
i.subtotal.Alignment = CellHorizontalAlignmentRight
|
||||||
|
|
||||||
|
i.total = i.NewCell("")
|
||||||
|
i.total.BackgroundColor = lightBlue
|
||||||
|
i.total.Style = headingStyle
|
||||||
|
i.total.Alignment = CellHorizontalAlignmentRight
|
||||||
|
i.total.BorderColor = lightBlue
|
||||||
|
|
||||||
// Default item columns.
|
// Default item columns.
|
||||||
quantityCol := i.NewColumn("Quantity")
|
quantityCol := i.NewColumn("Quantity")
|
||||||
@ -244,16 +265,56 @@ func (i *Invoice) AddLine(values ...string) {
|
|||||||
i.lines = append(i.lines, line)
|
i.lines = append(i.lines, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Invoice) AddSubtotal(value string) *InvoiceCell {
|
func (i *Invoice) Subtotal() *InvoiceCell {
|
||||||
return nil
|
return i.subtotal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Invoice) AddTotal(value string) *InvoiceCell {
|
func (i *Invoice) SetSubtotal(value string) *InvoiceCell {
|
||||||
return nil
|
i.subtotal.Value = value
|
||||||
|
return i.subtotal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Invoice) AddTotalsLine(desc, value string) *InvoiceCell {
|
func (i *Invoice) Total() *InvoiceCell {
|
||||||
return nil
|
return i.total
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) SetTotal(value string) *InvoiceCell {
|
||||||
|
i.total.Value = value
|
||||||
|
return i.total
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) TotalLines() [][2]*InvoiceCell {
|
||||||
|
return i.totals
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) Notes() string {
|
||||||
|
return i.notes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) SetNotes(notes string) {
|
||||||
|
i.notes = notes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) Terms() string {
|
||||||
|
return i.terms
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) SetTerms(terms string) {
|
||||||
|
i.terms = terms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Invoice) NewCell(value string) *InvoiceCell {
|
func (i *Invoice) NewCell(value string) *InvoiceCell {
|
||||||
@ -324,6 +385,29 @@ func (i *Invoice) drawAddress(title, name string, addr *InvoiceAddress) []*Style
|
|||||||
return paragraphs
|
return paragraphs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) drawSection(title, content string) []*StyledParagraph {
|
||||||
|
var paragraphs []*StyledParagraph
|
||||||
|
|
||||||
|
// Title paragraph.
|
||||||
|
if title != "" {
|
||||||
|
titleParagraph := newStyledParagraph(i.headingStyle)
|
||||||
|
titleParagraph.SetMargins(0, 0, 0, 5)
|
||||||
|
titleParagraph.Append(title)
|
||||||
|
|
||||||
|
paragraphs = append(paragraphs, titleParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content paragraph.
|
||||||
|
if content != "" {
|
||||||
|
contentParagraph := newStyledParagraph(i.defaultStyle)
|
||||||
|
contentParagraph.Append(content)
|
||||||
|
|
||||||
|
paragraphs = append(paragraphs, contentParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
return paragraphs
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Invoice) drawInformation() *Table {
|
func (i *Invoice) drawInformation() *Table {
|
||||||
table := newTable(2)
|
table := newTable(2)
|
||||||
|
|
||||||
@ -367,6 +451,57 @@ func (i *Invoice) drawInformation() *Table {
|
|||||||
return table
|
return table
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) drawTotals() *Table {
|
||||||
|
table := newTable(2)
|
||||||
|
|
||||||
|
totals := [][2]*InvoiceCell{}
|
||||||
|
if i.subtotal.Value != "" {
|
||||||
|
subtotalDesc := *i.subtotal
|
||||||
|
subtotalDesc.Value = "Subtotal"
|
||||||
|
|
||||||
|
totals = append(totals, [2]*InvoiceCell{&subtotalDesc, i.subtotal})
|
||||||
|
}
|
||||||
|
|
||||||
|
totals = append(totals, i.totals...)
|
||||||
|
|
||||||
|
if i.total.Value != "" {
|
||||||
|
totalDesc := *i.total
|
||||||
|
totalDesc.Value = "Total"
|
||||||
|
|
||||||
|
totals = append(totals, [2]*InvoiceCell{&totalDesc, i.total})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, total := range totals {
|
||||||
|
description, value := total[0], total[1]
|
||||||
|
|
||||||
|
// Add description.
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetBackgroundColor(description.BackgroundColor)
|
||||||
|
cell.SetHorizontalAlignment(value.Alignment)
|
||||||
|
cell.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
cell.SetBorderColor(value.BorderColor)
|
||||||
|
|
||||||
|
p := newStyledParagraph(description.Style)
|
||||||
|
p.SetMargins(0, 0, 1, 1)
|
||||||
|
p.Append(description.Value)
|
||||||
|
cell.SetContent(p)
|
||||||
|
|
||||||
|
// Add value.
|
||||||
|
cell = table.NewCell()
|
||||||
|
cell.SetBackgroundColor(value.BackgroundColor)
|
||||||
|
cell.SetHorizontalAlignment(value.Alignment)
|
||||||
|
cell.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
cell.SetBorderColor(value.BorderColor)
|
||||||
|
|
||||||
|
p = newStyledParagraph(value.Style)
|
||||||
|
p.SetMargins(0, 0, 1, 1)
|
||||||
|
p.Append(value.Value)
|
||||||
|
cell.SetContent(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Invoice) generateHeaderBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
func (i *Invoice) generateHeaderBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
// Create title paragraph.
|
// Create title paragraph.
|
||||||
titleParagraph := newStyledParagraph(i.titleStyle)
|
titleParagraph := newStyledParagraph(i.titleStyle)
|
||||||
@ -435,6 +570,7 @@ func (i *Invoice) generateLineBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
|||||||
// Draw item columns
|
// Draw item columns
|
||||||
for _, col := range i.columns {
|
for _, col := range i.columns {
|
||||||
paragraph := newStyledParagraph(col.Style)
|
paragraph := newStyledParagraph(col.Style)
|
||||||
|
paragraph.SetMargins(0, 0, 1, 0)
|
||||||
paragraph.Append(col.Description)
|
paragraph.Append(col.Description)
|
||||||
|
|
||||||
cell := table.NewCell()
|
cell := table.NewCell()
|
||||||
@ -449,6 +585,7 @@ func (i *Invoice) generateLineBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
|||||||
for _, line := range i.lines {
|
for _, line := range i.lines {
|
||||||
for _, itemCell := range line {
|
for _, itemCell := range line {
|
||||||
paragraph := newStyledParagraph(itemCell.Style)
|
paragraph := newStyledParagraph(itemCell.Style)
|
||||||
|
paragraph.SetMargins(0, 0, 1, 0)
|
||||||
paragraph.Append(itemCell.Value)
|
paragraph.Append(itemCell.Value)
|
||||||
|
|
||||||
cell := table.NewCell()
|
cell := table.NewCell()
|
||||||
@ -463,37 +600,83 @@ func (i *Invoice) generateLineBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
|||||||
return table.GeneratePageBlocks(ctx)
|
return table.GeneratePageBlocks(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateTotalBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
table := newTable(2)
|
||||||
|
table.SetMargins(0, 0, 5, 35)
|
||||||
|
|
||||||
|
mediumGrey := ColorRGBFrom8bit(195, 195, 195)
|
||||||
|
|
||||||
|
cell := table.NewCell()
|
||||||
|
cell.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 1)
|
||||||
|
cell.SetBorderColor(mediumGrey)
|
||||||
|
|
||||||
|
if i.notes != "" {
|
||||||
|
noteParagraphs := i.drawSection("Notes", i.notes)
|
||||||
|
|
||||||
|
noteDivision := newDivision()
|
||||||
|
for _, noteParagraph := range noteParagraphs {
|
||||||
|
noteParagraph.SetMargins(0, 0, 5, 0)
|
||||||
|
noteDivision.Add(noteParagraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.SetContent(noteDivision)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalsTable := i.drawTotals()
|
||||||
|
totalsTable.SetMargins(0, 0, 5, 0)
|
||||||
|
|
||||||
|
cell = table.NewCell()
|
||||||
|
cell.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 1)
|
||||||
|
cell.SetBorderColor(mediumGrey)
|
||||||
|
cell.SetContent(totalsTable)
|
||||||
|
|
||||||
|
return table.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Invoice) generateNoteBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
|
division := newDivision()
|
||||||
|
|
||||||
|
if i.terms != "" {
|
||||||
|
termParagraphs := i.drawSection("Terms and conditions", i.terms)
|
||||||
|
for _, termParagraph := range termParagraphs {
|
||||||
|
termParagraph.SetMargins(0, 0, 5, 0)
|
||||||
|
division.Add(termParagraph)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return division.GeneratePageBlocks(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated
|
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated
|
||||||
// if the contents wrap over multiple pages.
|
// if the contents wrap over multiple pages.
|
||||||
func (i *Invoice) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
func (i *Invoice) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
origCtx := ctx
|
origCtx := ctx
|
||||||
|
|
||||||
// Generate title blocks.
|
blockFuncs := []func(ctx DrawContext) ([]*Block, DrawContext, error){
|
||||||
blocks, ctx, err := i.generateHeaderBlocks(ctx)
|
i.generateHeaderBlocks,
|
||||||
if err != nil {
|
i.generateInformationBlocks,
|
||||||
return blocks, ctx, err
|
i.generateLineBlocks,
|
||||||
|
i.generateTotalBlocks,
|
||||||
|
i.generateNoteBlocks,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate address and information blocks.
|
var blocks []*Block
|
||||||
newBlocks, c, err := i.generateInformationBlocks(ctx)
|
for _, blockFunc := range blockFuncs {
|
||||||
if err != nil {
|
newBlocks, c, err := blockFunc(ctx)
|
||||||
return blocks, ctx, err
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks[len(blocks)-1].mergeBlocks(newBlocks[0])
|
|
||||||
blocks = append(blocks, newBlocks[1:]...)
|
|
||||||
ctx = c
|
|
||||||
|
|
||||||
// Generate line items blocks.
|
|
||||||
newBlocks, c, err = i.generateLineBlocks(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return blocks, ctx, err
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks[len(blocks)-1].mergeBlocks(newBlocks[0])
|
|
||||||
blocks = append(blocks, newBlocks[1:]...)
|
|
||||||
ctx = c
|
|
||||||
|
|
||||||
if i.positioning.isRelative() {
|
if i.positioning.isRelative() {
|
||||||
// Move back X to same start of line.
|
// Move back X to same start of line.
|
||||||
ctx.X = origCtx.X
|
ctx.X = origCtx.X
|
||||||
@ -502,7 +685,6 @@ func (i *Invoice) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
|||||||
if i.positioning.isAbsolute() {
|
if i.positioning.isAbsolute() {
|
||||||
// If absolute: return original context.
|
// If absolute: return original context.
|
||||||
return blocks, origCtx, nil
|
return blocks, origCtx, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks, ctx, nil
|
return blocks, ctx, nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user