# Receipts Module — Architecture Map

> **Last updated:** 2026-06-10
> **Status:** Living document — incrementally updated as new information is discovered

---

## 1. Purpose & Responsibilities

The Receipts module is a **read-heavy, audit-focused** module that manages:
- Viewing and filtering issued payment receipts
- Printing receipts (with print count tracking)
- Voiding receipts (cascades to underlying payment)
- Displaying voided receipts separately
- Providing receipt number generation (REC-YYYY-NNNNNN)

It does **NOT** directly manage:
- Creating receipts (Payments/PaymentService creates them as part of payment processing)
- Processing payments (Payments module)
- Treasury operations (Treasury module)
- Accounting entries (Accounting module)

**Key insight:** This module is essentially a **view layer** over the `receipts` table which is populated by the Payments module. It provides browsing, printing, and voiding capabilities but never creates receipts itself.

---

## 2. Directory & File Structure

```
app/Modules/Receipts/
├── bootstrap.php                      # Permission registration only (no menu, no events)
├── Routes.php                         # 4 web routes
├── Controllers/
│   └── ReceiptController.php         # index, voided, printReceipt, voidReceipt
├── Models/
│   └── Receipt.php                   # find, findWithDetails, generateNumber, search
└── Views/
    ├── index.php                     # Receipt list (active or voided)
    ├── print.php                     # Print-friendly receipt view
    └── voided.php                    # (uses same index.php with filter)
```

---

## 3. Database Schema (Production — Source of Truth)

### 3.1 `receipts` Table (412 rows as of 2026-06-10)

| Column | Type | Nullable | Key | Notes |
|--------|------|----------|-----|-------|
| id | bigint unsigned | NO | PRI | auto_increment |
| receipt_number | varchar(50) | NO | UNI | Format: REC-YYYY-NNNNNN |
| member_id | bigint unsigned | YES | MUL | FK to members |
| payment_id | bigint unsigned | YES | MUL | FK to payments |
| receipt_type | varchar(30) | NO | MUL | Default: 'payment' |
| amount | decimal(15,2) | NO | | Receipt amount |
| amount_in_words_ar | text | YES | | Arabic amount in words |
| description_ar | text | YES | | Receipt description |
| issued_by_employee_id | bigint unsigned | YES | | FK to employees |
| issued_at | timestamp | NO | MUL | Default: CURRENT_TIMESTAMP |
| is_voided | tinyint(1) | NO | MUL | Default: 0 |
| voided_at | timestamp | YES | | |
| voided_by | bigint unsigned | YES | | FK to employees |
| void_reason | text | YES | | Required when voiding |
| print_count | int unsigned | NO | | Default: 0 |
| last_printed_at | timestamp | YES | | |
| last_printed_by | bigint unsigned | YES | | FK to employees |
| created_at | timestamp | NO | | |

---

## 4. Core Business Flows

### 4.1 View Receipts

```
GET /receipts
- Filters: search (number/name/membership), date range
- Shows non-voided receipts by default
- Joins: members (name), employees (issued_by)
- Paginated (25 per page)
```

### 4.2 View Voided Receipts

```
GET /receipts/voided
- Same view but filtered to is_voided=1
- Allows tracking who voided and why
```

### 4.3 Print Receipt

```
GET /receipts/{id}/print
- Loads full receipt details (joins members, employees, payments, payment_requests)
- Extracts fee_breakdown from payment_request.notes JSON
- Increments print_count, records last_printed_at/by
- Renders print-friendly view
```

### 4.4 Void Receipt

```
POST /receipts/{id}/void
- Requires void_reason
- If receipt has payment_id:
    - Delegates to PaymentService::voidPayment() (cascading void)
    - PaymentService marks both payment and receipt as voided
- If receipt has no payment_id (standalone):
    - Directly marks receipt as voided
```

---

## 5. Events Dispatched

None. The Receipts module does not dispatch any events.

---

## 6. Events Consumed

None directly. However, voiding a receipt triggers `PaymentService::voidPayment()` which dispatches `payment.voided` — consumed by Treasury (custody reversal) and Accounting (GL reversal).

---

## 7. Cross-Module Dependencies

### 7.1 Receipts IMPORTS FROM:

| Module | What it uses |
|--------|-------------|
| Payments | PaymentService::voidPayment() for cascading void |
| Payments | Payment model (referenced in findWithDetails join) |

### 7.2 Other modules that IMPORT FROM/REFERENCE Receipts:

| Module | What it imports |
|--------|----------------|
| Payments | Creates rows in `receipts` table via PaymentService |
| Cashier | References receipt_number in queue views |
| Treasury | Passes receipt_number in payment collection responses |
| Reports | ReportEngine queries receipts for financial reports |

---

## 8. Permissions

| Key | Description | Used In Routes |
|-----|-------------|----------------|
| receipt.view | View receipts | (registered but routes use payment.view) |
| receipt.print | Print a receipt | (registered but routes use payment.view) |
| receipt.void | Void a receipt | (registered but routes use payment.void_receipt) |

**Important note:** The permissions registered in bootstrap.php (`receipt.view`, `receipt.print`, `receipt.void`) are NOT the same ones used in Routes.php (`payment.view`, `payment.void_receipt`). The routes use Payments module permissions — the Receipts module's own registered permissions appear unused.

---

## 9. Receipt Number Generation

| Type | Format | Table.Column | Example |
|------|--------|--------------|---------|
| Receipt | REC-YYYY-NNNNNN | receipts.receipt_number | REC-2026-000412 |

Generated by `Receipt::generateNumber()` — uses MAX(receipt_number) with LIKE pattern. This method is available for external callers (Payments module uses it when creating receipts).

---

## 10. Receipt Creation (External — by Payments Module)

Receipts are created by `PaymentService::processPayment()`, NOT by this module. The flow:

```
1. Payment is processed (from Treasury/Cashier/direct)
2. PaymentService creates payment record
3. PaymentService calls Receipt::generateNumber()
4. PaymentService inserts into `receipts` table:
   - receipt_number, member_id, payment_id, amount
   - description_ar, issued_by_employee_id, receipt_type
5. Returns receipt_number in response
```

---

## 11. High-Risk Areas

### 11.1 Permission Mismatch (LOW RISK — functional but confusing)
- bootstrap.php registers `receipt.view`, `receipt.print`, `receipt.void`
- Routes.php requires `payment.view`, `payment.void_receipt`
- This means receipt permissions are never actually checked — Payments permissions gate access
- If Payments permissions change, receipt access changes implicitly

### 11.2 Void Cascade
- Voiding a receipt with a payment_id triggers PaymentService::voidPayment()
- PaymentService void may trigger: payment.voided event → Treasury custody reversal → Accounting GL reversal
- If any step in the cascade fails, partial void state is possible

### 11.3 Receipt Without Payment
- Some receipts may have payment_id=NULL (standalone receipts)
- These are voided directly without payment cascade
- Origin of standalone receipts is unclear — may be legacy data

### 11.4 Print Count Tracking
- Controller increments print_count via raw UPDATE
- Receipt model also has incrementPrintCount() method (duplicated logic)
- No limit on reprinting — audit trail via last_printed_by

---

## 12. Known Patterns & Gotchas

1. **Not a standalone module**: This module is essentially a view/admin layer over data created by the Payments module
2. **No menu registration**: Receipts doesn't register a sidebar menu item — accessed via other modules' links or direct URL
3. **Fee breakdown from JSON**: Receipt print view extracts fee_breakdown from payment_request.notes JSON field — fragile if notes format changes
4. **412 receipts, 0 sales**: Most receipts are from membership payments, not POS sales (which have 0 rows)
5. **Receipt type field**: Defaults to 'payment' — no other types observed in current data

---

## Appendix: Files to Check Before Modifying Receipts

1. `app/Modules/Payments/Services/PaymentService.php` — Creates receipts, voids them
2. `app/Modules/Treasury/Services/TreasuryService.php` — References receipt_number
3. `app/Modules/Cashier/Views/queue.php` — Displays receipt info
4. `app/Modules/Payments/bootstrap.php` — May have receipt-related event handling
