mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Keep only the latest file of a Document Type in each property's folder 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
6d001d650e
commit
28b7b43372
4 changed files with 114 additions and 0 deletions
0
domain/bulk_document_download/__init__.py
Normal file
0
domain/bulk_document_download/__init__.py
Normal file
66
domain/bulk_document_download/package_plan.py
Normal file
66
domain/bulk_document_download/package_plan.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
"""The Download Package plan (ADR-0060).
|
||||
|
||||
Pure logic: given the documents resolved for a set of properties, decide what
|
||||
goes where in the ZIP — one folder per property, the latest file of each
|
||||
Document Type — and which rows are skipped and reported. No I/O: the
|
||||
orchestrator does the S3/DB work; this module only lays out the archive.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional, Sequence
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ResolvedDocument:
|
||||
"""One `uploaded_files` row resolved for packaging: its property identity
|
||||
(matched by `landlord_property_id`, ADR-0060), the display address enriched
|
||||
from the hubspot deals data, its Document Type (`file_type`, nullable), the
|
||||
S3 location to read it from, and when it was uploaded (for latest-per-type).
|
||||
"""
|
||||
|
||||
landlord_property_id: str
|
||||
address: str
|
||||
document_type: Optional[str]
|
||||
s3_bucket: str
|
||||
s3_key: str
|
||||
uploaded_at: datetime
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PackageEntry:
|
||||
"""One file to place in the Download Package: where it lands in the ZIP and
|
||||
the S3 object to stream in from."""
|
||||
|
||||
zip_path: str
|
||||
s3_bucket: str
|
||||
s3_key: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SkippedDocument:
|
||||
"""A resolved row left out of the package, with the reason (surfaced in the
|
||||
run's `sub_task.outputs`, ADR-0060)."""
|
||||
|
||||
landlord_property_id: str
|
||||
s3_key: str
|
||||
reason: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DownloadPackagePlan:
|
||||
"""The laid-out archive: the files to include and the rows skipped."""
|
||||
|
||||
entries: tuple[PackageEntry, ...]
|
||||
skipped: tuple[SkippedDocument, ...]
|
||||
|
||||
|
||||
def plan_download_package(
|
||||
documents: Sequence[ResolvedDocument],
|
||||
) -> DownloadPackagePlan:
|
||||
"""Lay out a Download Package from resolved documents (ADR-0060): one folder
|
||||
per property, the latest file of each Document Type, null-Document-Type rows
|
||||
skipped and reported."""
|
||||
raise NotImplementedError
|
||||
0
tests/domain/bulk_document_download/__init__.py
Normal file
0
tests/domain/bulk_document_download/__init__.py
Normal file
48
tests/domain/bulk_document_download/test_package_plan.py
Normal file
48
tests/domain/bulk_document_download/test_package_plan.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"""The Download Package plan (ADR-0060) — pure layout of the ZIP from resolved
|
||||
documents: one folder per property, latest file of each Document Type,
|
||||
null-Document-Type rows skipped and reported."""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from domain.bulk_document_download.package_plan import (
|
||||
ResolvedDocument,
|
||||
plan_download_package,
|
||||
)
|
||||
|
||||
|
||||
def _doc(
|
||||
*,
|
||||
landlord_property_id: str = "LP1",
|
||||
address: str = "12 Oak Street",
|
||||
document_type: str = "site_note",
|
||||
s3_key: str = "a.pdf",
|
||||
uploaded_at: datetime = datetime(2026, 1, 1, tzinfo=timezone.utc),
|
||||
) -> ResolvedDocument:
|
||||
return ResolvedDocument(
|
||||
landlord_property_id=landlord_property_id,
|
||||
address=address,
|
||||
document_type=document_type,
|
||||
s3_bucket="src-bucket",
|
||||
s3_key=s3_key,
|
||||
uploaded_at=uploaded_at,
|
||||
)
|
||||
|
||||
|
||||
def test_keeps_only_the_latest_file_of_a_document_type_in_the_property_folder() -> None:
|
||||
# Arrange — two site_note files for the same property, uploaded at
|
||||
# different times; only the newest should be packaged.
|
||||
older = _doc(
|
||||
s3_key="old.pdf", uploaded_at=datetime(2026, 1, 1, tzinfo=timezone.utc)
|
||||
)
|
||||
newer = _doc(
|
||||
s3_key="new.pdf", uploaded_at=datetime(2026, 6, 1, tzinfo=timezone.utc)
|
||||
)
|
||||
|
||||
# Act
|
||||
plan = plan_download_package([older, newer])
|
||||
|
||||
# Assert — one entry, the newer file, foldered under the property.
|
||||
assert len(plan.entries) == 1
|
||||
entry = plan.entries[0]
|
||||
assert entry.s3_key == "new.pdf"
|
||||
assert entry.zip_path.startswith("12 Oak Street (LP1)/")
|
||||
Loading…
Add table
Reference in a new issue