"""ABConnect 8_01 inventory, packing, and shipping contracts.
Checked against the server release DTOs and bundled ACPortal schema. Explicit
nulls in these write models clear nullable values; omitted fields stay omitted.
"""
from __future__ import annotations
from datetime import datetime
from typing import Any
from uuid import UUID
from pydantic import Field
from ab.api.models.base import RequestModel, ResponseModel
[docs]
class PackingRequestModel(RequestModel):
"""Strict packing input retaining explicit nulls for nullable server fields."""
[docs]
@classmethod
def check(cls, data: Any, exclude_unset: bool = True) -> Any:
"""Validate before transport without dropping explicit field clears."""
if isinstance(data, list):
return [cls.check(item, exclude_unset=exclude_unset) for item in data]
return cls.model_validate(data).model_dump(
by_alias=True,
exclude_unset=exclude_unset,
mode="json",
)
[docs]
class JobInventoryItemModel(PackingRequestModel):
"""JobInventoryItemModel contract from server release 8_01."""
sequence_no: int = Field(alias="sequenceNo", ge=1, le=1000, description="Display sequence within the job.")
quantity: int = Field(alias="quantity", ge=1, le=9999999, description="Number of physical items or handling units.")
name: str | None = Field(default=None, alias="name", max_length=250, description="Display name.")
is_active: bool = Field(alias="isActive", description="Whether this record participates in active packing.")
length: float | None = Field(default=None, alias="length", ge=0, le=9999, description="Length in inches.")
width: float | None = Field(default=None, alias="width", ge=0, le=9999, description="Width in inches.")
height: float | None = Field(default=None, alias="height", ge=0, le=9999, description="Height in inches.")
weight: float | None = Field(default=None, alias="weight", ge=0, le=999999, description="Weight in pounds.")
value: float | None = Field(
default=None, alias="value", ge=0, le=9999999.99, description="Declared inventory value."
)
c_pack_id: UUID | None = Field(default=None, alias="cPackId", description="CPack definition UUID.")
eccn: str | None = Field(
default=None, alias="eccn", max_length=16, description="Export Control Classification Number."
)
schedule_b: str | None = Field(
default=None, alias="scheduleB", max_length=16, description="Schedule B export classification."
)
customer_item_id: str | None = Field(
default=None, alias="customerItemId", max_length=50, description="Customer-supplied item reference."
)
item_notes: str | None = Field(
default=None, alias="itemNotes", max_length=250, description="Inventory notes, up to 250 characters."
)
noted_conditions: str | None = Field(
default=None,
alias="notedConditions",
max_length=250,
description="Observed inventory condition, up to 250 characters.",
)
auto_pack_off: bool = Field(
default=False, alias="autoPackOff", description="Disable automatic packing for this inventory item."
)
parent_inventory_item_id: int | None = Field(
default=None,
alias="parentInventoryItemId",
description="Parent inventory record ID, or null to clear the relationship.",
)
common_inventory_item_id: int | None = Field(
default=None, alias="commonInventoryItemId", description="Company common-inventory record ID."
)
labor_minutes: int = Field(
default=0, alias="laborMinutes", ge=0, le=6000000, description="Estimated packing labor in minutes."
)
commodity_id: int | None = Field(default=None, alias="commodityId", description="Commodity classification ID.")
[docs]
class JobInventoryItem(ResponseModel):
"""JobInventoryItem contract from server release 8_01."""
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
job_id: UUID | None = Field(default=None, alias="jobId", description="Owning job UUID.")
sequence_no: int | None = Field(default=None, alias="sequenceNo", description="Display sequence within the job.")
quantity: int | None = Field(
default=None, alias="quantity", description="Number of physical items or handling units."
)
name: str | None = Field(default=None, alias="name", description="Display name.")
is_active: bool | None = Field(
default=None, alias="isActive", description="Whether this record participates in active packing."
)
length: float | None = Field(default=None, alias="length", description="Length in inches.")
width: float | None = Field(default=None, alias="width", description="Width in inches.")
height: float | None = Field(default=None, alias="height", description="Height in inches.")
weight: float | None = Field(default=None, alias="weight", description="Weight in pounds.")
value: float | None = Field(default=None, alias="value", description="Declared inventory value.")
c_pack_id: UUID | None = Field(default=None, alias="cPackId", description="CPack definition UUID.")
eccn: str | None = Field(default=None, alias="eccn", description="Export Control Classification Number.")
schedule_b: str | None = Field(default=None, alias="scheduleB", description="Schedule B export classification.")
customer_item_id: str | None = Field(
default=None, alias="customerItemId", description="Customer-supplied item reference."
)
item_notes: str | None = Field(
default=None, alias="itemNotes", description="Inventory notes, up to 250 characters."
)
noted_conditions: str | None = Field(
default=None, alias="notedConditions", description="Observed inventory condition, up to 250 characters."
)
auto_pack_off: bool | None = Field(
default=None, alias="autoPackOff", description="Disable automatic packing for this inventory item."
)
document_exists: bool | None = Field(default=None, alias="documentExists", description="Document exists.")
parent_inventory_item_id: int | None = Field(
default=None,
alias="parentInventoryItemId",
description="Parent inventory record ID, or null to clear the relationship.",
)
common_inventory_item_id: int | None = Field(
default=None, alias="commonInventoryItemId", description="Company common-inventory record ID."
)
labor_minutes: int | None = Field(
default=None, alias="laborMinutes", description="Estimated packing labor in minutes."
)
commodity_id: int | None = Field(default=None, alias="commodityId", description="Commodity classification ID.")
cubic_feet: float | None = Field(default=None, alias="cubicFeet", description="Cubic feet.")
[docs]
class ContentHandlingUnitModel(PackingRequestModel):
"""ContentHandlingUnitModel contract from server release 8_01."""
count: int = Field(
default=0, alias="count", ge=0, le=9999999, description="Quantity assigned to the parent handling unit."
)
[docs]
class AddContentHandlingUnitModel(ContentHandlingUnitModel):
"""AddContentHandlingUnitModel contract from server release 8_01."""
id: int = Field(default=0, alias="id", description="Identifier of this record; scoped to the job.")
[docs]
class InventoryModel(PackingRequestModel):
"""InventoryModel contract from server release 8_01."""
count: int = Field(
default=0, alias="count", ge=0, le=9999999, description="Quantity assigned to the parent handling unit."
)
[docs]
class AddInventoryModel(InventoryModel):
"""AddInventoryModel contract from server release 8_01."""
id: int = Field(default=0, alias="id", description="Identifier of this record; scoped to the job.")
[docs]
class JobHandlingUnitModel(PackingRequestModel):
"""JobHandlingUnitModel contract from server release 8_01."""
quantity: int = Field(alias="quantity", ge=1, le=9999999, description="Number of physical items or handling units.")
is_active: bool = Field(alias="isActive", description="Whether this record participates in active packing.")
sequence_no: int = Field(alias="sequenceNo", ge=0, le=1000, description="Display sequence within the job.")
length: float | None = Field(default=None, alias="length", ge=0, le=9999, description="Length in inches.")
width: float | None = Field(default=None, alias="width", ge=0, le=9999, description="Width in inches.")
height: float | None = Field(default=None, alias="height", ge=0, le=9999, description="Height in inches.")
weight: float | None = Field(default=None, alias="weight", ge=0, le=999999, description="Weight in pounds.")
container_type_id: int | None = Field(
default=None, alias="containerTypeId", description="Handling-unit container type ID."
)
fill_id: int | None = Field(default=None, alias="fillId", description="Packing fill material ID.")
fill_rate: float | None = Field(
default=None, alias="fillRate", ge=0, le=100, description="Packing fill percentage, from 0 through 100."
)
inches_to_add: float | None = Field(
default=None, alias="inchesToAdd", ge=0, le=1000, description="Packing allowance in inches."
)
container_thickness: float | None = Field(
default=None, alias="containerThickness", ge=0, le=99, description="Container wall thickness in inches."
)
freight_class_id: UUID | None = Field(
default=None, alias="freightClassId", description="Freight classification UUID."
)
nmfc_item_no: str | None = Field(
default=None,
alias="nmfcItemNo",
max_length=50,
description="National Motor Freight Classification item number.",
)
labor_minutes: int | None = Field(
default=None, alias="laborMinutes", ge=0, le=6000000, description="Estimated packing labor in minutes."
)
declared_value: float | None = Field(
default=None, alias="declaredValue", ge=0, le=9999999.99, description="Declared handling-unit value."
)
name: str | None = Field(default=None, alias="name", max_length=250, description="Display name.")
has_custom_name: bool = Field(
default=False, alias="hasCustomName", description="Whether the display name was supplied by the caller."
)
[docs]
class AddJobHandlingUnitModel(JobHandlingUnitModel):
"""AddJobHandlingUnitModel contract from server release 8_01."""
content_handling_units: list[AddContentHandlingUnitModel] | None = Field(
default=None, alias="contentHandlingUnits", description="Nested handling units and their assigned quantities."
)
inventory_items: list[AddInventoryModel] | None = Field(
default=None,
alias="inventoryItems",
description="Inventory records and quantities contained by this handling unit.",
)
[docs]
class ContentInventoryItem(ResponseModel):
"""ContentInventoryItem contract from server release 8_01."""
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
count: int | None = Field(default=None, alias="count", description="Quantity assigned to the parent handling unit.")
[docs]
class ContentHandlingUnit(ResponseModel):
"""ContentHandlingUnit contract from server release 8_01."""
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
count: int | None = Field(default=None, alias="count", description="Quantity assigned to the parent handling unit.")
[docs]
class HandlingUnitMaterial(ResponseModel):
"""HandlingUnitMaterial contract from server release 8_01."""
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
material_id: int | None = Field(default=None, alias="materialId", description="Company material definition ID.")
material_name: str | None = Field(default=None, alias="materialName", description="Material name.")
material_description: str | None = Field(
default=None, alias="materialDescription", description="Material description."
)
quantity_planned: float | None = Field(
default=None, alias="quantityPlanned", description="Planned material quantity."
)
unit_cost: float | None = Field(default=None, alias="unitCost", description="Cost per material unit.")
added_by_auto_packer: bool | None = Field(
default=None, alias="addedByAutoPacker", description="Whether automatic packing added this material."
)
waste_quantity: float | None = Field(
default=None, alias="wasteQuantity", description="Material quantity consumed as waste."
)
quantity: float | None = Field(
default=None, alias="quantity", description="Number of physical items or handling units."
)
[docs]
class ContainerDimensions(ResponseModel):
"""ContainerDimensions contract from server release 8_01."""
length: float | None = Field(default=None, alias="length", description="Length in inches.")
width: float | None = Field(default=None, alias="width", description="Width in inches.")
height: float | None = Field(default=None, alias="height", description="Height in inches.")
[docs]
class ContainerHandlingUnitMaterial(HandlingUnitMaterial):
"""ContainerHandlingUnitMaterial contract from server release 8_01."""
dimensions: ContainerDimensions | None = Field(default=None, alias="dimensions", description="Dimensions.")
[docs]
class JobHandlingUnit(ResponseModel):
"""JobHandlingUnit contract from server release 8_01."""
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
job_id: UUID | None = Field(default=None, alias="jobId", description="Owning job UUID.")
quantity: int | None = Field(
default=None, alias="quantity", description="Number of physical items or handling units."
)
is_active: bool | None = Field(
default=None, alias="isActive", description="Whether this record participates in active packing."
)
sequence_no: int | None = Field(default=None, alias="sequenceNo", description="Display sequence within the job.")
length: float | None = Field(default=None, alias="length", description="Length in inches.")
width: float | None = Field(default=None, alias="width", description="Width in inches.")
height: float | None = Field(default=None, alias="height", description="Height in inches.")
weight: float | None = Field(default=None, alias="weight", description="Weight in pounds.")
container_type_id: int | None = Field(
default=None, alias="containerTypeId", description="Handling-unit container type ID."
)
container_name: str | None = Field(default=None, alias="containerName", description="Container name.")
fill_id: int | None = Field(default=None, alias="fillId", description="Packing fill material ID.")
fill_rate: float | None = Field(
default=None, alias="fillRate", description="Packing fill percentage, from 0 through 100."
)
inches_to_add: float | None = Field(default=None, alias="inchesToAdd", description="Packing allowance in inches.")
container_thickness: float | None = Field(
default=None, alias="containerThickness", description="Container wall thickness in inches."
)
freight_class_id: UUID | None = Field(
default=None, alias="freightClassId", description="Freight classification UUID."
)
nmfc_item_no: str | None = Field(
default=None, alias="nmfcItemNo", description="National Motor Freight Classification item number."
)
labor_minutes: int | None = Field(
default=None, alias="laborMinutes", description="Estimated packing labor in minutes."
)
declared_value: float | None = Field(
default=None, alias="declaredValue", description="Declared handling-unit value."
)
document_exists: bool | None = Field(default=None, alias="documentExists", description="Document exists.")
name: str | None = Field(default=None, alias="name", description="Display name.")
has_custom_name: bool | None = Field(
default=None, alias="hasCustomName", description="Whether the display name was supplied by the caller."
)
inventory_items: list[ContentInventoryItem] | None = Field(
default=None,
alias="inventoryItems",
description="Inventory records and quantities contained by this handling unit.",
)
content_handling_units: list[ContentHandlingUnit] | None = Field(
default=None, alias="contentHandlingUnits", description="Nested handling units and their assigned quantities."
)
materials: list[HandlingUnitMaterial] | None = Field(
default=None, alias="materials", description="Complete material arrangement for this handling unit."
)
container_handling_unit_material_id: int | None = Field(
default=None,
alias="containerHandlingUnitMaterialId",
description="Assigned handling-unit material row ID, or null to clear.",
)
container_handling_unit_material: ContainerHandlingUnitMaterial | None = Field(
default=None, alias="containerHandlingUnitMaterial", description="Container handling unit material."
)
material_total_cost: float | None = Field(
default=None, alias="materialTotalCost", description="Material total cost."
)
is_used_in_shipment: bool | None = Field(default=None, alias="isUsedInShipment", description="Is used in shipment.")
cubic_feet: float | None = Field(default=None, alias="cubicFeet", description="Cubic feet.")
[docs]
class JobHandlingUnitDetails(JobHandlingUnit):
"""JobHandlingUnitDetails contract from server release 8_01."""
pass
[docs]
class HandlingUnitMaterialModel(PackingRequestModel):
"""HandlingUnitMaterialModel contract from server release 8_01."""
material_id: int = Field(default=0, alias="materialId", description="Company material definition ID.")
quantity_planned: float = Field(default=0.0, alias="quantityPlanned", description="Planned material quantity.")
unit_cost: float = Field(default=0.0, alias="unitCost", description="Cost per material unit.")
added_by_auto_packer: bool = Field(
default=False, alias="addedByAutoPacker", description="Whether automatic packing added this material."
)
waste_quantity: float = Field(
default=0.0, alias="wasteQuantity", description="Material quantity consumed as waste."
)
[docs]
class ManageableHandlingUnitMaterialModel(HandlingUnitMaterialModel):
"""ManageableHandlingUnitMaterialModel contract from server release 8_01."""
id: int = Field(default=0, alias="id", description="Identifier of this record; scoped to the job.")
[docs]
class ManageableJobHandlingUnitModel(JobHandlingUnitModel):
"""ManageableJobHandlingUnitModel contract from server release 8_01."""
id: int = Field(default=0, alias="id", description="Identifier of this record; scoped to the job.")
container_handling_unit_material_id: int | None = Field(
default=None,
alias="containerHandlingUnitMaterialId",
description="Assigned handling-unit material row ID, or null to clear.",
)
materials: list[ManageableHandlingUnitMaterialModel] | None = Field(
default=None, alias="materials", description="Complete material arrangement for this handling unit."
)
content_handling_units: list[AddContentHandlingUnitModel] | None = Field(
default=None, alias="contentHandlingUnits", description="Nested handling units and their assigned quantities."
)
[docs]
class ManageHandlingUnitsModel(PackingRequestModel):
"""ManageHandlingUnitsModel contract from server release 8_01."""
job_modified_date: datetime | None = Field(
default=None,
alias="jobModifiedDate",
description="Last observed job modification timestamp for conflict detection.",
)
force_update: bool = Field(
default=False,
alias="forceUpdate",
description="Override a modification conflict only when explicitly intended.",
)
handling_units: list[ManageableJobHandlingUnitModel] | None = Field(
default=None, alias="handlingUnits", description="Complete handling-unit arrangement to manage."
)
[docs]
class ManageHandlingUnitsResponse(ResponseModel):
"""ManageHandlingUnitsResponse contract from server release 8_01."""
success: bool | None = Field(default=None, alias="success", description="Success.")
error_message: str | None = Field(default=None, alias="errorMessage", description="Error message.")
job_modified_date: datetime | None = Field(
default=None,
alias="jobModifiedDate",
description="Last observed job modification timestamp for conflict detection.",
)
handling_units: list[JobHandlingUnitDetails] | None = Field(
default=None, alias="handlingUnits", description="Complete handling-unit arrangement to manage."
)
[docs]
class SetHandlingUnitContainerMaterialModel(PackingRequestModel):
"""SetHandlingUnitContainerMaterialModel contract from server release 8_01."""
container_handling_unit_material_id: int | None = Field(
default=None,
alias="containerHandlingUnitMaterialId",
description="Assigned handling-unit material row ID, or null to clear.",
)
[docs]
class JobTransportationHandlingUnit(ResponseModel):
"""JobTransportationHandlingUnit contract from server release 8_01."""
quantity: int | None = Field(
default=None, alias="quantity", description="Number of physical items or handling units."
)
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
[docs]
class Shipping(ResponseModel):
"""Shipping contract from server release 8_01."""
id: int | None = Field(default=None, alias="id", description="Identifier of this record; scoped to the job.")
name: str | None = Field(default=None, alias="name", description="Display name.")
handling_units: list[JobTransportationHandlingUnit] | None = Field(
default=None, alias="handlingUnits", description="Complete handling-unit arrangement to manage."
)
freight_quote_options: list[UUID] | None = Field(
default=None, alias="freightQuoteOptions", description="Freight quote options."
)
is_archived: bool | None = Field(default=None, alias="isArchived", description="Is archived.")