# create_product Lambda

## Description

AWS Lambda function that creates a product in the GraphQL Gateway as part of the **GRPS ingestion Step Function**.

Given a state machine context (sourced from GRPS), the lambda:

1. **Checks** whether a product already exists by UPC via `productByUpc` query
2. **If found** — stores the existing `productId` in the context and passes it downstream
3. **If not found** — creates a new product via `createProduct` mutation and stores the new `productId`

The resulting state machine context (including `product_id`) is returned and passed to the next lambda in the Step Function.

## Input

The lambda receives a state machine context JSON with the following structure:

```json
{
  "project": {
    "name": "Project Name",
    "project_code": "xxxxxxx",
    "project_id": 0000000,
    "artist": {
      "name": "Artist Name",
      "spotify_uri": "spotify:artist:...",
      "apple_id": "123456"
    }
  },
  "product": {
    "upc": "xxxxxxxxxxxx",
    "product_name": "Product Name",
    "grid": "Axxxxxxxxxxxxxxxxxxxxx",
    "display_artists": [
      {
        "name": "Artist Name",
        "spotify_uri": "spotify:artist:...",
        "apple_id": "123456"
      }
    ],
    "vendor_id": 00000,
    "subaccount_id": 00000,
    "parent_repertoire_owner_code": "xxxx",
    "repertoire_owner_code": "xxxx"
  },
  "tracks": [...],
  "label_participants": [
    {
      "name": "Artist Name",
      "artist_id": "123",
      "label_participant_id": "456",
      "label_participant_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "role": "MAIN_ARTIST"
    }
  ]
}
```

### Notes on `display_artists` and `label_participants`

- `display_artists` on the product are matched to `label_participants` by **name** to build the `participations` payload for the GraphQL mutation
- Each `label_participant` must have a valid `label_participant_uuid` — these are expected to be created by an earlier step in the Step Function
- `role` must be a valid `ProductArtistRole` GraphQL enum value (e.g. `MAIN_ARTIST`, `FEATURED_ARTIST`, `PRODUCER`, etc.)
- If a `display_artist` has no matching `label_participant`, `labelParticipantUuid` will be `None` and the GraphQL call will fail validation

## Output

Returns the full state machine context with `product.product_id` populated:

```json
{
  "product": {
    "product_id": 0000000,
    "upc": "xxxxxxxxxxxx",
    ...
  },
  ...
}
```

## Environment Variables

| Variable | Required | Default | Description |
|---|---|---|---|
| `GRAPHQL_GATEWAY_URL` | ✅ Yes | — | URL of the GraphQL Gateway |
| `OA_USER` | ✅ Yes | — | Orchard user ID sent as `Orchard-User-Id` header |
| `Environment` | No | `dev` | Deployment environment |
| `LOGGING_LEVEL` | No | `INFO` | Python logging level |

## Local Development

Copy `.env.shadow` to `.env` and fill in the required values:

```bash
cp .env.shadow .env
```

## Testing

Tests use `pytest` and are located in `tests/unit/`.

Run from the **project root** (required so the `common` package is on the path):

```bash
cd /path/to/lambda-data-platform-grps-ingester
python -m pytest lambda/create_product/tests/ -v
```

Run with coverage:

```bash
python -m pytest lambda/create_product/tests/ --cov=lambda/create_product/src --cov-report=term
```

Run linting:

```bash
cd lambda/create_product
python -m flake8 src/ tests/
```
