# Adjustment File Initialize

This Lambda function is the entry point for the adjustment file ingestion workflow. It validates incoming events and initializes a batch record for processing.

## Overview

Triggered by `abacus_outbox` when a `file_upload.completed` event occurs for an adjustment file.

**Position in Workflow:**
```
EventBridge
  ↓ file_upload.completed
[Adjustment File Initialize]     ← You are here
  ↓ adjustment_batch.initialized
Adjustment File Prepare
  ↓ adjustment_batch.prepared
Adjustment File Process Batch
  ↓
Adjustment File Complete
```

**Workflow Steps:**
1.  **Event Validation:** Validates the event structure using Pydantic.
2.  **Data Retrieval:** Queries the `file_upload` and `statement_period` tables.
3.  **Validation:**
    *   Ensures file upload status is `complete`.
    *   Ensures file upload type is `adjustments`.
4.  **Batch Initialization:** Creates or retrieves a `worksheet_flowthrough_batch` record with status `pending`.
    *   If already exists, ensures the batch is for the `current` statement period
5.  **Output:** Returns the batch ID, S3 bucket, and S3 key

## Performance Characteristics

- **Typical Duration:** < 2 seconds
- **Memory Requirements:** Low
- **Expected Volume:** Low frequency (per adjustment file upload event)

## Event Schema

**Input Event:**
```json
{
  "detail": {
    "metadata": {
      "correlation_id": "550e8400-e29b-41d4-a716-446655440000",
      "target_id": 123,
      "target_type": "file_upload"
    },
    "data": {
      "upload_type": "adjustments"
    }
  }
}
```

**Output Response:**
```json
{
  "metadata": {
    "correlation_id": "550e8400-e29b-41d4-a716-446655440000",
    "target_id": 456,
    "target_type": "worksheet_adjustment_batch"
  },
  "data": {
    "s3_bucket": "qa-abacus-adjustments",
    "s3_key": "uploads/2025/11/adjustment_file.csv"
  }
}
```

## Architecture & Design

*   **Hexagonal Architecture:** Separation of concerns between the core logic (`processor.py`), data access (`connectors/`), and schemas (`schemas/`).
*   **Type Safety:** Uses **Pydantic** models for strict typing of database records and events, ensuring data integrity throughout the application.
*   **Idempotency:** Designed to be safely retriable. If a batch already exists for a given file upload, it returns the existing ID instead of creating a duplicate.

## Database Dependencies

**Tables:**
- `file_upload` (read) - Source of upload metadata and S3 location
- `worksheet_flowthrough_batch` (write) - Creates/retrieves batch records for tracking
- `statement_period` (read) - Validates that batch is for current period

**Key Constraints:**
- Unique constraint on `worksheet_flowthrough_batch(file_upload_id)` ensures idempotency
- Foreign key relationship between batch and file_upload

## Edge Cases & Error Handling

| Scenario | Behavior | Retry Strategy |
| :--- | :--- | :--- |
| **File Upload Not Found** | Raises `FileUploadNotFoundError` if the file_upload record doesn't exist in database. | **Non-Retriable** |
| **Invalid Upload Status** | Raises `InvalidUploadStatusError` if `upload_status != 'complete'`. File must finish uploading before batch initialization. | **Non-Retriable** |
| **Invalid Upload Type** | Raises `InvalidUploadTypeError` if `upload_type != 'adjustments'`. This lambda only processes adjustment files. | **Non-Retriable** |
| **Statement Period Not Found** | Raises `StatementPeriodNotFoundError` if no current statement period exists in database. | **Non-Retriable** |
| **Batch Period Mismatch** | Raises `BatchStatementPeriodMismatchError` if an existing batch links to a different `statement_period_id` than the current period. Batch may be for a previous period. | **Non-Retriable** |
| **Invalid Batch Status** | Raises `InvalidBatchStatusError` if an existing batch has status other than `pending`. Batch may have already been processed. | **Non-Retriable** |
| **Adjustment File Creation** | Raises `StatementPeriodAdjustmentFileCreateError` if unable to create adjustment file record. | **Non-Retriable**  |
| **Adjustment File States Creation** | Raises `StatementPeriodAdjustmentFileStatesCreateError` if unable to create adjustment file states. | **Non-Retriable**  |
| **Concurrent Creation** | Handles `IntegrityError` gracefully. If two events try to create the same batch simultaneously, recovers and returns the existing batch ID. | **Handled Internally** |
| **Concurrent Creation Conflict** | Raises `TransientError` if IntegrityError occurs but existing batch cannot be found (rare race condition). | **Retriable** (via Step Functions) |
| **DB Connection** | Raises `TransientError` for temporary database connection issues (connection lost, timeout, server gone away). | **Retriable** (via Step Functions) |
| **Missing Correlation ID** | Generates a new UUID if `correlation_id` is missing from the event. | **Handled Internally** |
| **Event Validation** | Lambda handler raises `ValidationError` if event structure is invalid. | **Non-Retriable** |

## Environment Variables

| Variable | Description | Example |
|----------|-------------|---------|
| `ENVIRONMENT` | Deployment environment | `qa`, `prod` |
| `MYSQL_DB_HOST` | MySQL database host | `qa-db-royalty-accounting.theorchard.io` |
| `MYSQL_DB_NAME` | MySQL database name | `royalty_accounting` |
| `MYSQL_DB_USER` | MySQL username | `royalties` |

## Requirements

- Python 3.13
- [uv](https://docs.astral.sh/uv/) - Fast Python package manager
- Docker (for containerized testing)

## Local Development

### Setup
1.  Copy the environment file:
    ```bash
    cp .env.shadow .env
    ```
2.  Install dependencies:
    ```bash
    make env_dev
    ```

### Running Tests
*   **Unit Tests:** `make test` (runs pytest with coverage)
*   **Linting:** `make lint` (check) or `make lint_fix` (auto-fix)
*   **Formatting:** `make format` (check) or `make format_fix` (auto-fix)
*   **Docker Tests:** `make docker_test` (runs linting and tests inside a container)
*   **Integration Tests:** `make docker_test_local_integration` (runs integration tests in Docker with full service dependencies)

### Running Locally
Run the Lambda function handler locally as a script:
```bash
make run
```

Or run as a Docker container:
```bash
make docker_local_up
```

## Deployment

Deploys via the [Jenkins pipeline](https://pipeline.theorchard.io/job/lambda-abacus-pipeline/). A webhook triggers the deploy for changes in this directory.