package pdf 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 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 if item.NetUnitPrice.Valid { unitPrice, _ = strconv.ParseFloat(item.NetUnitPrice.String, 64) } if item.NetPrice.Valid { totalPrice, _ = strconv.ParseFloat(item.NetPrice.String, 64) subtotal += totalPrice } lineItemsData = append(lineItemsData, PurchaseOrderLineItemTemplateData{ Title: item.Title, Description: template.HTML(item.Description), Quantity: item.Quantity, UnitPrice: unitPrice, 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 YourReference string IssueDateString string OrderedFrom string DeliverTo string DispatchBy string ShippingInstructions string CurrencyCode string CurrencySymbol string LineItems []PurchaseOrderLineItemTemplateData Subtotal float64 GSTAmount float64 Total float64 ShowGST bool LogoDataURI string }{ PONumber: poNumber, PrincipleName: data.Principle.Name, YourReference: data.PurchaseOrder.PrincipleReference, IssueDateString: data.IssueDateString, OrderedFrom: data.PurchaseOrder.OrderedFrom, DeliverTo: data.PurchaseOrder.DeliverTo, DispatchBy: data.PurchaseOrder.DispatchBy, ShippingInstructions: data.PurchaseOrder.ShippingInstructions, 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() }