Files
accounted/lib/invoices/reminders-enabled.ts
T
MattssonandClaude Fable 5 e92b5a59b2 fix(reminders): settings UI discloses that automatic sending is disabled (#2033)
* fix(reminders): settings UI discloses that automatic sending is disabled

The invoice reminder cron has answered 503 since May 2026 (PR #583), so
no automatic reminders are sent, but the settings UI still let users
configure reminder day levels as if sending worked.

Introduce REMINDERS_SENDING_ENABLED (lib/invoices/reminders-enabled.ts)
as the single shared flag read by both sides: the cron route uses it as
its 503 gate (with the original sending pipeline restored behind it, so
re-enabling later is one flag flip), and the invoice settings form shows
an attn notice while the flag is off. Schedule settings stay editable;
notice strings added to both sv and en locales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NtvffGr6uVk2J2Skuz6L98

* docs(reminders): correct the re-enable contract after skeptic review

The flag docblock, route docblock, and test header claimed flipping
REMINDERS_SENDING_ENABLED alone resumes sending. False on hosted: the
route has had no vercel.json cron entry since PR #559 and the crontab
ratchet pins it in INTENTIONALLY_UNSCHEDULED, and POST requires the cron
secret so no dashboard can trigger it. Rewrite the claims into the real
re-enable checklist and record the pre-flip prerequisites surfaced by
review: invoice_reminders lacks a unique (invoice_id, reminder_level)
constraint and the fee entry is booked before the reminder row, so a run
dying mid-batch double-books the fee; the backlog would get highest-level
reminders first. Comments and a test name only; no runtime change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NtvffGr6uVk2J2Skuz6L98

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 21:43:19 +02:00

37 lines
1.9 KiB
TypeScript

/**
* Master switch for automatic invoice reminder sending.
*
* Sending was deliberately gated off in May 2026 (PR #583): the reminder
* cron route answers 503 and no reminder emails go out, while the schedule
* settings (send_invoice_reminders, reminder_days_level_1/2/3) remain
* editable and are honored per company once sending is on.
*
* Both sides of that gate read this one constant: the cron route uses it as
* its 503 gate, and the invoice settings form uses it to disclose to users
* that automatic sending is currently disabled. Flipping it opens the route
* and removes the notice in the same change.
*
* Re-enabling sending is a founder product decision and takes MORE than
* this flip. The checklist (verified against the repo 2026-08-30):
*
* 1. Flip this flag to true.
* 2. Hosted: the route has had no vercel.json cron entry since PR #559,
* and scripts/__tests__/generate-crontabs.test.ts pins it in
* INTENTIONALLY_UNSCHEDULED (the ratchet fails if it is scheduled).
* Add the cron entry back and drop the pin together. Self-hosted
* crontabs built from docs/SELF-HOSTING.md may already hit the route,
* so those installs resume on the flag flip alone.
* 3. Before any flip, make the reminder run idempotent: invoice_reminders
* has no unique (invoice_id, reminder_level) constraint and
* processOverdueReminders books the reminder fee entry BEFORE inserting
* the invoice_reminders row, so a run dying mid-batch double-books the
* fee (Dr 1510 / Cr 3990) on the next run. Also decide how to handle
* the backlog: determineReminderLevel sends the highest eligible level
* first, so long-overdue customers would get a final notice with fee
* and interest as their first-ever reminder.
*
* Kept dependency-free on purpose: it is imported from both server code
* (the cron route) and client components (the settings form).
*/
export const REMINDERS_SENDING_ENABLED = false as boolean