107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
|
|
from datetime import datetime
|
||
|
|
from typing import Any, Dict, List, Literal, Optional
|
||
|
|
|
||
|
|
from pydantic import BaseModel, Field, field_validator
|
||
|
|
|
||
|
|
|
||
|
|
ShipmentStatus = Literal[
|
||
|
|
"draft",
|
||
|
|
"submitted",
|
||
|
|
"booked",
|
||
|
|
"in_transit",
|
||
|
|
"delivered",
|
||
|
|
"cancelled",
|
||
|
|
"failed",
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoAddress(BaseModel):
|
||
|
|
recipient_name: str = Field(min_length=2, max_length=150)
|
||
|
|
company_name: Optional[str] = Field(default=None, max_length=150)
|
||
|
|
address_line1: str = Field(min_length=2, max_length=200)
|
||
|
|
address_line2: Optional[str] = Field(default=None, max_length=200)
|
||
|
|
postal_code: str = Field(min_length=2, max_length=20)
|
||
|
|
city: str = Field(min_length=2, max_length=120)
|
||
|
|
country_code: str = Field(min_length=2, max_length=2)
|
||
|
|
phone: Optional[str] = Field(default=None, max_length=50)
|
||
|
|
email: Optional[str] = Field(default=None, max_length=150)
|
||
|
|
|
||
|
|
@field_validator("country_code")
|
||
|
|
@classmethod
|
||
|
|
def normalize_country_code(cls, value: str) -> str:
|
||
|
|
return value.strip().upper()
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoParcelInput(BaseModel):
|
||
|
|
weight_kg: float = Field(gt=0, le=2000)
|
||
|
|
length_cm: Optional[float] = Field(default=None, gt=0, le=400)
|
||
|
|
width_cm: Optional[float] = Field(default=None, gt=0, le=400)
|
||
|
|
height_cm: Optional[float] = Field(default=None, gt=0, le=400)
|
||
|
|
description: str = Field(min_length=1, max_length=255)
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoBookingCreate(BaseModel):
|
||
|
|
case_id: int = Field(gt=0)
|
||
|
|
customer_id: Optional[int] = Field(default=None, gt=0)
|
||
|
|
contact_id: Optional[int] = Field(default=None, gt=0)
|
||
|
|
product_code: str = Field(min_length=1, max_length=80)
|
||
|
|
product_name: Optional[str] = Field(default=None, max_length=180)
|
||
|
|
carrier_code: Optional[str] = Field(default=None, max_length=80)
|
||
|
|
carrier_name: Optional[str] = Field(default=None, max_length=120)
|
||
|
|
service_codes: List[str] = Field(default_factory=list, max_length=30)
|
||
|
|
own_agreement: bool = False
|
||
|
|
automatic_select_service_point: bool = False
|
||
|
|
address: ShipmondoAddress
|
||
|
|
parcels: List[ShipmondoParcelInput] = Field(min_length=1, max_length=30)
|
||
|
|
|
||
|
|
@field_validator("service_codes")
|
||
|
|
@classmethod
|
||
|
|
def normalize_service_codes(cls, values: List[str]) -> List[str]:
|
||
|
|
return list(dict.fromkeys(value.strip().upper() for value in values if value.strip()))
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoBookingResponse(BaseModel):
|
||
|
|
id: int
|
||
|
|
booking_ref: str
|
||
|
|
case_id: int
|
||
|
|
customer_id: Optional[int] = None
|
||
|
|
contact_id: Optional[int] = None
|
||
|
|
product_code: str
|
||
|
|
product_name: Optional[str] = None
|
||
|
|
carrier_code: Optional[str] = None
|
||
|
|
carrier_name: Optional[str] = None
|
||
|
|
service_codes: List[str] = Field(default_factory=list)
|
||
|
|
shipment_status: ShipmentStatus
|
||
|
|
recipient_name: str
|
||
|
|
city: str
|
||
|
|
country_code: str
|
||
|
|
tracking_number: Optional[str] = None
|
||
|
|
tracking_url: Optional[str] = None
|
||
|
|
label_url: Optional[str] = None
|
||
|
|
total_amount: Optional[float] = None
|
||
|
|
currency: Optional[str] = None
|
||
|
|
dry_run: bool
|
||
|
|
submitted_at: Optional[datetime] = None
|
||
|
|
created_at: datetime
|
||
|
|
updated_at: datetime
|
||
|
|
parcels: List[ShipmondoParcelInput] = Field(default_factory=list)
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoBookingListResponse(BaseModel):
|
||
|
|
items: List[ShipmondoBookingResponse]
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoBookingSubmitResponse(BaseModel):
|
||
|
|
booking_ref: str
|
||
|
|
status: ShipmentStatus
|
||
|
|
dry_run: bool
|
||
|
|
tracking_number: Optional[str] = None
|
||
|
|
tracking_url: Optional[str] = None
|
||
|
|
label_url: Optional[str] = None
|
||
|
|
total_amount: Optional[float] = None
|
||
|
|
currency: Optional[str] = None
|
||
|
|
|
||
|
|
|
||
|
|
class ShipmondoProductListResponse(BaseModel):
|
||
|
|
items: List[Dict[str, Any]]
|