Source code for ab.api.models.documents

"""Document models for the ACPortal API."""

from __future__ import annotations

from typing import List, Optional, Union

from pydantic import AliasChoices, Field

from ab.api.models.base import RequestModel, ResponseModel
from ab.api.models.enums import DocumentType
from ab.api.models.mixins import IdentifiedModel


[docs] class DocumentListParams(RequestModel): """Query parameters for GET /documents/list.""" job_display_id: Optional[str] = Field(None, alias="jobDisplayId", description="Job display identifier")
[docs] class Document(ResponseModel, IdentifiedModel): """Document record — GET /documents/list and embedded in Job response. Live API field names differ from swagger: ``path`` not ``docPath``, ``typeName`` not ``docType``, ``shared`` not ``sharingLevel``. """ path: Optional[str] = Field(None, description="Document storage path") thumbnail_path: Optional[str] = Field(None, alias="thumbnailPath", description="Thumbnail path") description: Optional[str] = Field(None, description="Document description") type_name: Optional[str] = Field(None, alias="typeName", description="Document type name") type_id: Optional[int] = Field(None, alias="typeId", description="Document type ID") file_name: Optional[str] = Field(None, alias="fileName", description="Original file name") shared: Optional[int] = Field(None, description="Sharing level (0=private)") tags: Optional[List] = Field(None, description="Document tags") job_items: Optional[List] = Field(None, alias="jobItems", description="Associated job items")
[docs] class DocumentUpdateRequest(RequestModel): """Body for PUT /documents/update/{docId}. API 7.11 binds the PascalCase ACPortal model (``FileName``, ``TypeId``, ``Shared``, ``Tags``, ``JobItems``). The older SDK names ``docType`` and ``sharingLevel`` are still accepted as input aliases but serialize to the current wire contract. """ file_name: Optional[str] = Field( None, alias="FileName", validation_alias=AliasChoices("FileName", "fileName"), serialization_alias="FileName", description="Updated file name", ) type_id: Optional[int] = Field( None, alias="TypeId", validation_alias=AliasChoices("TypeId", "typeId", "docType", "doc_type"), serialization_alias="TypeId", description="Updated document type ID", ) shared: Optional[int] = Field( None, alias="Shared", validation_alias=AliasChoices("Shared", "shared", "sharingLevel", "sharing_level"), serialization_alias="Shared", description="Updated sharing level", ) tags: Optional[List[str]] = Field( None, alias="Tags", validation_alias=AliasChoices("Tags", "tags"), serialization_alias="Tags", description="Free-form tags to attach to the document.", ) job_items: Optional[List[str]] = Field( None, alias="JobItems", validation_alias=AliasChoices("JobItems", "jobItems", "job_items"), serialization_alias="JobItems", description="Associated job item UUIDs.", )
[docs] class DocumentUploadRequest(RequestModel): """Multipart form fields for ``POST /documents``. The file itself is sent as a separate ``file`` multipart part — this model carries only the accompanying form fields. Aliases are **PascalCase** to match the swagger multipart contract exactly (``JobDisplayId``, ``DocumentType``, ``Shared``, ``JobItems`` …), which differs from the camelCase convention used elsewhere, so each alias is declared explicitly. An *item photo* is just this request with ``document_type=DocumentType.ITEM_PHOTO`` and ``job_items`` set to the target item UUID(s); the :meth:`~ab.api.endpoints.documents.DocumentsEndpoint.upload_item_photo` helper fills those in for you. """ job_display_id: str = Field( ..., alias="JobDisplayId", description="Job display ID the document belongs to (e.g. '2000000').", ) document_type: Union[DocumentType, int] = Field( ..., alias="DocumentType", description="Document type ID; see DocumentType (6 = Item Photo).", ) document_type_description: Optional[str] = Field( None, alias="DocumentTypeDescription", description="Human-readable label for the document type.", ) shared: int = Field( 0, alias="Shared", description="Sharing bitmask (0 = private); controls portal visibility.", ) tags: Optional[List[str]] = Field( None, alias="Tags", description="Free-form tags to attach to the document.", ) job_items: Optional[List[str]] = Field( None, alias="JobItems", description="Item UUID(s) to associate the document with (required for item photos).", ) rfq_id: Optional[int] = Field( None, alias="RfqId", description="RFQ ID to associate the document with, if applicable.", )
[docs] class UploadedFile(ResponseModel): """A single file entry within a :class:`DocumentUploadResponse`. The upload response shape is not described in swagger; fields mirror the document records the live API has been observed to return and are all optional so deserialization stays resilient (``ResponseModel`` allows and warns on unknown fields). """ id: Optional[int] = Field(None, description="Server-assigned document/file ID.") file_name: Optional[str] = Field(None, alias="fileName", description="Stored file name.") file_size: Optional[int] = Field(None, alias="fileSize", description="File size in bytes.") document_type: Optional[str] = Field( None, alias="documentType", description="Document type name as echoed by the server.", ) item_id: Optional[int] = Field(None, alias="itemId", description="Associated job item ID, if any.") thumbnail_url: Optional[str] = Field( None, alias="thumbnailUrl", description="URL to the generated thumbnail, if any.", )
[docs] class DocumentDetails(ResponseModel): """Document detail payload embedded in ``DocumentUploadResponse``. Owner source: ``SaveDocumentResponse.DocumentDetails`` in AB.ABCEntities. The live API usually emits camelCase, while the C# model is PascalCase, so both forms are accepted. """ id: Optional[Union[str, int]] = Field( None, alias="id", validation_alias=AliasChoices("id", "Id"), serialization_alias="id", description="Server-assigned document ID.", ) path: Optional[str] = Field( None, alias="path", validation_alias=AliasChoices("path", "Path"), serialization_alias="path", description="Document storage path.", ) thumbnail_path: Optional[str] = Field( None, alias="thumbnailPath", validation_alias=AliasChoices("thumbnailPath", "ThumbnailPath"), serialization_alias="thumbnailPath", description="Thumbnail path.", ) description: Optional[str] = Field( None, alias="description", validation_alias=AliasChoices("description", "Description"), serialization_alias="description", description="Document description.", ) type_name: Optional[str] = Field( None, alias="typeName", validation_alias=AliasChoices("typeName", "TypeName"), serialization_alias="typeName", description="Document type name.", ) type_id: Optional[int] = Field( None, alias="typeId", validation_alias=AliasChoices("typeId", "TypeId"), serialization_alias="typeId", description="Document type ID.", ) file_name: Optional[str] = Field( None, alias="fileName", validation_alias=AliasChoices("fileName", "FileName"), serialization_alias="fileName", description="Original file name.", ) shared: Optional[int] = Field( None, alias="shared", validation_alias=AliasChoices("shared", "Shared"), serialization_alias="shared", description="Sharing level.", ) tags: Optional[List] = Field( None, alias="tags", validation_alias=AliasChoices("tags", "Tags"), serialization_alias="tags", description="Document tags.", ) job_items: Optional[List] = Field( None, alias="jobItems", validation_alias=AliasChoices("jobItems", "JobItems"), serialization_alias="jobItems", description="Associated job items.", )
[docs] class DocumentUploadResponse(ResponseModel): """Response body for ``POST /documents``. Provisional shape (no swagger schema / live capture yet); all fields are optional and ``ResponseModel`` tolerates drift, so this never breaks deserialization even if the server adds or renames fields. """ success: Optional[bool] = Field(None, description="Whether the upload succeeded.") successfully: Optional[bool] = Field(None, description="Legacy success flag returned by some upload paths.") message: Optional[str] = Field(None, description="Human-readable status or error message.") amazon_exception: Optional[bool] = Field( None, alias="amazonException", description="Whether an Amazon/S3 storage exception occurred." ) amazon_error_message: Optional[str] = Field( None, alias="amazonErrorMessage", description="Amazon/S3 error message when upload storage fails." ) amazon_error_code: Optional[Union[str, int]] = Field( None, alias="amazonErrorCode", description="Amazon/S3 error code when upload storage fails." ) document_details: Optional[DocumentDetails] = Field( None, alias="documentDetails", description="Document detail payload returned by the server." ) uploaded_files: Optional[List[UploadedFile]] = Field( None, alias="uploadedFiles", description="Per-file results for the upload.", ) id: Optional[int] = Field(None, description="Document ID when a single file was uploaded.") file_name: Optional[str] = Field( None, alias="fileName", description="Stored file name when a single file was uploaded.", )