# SubmitTimecard

## Permission Scope

`timecard`

## Overview

SubmitTimecard transitions an OPEN Timecard to SUBMITTED, recording `submittedAt`, and in the same transaction mirrors it with a bundled approval-module request (one step, timecard-approver role, quorum ANY), linked by `targetEntityId`.

## Business Rules

- Only a Timecard currently in OPEN state may be submitted (OPEN → SUBMITTED)
- SUBMITTED state always carries `submittedAt`
- Category totals must already reconcile to the sum of covered CalculatedTimeBlocks before submission is accepted
- Submission is rejected if, after excluding the requester (self-approval rules), no eligible approver (timecard-approver role) remains, so no request is ever created unapprovable (ADR-003)
- Creates the mirroring approval-module request via `createApprovalRequest` in direct mode: one step, assignee is the timecard-approver role with `roleQuorum: "ANY"`, `targetEntityType: "Timecard"` and `targetEntityId` set to the Timecard's id; the approver role's `roleId` is injected into time-tracking's `defineModule` params by the app layer
- Submitting does not itself change category totals; it only advances status, stamps the submission time, and creates the mirroring approval request

## Process Flow

```mermaid
flowchart TD
    A[Request to submit a Timecard] --> B[Look up Timecard]
    B --> C{Timecard exists and status = OPEN?}
    C -- No, not found --> D[Reject: TIMECARD_NOT_FOUND]
    C -- No, wrong status --> E[Reject: INVALID_STATUS_TRANSITION]
    C -- Yes --> F{At least one active approver other than the requester exists?}
    F -- No --> R1[Reject: NO_ELIGIBLE_APPROVER]
    F -- Yes --> G[Set status = SUBMITTED, submittedAt = now]
    G --> H[Create bundled approval request: one step, timecard-approver role, quorum ANY, targetEntityId = Timecard id]
    H --> I[Timecard awaits approver decision]
```

## External Dependencies

- approval module (cross-module, bundled) - mirroring approval request created for the SUBMITTED decision in direct mode, one step, timecard-approver role, quorum ANY, linked by `targetEntityId` (ADR-003)

## Error Scenarios

- **TIMECARD_NOT_FOUND**: no Timecard exists for the given id
- **INVALID_STATUS_TRANSITION**: the Timecard's current status does not permit this transition
- **NO_ELIGIBLE_APPROVER**: after excluding the requester, no eligible approver (timecard-approver role) remains, so the mirroring approval request could not be created

## Test Cases

- rejects with TIMECARD_NOT_FOUND when no Timecard exists for the given id
- rejects with INVALID_STATUS_TRANSITION when the Timecard is not OPEN
- rejects with NO_ELIGIBLE_APPROVER when the only approver is the requester
- creates a mirroring approval request and transitions to SUBMITTED with submittedAt
- rejects with APPROVAL_STEP_FAILED when the approval request cannot be created
