Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ def sync_detailed(
) -> Response[ErrorResponse | OperationEnvelopeReportResponse]:
"""Transition Filing Status

Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed →
archived). Use 'file-report' to reach 'filed' so audit fields land cleanly.
Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed ↔
archived). Archiving takes a filed report off the current list without deleting it; unarchiving
returns it to 'filed'. Use 'file-report' to file a draft so audit fields land cleanly.

**Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours
return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.
Expand All @@ -123,10 +124,11 @@ def sync_detailed(
body (TransitionFilingStatusRequest): Generic filing-status transition — escape hatch for
non-file moves.

Used for `draft → under_review` (submit for review) and
`filed → archived` (supersede / retire). Filing the package goes
through :class:`FileReportRequest` so `filed_at` / `filed_by`
audit fields land cleanly.
Used for `draft ↔ under_review` (submit for review, or send back),
`filed → archived` (take a filed report off the current list) and
`archived → filed` (bring it back). Filing a draft goes through
:class:`FileReportRequest` so `filed_at` / `filed_by` audit fields
land cleanly.

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
Expand Down Expand Up @@ -158,8 +160,9 @@ def sync(
) -> ErrorResponse | OperationEnvelopeReportResponse | None:
"""Transition Filing Status

Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed →
archived). Use 'file-report' to reach 'filed' so audit fields land cleanly.
Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed ↔
archived). Archiving takes a filed report off the current list without deleting it; unarchiving
returns it to 'filed'. Use 'file-report' to file a draft so audit fields land cleanly.

**Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours
return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.
Expand All @@ -170,10 +173,11 @@ def sync(
body (TransitionFilingStatusRequest): Generic filing-status transition — escape hatch for
non-file moves.

Used for `draft → under_review` (submit for review) and
`filed → archived` (supersede / retire). Filing the package goes
through :class:`FileReportRequest` so `filed_at` / `filed_by`
audit fields land cleanly.
Used for `draft ↔ under_review` (submit for review, or send back),
`filed → archived` (take a filed report off the current list) and
`archived → filed` (bring it back). Filing a draft goes through
:class:`FileReportRequest` so `filed_at` / `filed_by` audit fields
land cleanly.

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
Expand All @@ -200,8 +204,9 @@ async def asyncio_detailed(
) -> Response[ErrorResponse | OperationEnvelopeReportResponse]:
"""Transition Filing Status

Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed →
archived). Use 'file-report' to reach 'filed' so audit fields land cleanly.
Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed ↔
archived). Archiving takes a filed report off the current list without deleting it; unarchiving
returns it to 'filed'. Use 'file-report' to file a draft so audit fields land cleanly.

**Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours
return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.
Expand All @@ -212,10 +217,11 @@ async def asyncio_detailed(
body (TransitionFilingStatusRequest): Generic filing-status transition — escape hatch for
non-file moves.

Used for `draft → under_review` (submit for review) and
`filed → archived` (supersede / retire). Filing the package goes
through :class:`FileReportRequest` so `filed_at` / `filed_by`
audit fields land cleanly.
Used for `draft ↔ under_review` (submit for review, or send back),
`filed → archived` (take a filed report off the current list) and
`archived → filed` (bring it back). Filing a draft goes through
:class:`FileReportRequest` so `filed_at` / `filed_by` audit fields
land cleanly.

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
Expand Down Expand Up @@ -245,8 +251,9 @@ async def asyncio(
) -> ErrorResponse | OperationEnvelopeReportResponse | None:
"""Transition Filing Status

Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed →
archived). Use 'file-report' to reach 'filed' so audit fields land cleanly.
Move a Report along the non-file legs of the filing lifecycle (draft ↔ under_review, filed ↔
archived). Archiving takes a filed report off the current list without deleting it; unarchiving
returns it to 'filed'. Use 'file-report' to file a draft so audit fields land cleanly.

**Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours
return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.
Expand All @@ -257,10 +264,11 @@ async def asyncio(
body (TransitionFilingStatusRequest): Generic filing-status transition — escape hatch for
non-file moves.

Used for `draft → under_review` (submit for review) and
`filed → archived` (supersede / retire). Filing the package goes
through :class:`FileReportRequest` so `filed_at` / `filed_by`
audit fields land cleanly.
Used for `draft ↔ under_review` (submit for review, or send back),
`filed → archived` (take a filed report off the current list) and
`archived → filed` (bring it back). Filing a draft goes through
:class:`FileReportRequest` so `filed_at` / `filed_by` audit fields
land cleanly.

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
Expand Down
25 changes: 19 additions & 6 deletions robosystems_client/clients/ledger_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2186,9 +2186,20 @@ def create_report(
envelope = self._call_op("Create report", response)
return self._typed_result("Create report", envelope, ReportResponse)

def list_reports(self, graph_id: str) -> list[ListLedgerReportsReportsReports]:
"""List all reports for a graph (includes received shared reports)."""
data = self._query(graph_id, LIST_LEDGER_REPORTS_GQL)
def list_reports(
self, graph_id: str, lifecycle: str | None = None
) -> list[ListLedgerReportsReportsReports]:
"""List reports for a graph (includes received shared reports).

Args:
graph_id: The graph to list.
lifecycle: ``"current"`` (the server default) leaves archived
reports out, ``"archived"`` returns only those, ``"all"`` every
report. The enum names ``"CURRENT"`` / ``"ARCHIVED"`` /
``"ALL"`` are also accepted.
"""
variables = {"lifecycle": lifecycle.upper()} if lifecycle else None
data = self._query(graph_id, LIST_LEDGER_REPORTS_GQL, variables)
page = ListLedgerReports.model_validate(data).reports
return page.reports if page else []

Expand Down Expand Up @@ -2372,9 +2383,11 @@ def transition_filing_status(
) -> ReportResponse:
"""Move a Report along the non-file legs of the filing lifecycle.

Use ``file_report()`` to reach 'filed' so audit fields land cleanly.
Other transitions (draft ↔ under_review, filed → archived) go through
here so the legal-transition graph stays in one place.
Use ``file_report()`` to file a draft so audit fields land cleanly.
Other transitions (draft ↔ under_review, filed ↔ archived) go through
here so the legal-transition graph stays in one place. Archiving takes
a filed report off the current list without deleting it; unarchiving
(``target_status="filed"``) brings it back.
"""
body = TransitionFilingStatusRequest(
report_id=report_id, target_status=target_status
Expand Down
3 changes: 2 additions & 1 deletion robosystems_client/graphql/generated/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .base_client import BaseClient
from .base_model import BaseModel, Upload
from .client import Client
from .enums import ReportDownloadFormat
from .enums import ReportDownloadFormat, ReportLifecycle
from .exceptions import (
GraphQLClientError,
GraphQLClientGraphQLError,
Expand Down Expand Up @@ -676,6 +676,7 @@
"MappingCandidates",
"MappingCandidatesMappingCandidates",
"ReportDownloadFormat",
"ReportLifecycle",
"SEARCH_LIBRARY_ELEMENTS_GQL",
"SearchLibraryElements",
"SearchLibraryElementsSearchLibraryElements",
Expand Down
8 changes: 5 additions & 3 deletions robosystems_client/graphql/generated/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from .base_client import BaseClient
from .base_model import UNSET, UnsetType
from .enums import ReportDownloadFormat
from .enums import ReportDownloadFormat, ReportLifecycle
from .get_information_block import GetInformationBlock
from .get_investor_holdings import GetInvestorHoldings
from .get_investor_portfolio_block import GetInvestorPortfolioBlock
Expand Down Expand Up @@ -768,8 +768,10 @@ def list_ledger_publish_lists(
data = self.get_data(response)
return ListLedgerPublishLists.model_validate(data)

def list_ledger_reports(self, **kwargs: Any) -> ListLedgerReports:
variables: dict[str, object] = {}
def list_ledger_reports(
self, lifecycle: Union[Optional[ReportLifecycle], UnsetType] = UNSET, **kwargs: Any
) -> ListLedgerReports:
variables: dict[str, object] = {"lifecycle": lifecycle}
response = self.execute(
query=LIST_LEDGER_REPORTS_GQL,
operation_name="ListLedgerReports",
Expand Down
6 changes: 6 additions & 0 deletions robosystems_client/graphql/generated/enums.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from enum import Enum


class ReportLifecycle(str, Enum):
CURRENT = "CURRENT"
ARCHIVED = "ARCHIVED"
ALL = "ALL"


class ReportDownloadFormat(str, Enum):
HOLON_JSONLD = "HOLON_JSONLD"
XBRL_2_1 = "XBRL_2_1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ListLedgerReportsReportsReports(BaseModel):
name: str
taxonomy_id: str = Field(alias="taxonomyId")
generation_status: str = Field(alias="generationStatus")
filing_status: str = Field(alias="filingStatus")
period_type: str = Field(alias="periodType")
period_start: Optional[str] = Field(alias="periodStart")
period_end: Optional[str] = Field(alias="periodEnd")
Expand Down
5 changes: 3 additions & 2 deletions robosystems_client/graphql/generated/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1592,13 +1592,14 @@
"""

LIST_LEDGER_REPORTS_GQL = """
query ListLedgerReports {
reports {
query ListLedgerReports($lifecycle: ReportLifecycle) {
reports(lifecycle: $lifecycle) {
reports {
id
name
taxonomyId
generationStatus
filingStatus
periodType
periodStart
periodEnd
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
query ListLedgerReports {
reports {
query ListLedgerReports($lifecycle: ReportLifecycle) {
reports(lifecycle: $lifecycle) {
reports {
id name taxonomyId generationStatus periodType
id name taxonomyId generationStatus filingStatus periodType
periodStart periodEnd comparative mappingId aiGenerated
createdAt lastGenerated entityName
sourceGraphId sourceReportId sharedAt
Expand Down
17 changes: 14 additions & 3 deletions robosystems_client/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,13 @@ type Query {
"""
closingBookStructures: ClosingBookStructures

"""List all report definitions for this graph."""
reports: ReportList
"""List report definitions for this graph, newest first."""
reports(
"""
`CURRENT` (the default) leaves out archived reports, `ARCHIVED` returns only those, `ALL` returns every report.
"""
lifecycle: ReportLifecycle! = CURRENT
): ReportList

"""Single report definition with structures + entity name."""
report(
Expand Down Expand Up @@ -2453,6 +2458,12 @@ type StructureSummary {
blockType: String!
}

enum ReportLifecycle {
CURRENT
ARCHIVED
ALL
}

type ReportPackage {
id: ID!
name: String!
Expand Down Expand Up @@ -3000,7 +3011,7 @@ type ReportBundleDownload {
generationCount: Int!

"""
Content the Report carries that this flavor does not. `disclosure_notes`: the XBRL 2.1 zip ships statements only — tenant-authored disclosure notes render on screen and ride the Tavi and holon flavors, but are excluded from this file. The Tavi compiled model carries the statements and notes but has no home for `ib_envelopes` (the per-Network Information Block payloads), `definition_links` (equivalence, general-special, essence-alias and mapping arcs), `reporting_style`, `framework_pins`, `fact_sets` (the FactSet partition and each fact's structure pin) or `filing_lifecycle` (filing status, supersession, share provenance); all of it rides the holon flavor.
Content the Report carries that this flavor does not. `disclosure_notes`: the XBRL 2.1 zip ships statements only — tenant-authored disclosure notes render on screen and ride the Tavi and holon flavors, but are excluded from this file. The Tavi compiled model carries the statements, notes, reporting style and FactSet partition but has no home for `ib_envelopes` (the per-Network Information Block payloads), `definition_links` (equivalence, general-special, essence-alias and mapping arcs), `framework_pins` or `filing_lifecycle` (filing status, supersession, share provenance); all of it rides the holon flavor.
"""
omittedContent: [String!]!
}
Expand Down
14 changes: 8 additions & 6 deletions robosystems_client/models/transition_filing_status_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
class TransitionFilingStatusRequest:
"""Generic filing-status transition — escape hatch for non-file moves.

Used for `draft → under_review` (submit for review) and
`filed → archived` (supersede / retire). Filing the package goes
through :class:`FileReportRequest` so `filed_at` / `filed_by`
audit fields land cleanly.
Used for `draft ↔ under_review` (submit for review, or send back),
`filed → archived` (take a filed report off the current list) and
`archived → filed` (bring it back). Filing a draft goes through
:class:`FileReportRequest` so `filed_at` / `filed_by` audit fields
land cleanly.

Attributes:
report_id (str): The Report to transition.
target_status (str): Target lifecycle state: `under_review` (submit a draft for review) or `archived` (supersede
/ retire a filed report). Reaching `filed` goes through `file-report` so audit fields land cleanly.
target_status (str): Target lifecycle state: `under_review` (submit a draft for review), `draft` (send it back),
`archived` (take a filed report off the current list; it stays a record) or `filed` (unarchive). Filing a draft
goes through `file-report` so audit fields land cleanly.
"""

report_id: str
Expand Down
25 changes: 25 additions & 0 deletions tests/test_ledger_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,31 @@ def test_list_accounts_with_pagination(self, mock_execute, mock_config, graph_id
assert variables["classification"] == "asset"
assert variables["limit"] == 50

@patch("robosystems_client.graphql.client.GraphQLClient.execute")
def test_list_reports_default_leaves_lifecycle_to_the_server(
self, mock_execute, mock_config, graph_id
):
mock_execute.return_value = {"reports": {"reports": []}}
client = LedgerClient(mock_config)
assert client.list_reports(graph_id) == []
query, variables = mock_execute.call_args[0][1], mock_execute.call_args[0][2]
assert "reports(lifecycle: $lifecycle)" in query
assert "filingStatus" in query
assert not variables

@pytest.mark.parametrize(
("lifecycle", "sent"),
[("archived", "ARCHIVED"), ("ALL", "ALL"), ("current", "CURRENT")],
)
@patch("robosystems_client.graphql.client.GraphQLClient.execute")
def test_list_reports_forwards_lifecycle(
self, mock_execute, lifecycle, sent, mock_config, graph_id
):
mock_execute.return_value = {"reports": {"reports": []}}
client = LedgerClient(mock_config)
client.list_reports(graph_id, lifecycle=lifecycle)
assert mock_execute.call_args[0][2] == {"lifecycle": sent}

@patch("robosystems_client.graphql.client.GraphQLClient.execute")
def test_get_trial_balance(self, mock_execute, mock_config, graph_id):
mock_execute.return_value = {
Expand Down
Loading