#!/usr/bin/env python3 import sys import os from datetime import datetime, timedelta from dotenv import load_dotenv # load same environment config as Flask load_dotenv("/home/def/otb_billing/.env") sys.path.append("/home/def/otb_billing/backend") from app import get_db_connection, send_configured_email, recalc_invoice_totals REMINDER_DAYS = 7 OVERDUE_DAYS = 14 def main(): print(f"[{datetime.now().isoformat()}] invoice_reminder_worker starting") checked_count = 0 reminder_sent_count = 0 overdue_sent_count = 0 skipped_count = 0 conn = get_db_connection() cursor = conn.cursor(dictionary=True) now = datetime.utcnow() cursor.execute(""" SELECT i.id, i.invoice_number, i.created_at, i.client_id, c.email, c.company_name, c.contact_name FROM invoices i JOIN clients c ON c.id = i.client_id WHERE i.status IN ('pending','sent') """) invoices = cursor.fetchall() for inv in invoices: age = (now - inv["created_at"]).days email = inv["email"] if not email: continue name = inv.get("contact_name") or inv.get("company_name") or "Client" portal_url = f"https://portal.outsidethebox.top/portal/invoice/{inv['id']}" if age >= OVERDUE_DAYS: subject = f"Invoice {inv['invoice_number']} is overdue" body = f""" Hello {name}, Invoice {inv['invoice_number']} is now overdue. Amount Due: {recalc_invoice_totals(inv['id'])['total']} View invoice: {portal_url} Please arrange payment at your earliest convenience. OutsideTheBox """ send_configured_email( to_email=email, subject=subject, body=body, attachments=None, email_type="invoice_overdue", invoice_id=inv["id"] ) elif age >= REMINDER_DAYS: subject = f"Invoice {inv['invoice_number']} reminder" body = f""" Hello {name}, This is a reminder that invoice {inv['invoice_number']} is still outstanding. Amount Due: {recalc_invoice_totals(inv['id'])['total']} View invoice: {portal_url} Thank you. OutsideTheBox """ send_configured_email( to_email=email, subject=subject, body=body, attachments=None, email_type="invoice_reminder", invoice_id=inv["id"] ) conn.close() print(f"[{datetime.now().isoformat()}] checked={checked_count} reminders_sent={reminder_sent_count} overdue_sent={overdue_sent_count} skipped={skipped_count}") if __name__ == "__main__": main()