293 lines
8.5 KiB
Go
293 lines
8.5 KiB
Go
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
|
|
}
|