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
|
from datetime import datetime
from decimal import Decimal
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional
class ProductCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=255)
sku: str = Field(
...,
min_length=1,
max_length=100,
description="Stock-keeping unit — must be unique",
)
quantity_in_stock: int = Field(
..., ge=0, description="Initial stock level, cannot be negative"
)
class ProductUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=255)
quantity_in_stock: Optional[int] = Field(None, ge=0)
class ProductOut(BaseModel):
id: int
name: str
sku: str
quantity_in_stock: int
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class StockMovementOut(BaseModel):
id: int
product_id: int
order_id: int
movement_type: str
quantity_change: int
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class ReservedItem(BaseModel):
product_id: int
quantity: int
class FailedItem(BaseModel):
product_id: int
quantity: int
class StockReservedEvent(BaseModel):
"""
Emitted on the 'inventory' topic when stock is successfully reserved.
Example payload:
{
"order_id": 123,
"status": "SUCCESS",
"reserved_items": [
{"product_id": 101, "quantity": 2},
{"product_id": 102, "quantity": 1}
]
}
"""
order_id: int
status: str = "SUCCESS"
reserved_items: list[ReservedItem]
class StockReservationFailedEvent(BaseModel):
"""
Emitted on the 'inventory' topic when stock cannot be reserved.
Example payload:
{
"order_id": 123,
"status": "FAILED",
"reason": "INSUFFICIENT_STOCK",
"failed_items": [{"product_id": 102, "quantity": 5}]
}
"""
order_id: int
status: str = "FAILED"
reason: str = "INSUFFICIENT_STOCK"
failed_items: list[FailedItem]
|