# Bad Debt Write-Off (חוב אבוד)

**Date:** 2026-06-01
**Status:** Draft
**Spec:** 168
**Tier:** All tiers
**Depends on:** `invoices-core`, `partial-payment-recording`, `foundation-auth-rbac`
**Referenced by:** `invoices-core`, `financial-statements`, `israeli-tax-reports`

---

## Overview

When a customer does not pay an invoice and collection is deemed unlikely, the debt can be written off as a "bad debt" (חוב אבוד). Under Israeli tax law, a written-off bad debt allows the creditor to reclaim the VAT already remitted to the ITA for that invoice — but only after following a formal notification process (sending a registered letter to the debtor and notifying the ITA).

This spec defines the write-off workflow, the accounting impact, the VAT reclaim tracking, and the reporting interface.

---

## Write-Off Eligibility

An invoice is eligible for bad debt write-off when:
- `status IN ('TAX_ISSUED', 'PARTIALLY_PAID')` — invoice was issued but not (fully) paid
- Invoice age ≥ `tenant_settings.bad_debt_threshold_days` past due date (default 90; ITA minimum — configurable per tenant)
- Tenant has a valid VAT registration (only VAT-registered businesses can reclaim VAT)

Invoices in `DRAFT`, `SENT`, `APPROVED`, or `PAID` status cannot be written off. `VOID` invoices are already cancelled.

### `WRITTEN_OFF` vs `BAD_DEBT`

Two distinct terminal collection outcomes share the eligibility rules above:

- **`BAD_DEBT`** (חוב אבוד) — the VAT-reclaim path defined by the full flow below. Debt deemed uncollectable; tenant intends to reclaim remitted VAT via the ITA Section 24A process. This is the default and most common outcome.
- **`WRITTEN_OFF`** — a plain write-off with **no VAT reclaim**. Used when the tenant forgives/cancels the receivable for goodwill or commercial reasons (not legal uncollectability), or is not VAT-registered, or chooses not to pursue the ITA reclaim. Same `[Write off as bad debt]` entry point: when the confirmation modal's **"Log VAT reclaim request"** checkbox is **unchecked**, the resulting status is `WRITTEN_OFF` and no `bad_debt_vat_reclaims` row is created; when checked, status is `BAD_DEBT`.

Both are reachable only from `TAX_ISSUED` or `PARTIALLY_PAID` and both require OWNER or ADMIN. Both appear as a deduction from revenue in the P&L (spec 170). The fields `bad_debt_at` / `bad_debt_reason` / `bad_debt_note` are populated for both (the column names predate the split; they record the write-off date and reason regardless of VAT-reclaim choice).

**Settings:** the threshold is configurable in `/settings/invoicing` → "Overdue & Collections" sub-section — *"Bad debt threshold: number of days overdue before an invoice is flagged for write-off (default: 90)."* Stored in `tenant_settings.bad_debt_threshold_days`.

---

## Write-Off Flow

### Staff-initiated

On invoice detail page for eligible invoices: **[Write off as bad debt]** button (visible to OWNER/ADMIN only, requires `invoices:write`).

**Confirmation modal:**

```
┌──────────────────────────────────────────────────────────────┐
│  Write off INV-0042?                                    [✕]  │
│                                                              │
│  Customer:    Acme Corp                                      │
│  Invoice:     INV-0042   Issued: 2026-01-15                  │
│  Amount due:  ₪12,700   (₪0 received)                       │
│                                                              │
│  Write-off date *   [2026-06-01_____]                        │
│  Reason *           [Customer declared bankruptcy___________] │
│                     Bankruptcy · Collection failed · Other   │
│                                                              │
│  VAT reclaim (if applicable):                                │
│  ☑ Log VAT reclaim request (₪1,932 — 18% of ₪10,768)       │
│    ⓘ Requires sending registered letter to customer.         │
│    Confirm you have sent / will send the notification.       │
│                                                              │
│  [Cancel]                    [Write off invoice]             │
└──────────────────────────────────────────────────────────────┘
```

### After confirmation

1. Invoice status → `BAD_DEBT` if VAT reclaim checked, else `WRITTEN_OFF` (both new terminal statuses)
2. `invoices.bad_debt_at = NOW()`, `invoices.bad_debt_reason = reason`
3. If VAT reclaim checked: create `bad_debt_vat_reclaims` row with `status = 'pending'` (skipped for `WRITTEN_OFF`)
4. Notification sent to OWNER: "Invoice INV-0042 written off as bad debt."
5. Webhook `invoice.written_off` emitted

### Recovery after write-off (debtor pays later)

`BAD_DEBT` / `WRITTEN_OFF` are terminal *collection outcomes*, not immutable end states — a debtor can pay after a write-off, and Israeli VAT law then requires the previously **reclaimed VAT to be re-remitted**. The recovery path:

**Entry points** (a payment lands against a written-off invoice):
- Manual: invoice detail for a `BAD_DEBT`/`WRITTEN_OFF` invoice shows **[Record recovery payment]** (OWNER/ADMIN, `invoices:write`).
- Reconcile: `payment-reconciliation` (spec 157) and `bank-statement-import` (spec 167) — when an incoming payment is matched to a `BAD_DEBT`/`WRITTEN_OFF` invoice, the match action routes through this recovery flow instead of normal payment recording (those specs link here; they do not define their own write-off-reversal logic).

**On recovery confirmation:**
1. Record an `invoice_payments` row (spec 80) for the recovered amount.
2. Invoice status → `PARTIALLY_PAID` (partial recovery) or `PAID` (full); `bad_debt_at`/`bad_debt_reason`/`bad_debt_note` retained for audit (the write-off historically happened).
3. If a `bad_debt_vat_reclaims` row exists and its `status = 'approved'` (VAT was reclaimed from the ITA), create a **re-remittance obligation**: set reclaim `status = 'reversed'`, record `reversed_at`, and surface the re-remit VAT amount in the next VAT report period (spec 171) as output VAT owed back. If the reclaim is still `pending`/`submitted` (not yet approved), it is cancelled (`status = 'cancelled'`) — no reclaim was realized, nothing to re-remit.
4. P&L (spec 170): the bad-debt deduction is unwound for the recovered portion in the recovery period.
5. Webhook `invoice.recovered` emitted; notification to OWNER.

`bad_debt_vat_reclaims.status` enum extends to include `'reversed'` and `'cancelled'`.

---

## Schema Delta

```sql
-- invoices status enum extended:
-- Add 'BAD_DEBT' and 'WRITTEN_OFF' to CHECK constraint or application-level enum
-- (BAD_DEBT = with VAT reclaim; WRITTEN_OFF = plain write-off, no reclaim — see Eligibility section)
ALTER TABLE invoices ADD COLUMN bad_debt_at     TIMESTAMPTZ;
ALTER TABLE invoices ADD COLUMN bad_debt_reason TEXT;          -- 'bankruptcy' | 'collection_failed' | 'other'
ALTER TABLE invoices ADD COLUMN bad_debt_note   TEXT;          -- optional free text

-- Bad-debt flagging threshold (days overdue before an invoice is surfaced for write-off):
ALTER TABLE tenant_settings ADD COLUMN bad_debt_threshold_days INT NOT NULL DEFAULT 90;

-- VAT reclaim tracking
CREATE TABLE bad_debt_vat_reclaims (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
  invoice_id      UUID NOT NULL REFERENCES invoices(id) ON DELETE CASCADE,
  vat_amount      NUMERIC(12,2) NOT NULL,           -- VAT amount to reclaim (= invoice.vat_amount - paid VAT)
  status          TEXT NOT NULL DEFAULT 'pending',  -- 'pending' | 'submitted' | 'approved' | 'rejected' | 'reversed' | 'cancelled'
  registered_letter_sent_at DATE,                   -- date registered letter sent to customer (legal requirement)
  ita_submission_date DATE,                         -- date submitted to ITA
  ita_reference   TEXT,                             -- ITA case reference number
  resolved_at     TIMESTAMPTZ,
  reversed_at     TIMESTAMPTZ,                       -- set when debtor pays after reclaim approved → VAT re-remitted
  notes           TEXT,
  created_at      TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_bad_debt_vat_tenant ON bad_debt_vat_reclaims(tenant_id, created_at DESC);
```

---

## VAT Reclaim Process

### Legal requirement (Israeli law)

Before reclaiming VAT on a bad debt (under Israeli VAT Regulations, Section 24A):
1. The creditor must send a **registered letter** (דואר רשום) to the debtor notifying them of the write-off
2. The notification must be sent within **6 months** of deciding to write off
3. After sending the letter, the creditor can submit a VAT reclaim to the ITA (Form 1220 or online portal)
4. The ITA processes and approves/rejects the reclaim

### Zync tracking

The `bad_debt_vat_reclaims` table tracks:
- The intended VAT amount to reclaim
- Whether the registered letter was sent (and when)
- ITA submission date + reference
- Resolution status

### VAT reclaim progress UI

On invoice detail (BAD_DEBT status) → "VAT Reclaim" panel:

```
┌──────────────────────────────────────────────────────────────┐
│  VAT Reclaim Status                                          │
│                                                              │
│  Amount to reclaim: ₪1,932                                  │
│                                                              │
│  ○ Registered letter sent  [Mark as sent: ________date____]  │
│  ○ Submitted to ITA        [ITA reference: _______________]  │
│  ○ Resolved                                                  │
│                                                              │
│  Status: ● Pending (letter not yet sent)                     │
│                                                              │
│  [Update reclaim status]                                     │
└──────────────────────────────────────────────────────────────┘
```

Staff updates the reclaim status as they complete each step.

---

## Reporting

### Bad Debt screen — `/reports/bad-debt`

The consolidated bad-debt screen (reached from the reports hub, spec 103, and the Tax & Compliance nav group). Two sections on one page so a tenant tracking several open reclaims has a single worklist instead of visiting each invoice:

```
┌──────────────────────────────────────────────────────────────┐
│  Bad Debt & VAT Reclaims                  [Year 2026 ▾] [⬇ xlsx]│
│                                                              │
│  Written off this year   ₪45,200   ·   VAT reclaimed ₪6,882  │
│  ─────────────────────────────────────────────────────────── │
│  Open VAT reclaims (action needed)                           │
│  Invoice    Customer     VAT      Stage              Action  │
│  INV-0042   Acme Corp    ₪1,932   ○ letter not sent  [Update]│
│  INV-0051   Beta Ltd     ₪880     ● submitted to ITA [Update]│
│  ─────────────────────────────────────────────────────────── │
│  All written-off invoices (BAD_DEBT + WRITTEN_OFF)           │
│  INV-0042   Acme Corp   ₪12,700  BAD_DEBT   2026-06-01       │
└──────────────────────────────────────────────────────────────┘
```

- **Open VAT reclaims** renders `GET /api/bad-debt-reclaims?status=pending,submitted`; each row's **[Update]** opens the same status editor as the invoice-detail VAT-Reclaim panel (`PATCH /api/bad-debt-reclaims/:id`) — no need to open each invoice.
- **All written-off invoices** lists both statuses from the report endpoint; row click → invoice detail.
- Requires `reports:read`; status updates require `invoices:write`.

### Bad Debt Report (data)

`GET /api/reports/bad-debt?year=2026`

```json
{
  "year": 2026,
  "total_written_off": 45200,
  "total_vat_reclaimed": 6882,
  "by_reason": { "bankruptcy": 1, "collection_failed": 3, "other": 0 },
  "invoices": [
    {
      "invoice_number": "INV-0042",
      "customer_name": "Acme Corp",
      "amount": 12700,
      "vat_amount": 1932,
      "bad_debt_at": "2026-06-01",
      "vat_reclaim_status": "pending",
      "registered_letter_sent": false
    }
  ]
}
```

Excel download: `GET /api/reports/bad-debt/xlsx?year=2026`

Report used for annual income tax calculation (bad debts reduce taxable income) and for ITA VAT reclaim submissions.

---

## Financial Statement Impact

In the P&L statement (spec 170), bad debt write-offs appear as a **deduction from revenue**:
- Gross revenue includes all TAX_ISSUED invoices
- "Bad debt write-offs" is a line item deducted from gross revenue
- Net revenue = gross revenue − bad debt write-offs

The VAT reclaim (when approved) is shown as a credit in the "Other income" section.

---

## API

```
POST   /api/invoices/:id/write-off
       → write off invoice as bad debt
         body: { reason: 'bankruptcy'|'collection_failed'|'other', note?: string, log_vat_reclaim: boolean }
         Requires: invoices:write + OWNER or ADMIN role
         Returns: { invoiceId, vatReclaimId? }

GET    /api/bad-debt-reclaims
       → list VAT reclaim records (paginated)
         query: { status?, year? }
         Requires: invoices:read

PATCH  /api/bad-debt-reclaims/:id
       → update reclaim status
         body: { registered_letter_sent_at?, ita_submission_date?, ita_reference?, status?, notes? }
         Requires: invoices:write

GET    /api/reports/bad-debt
       → bad debt report data
         query: { year }
         Requires: reports:read

GET    /api/reports/bad-debt/xlsx
       → Excel download
         Requires: reports:export
```

---

## Architecture Decisions

| Decision | Choice | Reason |
|----------|--------|--------|
| `BAD_DEBT` as invoice status | Not a flag | Status is visible throughout the app (list, badges, portal); consistent with other terminal states (VOID, PAID) |
| Separate VAT reclaim table | Not columns on invoices | Reclaim has its own lifecycle (pending → submitted → approved); multiple steps; table allows one-per-invoice but with clear status tracking |
| Manual reclaim status update | Not automatic | ITA process requires physical letter + ITA portal submission; Zync can only track, not automate, the legal steps |
| 90-day eligibility threshold | Configurable per tenant | ITA sets no strict minimum period; 90 days is conservative practice; some tenants may write off faster or slower |
| Write-off requires OWNER/ADMIN | Not any invoices:write | Write-off is financially consequential; accidental or unauthorized write-offs would distort revenue reports; privilege escalation appropriate |
