File size: 2,048 Bytes
c2ea771
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from datetime import datetime

from pydantic import Field

from cbh.api.common.dto import TradeDirection
from cbh.api.rules.dto import RuleAction, RuleScope
from cbh.core.database import MongoBaseModel


class RuleModel(MongoBaseModel):
    """A broker's own logic, written down once and replayed on every line.

    Matching is deterministic and narrow: every condition that is set must
    hold. A rule with no conditions at all is refused on the way in, because it
    would silently touch the whole pack.
    """

    name: str
    description: str | None = None
    scope: RuleScope = RuleScope.CLIENT
    clientProfileId: str | None = None
    active: bool = True

    codePrefix: str | None = None
    originCountry: str | None = None
    destinationCountry: str | None = None
    direction: TradeDirection | None = None
    descriptionContains: str | None = None

    action: RuleAction = RuleAction.NOTE
    pinnedCode: str | None = None
    documentCodes: list[str] = Field(default_factory=list)
    note: str | None = None

    createdFromBatchId: str | None = None
    createdFromRowIndex: int | None = None
    createdBy: str | None = None

    hitCount: int = 0
    datetimeLastHit: datetime | None = None

    datetimeInserted: datetime = Field(default_factory=datetime.now)
    datetimeUpdated: datetime = Field(default_factory=datetime.now)

    @property
    def conditions(self) -> dict[str, str]:
        """The conditions actually set, for display and for specificity."""
        present = {
            "codePrefix": self.codePrefix,
            "originCountry": self.originCountry,
            "destinationCountry": self.destinationCountry,
            "direction": self.direction.name if self.direction else None,
            "descriptionContains": self.descriptionContains,
        }
        return {key: value for key, value in present.items() if value}

    @property
    def specificity(self) -> int:
        """How many conditions a rule sets. The narrowest rule wins a conflict."""
        return len(self.conditions)