dodil/erp-brick-product

src/brick_product/domain/events.py

"""Domain events: one per workflow transition, named for what happened. An aggregate records them in
`.events`; nothing publishes them yet — a brick that needs another to react calls its seam.
"""
from dataclasses import dataclass


@dataclass(frozen=True)
class ProductAdded:
    """add_product: product none → draft. The code is fixed from now on."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class DuplicateChecked:
    """ai_check_duplicate: product draft → draft. A likely duplicate is shown; nothing is merged."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class DetailsSuggested:
    """ai_suggest_details: product draft → draft. A suggestion the catalogue manager accepts or changes."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class UnitsSet:
    """set_units: product draft → draft. Purchase, sales and issue units chosen."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class UnitAdded:
    """add_unit: product active → active. The new unit can be bought, sold or issued from now."""
    product_id: str
    unit_code: str = ""
    by: str = ""


@dataclass(frozen=True)
class ProductCompleted:
    """complete_product: product draft → draft."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class ProductActivated:
    """activate_product: product draft → active. Offered to sales."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class ProductRenamed:
    """rename_product: product active → active. Documents already raised keep their copy."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class ProductArchived:
    """archive_product: product active → archived. No new lines; existing documents unchanged."""
    product_id: str
    by: str = ""


@dataclass(frozen=True)
class ProductReactivated:
    """reactivate_product: product archived → active."""
    product_id: str
    reason: str = ""
    by: str = ""


@dataclass(frozen=True)
class PriceListOpened:
    """open_price_list: price_list none → draft. Based on another list, or standalone."""
    price_list_id: str
    by: str = ""


@dataclass(frozen=True)
class PricesSet:
    """set_prices: price_list draft → draft. Dated rows; nothing visible to sales yet."""
    price_list_id: str
    by: str = ""


@dataclass(frozen=True)
class PricesChecked:
    """ai_price_check: price_list draft → draft. Outliers are listed for the pricing manager."""
    price_list_id: str
    by: str = ""


@dataclass(frozen=True)
class PriceListPublished:
    """publish_price_list: price_list draft → published, or a pending change of a published list goes live."""
    price_list_id: str
    by: str = ""


@dataclass(frozen=True)
class PricesChanged:
    """change_prices: price_list published → published. New rows with a later valid_from; old rows never edited."""
    price_list_id: str
    by: str = ""


@dataclass(frozen=True)
class CustomerAssigned:
    """assign_customer: price_list published → published. Their prices in this currency resolve from this list."""
    price_list_id: str
    bp_id: int = 0
    by: str = ""


@dataclass(frozen=True)
class PriceListRetired:
    """retire_price_list: price_list published → retired. Assigned customers fall back to the default list."""
    price_list_id: str
    by: str = ""


@dataclass(frozen=True)
class ProductTypeChanged:
    """change_product_type: product draft → draft. Kind, stocked default and activation requirements follow the new type."""
    product_id: str
    product_type_code: str = ""
    by: str = ""