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
51 changes: 43 additions & 8 deletions robosystems_client/clients/ledger_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1358,13 +1358,17 @@ def list_structures(
page = ListLedgerStructures.model_validate(data).structures
return page.structures if page else []

def list_mappings(self, graph_id: str) -> list[ListLedgerMappingsMappingsStructures]:
def list_mappings(
self, graph_id: str, *, entity_id: str | None = None
) -> list[ListLedgerMappingsMappingsStructures]:
"""List active CoA→reporting mapping structures, the book mapping first.

Each carries ``framework``: the reporting framework it maps the chart
into. A chart holds one mapping per framework.
into (a chart holds one mapping per framework), and ``entity_id``: the
entity whose chart it maps from, so whose reports it can produce.
``entity_id`` keeps that entity's mappings only.
"""
data = self._query(graph_id, LIST_LEDGER_MAPPINGS_GQL)
data = self._query(graph_id, LIST_LEDGER_MAPPINGS_GQL, {"entityId": entity_id})
page = ListLedgerMappings.model_validate(data).mappings
return page.structures if page else []

Expand All @@ -1383,16 +1387,19 @@ def get_mapping_coverage(
return GetLedgerMappingCoverage.model_validate(data).mapping_coverage

def get_mapping_candidates(
self, graph_id: str, classification: str
self, graph_id: str, classification: str, *, entity_id: str | None = None
) -> list[MappingCandidatesMappingCandidates]:
"""rs-gaap concepts a CoA element of the given EFS ``classification``
(asset / liability / equity / revenue / expense) may map to — limited
to concepts that render under the graph's active Reporting Style,
with statement-level subtotals excluded. Use this to populate the
mapping picker so it never offers an unreachable target.
to concepts that render under the Reporting Style of the entity whose
chart is being mapped (``entity_id``, default the group parent), with
statement-level subtotals excluded. Use this to populate the mapping
picker so it never offers an unreachable target.
"""
data = self._query(
graph_id, MAPPING_CANDIDATES_GQL, {"classification": classification}
graph_id,
MAPPING_CANDIDATES_GQL,
{"classification": classification, "entityId": entity_id},
)
return MappingCandidates.model_validate(data).mapping_candidates

Expand Down Expand Up @@ -1454,6 +1461,7 @@ def get_information_block(
series: bool | None = None,
series_history: int | None = None,
series_forecast: int | None = None,
entity_id: str | None = None,
) -> InformationBlock | None:
"""Fetch an Information Block envelope by id — the cross-block-type read.

Expand All @@ -1474,6 +1482,12 @@ def get_information_block(
``series_history`` / ``series_forecast`` window the series to its
seam-adjacent columns — the last N actual columns and the first N
forecast columns; ``None`` = unbounded.

``entity_id`` picks whose books a block shared by the group reads
(statements, metrics, disclosures); ``None`` = the scenario's entity,
else the group parent. A schedule, reconciliation or forecast always
reads its own entity's. The envelope's ``entity_id`` names the entity
it read.
"""
data = self._query(
graph_id,
Expand All @@ -1484,6 +1498,7 @@ def get_information_block(
"series": series,
"seriesHistory": series_history,
"seriesForecast": series_forecast,
"entityId": entity_id,
},
)
return GetInformationBlock.model_validate(data).information_block
Expand All @@ -1497,13 +1512,19 @@ def list_information_blocks(
limit: int | None = None,
offset: int | None = None,
scenario_id: str | None = None,
entity_id: str | None = None,
) -> list[ListInformationBlocksInformationBlocks]:
"""List Information Block envelopes, optionally filtered.

Replaces the old ``list_schedules`` method — use
``block_type='schedule'`` for the same set of blocks.
``scenario_id`` (a forecast block's structure id) threads into each
envelope's FactSet binding.

``entity_id`` (``None`` = the scenario's entity, else the group
parent) lists the blocks shared by the group plus that entity's own
schedules, reconciliations and forecasts, never another entity's;
shared blocks read its books.
"""
data = self._query(
graph_id,
Expand All @@ -1514,6 +1535,7 @@ def list_information_blocks(
"limit": limit,
"offset": offset,
"scenarioId": scenario_id,
"entityId": entity_id,
},
)
return ListInformationBlocks.model_validate(data).information_blocks
Expand Down Expand Up @@ -1604,12 +1626,16 @@ def create_schedule(
asset_element_id: str | None = None,
auto_reverse: bool = False,
booked_on: str | None = None,
entity_id: str | None = None,
) -> InformationBlockEnvelope:
"""Create a new schedule with pre-generated monthly facts.

``booked_on`` (``YYYY-MM-DD``) is the day the schedule's cost went on
the books, when that is before its first period. The schedule
reconciliation carries the cost from that day.

``entity_id`` is the entity whose books the schedule belongs to;
``None`` = the group parent.
"""
payload_dict: dict[str, Any] = {
"name": name,
Expand All @@ -1627,6 +1653,8 @@ def create_schedule(
}
if taxonomy_id:
payload_dict["taxonomy_id"] = taxonomy_id
if entity_id:
payload_dict["entity_id"] = entity_id
schedule_metadata: dict[str, Any] = {}
if method:
schedule_metadata["method"] = method
Expand Down Expand Up @@ -2636,6 +2664,7 @@ def create_report(
period_type: str = "quarterly",
comparative: bool = True,
periods: list[PeriodSpec | dict[str, Any]] | None = None,
entity_id: str | None = None,
) -> ReportResponse:
"""Generate report facts from the ledger and publish a Report
definition. Synchronous — returns the published report header.
Expand All @@ -2647,6 +2676,10 @@ def create_report(
``{"start", "end", "label"}`` dicts — for multi-period layouts
(YTD-by-quarter, multi-year). When given, the server ignores
``period_start`` / ``period_end`` / ``comparative``.

``entity_id`` is the entity the report is for; ``None`` = the entity
whose chart ``mapping_id`` maps from. Named alongside another entity's
mapping, the server refuses it.
"""
body = CreateReportRequest(
name=name,
Expand All @@ -2661,6 +2694,8 @@ def create_report(
body.periods = [
p if isinstance(p, PeriodSpec) else PeriodSpec.from_dict(p) for p in periods
]
if entity_id:
body.entity_id = entity_id
response = op_create_report(graph_id=graph_id, body=body, client=self._get_client())
envelope = self._call_op("Create report", response)
return self._typed_result("Create report", envelope, ReportResponse)
Expand Down
22 changes: 18 additions & 4 deletions robosystems_client/graphql/generated/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def get_information_block(
scenario_id: Union[Optional[str], UnsetType] = UNSET,
series_history: Union[Optional[int], UnsetType] = UNSET,
series_forecast: Union[Optional[int], UnsetType] = UNSET,
entity_id: Union[Optional[str], UnsetType] = UNSET,
**kwargs: Any,
) -> GetInformationBlock:
variables: dict[str, object] = {
Expand All @@ -258,6 +259,7 @@ def get_information_block(
"series": series,
"seriesHistory": series_history,
"seriesForecast": series_forecast,
"entityId": entity_id,
}
response = self.execute(
query=GET_INFORMATION_BLOCK_GQL,
Expand Down Expand Up @@ -591,6 +593,7 @@ def list_information_blocks(
limit: Union[Optional[int], UnsetType] = UNSET,
offset: Union[Optional[int], UnsetType] = UNSET,
scenario_id: Union[Optional[str], UnsetType] = UNSET,
entity_id: Union[Optional[str], UnsetType] = UNSET,
**kwargs: Any,
) -> ListInformationBlocks:
variables: dict[str, object] = {
Expand All @@ -599,6 +602,7 @@ def list_information_blocks(
"limit": limit,
"offset": offset,
"scenarioId": scenario_id,
"entityId": entity_id,
}
response = self.execute(
query=LIST_INFORMATION_BLOCKS_GQL,
Expand Down Expand Up @@ -791,8 +795,10 @@ def list_ledger_journal_entries(
data = self.get_data(response)
return ListLedgerJournalEntries.model_validate(data)

def list_ledger_mappings(self, **kwargs: Any) -> ListLedgerMappings:
variables: dict[str, object] = {}
def list_ledger_mappings(
self, entity_id: Union[Optional[str], UnsetType] = UNSET, **kwargs: Any
) -> ListLedgerMappings:
variables: dict[str, object] = {"entityId": entity_id}
response = self.execute(
query=LIST_LEDGER_MAPPINGS_GQL,
operation_name="ListLedgerMappings",
Expand Down Expand Up @@ -916,8 +922,16 @@ def list_ledger_unmapped_elements(
data = self.get_data(response)
return ListLedgerUnmappedElements.model_validate(data)

def mapping_candidates(self, classification: str, **kwargs: Any) -> MappingCandidates:
variables: dict[str, object] = {"classification": classification}
def mapping_candidates(
self,
classification: str,
entity_id: Union[Optional[str], UnsetType] = UNSET,
**kwargs: Any,
) -> MappingCandidates:
variables: dict[str, object] = {
"classification": classification,
"entityId": entity_id,
}
response = self.execute(
query=MAPPING_CANDIDATES_GQL,
operation_name="MappingCandidates",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class GetInformationBlockInformationBlock(BaseModel):
category: str
taxonomy_id: Optional[str] = Field(alias="taxonomyId")
taxonomy_name: Optional[str] = Field(alias="taxonomyName")
entity_id: Optional[str] = Field(alias="entityId")
information_model: "GetInformationBlockInformationBlockInformationModel" = Field(
alias="informationModel"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ListInformationBlocksInformationBlocks(BaseModel):
category: str
taxonomy_id: Optional[str] = Field(alias="taxonomyId")
taxonomy_name: Optional[str] = Field(alias="taxonomyName")
entity_id: Optional[str] = Field(alias="entityId")
information_model: "ListInformationBlocksInformationBlocksInformationModel" = Field(
alias="informationModel"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class ListLedgerMappingsMappingsStructures(BaseModel):
taxonomy_id: str = Field(alias="taxonomyId")
is_active: bool = Field(alias="isActive")
framework: Optional[str]
entity_id: Optional[str] = Field(alias="entityId")


ListLedgerMappings.model_rebuild()
Expand Down
17 changes: 11 additions & 6 deletions robosystems_client/graphql/generated/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,14 @@
"""

GET_INFORMATION_BLOCK_GQL = """
query GetInformationBlock($id: ID!, $scenarioId: String, $series: Boolean! = false, $seriesHistory: Int, $seriesForecast: Int) {
query GetInformationBlock($id: ID!, $scenarioId: String, $series: Boolean! = false, $seriesHistory: Int, $seriesForecast: Int, $entityId: String) {
informationBlock(
id: $id
scenarioId: $scenarioId
series: $series
seriesHistory: $seriesHistory
seriesForecast: $seriesForecast
entityId: $entityId
) {
id
blockType
Expand All @@ -294,6 +295,7 @@
category
taxonomyId
taxonomyName
entityId
informationModel {
conceptArrangement
memberArrangement
Expand Down Expand Up @@ -1192,13 +1194,14 @@
"""

LIST_INFORMATION_BLOCKS_GQL = """
query ListInformationBlocks($blockType: String, $category: String, $limit: Int, $offset: Int, $scenarioId: String) {
query ListInformationBlocks($blockType: String, $category: String, $limit: Int, $offset: Int, $scenarioId: String, $entityId: String) {
informationBlocks(
blockType: $blockType
category: $category
limit: $limit
offset: $offset
scenarioId: $scenarioId
entityId: $entityId
) {
id
blockType
Expand All @@ -1207,6 +1210,7 @@
category
taxonomyId
taxonomyName
entityId
informationModel {
conceptArrangement
memberArrangement
Expand Down Expand Up @@ -1608,8 +1612,8 @@
"""

LIST_LEDGER_MAPPINGS_GQL = """
query ListLedgerMappings {
mappings {
query ListLedgerMappings($entityId: String) {
mappings(entityId: $entityId) {
structures {
id
name
Expand All @@ -1618,6 +1622,7 @@
taxonomyId
isActive
framework
entityId
}
}
}
Expand Down Expand Up @@ -1840,8 +1845,8 @@
"""

MAPPING_CANDIDATES_GQL = """
query MappingCandidates($classification: String!) {
mappingCandidates(classification: $classification) {
query MappingCandidates($classification: String!, $entityId: String) {
mappingCandidates(classification: $classification, entityId: $entityId) {
id
name
qname
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ query GetInformationBlock(
$series: Boolean! = false
$seriesHistory: Int
$seriesForecast: Int
$entityId: String
) {
informationBlock(
id: $id
scenarioId: $scenarioId
series: $series
seriesHistory: $seriesHistory
seriesForecast: $seriesForecast
entityId: $entityId
) {
id blockType name displayName category
taxonomyId taxonomyName
taxonomyId taxonomyName entityId
informationModel { conceptArrangement memberArrangement }
artifact { topic rendererNote template mechanics }
elements {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ query ListInformationBlocks(
$limit: Int
$offset: Int
$scenarioId: String
$entityId: String
) {
informationBlocks(
blockType: $blockType
category: $category
limit: $limit
offset: $offset
scenarioId: $scenarioId
entityId: $entityId
) {
id blockType name displayName category
taxonomyId taxonomyName
taxonomyId taxonomyName entityId
informationModel { conceptArrangement memberArrangement }
artifact { topic rendererNote template mechanics }
elements {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
query ListLedgerMappings {
mappings {
query ListLedgerMappings($entityId: String) {
mappings(entityId: $entityId) {
structures {
id name description blockType taxonomyId isActive framework
id name description blockType taxonomyId isActive framework entityId
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
query MappingCandidates($classification: String!) {
mappingCandidates(classification: $classification) {
query MappingCandidates($classification: String!, $entityId: String) {
mappingCandidates(classification: $classification, entityId: $entityId) {
id
name
qname
Expand Down
Loading
Loading