# Invoice Credit Notes

**Date:** 2026-05-31  
**Status:** Draft  
**Spec:** 86  
**Tier:** All tiers  
**Depends on:** `invoices-core`, `foundation-auth-rbac`, `audit-compliance`  
**Referenced by:** `invoices-core`

---

## Overview

Credit notes (חשבונית זיכוי) are negative-total invoices issued to reverse or partially cancel a previously issued invoice. Spec 15 (`invoices-core`) already reserves the data shape: `invoices.source = 'credit_note'` with negative line totals and `parent_invoice_id` linking to the original. This spec defines the creation flow, UI, and status lifecycle.

---

## Data Model

No new tables. Spec 15 already provides:

```sql
-- Already in spec 15:
-- invoices.source TEXT (values: 'invoice' | 'proforma' | 'credit_note')
-- ALTER TABLE invoices ADD COLUMN parent_invoice_id UUID;
```

Credit notes are rows in `invoices` where:
- `source = 'credit_note'`
- All `invoice_lines.unit_price` values are **negative** (or `invoice_lines.quantity` is negative)
- `invoices.total` is negative
- `parent_invoice_id` references the original invoice

---

## Status Lifecycle

A credit note (חשבונית זיכוי) is a **business-issued reversal** — the customer does not approve it. It therefore **skips the customer-approval states** (`SENT`, `APPROVED`) that a normal sales invoice passes through. It shares the `InvoiceStatus` enum with regular invoices but uses only this subset:

```
DRAFT  ──[Issue credit note]──►  TAX_ISSUED  ──►  PAID/PARTIALLY_PAID
  │
  └──[Void / Delete draft]──►  (removed)
```

- **DRAFT** — being composed; no credit-note number assigned yet; freely editable; deletable.
- **TAX_ISSUED** — the IL-law-required issued state. On this transition the credit-note number is assigned from the `credit_note` sequence and the document is pushed to the configured ITA adapter (`createCreditNote`, spec 16). This is the terminal *issued* state for a full reversal — no customer approval ever applies.
- **PAID / PARTIALLY_PAID** — only relevant when the credit note is settled by refunding the customer; `amount_paid` and `PARTIALLY_PAID` (spec 80) apply identically.

A credit note is **never** in `SENT` or `APPROVED`: those represent the customer agreeing to a proposal/invoice, which has no meaning for a reversal the business issues unilaterally.

---

## Creation Flow

### From Invoice Detail Page

Accessible when original invoice `status IN ('SENT', 'APPROVED', 'TAX_ISSUED', 'PAID')`:

```
┌──────────────────────────────────────────────────────────────┐
│  Invoice #INV-0042                          [⋯ More actions]  │
│                                                              │
│  ⋯ More actions menu:                                        │
│  ├ Send reminder                                             │
│  ├ Duplicate                                                 │
│  └ Create credit note  ← only for qualifying statuses       │
└──────────────────────────────────────────────────────────────┘
```

### Credit Note Creation Form

Pre-filled from parent invoice; all fields editable:

```
┌──────────────────────────────────────────────────────────────┐
│  New Credit Note                                             │
│  Crediting: Invoice #INV-0042 (₪3,500)                      │
│                                                              │
│  ● Full credit    ○ Partial credit                           │
│                                                              │
│  ── Line items (pre-filled, negate to edit) ─────────────── │
│                                                              │
│  Description             Qty    Price      Total             │
│  Web design — homepage    1     −₪3,500   −₪3,500           │
│                                                              │
│  [+ Add line]                                                │
│                                                              │
│  Reason:  [Cancellation per client request_____________]     │
│                                                              │
│  Credit total:  −₪3,500                                      │
│                                                              │
│  [Cancel]            [Save as Draft]   [Issue credit note]   │
└──────────────────────────────────────────────────────────────┘
```

**Full credit** mode: copies all parent invoice lines with negated quantities. Locked to parent totals.  
**Partial credit** mode: staff enters custom lines (freely editable quantities and prices, must be negative).

### Actions

- **[Save as Draft]** — persists the credit note in `DRAFT` (no number assigned, nothing pushed). Used when the document needs review before issuance.
- **[Issue credit note]** — the issuance action (also available on an existing `DRAFT` credit note's detail page). It runs in a single transaction:
  1. Validates the reason and that the credit total does not exceed the parent total.
  2. Assigns the credit-note number from the `credit_note` sequence (`nextInvoiceNumber(db, tenantId, 'credit_note')` → `CN-00001`). **The number is assigned at issue, never in draft** — gap-free numbering requirement.
  3. Sets `status = 'TAX_ISSUED'`, `tax_issued_at = now()`.
  4. If an invoice adapter is active, enqueues the adapter push (`adapter.createCreditNote`, spec 16; Morning type `305`). On the native ITA path (`ita-einvoice`, spec 165) registers the credit note directly with the ITA.
  5. Writes an audit record (spec 28).

A `DRAFT` credit note can be **voided/deleted** before issuance (see Draft Deletion). Once `TAX_ISSUED`, a credit note is immutable — like any tax document, correction is itself a further document, not an edit.

### Draft Deletion

A credit note that is still `DRAFT` (never issued, no number assigned) can be discarded outright:

```
┌──────────────────────────────────────────────────────────────┐
│  Delete draft credit note?                                   │
│  This credit note has not been issued and has no number.     │
│  It will be permanently removed.                             │
│  [Cancel]                              [Delete draft]        │
└──────────────────────────────────────────────────────────────┘
```

`DELETE /api/invoices/:id` (existing spec 15 endpoint) applies; it is rejected for any credit note whose `status != 'DRAFT'`. After issuance there is no delete path — only a reversing document.

### Reason Field

`invoices.notes` stores the credit reason. Required on credit note creation.

---

## Invoice Detail: Credit Notes Tab

Original invoice detail view gains a "Credit Notes" tab when one or more credit notes exist:

```
┌──────────────────────────────────────────────────────────────┐
│  Invoice #INV-0042                                           │
│  [Details]  [Activity]  [Payments]  [History]  [Credits]     │
│                                                              │
│  Credit notes issued against this invoice:                  │
│                                                              │
│  CN-00001   2026-05-28   −₪3,500   TAX_ISSUED               │
│                                          [View]             │
│                                                              │
│  Net invoiced:  ₪3,500 − ₪3,500 = ₪0                        │
└──────────────────────────────────────────────────────────────┘
```

Credit note list shows: credit note number, date, amount, status. "Net invoiced" computed as `parent.total + SUM(credit_notes.total)`.

---

## Invoice Number

Credit notes use their own sequence type `'credit_note'` in `invoice_sequences`:

```ts
// type = 'credit_note' → prefix 'CN-' + padded(last_number, 5) e.g. 'CN-00001'
await nextInvoiceNumber(db, tenantId, 'credit_note')
```

---

## Constraints

- Only one draft credit note per parent invoice at a time (prevent accidental duplicates)
- Total credit cannot exceed parent invoice total (validation at save)
- Cannot credit a DRAFT parent invoice
- Credit notes for TAX_ISSUED invoices must themselves be TAX_ISSUED before sending to customer (IL law requirement)

---

## API

```
POST /api/invoices/:id/credit-note
     → create credit note from parent invoice
       body: { mode: 'full' | 'partial', lines?: [...], reason: string }
       Creates invoice with source='credit_note', parent_invoice_id=:id
       Requires: invoices:write

GET /api/invoices/:id/credit-notes
     → list credit notes for parent invoice
       Requires: invoices:read

POST /api/invoices/:creditNoteId/issue
     → issue a DRAFT credit note (DRAFT → TAX_ISSUED)
       Assigns CN number from the 'credit_note' sequence, sets tax_issued_at,
       and (if an adapter is active) enqueues adapter.createCreditNote push.
       Rejected (422) if status != 'DRAFT' or credit total exceeds parent total.
       Requires: invoices:write
```

Draft deletion uses the existing `DELETE /api/invoices/:id` (spec 15), which rejects any credit note with `status != 'DRAFT'`.

Standard invoice endpoints (`GET/PATCH/POST /api/invoices`) apply to credit notes via `source = 'credit_note'` filter; no separate routes needed.

---

## Architecture Decisions

| Decision | Choice | Reason |
|----------|--------|--------|
| Credit notes = invoices | Not separate table | Spec 15 already reserves this shape; same PDF rendering, same status lifecycle, same email sending — no duplication |
| Separate `credit_note` sequence | Not shared with invoices | IL law requires distinct credit note numbering series; `CN-00001` ≠ `INV-00001` |
| Full vs partial mode | Not always partial | Full credit is 90% of use cases; pre-filling negated lines avoids manual data entry errors |
| Draft limit per parent | One at a time | Multiple drafts for same invoice are almost certainly user error; enforced at API, not DB (allow_multiple flag possible future extension) |
| Skip SENT/APPROVED states | Direct `DRAFT → TAX_ISSUED` | A credit note is a business-issued reversal, not a customer-approved sale; `SENT`/`APPROVED` model customer agreement, which has no meaning here. Reusing them would dead-end the document or imply an approval that never happens. |
| Number assigned at issue | Not at draft save | IL law requires gap-free credit-note numbering; assigning at draft would burn numbers on discarded drafts. The `[Issue credit note]` action is the single point that allocates the number and pushes to the adapter. |
| Draft deletable, issued immutable | `DELETE` only while DRAFT | Before issuance nothing is registered externally, so a draft is safely discardable; after `TAX_ISSUED` the document is filed with the ITA and can only be corrected by a further document. |
