From 645218cbe8f90ada346eff2d6d63e3fb47aad008 Mon Sep 17 00:00:00 2001 From: "Joseph T. French" Date: Wed, 30 Sep 2026 18:22:03 -0500 Subject: [PATCH] feat: carry each chart mapping's framework Regenerated against robosystems#1608, which anchors each coa_mapping structure to a mapping taxonomy the chart owns: - TaxonomyBlockStructureRequest / TaxonomyBlockStructure gain an optional target_framework (coa_mapping only) - the GraphQL Structure type gains framework; LedgerClient.list_mappings and list_structures now return it, the book mapping listed first Claude-Session: https://claude.ai/code/session_01HdEHDANCXBjrPfKagNDgSB --- robosystems_client/clients/ledger_client.py | 6 +++++- .../graphql/generated/list_ledger_mappings.py | 1 + .../generated/list_ledger_structures.py | 1 + .../graphql/generated/operations.py | 2 ++ .../ledger/ListLedgerMappings.graphql | 2 +- .../ledger/ListLedgerStructures.graphql | 2 +- robosystems_client/graphql/schema.graphql | 5 +++++ .../models/taxonomy_block_structure.py | 20 ++++++++++++++++++ .../taxonomy_block_structure_request.py | 21 +++++++++++++++++++ tests/test_ledger_client.py | 5 ++++- 10 files changed, 61 insertions(+), 4 deletions(-) diff --git a/robosystems_client/clients/ledger_client.py b/robosystems_client/clients/ledger_client.py index fab6067f..e4afea93 100644 --- a/robosystems_client/clients/ledger_client.py +++ b/robosystems_client/clients/ledger_client.py @@ -1198,7 +1198,11 @@ def list_structures( return page.structures if page else [] def list_mappings(self, graph_id: str) -> list[ListLedgerMappingsMappingsStructures]: - """List active CoA→reporting mapping structures.""" + """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. + """ data = self._query(graph_id, LIST_LEDGER_MAPPINGS_GQL) page = ListLedgerMappings.model_validate(data).mappings return page.structures if page else [] diff --git a/robosystems_client/graphql/generated/list_ledger_mappings.py b/robosystems_client/graphql/generated/list_ledger_mappings.py index 3222eda5..dcaa20ec 100644 --- a/robosystems_client/graphql/generated/list_ledger_mappings.py +++ b/robosystems_client/graphql/generated/list_ledger_mappings.py @@ -20,6 +20,7 @@ class ListLedgerMappingsMappingsStructures(BaseModel): block_type: str = Field(alias="blockType") taxonomy_id: str = Field(alias="taxonomyId") is_active: bool = Field(alias="isActive") + framework: Optional[str] ListLedgerMappings.model_rebuild() diff --git a/robosystems_client/graphql/generated/list_ledger_structures.py b/robosystems_client/graphql/generated/list_ledger_structures.py index fd25a998..60ad1869 100644 --- a/robosystems_client/graphql/generated/list_ledger_structures.py +++ b/robosystems_client/graphql/generated/list_ledger_structures.py @@ -20,6 +20,7 @@ class ListLedgerStructuresStructuresStructures(BaseModel): block_type: str = Field(alias="blockType") taxonomy_id: str = Field(alias="taxonomyId") is_active: bool = Field(alias="isActive") + framework: Optional[str] ListLedgerStructures.model_rebuild() diff --git a/robosystems_client/graphql/generated/operations.py b/robosystems_client/graphql/generated/operations.py index 5517d09f..87c90aa2 100644 --- a/robosystems_client/graphql/generated/operations.py +++ b/robosystems_client/graphql/generated/operations.py @@ -1564,6 +1564,7 @@ blockType taxonomyId isActive + framework } } } @@ -1637,6 +1638,7 @@ blockType taxonomyId isActive + framework } } } diff --git a/robosystems_client/graphql/operations/ledger/ListLedgerMappings.graphql b/robosystems_client/graphql/operations/ledger/ListLedgerMappings.graphql index 8e3edb6a..648bc38e 100644 --- a/robosystems_client/graphql/operations/ledger/ListLedgerMappings.graphql +++ b/robosystems_client/graphql/operations/ledger/ListLedgerMappings.graphql @@ -1,7 +1,7 @@ query ListLedgerMappings { mappings { structures { - id name description blockType taxonomyId isActive + id name description blockType taxonomyId isActive framework } } } diff --git a/robosystems_client/graphql/operations/ledger/ListLedgerStructures.graphql b/robosystems_client/graphql/operations/ledger/ListLedgerStructures.graphql index a6e6ad2e..31c5a684 100644 --- a/robosystems_client/graphql/operations/ledger/ListLedgerStructures.graphql +++ b/robosystems_client/graphql/operations/ledger/ListLedgerStructures.graphql @@ -1,7 +1,7 @@ query ListLedgerStructures($taxonomyId: String, $blockType: String) { structures(taxonomyId: $taxonomyId, blockType: $blockType) { structures { - id name description blockType taxonomyId isActive + id name description blockType taxonomyId isActive framework } } } diff --git a/robosystems_client/graphql/schema.graphql b/robosystems_client/graphql/schema.graphql index a04d79d8..de68b181 100644 --- a/robosystems_client/graphql/schema.graphql +++ b/robosystems_client/graphql/schema.graphql @@ -1878,6 +1878,11 @@ type Structure { blockType: String! taxonomyId: String! isActive: Boolean! + + """ + `coa_mapping` only: the reporting framework the mapping maps the chart into (e.g. `rs-gaap`). A chart holds one mapping per framework. + """ + framework: String } """A mapping structure with all its associations.""" diff --git a/robosystems_client/models/taxonomy_block_structure.py b/robosystems_client/models/taxonomy_block_structure.py index ffd193d3..19c908d4 100644 --- a/robosystems_client/models/taxonomy_block_structure.py +++ b/robosystems_client/models/taxonomy_block_structure.py @@ -21,6 +21,7 @@ class TaxonomyBlockStructure: block_type (str): description (None | str | Unset): role_uri (None | str | Unset): + target_framework (None | str | Unset): `coa_mapping` only: the framework the mapping maps into. """ id: str @@ -28,6 +29,7 @@ class TaxonomyBlockStructure: block_type: str description: None | str | Unset = UNSET role_uri: None | str | Unset = UNSET + target_framework: None | str | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -49,6 +51,12 @@ def to_dict(self) -> dict[str, Any]: else: role_uri = self.role_uri + target_framework: None | str | Unset + if isinstance(self.target_framework, Unset): + target_framework = UNSET + else: + target_framework = self.target_framework + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -62,6 +70,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["description"] = description if role_uri is not UNSET: field_dict["role_uri"] = role_uri + if target_framework is not UNSET: + field_dict["target_framework"] = target_framework return field_dict @@ -92,12 +102,22 @@ def _parse_role_uri(data: object) -> None | str | Unset: role_uri = _parse_role_uri(d.pop("role_uri", UNSET)) + def _parse_target_framework(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_framework = _parse_target_framework(d.pop("target_framework", UNSET)) + taxonomy_block_structure = cls( id=id, name=name, block_type=block_type, description=description, role_uri=role_uri, + target_framework=target_framework, ) taxonomy_block_structure.additional_properties = d diff --git a/robosystems_client/models/taxonomy_block_structure_request.py b/robosystems_client/models/taxonomy_block_structure_request.py index 379d5a16..13ef89f2 100644 --- a/robosystems_client/models/taxonomy_block_structure_request.py +++ b/robosystems_client/models/taxonomy_block_structure_request.py @@ -37,6 +37,8 @@ class TaxonomyBlockStructureRequest: vocabulary). A disclosure note footing members to a total is `roll_up`. Null leaves the pattern unset. description (None | str | Unset): role_uri (None | str | Unset): + target_framework (None | str | Unset): `coa_mapping` only: the framework this mapping maps the chart into, e.g. + `rs-gaap`. Omitted means the graph's book framework. A chart holds one mapping per framework. metadata (TaxonomyBlockStructureRequestMetadata | Unset): """ @@ -47,6 +49,7 @@ class TaxonomyBlockStructureRequest: ) = UNSET description: None | str | Unset = UNSET role_uri: None | str | Unset = UNSET + target_framework: None | str | Unset = UNSET metadata: TaxonomyBlockStructureRequestMetadata | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -77,6 +80,12 @@ def to_dict(self) -> dict[str, Any]: else: role_uri = self.role_uri + target_framework: None | str | Unset + if isinstance(self.target_framework, Unset): + target_framework = UNSET + else: + target_framework = self.target_framework + metadata: dict[str, Any] | Unset = UNSET if not isinstance(self.metadata, Unset): metadata = self.metadata.to_dict() @@ -95,6 +104,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["description"] = description if role_uri is not UNSET: field_dict["role_uri"] = role_uri + if target_framework is not UNSET: + field_dict["target_framework"] = target_framework if metadata is not UNSET: field_dict["metadata"] = metadata @@ -154,6 +165,15 @@ def _parse_role_uri(data: object) -> None | str | Unset: role_uri = _parse_role_uri(d.pop("role_uri", UNSET)) + def _parse_target_framework(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_framework = _parse_target_framework(d.pop("target_framework", UNSET)) + _metadata = d.pop("metadata", UNSET) metadata: TaxonomyBlockStructureRequestMetadata | Unset if isinstance(_metadata, Unset): @@ -167,6 +187,7 @@ def _parse_role_uri(data: object) -> None | str | Unset: concept_arrangement=concept_arrangement, description=description, role_uri=role_uri, + target_framework=target_framework, metadata=metadata, ) diff --git a/tests/test_ledger_client.py b/tests/test_ledger_client.py index dd807d47..e957bfe8 100644 --- a/tests/test_ledger_client.py +++ b/tests/test_ledger_client.py @@ -255,8 +255,9 @@ def test_list_mappings_unwraps_structures(self, mock_execute, mock_config, graph "name": "CoA → GAAP", "description": None, "blockType": "coa_mapping", - "taxonomyId": "tax_usgaap", + "taxonomyId": "tax_map_gaap", "isActive": True, + "framework": "rs-gaap", } ] } @@ -265,6 +266,7 @@ def test_list_mappings_unwraps_structures(self, mock_execute, mock_config, graph mappings = client.list_mappings(graph_id) assert len(mappings) == 1 assert mappings[0].block_type == "coa_mapping" + assert mappings[0].framework == "rs-gaap" @patch("robosystems_client.graphql.client.GraphQLClient.execute") def test_get_fiscal_calendar(self, mock_execute, mock_config, graph_id): @@ -1272,6 +1274,7 @@ def test_list_structures(self, mock_execute, mock_config, graph_id): "blockType": "income_statement", "taxonomyId": "tax_usgaap", "isActive": True, + "framework": None, } ] }