# GenerateVariants

## Permission Scope

product

## Overview

generateVariants creates product variants from the cartesian product of attribute values assigned to an ACTIVE product. Each new variant creates a corresponding Item in item-management with a SKU produced by the injectable SKU generation strategy (default: sequential numbering based on product code). Generation is idempotent — existing axis value combinations are skipped.

The SKU generation strategy is injectable at module configuration time. The default strategy produces SKUs like `CLASSIC-TSHIRT-001`, `CLASSIC-TSHIRT-002` using sequential numbering per product. This avoids coupling SKUs to attribute value labels, ensuring label changes do not create inconsistencies. Custom strategies receive both attribute value IDs and their labels, and can implement any pattern (attribute-value slug, brand prefix, hash-based, etc.).

## Business Rules

- Target product must exist and be in ACTIVE status
- Product must have at least one attribute with assigned values
- Each unique combination of attribute values produces one variant
- Existing combinations are skipped (idempotent generation)
- Each new variant creates exactly one Item in item-management via createItem
- Generated Items are created in DRAFT status
- Generated Items inherit the product's configured UoM
- SKU is produced by the configured SKU generation strategy (receives product code, axis value IDs, current variant count for sequential numbering, and axis value labels)
- ProductVariant records store productId, axis value combination, and generated itemId
- Generation fails atomically if any Item creation fails (no partial generation)

## Process Flow

```mermaid
flowchart TD
    A[Receive generate request] --> B{Product exists?}
    B -->|No| C[Return error: PRODUCT_NOT_FOUND]
    B -->|Yes| D{Status is ACTIVE?}
    D -->|No| E[Return error: INVALID_PRODUCT_STATUS]
    D -->|Yes| F[Collect all attribute assignments and values]
    F --> G{Any attributes assigned?}
    G -->|No| H[Return error: NO_VARIANT_AXES]
    G -->|Yes| I[Compute cartesian product of attribute values]
    I --> J{For each combination}
    J --> K{Variant already exists?}
    K -->|Yes| L[Skip]
    K -->|No| M[Generate SKU via strategy]
    M --> N[Create Item in item-management]
    N --> O[Create ProductVariant record]
    O --> J
    J -->|All done| P[Return generated variants]
```

## External Dependencies

- [item-management::createItem](../../../item-management/docs/command/CreateItem.md) - Creates an Item for each new variant with generated SKU and inherited UoM

## Error Scenarios

- **PRODUCT_NOT_FOUND**: Specified product ID does not exist
- **INVALID_PRODUCT_STATUS**: Product is not in ACTIVE status (DRAFT or ARCHIVED)
- **NO_VARIANT_AXES**: Product has no attributes with assigned values
- **ATTRIBUTE_NOT_FOUND**: Specified attribute ID does not exist
- **ATTRIBUTE_VALUE_NOT_FOUND**: Referenced attribute value no longer exists (data integrity check)
- **ITEM_CREATION_FAILED**: Item creation in item-management failed (e.g., duplicate SKU) — entire generation is rolled back

## Test Cases

- should return ProductNotFoundError when product does not exist
- should return InvalidProductStatusError when product is not ACTIVE
- should return NoVariantAxesError when no attribute assignments exist
- should return AttributeNotFoundError when referenced attribute no longer exists
- should return AttributeValueNotFoundError when referenced value no longer exists
- should skip existing variant combinations (idempotency)
- should return ItemCreationFailedError when item creation fails
- should pass axis value labels to skuStrategy
- should generate multi-axis cartesian product variants
- should only generate new combinations when some already exist
- should generate variants successfully
