From 3950cef4c9b11e0a0f30fcae5872b4071fb40540 Mon Sep 17 00:00:00 2001 From: Finley Ghosh Date: Sun, 7 Dec 2025 22:15:09 +1100 Subject: [PATCH] Ensuring automatic quote reminder emails have pdfs --- go/internal/cmc/handlers/quotes/quotes.go | 98 ++++++++++------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/go/internal/cmc/handlers/quotes/quotes.go b/go/internal/cmc/handlers/quotes/quotes.go index 07e1114e..b9aa368f 100644 --- a/go/internal/cmc/handlers/quotes/quotes.go +++ b/go/internal/cmc/handlers/quotes/quotes.go @@ -5,7 +5,6 @@ import ( "database/sql" "encoding/json" "fmt" - "io" "log" "net/http" "os" @@ -447,7 +446,12 @@ func (h *QuotesHandler) DailyQuoteExpirationCheck() { q["UserEmail"].(string), ) - err := h.SendQuoteReminderEmail( + // Construct PDF path from filesystem + enquiryRef := q["EnquiryRef"].(string) + pdfPath := fmt.Sprintf("/root/webroot/pdf/%s.pdf", enquiryRef) + pdfFilename := fmt.Sprintf("%s.pdf", enquiryRef) + + err := h.SendQuoteReminderEmailWithPDF( context.Background(), q["ID"].(int32), job.ReminderType, @@ -457,7 +461,8 @@ func (h *QuotesHandler) DailyQuoteExpirationCheck() { templateData, ccs, nil, - false, + pdfPath, + pdfFilename, ) if err != nil { fmt.Printf("Error sending %s for quote %v: %v\n", job.ReminderType.String(), q["ID"], err) @@ -530,10 +535,8 @@ func (h *QuotesHandler) SendQuoteReminderEmail(ctx context.Context, quoteID int3 return nil } -// SendQuoteReminderEmailWithAttachment is like SendQuoteReminderEmail but includes a PDF attachment -func (h *QuotesHandler) SendQuoteReminderEmailWithAttachment(ctx context.Context, quoteID int32, reminderType QuoteReminderType, recipient string, subject string, templateName string, templateData map[string]interface{}, ccs []string, username *string, pdfPath string, pdfFilename string, sourceReq *http.Request) error { - log.Printf("SendQuoteReminderEmailWithAttachment called for quote %d, recipient: %s, PDF URL: %s", quoteID, recipient, pdfPath) - +// SendQuoteReminderEmailWithPDF sends a reminder email with PDF attachment loaded from filesystem +func (h *QuotesHandler) SendQuoteReminderEmailWithPDF(ctx context.Context, quoteID int32, reminderType QuoteReminderType, recipient string, subject string, templateName string, templateData map[string]interface{}, ccs []string, username *string, pdfPath string, pdfFilename string) error { // Safeguard: check for valid recipient if strings.TrimSpace(recipient) == "" { return fmt.Errorf("recipient email is required") @@ -547,54 +550,38 @@ func (h *QuotesHandler) SendQuoteReminderEmailWithAttachment(ctx context.Context return fmt.Errorf("invalid reminder type: %v", reminderType) } - // Download PDF from URL and prepare attachment if available - var attachments []interface{} - - // Create authenticated request for PDF download - req, err := auth.NewAuthenticatedRequest("GET", pdfPath, sourceReq) + // Check if reminder already sent + reminders, err := h.queries.GetQuoteRemindersByType(ctx, db.GetQuoteRemindersByTypeParams{ + QuoteID: quoteID, + ReminderType: int32(reminderType), + }) if err != nil { - log.Printf("Failed to create PDF download request for quote %d: %v", quoteID, err) - } else { - client := &http.Client{} - resp, err := client.Do(req) - if err == nil && resp.StatusCode == 200 { - defer resp.Body.Close() - - // Create temporary file for the PDF - tmpFile, err := os.CreateTemp("", "quote_*.pdf") - if err == nil { - defer os.Remove(tmpFile.Name()) - defer tmpFile.Close() - - // Copy PDF content to temp file - if _, err := io.Copy(tmpFile, resp.Body); err == nil { - attachments = []interface{}{ - struct { - Filename string - FilePath string - }{ - Filename: pdfFilename, - FilePath: tmpFile.Name(), - }, - } - log.Printf("Successfully downloaded and attached PDF for quote %d: %s (tmpFile: %s)", quoteID, pdfFilename, tmpFile.Name()) - } else { - log.Printf("Failed to copy PDF content for quote %d: %v", quoteID, err) - } - } else { - log.Printf("Failed to create temporary file for quote %d PDF: %v", quoteID, err) - } - } else if err != nil { - log.Printf("Failed to download PDF from %s for quote %d: %v", pdfPath, quoteID, err) - } else if resp != nil { - defer resp.Body.Close() - log.Printf("PDF download returned status %d for quote %d at %s", resp.StatusCode, quoteID, pdfPath) - } + return fmt.Errorf("failed to check existing reminders: %w", err) + } + + // Exit if the email has already been sent + if len(reminders) > 0 { + return nil + } + + // Prepare PDF attachment if file exists + var attachments []interface{} + if _, err := os.Stat(pdfPath); err == nil { + attachments = []interface{}{ + struct { + Filename string + FilePath string + }{ + Filename: pdfFilename, + FilePath: pdfPath, + }, + } + log.Printf("Attaching PDF for quote %d: %s", quoteID, pdfPath) + } else { + log.Printf("PDF not found for quote %d at %s, sending without attachment", quoteID, pdfPath) } - // If PDF download fails, just send email without attachment // Send the email (with or without attachment) - log.Printf("Sending email for quote %d with %d attachment(s)", quoteID, len(attachments)) err = h.emailService.SendTemplateEmailWithAttachments( recipient, subject, @@ -692,8 +679,8 @@ func (h *QuotesHandler) SendManualReminder(w http.ResponseWriter, r *http.Reques ccs = append(ccs, userEmail) } - // Attach PDF quote from URL - pdfURL := fmt.Sprintf("https://stg.cmctechnologies.com.au/pdf/%s.pdf", enquiryRef) + // Attach PDF quote from filesystem + pdfPath := fmt.Sprintf("/root/webroot/pdf/%s.pdf", enquiryRef) pdfFilename := fmt.Sprintf("%s.pdf", enquiryRef) // Get username from request @@ -701,7 +688,7 @@ func (h *QuotesHandler) SendManualReminder(w http.ResponseWriter, r *http.Reques usernamePtr := &username // Send the reminder with attachment - err = h.SendQuoteReminderEmailWithAttachment( + err = h.SendQuoteReminderEmailWithPDF( r.Context(), int32(quoteID), reminderType, @@ -711,9 +698,8 @@ func (h *QuotesHandler) SendManualReminder(w http.ResponseWriter, r *http.Reques templateData, ccs, usernamePtr, - pdfURL, + pdfPath, pdfFilename, - r, ) if err != nil {