2026-01-25 05:30:43 -08:00
|
|
|
package documents
|
2026-01-21 05:14:27 -08:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"html/template"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strconv"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// PurchaseOrderLineItemTemplateData represents a PO line item for template rendering
|
|
|
|
|
type PurchaseOrderLineItemTemplateData struct {
|
|
|
|
|
Title string
|
|
|
|
|
Description template.HTML
|
|
|
|
|
Quantity string
|
|
|
|
|
UnitPrice float64
|
2026-01-25 05:30:43 -08:00
|
|
|
Discount float64
|
2026-01-21 05:14:27 -08:00
|
|
|
TotalPrice float64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BuildPurchaseOrderHTML generates the complete HTML for a purchase order using templates
|
|
|
|
|
func (g *HTMLDocumentGenerator) BuildPurchaseOrderHTML(data *PurchaseOrderPDFData, totalPages int, currentPage int) string {
|
|
|
|
|
poNumber := data.PurchaseOrder.Title
|
|
|
|
|
|
|
|
|
|
// Calculate totals
|
|
|
|
|
subtotal := 0.0
|
|
|
|
|
lineItemsData := []PurchaseOrderLineItemTemplateData{}
|
|
|
|
|
|
|
|
|
|
for _, item := range data.LineItems {
|
|
|
|
|
unitPrice := 0.0
|
|
|
|
|
totalPrice := 0.0
|
2026-01-25 05:30:43 -08:00
|
|
|
discount := 0.0
|
2026-01-21 05:14:27 -08:00
|
|
|
|
|
|
|
|
if item.NetUnitPrice.Valid {
|
|
|
|
|
unitPrice, _ = strconv.ParseFloat(item.NetUnitPrice.String, 64)
|
|
|
|
|
}
|
|
|
|
|
if item.NetPrice.Valid {
|
|
|
|
|
totalPrice, _ = strconv.ParseFloat(item.NetPrice.String, 64)
|
|
|
|
|
subtotal += totalPrice
|
|
|
|
|
}
|
2026-01-25 05:30:43 -08:00
|
|
|
if item.DiscountAmountTotal.Valid {
|
|
|
|
|
discount, _ = strconv.ParseFloat(item.DiscountAmountTotal.String, 64)
|
|
|
|
|
}
|
2026-01-21 05:14:27 -08:00
|
|
|
|
|
|
|
|
lineItemsData = append(lineItemsData, PurchaseOrderLineItemTemplateData{
|
|
|
|
|
Title: item.Title,
|
|
|
|
|
Description: template.HTML(item.Description),
|
|
|
|
|
Quantity: item.Quantity,
|
|
|
|
|
UnitPrice: unitPrice,
|
2026-01-25 05:30:43 -08:00
|
|
|
Discount: discount,
|
2026-01-21 05:14:27 -08:00
|
|
|
TotalPrice: totalPrice,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gstAmount := 0.0
|
|
|
|
|
total := subtotal
|
|
|
|
|
if data.ShowGST {
|
|
|
|
|
gstAmount = subtotal * 0.1
|
|
|
|
|
total = subtotal + gstAmount
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prepare template data
|
|
|
|
|
templateData := struct {
|
|
|
|
|
PONumber string
|
|
|
|
|
PrincipleName string
|
2026-01-25 05:30:43 -08:00
|
|
|
YourReference template.HTML
|
2026-01-21 05:14:27 -08:00
|
|
|
IssueDateString string
|
2026-01-25 05:30:43 -08:00
|
|
|
OrderedFrom template.HTML
|
|
|
|
|
DeliverTo template.HTML
|
2026-01-21 05:14:27 -08:00
|
|
|
DispatchBy string
|
2026-01-25 05:30:43 -08:00
|
|
|
ShippingInstructions template.HTML
|
2026-01-21 05:14:27 -08:00
|
|
|
CurrencyCode string
|
|
|
|
|
CurrencySymbol string
|
|
|
|
|
LineItems []PurchaseOrderLineItemTemplateData
|
|
|
|
|
Subtotal float64
|
|
|
|
|
GSTAmount float64
|
|
|
|
|
Total float64
|
|
|
|
|
ShowGST bool
|
|
|
|
|
LogoDataURI string
|
|
|
|
|
}{
|
|
|
|
|
PONumber: poNumber,
|
|
|
|
|
PrincipleName: data.Principle.Name,
|
2026-01-25 05:30:43 -08:00
|
|
|
YourReference: template.HTML(data.PurchaseOrder.PrincipleReference),
|
2026-01-21 05:14:27 -08:00
|
|
|
IssueDateString: data.IssueDateString,
|
2026-01-25 05:30:43 -08:00
|
|
|
OrderedFrom: template.HTML(data.PurchaseOrder.OrderedFrom),
|
|
|
|
|
DeliverTo: template.HTML(data.PurchaseOrder.DeliverTo),
|
2026-01-21 05:14:27 -08:00
|
|
|
DispatchBy: data.PurchaseOrder.DispatchBy,
|
2026-01-25 05:30:43 -08:00
|
|
|
ShippingInstructions: template.HTML(data.PurchaseOrder.ShippingInstructions),
|
2026-01-21 05:14:27 -08:00
|
|
|
CurrencyCode: data.CurrencyCode,
|
|
|
|
|
CurrencySymbol: data.CurrencySymbol,
|
|
|
|
|
LineItems: lineItemsData,
|
|
|
|
|
Subtotal: subtotal,
|
|
|
|
|
GSTAmount: gstAmount,
|
|
|
|
|
Total: total,
|
|
|
|
|
ShowGST: data.ShowGST,
|
|
|
|
|
LogoDataURI: g.loadLogo("quote_logo.png"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Define template functions
|
|
|
|
|
funcMap := template.FuncMap{
|
|
|
|
|
"formatPrice": func(price float64) template.HTML {
|
|
|
|
|
formatted := FormatPriceWithCommas(fmt.Sprintf("%.2f", price))
|
|
|
|
|
return template.HTML(fmt.Sprintf("%s%s", data.CurrencySymbol, formatted))
|
|
|
|
|
},
|
|
|
|
|
"formatTotal": func(amount float64) template.HTML {
|
|
|
|
|
formatted := FormatPriceWithCommas(fmt.Sprintf("%.2f", amount))
|
|
|
|
|
return template.HTML(fmt.Sprintf("%s%s", data.CurrencySymbol, formatted))
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse and execute template
|
|
|
|
|
possiblePathSets := [][]string{
|
|
|
|
|
{
|
|
|
|
|
filepath.Join("internal", "cmc", "documents", "templates", "purchase-order.html"),
|
|
|
|
|
filepath.Join("internal", "cmc", "documents", "templates", "header.html"),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
filepath.Join("go", "internal", "cmc", "documents", "templates", "purchase-order.html"),
|
|
|
|
|
filepath.Join("go", "internal", "cmc", "documents", "templates", "header.html"),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
filepath.Join("templates", "pdf", "purchase-order.html"),
|
|
|
|
|
filepath.Join("templates", "pdf", "header.html"),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"/app/templates/pdf/purchase-order.html",
|
|
|
|
|
"/app/templates/pdf/header.html",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var tmpl *template.Template
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
for _, pathSet := range possiblePathSets {
|
|
|
|
|
tmpl, err = template.New("purchase-order.html").Funcs(funcMap).ParseFiles(pathSet...)
|
|
|
|
|
if err == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if tmpl == nil || err != nil {
|
|
|
|
|
fmt.Printf("Error parsing template from any path: %v\n", err)
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := tmpl.Execute(&buf, templateData); err != nil {
|
|
|
|
|
fmt.Printf("Error executing template: %v\n", err)
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf.String()
|
|
|
|
|
}
|