- Updated links in index_old.html, varekob_salg.html, log.html, opportunities.html, detail.html, and various frontend files to point to the new versioned sag URLs. - Modified reminder_notification_service.py to reflect the new sag URL structure in notifications. - Added FedEx shipment management functionality, including API client, service layer, and router for handling FedEx bookings, tracking, and cancellations. - Created database migration for FedEx shipments, including tables for shipments, packages, and tracking events.
106 lines
3.0 KiB
Python
106 lines
3.0 KiB
Python
from datetime import datetime
|
|
from typing import List, Optional, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
ShipmentStatus = Literal[
|
|
"draft",
|
|
"submitted",
|
|
"booked",
|
|
"in_transit",
|
|
"delivered",
|
|
"cancelled",
|
|
"failed",
|
|
]
|
|
|
|
|
|
class FedExAddress(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)
|
|
|
|
|
|
class FedExPackageInput(BaseModel):
|
|
weight_kg: float = Field(gt=0, le=2000)
|
|
length_cm: float = Field(gt=0, le=400)
|
|
width_cm: float = Field(gt=0, le=400)
|
|
height_cm: float = Field(gt=0, le=400)
|
|
description: str = Field(min_length=1, max_length=255)
|
|
|
|
|
|
class FedExBookingCreate(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)
|
|
service_type: Literal["PRIORITY", "ECONOMY"] = "PRIORITY"
|
|
pickup_window_start: datetime
|
|
pickup_window_end: datetime
|
|
address: FedExAddress
|
|
packages: List[FedExPackageInput] = Field(min_length=1, max_length=30)
|
|
|
|
|
|
class FedExBookingSubmitResponse(BaseModel):
|
|
booking_ref: str
|
|
status: ShipmentStatus
|
|
dry_run: bool
|
|
tracking_number: Optional[str] = None
|
|
label_url: Optional[str] = None
|
|
|
|
|
|
class FedExTrackingEvent(BaseModel):
|
|
status: str
|
|
event_timestamp: datetime
|
|
description: Optional[str] = None
|
|
location_city: Optional[str] = None
|
|
location_country: Optional[str] = None
|
|
|
|
|
|
class FedExBookingResponse(BaseModel):
|
|
id: int
|
|
booking_ref: str
|
|
case_id: int
|
|
customer_id: Optional[int] = None
|
|
contact_id: Optional[int] = None
|
|
service_type: str
|
|
shipment_status: ShipmentStatus
|
|
recipient_name: str
|
|
city: str
|
|
country_code: str
|
|
tracking_number: Optional[str] = None
|
|
label_url: Optional[str] = None
|
|
dry_run: bool
|
|
pickup_window_start: datetime
|
|
pickup_window_end: datetime
|
|
submitted_at: Optional[datetime] = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
packages: List[FedExPackageInput] = Field(default_factory=list)
|
|
|
|
|
|
class FedExBookingListResponse(BaseModel):
|
|
items: List[FedExBookingResponse]
|
|
|
|
|
|
class FedExTrackingResponse(BaseModel):
|
|
booking_ref: str
|
|
shipment_status: ShipmentStatus
|
|
tracking_number: Optional[str] = None
|
|
events: List[FedExTrackingEvent] = Field(default_factory=list)
|
|
|
|
|
|
class FedExCancelRequest(BaseModel):
|
|
reason: Optional[str] = Field(default=None, max_length=400)
|
|
|
|
|
|
class FedExCancelResponse(BaseModel):
|
|
booking_ref: str
|
|
status: ShipmentStatus
|
|
cancelled: bool
|