diff --git a/go/cmd/server/main.go b/go/cmd/server/main.go index 107c586c..5d073ba6 100644 --- a/go/cmd/server/main.go +++ b/go/cmd/server/main.go @@ -74,6 +74,7 @@ func main() { // Quote routes goRouter.HandleFunc("/quotes", quoteHandler.QuotesOutstandingView).Methods("GET") goRouter.HandleFunc("/quotes/send-reminder", quoteHandler.SendManualReminder).Methods("POST") + goRouter.HandleFunc("/quotes/disable-reminders", quoteHandler.DisableReminders).Methods("POST") // The following routes are currently disabled: /* diff --git a/go/internal/cmc/email/email.go b/go/internal/cmc/email/email.go index 270cad41..03e6ef92 100644 --- a/go/internal/cmc/email/email.go +++ b/go/internal/cmc/email/email.go @@ -65,20 +65,13 @@ func (es *EmailService) SendTemplateEmail(to string, subject string, templateNam func (es *EmailService) SendTemplateEmailWithAttachments(to string, subject string, templateName string, data interface{}, ccs []string, bccs []string, attachments []interface{}) error { // Convert interface{} attachments to []Attachment var typedAttachments []Attachment - fmt.Printf("DEBUG: Received %d attachments to convert\n", len(attachments)) - for i, att := range attachments { - fmt.Printf("DEBUG: Attachment %d type: %T\n", i, att) + for _, att := range attachments { if a, ok := att.(Attachment); ok { - fmt.Printf("DEBUG: Converted to Attachment type: %s -> %s\n", a.Filename, a.FilePath) typedAttachments = append(typedAttachments, a) } else if a, ok := att.(struct{ Filename, FilePath string }); ok { - fmt.Printf("DEBUG: Converted from anonymous struct: %s -> %s\n", a.Filename, a.FilePath) typedAttachments = append(typedAttachments, Attachment{Filename: a.Filename, FilePath: a.FilePath}) - } else { - fmt.Printf("DEBUG: Failed to convert attachment type %T\n", att) } } - fmt.Printf("DEBUG: Final typed attachments count: %d\n", len(typedAttachments)) defaultBccs := []string{"carpis@cmctechnologies.com.au"} bccs = append(defaultBccs, bccs...) diff --git a/go/internal/cmc/handlers/quotes/quotes.go b/go/internal/cmc/handlers/quotes/quotes.go index 4a661dfc..d6ee43d2 100644 --- a/go/internal/cmc/handlers/quotes/quotes.go +++ b/go/internal/cmc/handlers/quotes/quotes.go @@ -175,6 +175,7 @@ type QuoteQueries interface { GetRecentlyExpiredQuotes(ctx context.Context, dateSUB interface{}) ([]db.GetRecentlyExpiredQuotesRow, error) GetExpiringSoonQuotesOnDay(ctx context.Context, dateADD interface{}) ([]db.GetExpiringSoonQuotesOnDayRow, error) GetRecentlyExpiredQuotesOnDay(ctx context.Context, dateSUB interface{}) ([]db.GetRecentlyExpiredQuotesOnDayRow, error) + DisableQuoteReminders(ctx context.Context, params db.DisableQuoteRemindersParams) (sql.Result, error) } type EmailSender interface { @@ -522,17 +523,16 @@ func (h *QuotesHandler) SendQuoteReminderEmailWithAttachment(ctx context.Context // Copy PDF content to temp file if _, err := io.Copy(tmpFile, resp.Body); err == nil { - type Attachment struct { - Filename string - FilePath string - } attachments = []interface{}{ - Attachment{ + struct { + Filename string + FilePath string + }{ Filename: pdfFilename, FilePath: tmpFile.Name(), }, } - log.Printf("Successfully downloaded and attached PDF for quote %d: %s", quoteID, pdfFilename) + 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) } @@ -685,6 +685,51 @@ func (h *QuotesHandler) SendManualReminder(w http.ResponseWriter, r *http.Reques http.Redirect(w, r, "/go/quotes", http.StatusSeeOther) } +// DisableReminders handles POST requests to disable automatic reminders for a quote +func (h *QuotesHandler) DisableReminders(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // Parse form data + if err := r.ParseForm(); err != nil { + http.Error(w, "Invalid form data", http.StatusBadRequest) + return + } + + quoteIDStr := r.FormValue("quote_id") + if quoteIDStr == "" { + http.Error(w, "Missing quote_id", http.StatusBadRequest) + return + } + + quoteID, err := strconv.ParseInt(quoteIDStr, 10, 32) + if err != nil { + http.Error(w, "Invalid quote ID", http.StatusBadRequest) + return + } + + // Get username from request + username := getUsername(r) + + // Update the database to disable reminders + _, err = h.queries.DisableQuoteReminders(r.Context(), db.DisableQuoteRemindersParams{ + RemindersDisabledBy: sql.NullString{String: username, Valid: true}, + ID: int32(quoteID), + }) + + if err != nil { + log.Printf("Failed to disable reminders for quote %d: %v", quoteID, err) + http.Error(w, fmt.Sprintf("Failed to disable reminders: %v", err), http.StatusInternalServerError) + return + } + + log.Printf("Reminders disabled for quote %d by %s", quoteID, username) + // Redirect back to quotes page + http.Redirect(w, r, "/go/quotes", http.StatusSeeOther) +} + // Helper: get reminder type as string func reminderTypeString(reminderType int) string { switch reminderType {