package pdf import ( "fmt" "time" "code.springupsoftware.com/cmc/cmc-sales/internal/cmc/db" ) // QuotePDFData contains all data needed to generate a quote PDF type QuotePDFData struct { Document *db.Document Quote interface{} // Quote specific data Enquiry *db.Enquiry Customer *db.Customer Contact interface{} // Contact data User *db.GetUserRow LineItems []db.GetLineItemsTableRow Currency interface{} // Currency data CurrencySymbol string ShowGST bool CommercialComments string } // GenerateQuotePDF generates a PDF for a quote func GenerateQuotePDF(data *QuotePDFData, outputDir string) (string, error) { fmt.Printf("GenerateQuotePDF called with outputDir: %s\n", outputDir) gen := NewGenerator(outputDir) // First page with header gen.AddPage() gen.Page1Header() // Extract data for details box companyName := "" // TODO: Get from customer data if data.Customer != nil { companyName = data.Customer.Name } emailTo := "" // TODO: Get from contact attention := "" // TODO: Get from contact fromName := fmt.Sprintf("%s %s", data.User.FirstName, data.User.LastName) fromEmail := data.User.Email // Use CMC reference as the quote number quoteNumber := data.Document.CmcReference if data.Document.Revision > 0 { quoteNumber = fmt.Sprintf("%s.%d", quoteNumber, data.Document.Revision) } yourReference := fmt.Sprintf("Enquiry on %s", data.Document.Created.Format("2 Jan 2006")) issueDate := data.Document.Created.Format("2 January 2006") // Add details box gen.DetailsBox("QUOTE", companyName, emailTo, attention, fromName, fromEmail, quoteNumber, yourReference, issueDate) // Add page content if any // TODO: Add document pages content gen.Page1Footer() // Add pricing page gen.AddPage() gen.pdf.SetFont("Helvetica", "B", 14) gen.pdf.CellFormat(0, 10, "PRICING & SPECIFICATIONS", "", 1, "C", false, 0, "") gen.pdf.Ln(5) // Convert line items pdfItems := make([]LineItem, len(data.LineItems)) for i, item := range data.LineItems { unitPrice := 0.0 totalPrice := 0.0 // Parse prices if item.GrossUnitPrice.Valid { fmt.Sscanf(item.GrossUnitPrice.String, "%f", &unitPrice) } if item.GrossPrice.Valid { fmt.Sscanf(item.GrossPrice.String, "%f", &totalPrice) } pdfItems[i] = LineItem{ ItemNumber: item.ItemNumber, Quantity: item.Quantity, Title: item.Title, UnitPrice: unitPrice, TotalPrice: totalPrice, } } // Add line items table gen.AddLineItemsTable(pdfItems, data.CurrencySymbol, data.ShowGST) // Add commercial comments if any if data.CommercialComments != "" { gen.pdf.Ln(10) gen.pdf.SetFont("Helvetica", "B", 10) gen.pdf.CellFormat(0, 5, "COMMERCIAL COMMENTS", "", 1, "L", false, 0, "") gen.pdf.SetFont("Helvetica", "", 9) gen.pdf.MultiCell(0, 5, data.CommercialComments, "", "L", false) } // TODO: Add terms and conditions page // Generate filename filename := quoteNumber if data.Document.Revision > 0 { filename = fmt.Sprintf("%s_%d.pdf", quoteNumber, data.Document.Revision) } else { filename = fmt.Sprintf("%s.pdf", quoteNumber) } // Save PDF fmt.Printf("Saving PDF with filename: %s to outputDir: %s\n", filename, outputDir) err := gen.Save(filename) if err != nil { fmt.Printf("Error saving PDF: %v\n", err) } else { fmt.Printf("PDF saved successfully: %s\n", filename) } return filename, err } // InvoicePDFData contains all data needed to generate an invoice PDF type InvoicePDFData struct { Document *db.Document Invoice *db.Invoice Enquiry *db.Enquiry Customer *db.Customer Job interface{} // Job data LineItems []db.GetLineItemsTableRow Currency interface{} // Currency data CurrencySymbol string CurrencyCode string ShowGST bool ShipVia string FOB string IssueDate time.Time IssueDateString string BillTo string ShipTo string ShippingDetails string CustomerOrderNumber string JobTitle string PaymentTerms string CustomerABN string Subtotal float64 GSTAmount float64 Total float64 } // GenerateInvoicePDF generates a PDF for an invoice matching old TCPDF layout func GenerateInvoicePDF(data *InvoicePDFData, outputDir string) (string, error) { gen := NewGenerator(outputDir) // First page with header gen.AddPage() gen.Page1Header() // Title - TAX INVOICE gen.pdf.SetFont("Helvetica", "B", 18) gen.pdf.SetTextColor(0, 0, 0) gen.pdf.CellFormat(0, 10, "TAX INVOICE", "", 1, "C", false, 0, "") gen.pdf.Ln(3) // Shipping/Billing Box with payment details (matches old TCPDF layout) gen.AddInvoiceShippingBillingBox(data) // Details table - CUSTOMER ORDER NO, JOB #, FOB, PAYMENT TERMS, ABN gen.pdf.Ln(2) gen.AddInvoiceDetailsTable(data) gen.pdf.Ln(3) // Line items table with freight and totals (matches old TCPDF layout) gen.AddInvoiceLineItemsTableWithShipping(data) gen.Page1Footer() // Add terms and conditions page gen.AddTermsAndConditions() // Generate filename and save filename := fmt.Sprintf("%s.pdf", data.Invoice.Title) if err := gen.Save(filename); err != nil { return "", err } return filename, nil } // PurchaseOrderPDFData contains all data needed to generate a purchase order PDF type PurchaseOrderPDFData struct { Document *db.Document PurchaseOrder *db.PurchaseOrder Principle *db.Principle LineItems []db.GetLineItemsTableRow Currency interface{} // Currency data CurrencySymbol string ShowGST bool } // GeneratePurchaseOrderPDF generates a PDF for a purchase order func GeneratePurchaseOrderPDF(data *PurchaseOrderPDFData, outputDir string) (string, error) { gen := NewGenerator(outputDir) // First page with header gen.AddPage() gen.Page1Header() // Extract data for details box companyName := data.Principle.Name emailTo := "" // TODO: Get from principle contact attention := "" // TODO: Get from principle contact fromName := "" // TODO: Get from user fromEmail := "" // TODO: Get from user poNumber := data.PurchaseOrder.Title yourReference := data.PurchaseOrder.PrincipleReference issueDate := data.PurchaseOrder.IssueDate.Format("Monday, 2 January 2006") // Add details box gen.DetailsBox("PURCHASE ORDER", companyName, emailTo, attention, fromName, fromEmail, poNumber, yourReference, issueDate) // Add PO specific details gen.pdf.Ln(5) gen.pdf.SetFont("Helvetica", "B", 10) gen.pdf.CellFormat(40, 5, "Ordered From:", "", 0, "L", false, 0, "") gen.pdf.SetFont("Helvetica", "", 10) gen.pdf.MultiCell(0, 5, data.PurchaseOrder.OrderedFrom, "", "L", false) gen.pdf.SetFont("Helvetica", "B", 10) gen.pdf.CellFormat(40, 5, "Dispatch By:", "", 0, "L", false, 0, "") gen.pdf.SetFont("Helvetica", "", 10) gen.pdf.CellFormat(0, 5, data.PurchaseOrder.DispatchBy, "", 1, "L", false, 0, "") gen.pdf.SetFont("Helvetica", "B", 10) gen.pdf.CellFormat(40, 5, "Deliver To:", "", 0, "L", false, 0, "") gen.pdf.SetFont("Helvetica", "", 10) gen.pdf.MultiCell(0, 5, data.PurchaseOrder.DeliverTo, "", "L", false) if data.PurchaseOrder.ShippingInstructions != "" { gen.pdf.SetFont("Helvetica", "B", 10) gen.pdf.CellFormat(0, 5, "Shipping Instructions:", "", 1, "L", false, 0, "") gen.pdf.SetFont("Helvetica", "", 10) gen.pdf.MultiCell(0, 5, data.PurchaseOrder.ShippingInstructions, "", "L", false) } gen.Page1Footer() // Add line items page gen.AddPage() gen.pdf.SetFont("Helvetica", "B", 14) gen.pdf.CellFormat(0, 10, "ORDER DETAILS", "", 1, "C", false, 0, "") gen.pdf.Ln(5) // Convert line items pdfItems := make([]LineItem, len(data.LineItems)) for i, item := range data.LineItems { unitPrice := 0.0 totalPrice := 0.0 // Parse prices if item.GrossUnitPrice.Valid { fmt.Sscanf(item.GrossUnitPrice.String, "%f", &unitPrice) } if item.GrossPrice.Valid { fmt.Sscanf(item.GrossPrice.String, "%f", &totalPrice) } pdfItems[i] = LineItem{ ItemNumber: item.ItemNumber, Quantity: item.Quantity, Title: item.Title, UnitPrice: unitPrice, TotalPrice: totalPrice, } } // Add line items table gen.AddLineItemsTable(pdfItems, data.CurrencySymbol, data.ShowGST) // Generate filename filename := poNumber if data.Document.Revision > 0 { filename = fmt.Sprintf("%s-Rev%d.pdf", data.PurchaseOrder.Title, data.Document.Revision) } else { filename = fmt.Sprintf("%s.pdf", data.PurchaseOrder.Title) } // Save PDF err := gen.Save(filename) return filename, err }