Skip to content

Marketing

Referrals and campaigns.

Entity Relationship Diagram

Marketing ERD

Entities

iris.domain.marketing.entities

Marketing domain entities: Client, Opportunity, Product, SaleOrder, SaleOrderItem.

Client

Bases: NamedEntity

A client (individual or business) with contact, legal, and tax information.

client_type distinguishes between individual patients and institutional clients. Tax fields (tax_id, tax_id_type, tax_notes) and legal_address support invoicing requirements; all are optional.

Opportunity

Bases: NamedEntity

A sales opportunity linked to a client and responsible employee.

Tracks a potential sale from creation through to close (won or lost). is_active is False once the opportunity is closed; state changes are recorded as domain events (OpportunityWon, OpportunityLost) rather than by mutating this object.

Product

Bases: NamedEntity

A product or service offered by the laboratory.

product_type is a free-text classifier (e.g. "sequencing", "panel"). reference_price and tax_rate inform pricing at order time; is_active gates whether the product can appear in new SaleOrder items.

SaleOrder

Bases: NamedEntity

A sales order issued to a client from a specific branch.

Captures the commercial transaction: which Client ordered, from which Branch, on what date, and the monetary breakdown (amount, tax, discount, total). Line items are modelled separately as SaleOrderItem instances.

SaleOrderItem

A single line item within a sale order, referencing a product and its pricing.

Objects

iris.domain.marketing.objects

Marketing domain value objects: ClientType enum.

ClientType

Bases: Enum

Enumeration of client classification types.

Repositories

iris.domain.marketing.repositories

Repository interfaces for the marketing domain.

ClientRepository

Bases: CrudRepository[Client]

CRUD repository for Client entities.

find_by_type abstractmethod

find_by_type(client_type)

Return all clients of the given type.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_type(self, client_type: ClientType) -> Sequence[Client]:
    """Return all clients of the given type."""

get abstractmethod

get(identifier)

Return the entity matching identifier, or None if not found.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def get(self, identifier: str) -> T | None:
    """Return the entity matching `identifier`, or None if not found."""

save abstractmethod

save(entity)

Persist entity and return the saved version.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def save(self, entity: T) -> T:
    """Persist `entity` and return the saved version."""

delete abstractmethod

delete(identifier)

Remove the entity identified by identifier.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def delete(self, identifier: str) -> None:
    """Remove the entity identified by `identifier`."""

find_all abstractmethod

find_all()

Return all entities in the repository.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def find_all(self) -> Sequence[T]:
    """Return all entities in the repository."""

ProductRepository

Bases: CrudRepository[Product]

CRUD repository for Product entities.

find_active abstractmethod

find_active()

Return all active products.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_active(self) -> Sequence[Product]:
    """Return all active products."""

find_by_type abstractmethod

find_by_type(product_type)

Return all products of the given type.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_type(self, product_type: str) -> Sequence[Product]:
    """Return all products of the given type."""

get abstractmethod

get(identifier)

Return the entity matching identifier, or None if not found.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def get(self, identifier: str) -> T | None:
    """Return the entity matching `identifier`, or None if not found."""

save abstractmethod

save(entity)

Persist entity and return the saved version.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def save(self, entity: T) -> T:
    """Persist `entity` and return the saved version."""

delete abstractmethod

delete(identifier)

Remove the entity identified by identifier.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def delete(self, identifier: str) -> None:
    """Remove the entity identified by `identifier`."""

find_all abstractmethod

find_all()

Return all entities in the repository.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def find_all(self) -> Sequence[T]:
    """Return all entities in the repository."""

OpportunityRepository

Bases: CrudRepository[Opportunity]

CRUD repository for Opportunity entities.

find_by_client abstractmethod

find_by_client(client_id)

Return all opportunities associated with a given client.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_client(self, client_id: str) -> Sequence[Opportunity]:
    """Return all opportunities associated with a given client."""

find_active abstractmethod

find_active()

Return all currently active opportunities.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_active(self) -> Sequence[Opportunity]:
    """Return all currently active opportunities."""

find_by_employee abstractmethod

find_by_employee(employee_id)

Return all opportunities assigned to a given employee.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_employee(self, employee_id: str) -> Sequence[Opportunity]:
    """Return all opportunities assigned to a given employee."""

get abstractmethod

get(identifier)

Return the entity matching identifier, or None if not found.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def get(self, identifier: str) -> T | None:
    """Return the entity matching `identifier`, or None if not found."""

save abstractmethod

save(entity)

Persist entity and return the saved version.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def save(self, entity: T) -> T:
    """Persist `entity` and return the saved version."""

delete abstractmethod

delete(identifier)

Remove the entity identified by identifier.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def delete(self, identifier: str) -> None:
    """Remove the entity identified by `identifier`."""

find_all abstractmethod

find_all()

Return all entities in the repository.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def find_all(self) -> Sequence[T]:
    """Return all entities in the repository."""

SaleOrderRepository

Bases: CrudRepository[SaleOrder]

CRUD repository for SaleOrder entities.

find_by_client abstractmethod

find_by_client(client_id)

Return all sales orders for a given client.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_client(self, client_id: str) -> Sequence[SaleOrder]:
    """Return all sales orders for a given client."""

find_by_date_range abstractmethod

find_by_date_range(start, end)

Return all sales orders with a date within [start, end].

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_date_range(self, start: dt.date, end: dt.date) -> Sequence[SaleOrder]:
    """Return all sales orders with a date within [start, end]."""

find_by_branch abstractmethod

find_by_branch(branch_id)

Return all sales orders recorded in a given branch.

Source code in src/iris/domain/marketing/repositories.py
@abstractmethod
def find_by_branch(self, branch_id: str) -> Sequence[SaleOrder]:
    """Return all sales orders recorded in a given branch."""

get abstractmethod

get(identifier)

Return the entity matching identifier, or None if not found.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def get(self, identifier: str) -> T | None:
    """Return the entity matching `identifier`, or None if not found."""

save abstractmethod

save(entity)

Persist entity and return the saved version.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def save(self, entity: T) -> T:
    """Persist `entity` and return the saved version."""

delete abstractmethod

delete(identifier)

Remove the entity identified by identifier.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def delete(self, identifier: str) -> None:
    """Remove the entity identified by `identifier`."""

find_all abstractmethod

find_all()

Return all entities in the repository.

Source code in src/iris/domain/generic/repositories.py
@abstractmethod
def find_all(self) -> Sequence[T]:
    """Return all entities in the repository."""

Events

iris.domain.marketing.events

Domain events for the marketing bounded context.

ClientRegistered

Emitted when a new client is registered in the system.

ClientUpdated

Emitted when an existing client's information is updated.

OpportunityCreated

Emitted when a new sales opportunity is created.

OpportunityWon

Emitted when a sales opportunity is marked as won.

OpportunityLost

Emitted when a sales opportunity is marked as lost.

ProductCreated

Emitted when a new product is created in the catalog.

ProductDeactivated

Emitted when a product is deactivated and removed from sale.

SaleRecorded

Emitted when a sale order is recorded for a client.

Exceptions

iris.domain.marketing.exceptions

Exceptions for the marketing domain.

MarketingError

Bases: Exception

Base exception for the marketing domain.

ClientNotFoundError

Bases: MarketingError

Raised when a client cannot be found by the given identifier.

ProductNotFoundError

Bases: MarketingError

Raised when a product cannot be found by the given identifier.

ProductInactiveError

Bases: MarketingError

Raised when an operation requires an active product but the product is inactive.

OpportunityNotFoundError

Bases: MarketingError

Raised when an opportunity cannot be found by the given identifier.

OpportunityAlreadyClosedError

Bases: MarketingError

Raised when attempting to modify an opportunity that has already been won or lost.

SaleOrderNotFoundError

Bases: MarketingError

Raised when a sale order cannot be found by the given identifier.