forked from cosmicpython/code
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdomain_model.py
More file actions
107 lines (74 loc) · 2.47 KB
/
domain_model.py
File metadata and controls
107 lines (74 loc) · 2.47 KB
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from dataclasses import dataclass
from typing import List
from datetime import date
@dataclass
class OrderLine:
sku: str
quantity: int
@dataclass
class SkuLines:
lines: List[OrderLine]
@property
def skus(self):
return {l.sku for l in self.lines}
@property
def quantities(self):
return {l.sku: l.quantity for l in self.lines}
@dataclass
class Order(SkuLines):
def allocate(self, warehouse, shipments):
self.allocation = Allocation.for_order(self, warehouse, shipments)
self.allocation.decrement_source_quantities()
@dataclass
class Warehouse(SkuLines):
def can_allocate(self, line: OrderLine):
return line.sku in self.skus and self.quantities[line.sku] > line.quantity
def decrement_quantity(self, sku, quantity):
for line in self.lines:
if line.sku == sku:
line.quantity -= quantity
return
raise Exception(f'sku {sku} not found in warehouse skus ({self.skus})')
@dataclass
class Shipment(Warehouse):
eta: date = None
def __lt__(self, other):
return self.eta < other.eta
@dataclass
class AllocationLine:
sku: str
quantity: int
source: Warehouse
def decrement_source_quantity(self):
self.source.decrement_quantity(self.sku, self.quantity)
@dataclass
class Allocation:
lines: List[AllocationLine]
order: Order
@property
def skus(self):
return set(l.sku for l in self.lines)
@property
def sources(self):
return {l.sku: l.source for l in self.lines}
@staticmethod
def for_source(order: Order, source: Warehouse):
return Allocation(lines=[
AllocationLine(sku=line.sku, quantity=line.quantity, source=source)
for line in order.lines
if source.can_allocate(line)
], order=order)
@staticmethod
def for_order(order: Order, warehouse: Warehouse, shipments: List[Shipment]):
allocation = Allocation(lines=[], order=order)
for source in [warehouse] + sorted(shipments):
source_allocation = Allocation.for_source(order, source)
allocation.supplement_with(source_allocation)
return allocation
def supplement_with(self, other_allocation):
self.lines.extend(
l for l in other_allocation.lines if l.sku not in self.skus
)
def decrement_source_quantities(self):
for line in self.lines:
line.decrement_source_quantity()