# RequestLeaveCancel

## Permission Scope

`request`

## Overview

The requester files a cancellation of their own already-APPROVED leave, moving the `LeaveRequest` to CANCEL_PENDING and creating a second mirroring approval request; the ledger and time-tracking remain unchanged until the cancellation itself is decided.

## Business Rules

- Only reachable from APPROVED; there is no direct APPROVED -> CANCELLED transition — cancellation always routes through CANCEL_PENDING
- Only the original requester may file the cancellation
- Creates a new mirroring `approval`-module request (one step, leave-approver role, quorum ANY) for the cancellation decision through the injected approval seam; the created request's id becomes the LeaveRequest's current-decision `targetEntityId` (the original approval request is already resolved)
- `LeaveConsumption` rows are left untouched while CANCEL_PENDING — they are only touched on the subsequent approve/reject-cancel decision; leave-management never wrote a day status into time-tracking (the mapping is one-directional and pull-based), so nothing there changes either
- Filing is rejected if the sole eligible approver is the requester (same deadlock-avoidance rule as `requestLeave`, ADR-003)

## Process Flow

```mermaid
flowchart TD
    A[Requester files requestLeaveCancel against an APPROVED leave] --> B{Caller is the original requester?}
    B -- No --> R1[Reject: NOT_REQUESTER]
    B -- Yes --> C{Request status is APPROVED?}
    C -- No --> R2[Reject: INVALID_STATE_TRANSITION]
    C -- Yes --> D{Sole eligible approver is the requester?}
    D -- Yes --> R3[Reject: no valid approver]
    D -- No --> E[Transition LeaveRequest to CANCEL_PENDING]
    E --> F[Mirror a second bundled approval request for the cancellation decision]
    F --> G[Ledger and time-tracking remain unchanged]
```

## External Dependencies

- [leave-management::LeaveRequest](../model/LeaveRequest.md) - APPROVED -> CANCEL_PENDING transition
- approval module (cross-module, bundled) - mirroring approval request created for the cancellation decision (ADR-003)

## Error Scenarios

- **LEAVE_REQUEST_NOT_FOUND**: no LeaveRequest exists for the given id
- **INVALID_STATE_TRANSITION**: the LeaveRequest's current status does not permit this transition
- **NOT_REQUESTER**: the caller is not the worker who filed the request
- **NOT_ASSIGNEE**: no eligible approver exists other than the requester, or the resolver is not an eligible approver

## Test Cases

- filing a cancellation of an APPROVED leave moves it to CANCEL_PENDING and creates a mirroring approval request
- ledger and time-tracking are unchanged immediately after filing a cancellation
- filing a cancellation on a request that is not APPROVED is rejected
- filing a cancellation by a worker other than the original requester is rejected
- filing a cancellation is rejected when the sole eligible approver is the requester (NOT_ASSIGNEE)
- filing a cancellation mirrors a second approval request and stores its id as targetEntityId

> Note: the approval-module routing is now wired — requestLeaveCancel mirrors the cancellation
> decision through the injected approval seam (a deadlock-avoidance pre-check via `listUsersByRole`
> that rejects when the sole eligible approver is the requester → NOT_ASSIGNEE, then
> `createApprovalRequest` whose returned id is stored as the LeaveRequest's `targetEntityId`).

