# `ChargeController` plan ## Scope - **Controller**: `app/Http/Controllers/Api/Finance/ChargeController.php` - **Purpose**: list charges for a parent and manage extra/event charges (create/cancel/apply/mark paid). - **Primary dependency**: `App\Services\Billing\ChargeService` - **Resources**: - `ChargeListResource` (for list responses) - `ChargeActionResource` (for mutation responses) ## Routes All routes are under: - Base prefix: `/api/v1/finance/fees/charges` Endpoints: - `GET /api/v1/finance/fees/charges/` → `index` - `POST /api/v1/finance/fees/charges/extra` → `storeExtra` - `POST /api/v1/finance/fees/charges/event` → `storeEvent` - `POST /api/v1/finance/fees/charges/extra/{id}/cancel` → `cancelExtra` - `POST /api/v1/finance/fees/charges/extra/{id}/apply` → `applyExtra` - `POST /api/v1/finance/fees/charges/event/{id}/cancel` → `cancelEvent` - `POST /api/v1/finance/fees/charges/event/{id}/mark-paid` → `markEventPaid` ## Authentication & authorization - `storeExtra` / `storeEvent` require an authenticated user id (checked by `authenticatedUserIdOrUnauthorized()`). - Other endpoints currently do not call the helper; authorization is expected to be enforced by surrounding route middleware and/or service-layer checks. ## Requests/validation - `index`: `ChargeListRequest` (`parent_id` required; optional `school_year`) - `storeExtra`: `StoreExtraChargeRequest` (+ adds `created_by` from authenticated user) - `storeEvent`: `StoreEventChargeRequest` (+ adds `created_by`) - `applyExtra`: `ApplyExtraChargeRequest` (`invoice_id`) - `markEventPaid`: `MarkEventChargePaidRequest` (`paid`, optional `payment_id`) - `cancelEvent`: uses raw `Request` with query boolean `issue_credit` (default true) ## Response shapes Legacy `{ ok: ... }` shape: - `index`: - `{ ok:true, charges: ChargeListResource }` - Mutations: - `{ ok:(bool), charge: ChargeActionResource }` - HTTP status: - Create success: `201` - Duplicate charge success-case: `409` (when `error === "duplicate_charge"`) - Validation/business failure: `422` - Cancel/apply/mark-paid: `200` when ok, else `422` ## Side effects - `storeExtra` / `storeEvent` attach `created_by` for auditing. - `cancelEvent` optionally issues credits (controlled via `issue_credit` query flag). - `markEventPaid` can link to a `payment_id` when supplied. ## Error handling expectations - `storeExtra` / `storeEvent` catch unexpected exceptions: - return `500` `{ ok:false, message:"Unable to create ... charge." }` - Unauthorized (store endpoints) returns: - `401` `{ ok:false, message:"Unauthorized." }` ## Test plan (feature) - Listing: - Returns `ChargeListResource` payload for a parent with charges. - Create extra/event: - Unauthenticated → 401. - Valid payload → 201 and ok true. - Duplicate charge → 409. - Service exception → 500. - Apply extra: - Valid invoice id applies charge → 200. - Invalid invoice/charge → 422. - Cancel: - Extra cancel → 200/422 depending on service result. - Event cancel with `issue_credit=false` behaves accordingly. - Mark paid: - Toggle paid true/false; supports payment_id link.