dodil/erp-brick-projects

src/brick_projects/domain/state.py

"""The state names the customer sees (pj_state). The states and the transitions between them are code;
only their names and order are the customer's: 'In review' may be called 'With client'. Which states are
open, terminal or count as delivered follows from the code and is shown, never edited.
"""
from dataclasses import dataclass

from brick_projects.domain.errors import RuleBroken
from brick_projects.domain.values import OPEN_ITEM_STATES, ItemState


@dataclass
class State:
    """One item state's display name and position on the board."""
    state_id: str
    name: str = ""
    position: int = 0

    @property
    def is_open(self) -> bool:
        return self.state_id in OPEN_ITEM_STATES

    @property
    def is_terminal(self) -> bool:
        return not self.is_open

    @property
    def counts_as_delivered(self) -> bool:
        return self.state_id == ItemState.DONE.value

    def rename(self, name=None, position=None) -> bool:
        """True when something changed. A name is 1–40 characters; a position 0–99."""
        changed = False
        if name is not None:
            name = name.strip()
            if not 1 <= len(name) <= 40:
                raise RuleBroken("a state's name is 1 to 40 characters")
            changed |= name != self.name
            self.name = name
        if position is not None:
            if not 0 <= position <= 99:
                raise RuleBroken("a state's position is 0 to 99")
            changed |= position != self.position
            self.position = position
        return changed


DEFAULT_STATES = (("planned", "Planned", 0), ("in_progress", "In progress", 1), ("blocked", "Waiting on client", 2),
                  ("in_review", "In review", 3), ("done", "Done", 4), ("cancelled", "Descoped", 5))