From 062bd6e174ba79a502dda83ae016b55354496b2d Mon Sep 17 00:00:00 2001 From: "Joseph T. French" Date: Mon, 19 Oct 2026 23:14:02 -0500 Subject: [PATCH] feat: create_journal_entry tags a consolidating entry (adjustment_kind, adjusts_entity_id) An entry posted by hand in the group's consolidation entity names what it adjusts and the entity whose figures it adjusts, so the consolidation engine counts it toward what it already holds instead of proposing the elimination again. --- robosystems_client/clients/ledger_client.py | 13 +++++++++ tests/test_ledger_client.py | 32 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/robosystems_client/clients/ledger_client.py b/robosystems_client/clients/ledger_client.py index 7cb8ade..41c4144 100644 --- a/robosystems_client/clients/ledger_client.py +++ b/robosystems_client/clients/ledger_client.py @@ -2043,6 +2043,8 @@ def create_journal_entry( source: str = "manual", idempotency_key: str | None = None, entity_id: str | None = None, + adjustment_kind: str | None = None, + adjusts_entity_id: str | None = None, ) -> EventBlockEnvelope: """Create a journal entry with balanced line items (DR=CR enforced). @@ -2065,6 +2067,13 @@ def create_journal_entry( ``entity_id`` names the entity whose books the entry goes into; omitted, the group parent's. + ``adjustment_kind`` tags a consolidating entry in the group's + consolidation entity (``elimination_intercompany``, ``manual``, ...), with + ``adjusts_entity_id`` the entity whose figures it adjusts (required for + every kind but ``manual``). Only that entity's books take one; the + consolidation engine counts a tagged entry toward what it already holds, + so an elimination posted by hand is not proposed again. + A line dict may carry ``flow_qname``, the cash flow row its cash belongs to (a ``qname`` from ``get_flow_candidates``): only for a loan drawn or repaid, capital put in or taken out, an asset bought or sold. A flow on @@ -2082,6 +2091,10 @@ def create_journal_entry( } if transaction_id is not None: metadata["transaction_id"] = transaction_id + if adjustment_kind is not None: + metadata["adjustment_kind"] = adjustment_kind + if adjusts_entity_id is not None: + metadata["adjusts_entity_id"] = adjusts_entity_id body = self._build_event_block_request( event_type="journal_entry_recorded", event_category="adjustment", diff --git a/tests/test_ledger_client.py b/tests/test_ledger_client.py index 618dab2..e073745 100644 --- a/tests/test_ledger_client.py +++ b/tests/test_ledger_client.py @@ -809,6 +809,38 @@ def test_create_journal_entry_names_its_entity(self, mock_op, mock_config, graph ) assert mock_op.call_args.kwargs["body"].entity_id == "ent_sub" + @patch("robosystems_client.clients.ledger_client.op_create_event_block") + def test_create_journal_entry_tags_a_consolidating_entry( + self, mock_op, mock_config, graph_id + ): + mock_op.return_value = _mock_response(_envelope("create-event-block", {})) + client = LedgerClient(mock_config) + client.create_journal_entry( + graph_id, + posting_date="2026-07-31", + memo="Intercompany receivable", + line_items=self._LINE_ITEMS, + entity_id="ent_cons", + adjustment_kind="elimination_intercompany", + adjusts_entity_id="ent_sub", + ) + metadata = mock_op.call_args.kwargs["body"].metadata.to_dict() + assert metadata["adjustment_kind"] == "elimination_intercompany" + assert metadata["adjusts_entity_id"] == "ent_sub" + + @patch("robosystems_client.clients.ledger_client.op_create_event_block") + def test_create_journal_entry_sends_no_consolidating_tags_unasked( + self, mock_op, mock_config, graph_id + ): + mock_op.return_value = _mock_response(_envelope("create-event-block", {})) + client = LedgerClient(mock_config) + client.create_journal_entry( + graph_id, posting_date="2026-03-31", memo="X", line_items=self._LINE_ITEMS + ) + metadata = mock_op.call_args.kwargs["body"].metadata.to_dict() + assert "adjustment_kind" not in metadata + assert "adjusts_entity_id" not in metadata + @patch("robosystems_client.clients.ledger_client.op_create_event_block") def test_create_journal_entry_leaves_the_entity_to_the_server( self, mock_op, mock_config, graph_id