From 9197a83665bbbafc5b084a587fbbbf9894767aab Mon Sep 17 00:00:00 2001 From: "Joseph T. French" Date: Thu, 22 Oct 2026 18:36:19 -0500 Subject: [PATCH] feat(ledger): record_deconsolidation on the facade The generated-tier regens carried the operation; the LedgerClient facade did not. Added beside record_acquisition and record_ownership_change, with its test. The calendar and entity reads already return the generated models, which carry is_former and the unmapped-account fields. Claude-Session: https://claude.ai/code/session_015PxYaVzrbraKFeRALM7rXp --- robosystems_client/clients/ledger_client.py | 32 +++++++++++++++++++++ tests/test_ledger_client.py | 24 ++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/robosystems_client/clients/ledger_client.py b/robosystems_client/clients/ledger_client.py index a200eb5..9da3896 100644 --- a/robosystems_client/clients/ledger_client.py +++ b/robosystems_client/clients/ledger_client.py @@ -69,6 +69,9 @@ from ..api.robo_ledger_ledger_events.record_ownership_change import ( sync_detailed as op_record_ownership_change, ) +from ..api.robo_ledger_ledger_events.record_deconsolidation import ( + sync_detailed as op_record_deconsolidation, +) from ..api.robo_ledger_ledger_events.record_statement_balance import ( sync_detailed as op_record_statement_balance, ) @@ -630,6 +633,8 @@ from ..models.record_acquisition_request import RecordAcquisitionRequest from ..models.ownership_change_response import OwnershipChangeResponse from ..models.record_ownership_change_request import RecordOwnershipChangeRequest +from ..models.deconsolidation_response import DeconsolidationResponse +from ..models.record_deconsolidation_request import RecordDeconsolidationRequest from ..models.live_financial_statement_request import LiveFinancialStatementRequest from ..models.financial_statement_analysis_response import ( FinancialStatementAnalysisResponse, @@ -2720,6 +2725,33 @@ def record_ownership_change( "Record ownership change", envelope, OwnershipChangeResponse ) + def record_deconsolidation( + self, + graph_id: str, + *, + entity_id: str, + consideration: int, + basis: str, + ) -> DeconsolidationResponse: + """Record a member's leaving the group once ``left_on`` is set on it: + what the parent received for its shares in cents (0 for a dissolution) + and the ``basis``. Writes a draft in the consolidation entity, dated the + first day of the month after the member's last, that its close posts: + what the entity still held for the member is taken off, a member in full + has its results put back into the group's equity, and the difference is + the gain or loss on its leaving — the group's adjustment to the parent's + own gain (ASC 810).""" + body = RecordDeconsolidationRequest( + entity_id=entity_id, consideration=consideration, basis=basis + ) + response = op_record_deconsolidation( + graph_id=graph_id, body=body, client=self._get_client() + ) + envelope = self._call_op("Record deconsolidation", response) + return self._typed_result( + "Record deconsolidation", envelope, DeconsolidationResponse + ) + # ── Event blocks (generic preview + status transitions) ────────────── def create_event_block( diff --git a/tests/test_ledger_client.py b/tests/test_ledger_client.py index 33ad247..347c773 100644 --- a/tests/test_ledger_client.py +++ b/tests/test_ledger_client.py @@ -1195,6 +1195,30 @@ def test_record_ownership_change(self, mock_op, mock_config, graph_id): "basis": "Share purchase agreement", } + @patch("robosystems_client.clients.ledger_client.op_record_deconsolidation") + def test_record_deconsolidation(self, mock_op, mock_config, graph_id): + envelope = _envelope( + "record-deconsolidation", + { + "entity_id": "ent_cafe", + "period": "2026-06", + "consideration": 6200000, + "earnings_restored": 2440000, + "gain_loss": -2443412, + }, + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.record_deconsolidation( + graph_id, entity_id="ent_cafe", consideration=6200000, basis="Sale agreement" + ) + assert result["gain_loss"] == -2443412 + assert mock_op.call_args.kwargs["body"].to_dict() == { + "entity_id": "ent_cafe", + "consideration": 6200000, + "basis": "Sale agreement", + } + # ── Taxonomy / entity linking ───────────────────────────────────────────