diff --git a/robosystems_client/api/extensions_robo_ledger/op_create_manual_closing_entry.py b/robosystems_client/api/extensions_robo_ledger/op_create_agent.py similarity index 80% rename from robosystems_client/api/extensions_robo_ledger/op_create_manual_closing_entry.py rename to robosystems_client/api/extensions_robo_ledger/op_create_agent.py index 9ad5cc7..3c027d8 100644 --- a/robosystems_client/api/extensions_robo_ledger/op_create_manual_closing_entry.py +++ b/robosystems_client/api/extensions_robo_ledger/op_create_agent.py @@ -6,9 +6,7 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.create_manual_closing_entry_request import ( - CreateManualClosingEntryRequest, -) +from ...models.create_agent_request import CreateAgentRequest from ...models.http_validation_error import HTTPValidationError from ...models.operation_envelope import OperationEnvelope from ...models.operation_error import OperationError @@ -18,7 +16,7 @@ def _get_kwargs( graph_id: str, *, - body: CreateManualClosingEntryRequest, + body: CreateAgentRequest, idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -27,7 +25,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/create-manual-closing-entry".format( + "url": "/extensions/roboledger/{graph_id}/operations/create-agent".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -105,14 +103,13 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CreateManualClosingEntryRequest, + body: CreateAgentRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Manual Closing Entry + """Create Agent - Create a draft closing entry with manually specified line items — not tied to a schedule. Use for - one-off business events (asset disposal, correcting entry, impairment). Total debits must equal - total credits. + Create a counterparty record (customer, vendor, employee, etc.). The (source, external_id) pair is a + dedup key — a second insert with the same pair returns 409. Use update-agent to patch fields. **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. @@ -120,7 +117,7 @@ def sync_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateManualClosingEntryRequest): + body (CreateAgentRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -147,14 +144,13 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: CreateManualClosingEntryRequest, + body: CreateAgentRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Manual Closing Entry + """Create Agent - Create a draft closing entry with manually specified line items — not tied to a schedule. Use for - one-off business events (asset disposal, correcting entry, impairment). Total debits must equal - total credits. + Create a counterparty record (customer, vendor, employee, etc.). The (source, external_id) pair is a + dedup key — a second insert with the same pair returns 409. Use update-agent to patch fields. **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. @@ -162,7 +158,7 @@ def sync( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateManualClosingEntryRequest): + body (CreateAgentRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -184,14 +180,13 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CreateManualClosingEntryRequest, + body: CreateAgentRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Manual Closing Entry + """Create Agent - Create a draft closing entry with manually specified line items — not tied to a schedule. Use for - one-off business events (asset disposal, correcting entry, impairment). Total debits must equal - total credits. + Create a counterparty record (customer, vendor, employee, etc.). The (source, external_id) pair is a + dedup key — a second insert with the same pair returns 409. Use update-agent to patch fields. **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. @@ -199,7 +194,7 @@ async def asyncio_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateManualClosingEntryRequest): + body (CreateAgentRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -224,14 +219,13 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: CreateManualClosingEntryRequest, + body: CreateAgentRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Manual Closing Entry + """Create Agent - Create a draft closing entry with manually specified line items — not tied to a schedule. Use for - one-off business events (asset disposal, correcting entry, impairment). Total debits must equal - total credits. + Create a counterparty record (customer, vendor, employee, etc.). The (source, external_id) pair is a + dedup key — a second insert with the same pair returns 409. Use update-agent to patch fields. **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. @@ -239,7 +233,7 @@ async def asyncio( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateManualClosingEntryRequest): + body (CreateAgentRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/extensions_robo_ledger/op_create_closing_entry.py b/robosystems_client/api/extensions_robo_ledger/op_create_event_block.py similarity index 73% rename from robosystems_client/api/extensions_robo_ledger/op_create_closing_entry.py rename to robosystems_client/api/extensions_robo_ledger/op_create_event_block.py index a67572c..6b4dd9f 100644 --- a/robosystems_client/api/extensions_robo_ledger/op_create_closing_entry.py +++ b/robosystems_client/api/extensions_robo_ledger/op_create_event_block.py @@ -6,7 +6,7 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.create_closing_entry_operation import CreateClosingEntryOperation +from ...models.create_event_block_request import CreateEventBlockRequest from ...models.http_validation_error import HTTPValidationError from ...models.operation_envelope import OperationEnvelope from ...models.operation_error import OperationError @@ -16,7 +16,7 @@ def _get_kwargs( graph_id: str, *, - body: CreateClosingEntryOperation, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -25,7 +25,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/create-closing-entry".format( + "url": "/extensions/roboledger/{graph_id}/operations/create-event-block".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -103,14 +103,14 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CreateClosingEntryOperation, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Closing Entry + """Create Event Block - Create a draft closing entry pre-populated from a schedule's facts for the given period. Idempotent - — safe to call repeatedly; the `outcome` field describes what happened (`created`, `unchanged`, - `regenerated`, `removed`, `skipped`). + Persist a real-world business event. apply_handlers=False (default): capture-only, + status='captured'. apply_handlers=True: resolves an event_handler, fires the template, creates GL + entries atomically, status='classified'. Use preview-event-block to dry-run before committing. **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. @@ -118,11 +118,7 @@ def sync_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateClosingEntryOperation): CQRS-shaped body for `POST /operations/create-closing- - entry`. - - `structure_id` moves into the body so REST + MCP share a single body - type via the registrar. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -149,14 +145,14 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: CreateClosingEntryOperation, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Closing Entry + """Create Event Block - Create a draft closing entry pre-populated from a schedule's facts for the given period. Idempotent - — safe to call repeatedly; the `outcome` field describes what happened (`created`, `unchanged`, - `regenerated`, `removed`, `skipped`). + Persist a real-world business event. apply_handlers=False (default): capture-only, + status='captured'. apply_handlers=True: resolves an event_handler, fires the template, creates GL + entries atomically, status='classified'. Use preview-event-block to dry-run before committing. **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. @@ -164,11 +160,7 @@ def sync( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateClosingEntryOperation): CQRS-shaped body for `POST /operations/create-closing- - entry`. - - `structure_id` moves into the body so REST + MCP share a single body - type via the registrar. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -190,14 +182,14 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CreateClosingEntryOperation, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Closing Entry + """Create Event Block - Create a draft closing entry pre-populated from a schedule's facts for the given period. Idempotent - — safe to call repeatedly; the `outcome` field describes what happened (`created`, `unchanged`, - `regenerated`, `removed`, `skipped`). + Persist a real-world business event. apply_handlers=False (default): capture-only, + status='captured'. apply_handlers=True: resolves an event_handler, fires the template, creates GL + entries atomically, status='classified'. Use preview-event-block to dry-run before committing. **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. @@ -205,11 +197,7 @@ async def asyncio_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateClosingEntryOperation): CQRS-shaped body for `POST /operations/create-closing- - entry`. - - `structure_id` moves into the body so REST + MCP share a single body - type via the registrar. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -234,14 +222,14 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: CreateClosingEntryOperation, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Closing Entry + """Create Event Block - Create a draft closing entry pre-populated from a schedule's facts for the given period. Idempotent - — safe to call repeatedly; the `outcome` field describes what happened (`created`, `unchanged`, - `regenerated`, `removed`, `skipped`). + Persist a real-world business event. apply_handlers=False (default): capture-only, + status='captured'. apply_handlers=True: resolves an event_handler, fires the template, creates GL + entries atomically, status='classified'. Use preview-event-block to dry-run before committing. **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. @@ -249,11 +237,7 @@ async def asyncio( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateClosingEntryOperation): CQRS-shaped body for `POST /operations/create-closing- - entry`. - - `structure_id` moves into the body so REST + MCP share a single body - type via the registrar. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/extensions_robo_ledger/op_create_journal_entry.py b/robosystems_client/api/extensions_robo_ledger/op_create_event_handler.py similarity index 64% rename from robosystems_client/api/extensions_robo_ledger/op_create_journal_entry.py rename to robosystems_client/api/extensions_robo_ledger/op_create_event_handler.py index 0d4e4e2..93d3707 100644 --- a/robosystems_client/api/extensions_robo_ledger/op_create_journal_entry.py +++ b/robosystems_client/api/extensions_robo_ledger/op_create_event_handler.py @@ -6,7 +6,7 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.create_journal_entry_request import CreateJournalEntryRequest +from ...models.create_event_handler_request import CreateEventHandlerRequest from ...models.http_validation_error import HTTPValidationError from ...models.operation_envelope import OperationEnvelope from ...models.operation_error import OperationError @@ -16,7 +16,7 @@ def _get_kwargs( graph_id: str, *, - body: CreateJournalEntryRequest, + body: CreateEventHandlerRequest, idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -25,7 +25,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/create-journal-entry".format( + "url": "/extensions/roboledger/{graph_id}/operations/create-event-handler".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -103,14 +103,16 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CreateJournalEntryRequest, + body: CreateEventHandlerRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Journal Entry + """Create Event Handler - Create a new draft journal entry with balanced line items. Enforces DR=CR at the validation layer. - Entries are always created as drafts; posting happens via close-period or a future per-entry post - op. + Define a rule that fires GL transactions when a matching event block is created with + apply_handlers=True. Match criteria (event_type, event_category, match_source, match_agent_type, + etc.) act as AND-joined filters — null fields match anything. The highest-priority matching handler + wins. AI-suggested handlers (suggested_by='ai') require approval before they are eligible for + matching. **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. @@ -118,16 +120,7 @@ def sync_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateJournalEntryRequest): Create a new journal entry with balanced line items. - - Defaults to `status='draft'` for ongoing native writes (the normal - workflow: draft → review → post via close-period). Pass - `status='posted'` for historical data import where entries represent - already-happened business events that don't need review. - - Total debit amount must equal total credit amount or the request - is rejected with 422. `line_items` must contain at least two rows - (at least one debit, at least one credit). + body (CreateEventHandlerRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -154,14 +147,16 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: CreateJournalEntryRequest, + body: CreateEventHandlerRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Journal Entry + """Create Event Handler - Create a new draft journal entry with balanced line items. Enforces DR=CR at the validation layer. - Entries are always created as drafts; posting happens via close-period or a future per-entry post - op. + Define a rule that fires GL transactions when a matching event block is created with + apply_handlers=True. Match criteria (event_type, event_category, match_source, match_agent_type, + etc.) act as AND-joined filters — null fields match anything. The highest-priority matching handler + wins. AI-suggested handlers (suggested_by='ai') require approval before they are eligible for + matching. **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. @@ -169,16 +164,7 @@ def sync( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateJournalEntryRequest): Create a new journal entry with balanced line items. - - Defaults to `status='draft'` for ongoing native writes (the normal - workflow: draft → review → post via close-period). Pass - `status='posted'` for historical data import where entries represent - already-happened business events that don't need review. - - Total debit amount must equal total credit amount or the request - is rejected with 422. `line_items` must contain at least two rows - (at least one debit, at least one credit). + body (CreateEventHandlerRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -200,14 +186,16 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: CreateJournalEntryRequest, + body: CreateEventHandlerRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Journal Entry + """Create Event Handler - Create a new draft journal entry with balanced line items. Enforces DR=CR at the validation layer. - Entries are always created as drafts; posting happens via close-period or a future per-entry post - op. + Define a rule that fires GL transactions when a matching event block is created with + apply_handlers=True. Match criteria (event_type, event_category, match_source, match_agent_type, + etc.) act as AND-joined filters — null fields match anything. The highest-priority matching handler + wins. AI-suggested handlers (suggested_by='ai') require approval before they are eligible for + matching. **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. @@ -215,16 +203,7 @@ async def asyncio_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateJournalEntryRequest): Create a new journal entry with balanced line items. - - Defaults to `status='draft'` for ongoing native writes (the normal - workflow: draft → review → post via close-period). Pass - `status='posted'` for historical data import where entries represent - already-happened business events that don't need review. - - Total debit amount must equal total credit amount or the request - is rejected with 422. `line_items` must contain at least two rows - (at least one debit, at least one credit). + body (CreateEventHandlerRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -249,14 +228,16 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: CreateJournalEntryRequest, + body: CreateEventHandlerRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Journal Entry + """Create Event Handler - Create a new draft journal entry with balanced line items. Enforces DR=CR at the validation layer. - Entries are always created as drafts; posting happens via close-period or a future per-entry post - op. + Define a rule that fires GL transactions when a matching event block is created with + apply_handlers=True. Match criteria (event_type, event_category, match_source, match_agent_type, + etc.) act as AND-joined filters — null fields match anything. The highest-priority matching handler + wins. AI-suggested handlers (suggested_by='ai') require approval before they are eligible for + matching. **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. @@ -264,16 +245,7 @@ async def asyncio( Args: graph_id (str): idempotency_key (None | str | Unset): - body (CreateJournalEntryRequest): Create a new journal entry with balanced line items. - - Defaults to `status='draft'` for ongoing native writes (the normal - workflow: draft → review → post via close-period). Pass - `status='posted'` for historical data import where entries represent - already-happened business events that don't need review. - - Total debit amount must equal total credit amount or the request - is rejected with 422. `line_items` must contain at least two rows - (at least one debit, at least one credit). + body (CreateEventHandlerRequest): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/extensions_robo_ledger/op_create_transaction.py b/robosystems_client/api/extensions_robo_ledger/op_create_transaction.py deleted file mode 100644 index 1ffffd7..0000000 --- a/robosystems_client/api/extensions_robo_ledger/op_create_transaction.py +++ /dev/null @@ -1,289 +0,0 @@ -from http import HTTPStatus -from typing import Any, cast -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.create_transaction_request import CreateTransactionRequest -from ...models.http_validation_error import HTTPValidationError -from ...models.operation_envelope import OperationEnvelope -from ...models.operation_error import OperationError -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - *, - body: CreateTransactionRequest, - idempotency_key: None | str | Unset = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(idempotency_key, Unset): - headers["Idempotency-Key"] = idempotency_key - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/create-transaction".format( - graph_id=quote(str(graph_id), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - if response.status_code == 200: - response_200 = OperationEnvelope.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = OperationError.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = cast(Any, None) - return response_403 - - if response.status_code == 404: - response_404 = OperationError.from_dict(response.json()) - - return response_404 - - if response.status_code == 409: - response_409 = OperationError.from_dict(response.json()) - - return response_409 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = cast(Any, None) - return response_429 - - if response.status_code == 500: - response_500 = cast(Any, None) - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: CreateTransactionRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Transaction - - Create a standalone business-event Transaction without entries. Returns a transaction_id that can be - passed to create-journal-entry to attach one or more journal entries to this event. Use this when a - single event (invoice, payment, deposit) produces multiple entries over its lifecycle. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (CreateTransactionRequest): Create a standalone business-event Transaction. - - Use this when you want to record a real-world event (invoice, payment, - deposit, expense) first and then attach one or more journal entries to - it via `create-journal-entry` with the returned `transaction_id`. - - `amount` is in minor currency units (cents). `type` is free-form but - common values are: invoice, payment, bill, expense, deposit, transfer, - journal_entry. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | HTTPValidationError | OperationEnvelope | OperationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - idempotency_key=idempotency_key, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - body: CreateTransactionRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Transaction - - Create a standalone business-event Transaction without entries. Returns a transaction_id that can be - passed to create-journal-entry to attach one or more journal entries to this event. Use this when a - single event (invoice, payment, deposit) produces multiple entries over its lifecycle. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (CreateTransactionRequest): Create a standalone business-event Transaction. - - Use this when you want to record a real-world event (invoice, payment, - deposit, expense) first and then attach one or more journal entries to - it via `create-journal-entry` with the returned `transaction_id`. - - `amount` is in minor currency units (cents). `type` is free-form but - common values are: invoice, payment, bill, expense, deposit, transfer, - journal_entry. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | HTTPValidationError | OperationEnvelope | OperationError - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - body=body, - idempotency_key=idempotency_key, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: CreateTransactionRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Create Transaction - - Create a standalone business-event Transaction without entries. Returns a transaction_id that can be - passed to create-journal-entry to attach one or more journal entries to this event. Use this when a - single event (invoice, payment, deposit) produces multiple entries over its lifecycle. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (CreateTransactionRequest): Create a standalone business-event Transaction. - - Use this when you want to record a real-world event (invoice, payment, - deposit, expense) first and then attach one or more journal entries to - it via `create-journal-entry` with the returned `transaction_id`. - - `amount` is in minor currency units (cents). `type` is free-form but - common values are: invoice, payment, bill, expense, deposit, transfer, - journal_entry. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | HTTPValidationError | OperationEnvelope | OperationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - idempotency_key=idempotency_key, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - body: CreateTransactionRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Create Transaction - - Create a standalone business-event Transaction without entries. Returns a transaction_id that can be - passed to create-journal-entry to attach one or more journal entries to this event. Use this when a - single event (invoice, payment, deposit) produces multiple entries over its lifecycle. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (CreateTransactionRequest): Create a standalone business-event Transaction. - - Use this when you want to record a real-world event (invoice, payment, - deposit, expense) first and then attach one or more journal entries to - it via `create-journal-entry` with the returned `transaction_id`. - - `amount` is in minor currency units (cents). `type` is free-form but - common values are: invoice, payment, bill, expense, deposit, transfer, - journal_entry. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | HTTPValidationError | OperationEnvelope | OperationError - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - body=body, - idempotency_key=idempotency_key, - ) - ).parsed diff --git a/robosystems_client/api/extensions_robo_ledger/op_dispose_schedule.py b/robosystems_client/api/extensions_robo_ledger/op_dispose_schedule.py deleted file mode 100644 index 4c70d33..0000000 --- a/robosystems_client/api/extensions_robo_ledger/op_dispose_schedule.py +++ /dev/null @@ -1,285 +0,0 @@ -from http import HTTPStatus -from typing import Any, cast -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.dispose_schedule_request import DisposeScheduleRequest -from ...models.http_validation_error import HTTPValidationError -from ...models.operation_envelope import OperationEnvelope -from ...models.operation_error import OperationError -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - graph_id: str, - *, - body: DisposeScheduleRequest, - idempotency_key: None | str | Unset = UNSET, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - if not isinstance(idempotency_key, Unset): - headers["Idempotency-Key"] = idempotency_key - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/dispose-schedule".format( - graph_id=quote(str(graph_id), safe=""), - ), - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - if response.status_code == 200: - response_200 = OperationEnvelope.from_dict(response.json()) - - return response_200 - - if response.status_code == 400: - response_400 = OperationError.from_dict(response.json()) - - return response_400 - - if response.status_code == 401: - response_401 = cast(Any, None) - return response_401 - - if response.status_code == 403: - response_403 = cast(Any, None) - return response_403 - - if response.status_code == 404: - response_404 = OperationError.from_dict(response.json()) - - return response_404 - - if response.status_code == 409: - response_409 = OperationError.from_dict(response.json()) - - return response_409 - - if response.status_code == 422: - response_422 = HTTPValidationError.from_dict(response.json()) - - return response_422 - - if response.status_code == 429: - response_429 = cast(Any, None) - return response_429 - - if response.status_code == 500: - response_500 = cast(Any, None) - return response_500 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: DisposeScheduleRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Dispose Schedule (Sale or Abandonment) - - Atomically truncate a schedule past the disposal date and create a balanced disposal closing entry. - Computes accumulated depreciation from the schedule's own facts, derives net book value and - gain/loss, removes forward facts, and books the disposal entry in one call. Use when an asset is - sold or abandoned before the schedule runs to completion. For abandonment with no proceeds, omit - `sale_proceeds` and `proceeds_element_id`. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (DisposeScheduleRequest): Dispose a schedule early — combines truncation with a - disposal closing entry. - - Computes net book value from the schedule's own facts, truncates forward - periods, and creates a balanced disposal entry in one atomic operation. - Use when an asset is sold or abandoned before the schedule runs to completion. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | HTTPValidationError | OperationEnvelope | OperationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - idempotency_key=idempotency_key, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - graph_id: str, - *, - client: AuthenticatedClient, - body: DisposeScheduleRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Dispose Schedule (Sale or Abandonment) - - Atomically truncate a schedule past the disposal date and create a balanced disposal closing entry. - Computes accumulated depreciation from the schedule's own facts, derives net book value and - gain/loss, removes forward facts, and books the disposal entry in one call. Use when an asset is - sold or abandoned before the schedule runs to completion. For abandonment with no proceeds, omit - `sale_proceeds` and `proceeds_element_id`. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (DisposeScheduleRequest): Dispose a schedule early — combines truncation with a - disposal closing entry. - - Computes net book value from the schedule's own facts, truncates forward - periods, and creates a balanced disposal entry in one atomic operation. - Use when an asset is sold or abandoned before the schedule runs to completion. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | HTTPValidationError | OperationEnvelope | OperationError - """ - - return sync_detailed( - graph_id=graph_id, - client=client, - body=body, - idempotency_key=idempotency_key, - ).parsed - - -async def asyncio_detailed( - graph_id: str, - *, - client: AuthenticatedClient, - body: DisposeScheduleRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Dispose Schedule (Sale or Abandonment) - - Atomically truncate a schedule past the disposal date and create a balanced disposal closing entry. - Computes accumulated depreciation from the schedule's own facts, derives net book value and - gain/loss, removes forward facts, and books the disposal entry in one call. Use when an asset is - sold or abandoned before the schedule runs to completion. For abandonment with no proceeds, omit - `sale_proceeds` and `proceeds_element_id`. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (DisposeScheduleRequest): Dispose a schedule early — combines truncation with a - disposal closing entry. - - Computes net book value from the schedule's own facts, truncates forward - periods, and creates a balanced disposal entry in one atomic operation. - Use when an asset is sold or abandoned before the schedule runs to completion. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any | HTTPValidationError | OperationEnvelope | OperationError] - """ - - kwargs = _get_kwargs( - graph_id=graph_id, - body=body, - idempotency_key=idempotency_key, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - graph_id: str, - *, - client: AuthenticatedClient, - body: DisposeScheduleRequest, - idempotency_key: None | str | Unset = UNSET, -) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Dispose Schedule (Sale or Abandonment) - - Atomically truncate a schedule past the disposal date and create a balanced disposal closing entry. - Computes accumulated depreciation from the schedule's own facts, derives net book value and - gain/loss, removes forward facts, and books the disposal entry in one call. Use when an asset is - sold or abandoned before the schedule runs to completion. For abandonment with no proceeds, omit - `sale_proceeds` and `proceeds_element_id`. - - **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. - - Args: - graph_id (str): - idempotency_key (None | str | Unset): - body (DisposeScheduleRequest): Dispose a schedule early — combines truncation with a - disposal closing entry. - - Computes net book value from the schedule's own facts, truncates forward - periods, and creates a balanced disposal entry in one atomic operation. - Use when an asset is sold or abandoned before the schedule runs to completion. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Any | HTTPValidationError | OperationEnvelope | OperationError - """ - - return ( - await asyncio_detailed( - graph_id=graph_id, - client=client, - body=body, - idempotency_key=idempotency_key, - ) - ).parsed diff --git a/robosystems_client/api/extensions_robo_ledger/op_reverse_journal_entry.py b/robosystems_client/api/extensions_robo_ledger/op_preview_event_block.py similarity index 63% rename from robosystems_client/api/extensions_robo_ledger/op_reverse_journal_entry.py rename to robosystems_client/api/extensions_robo_ledger/op_preview_event_block.py index 12d2d21..2612252 100644 --- a/robosystems_client/api/extensions_robo_ledger/op_reverse_journal_entry.py +++ b/robosystems_client/api/extensions_robo_ledger/op_preview_event_block.py @@ -6,17 +6,17 @@ from ... import errors from ...client import AuthenticatedClient, Client +from ...models.create_event_block_request import CreateEventBlockRequest from ...models.http_validation_error import HTTPValidationError from ...models.operation_envelope import OperationEnvelope from ...models.operation_error import OperationError -from ...models.reverse_journal_entry_request import ReverseJournalEntryRequest from ...types import UNSET, Response, Unset def _get_kwargs( graph_id: str, *, - body: ReverseJournalEntryRequest, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -25,7 +25,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/reverse-journal-entry".format( + "url": "/extensions/roboledger/{graph_id}/operations/preview-event-block".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -103,14 +103,14 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: ReverseJournalEntryRequest, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Reverse Journal Entry + """Preview Event Block - Reverse a posted journal entry by creating a new offsetting entry (debits ↔ credits) and marking the - original as status='reversed'. Both entries stay in the ledger — the audit trail shows original + - reversal side by side. + Dry-run: resolve the matching handler and evaluate the transaction template without writing any + rows. Returns the matched handler + planned debit/credit lines + any validation errors. Use this + before create-event-block(apply_handlers=True) to confirm the GL plan. **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. @@ -118,16 +118,7 @@ def sync_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ReverseJournalEntryRequest): Reverse a posted journal entry. - - Creates a new entry whose line items flip the originals - (debits → credits, credits → debits), sets `reversal_of` on the new - entry to the original's id, marks the original as - `status='reversed'`, and posts the reversing entry immediately. - - This is how accountants correct posted entries — the original stays - in the audit trail, the reversal cancels its effect, and a - corrected entry can be created separately. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -154,14 +145,14 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: ReverseJournalEntryRequest, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Reverse Journal Entry + """Preview Event Block - Reverse a posted journal entry by creating a new offsetting entry (debits ↔ credits) and marking the - original as status='reversed'. Both entries stay in the ledger — the audit trail shows original + - reversal side by side. + Dry-run: resolve the matching handler and evaluate the transaction template without writing any + rows. Returns the matched handler + planned debit/credit lines + any validation errors. Use this + before create-event-block(apply_handlers=True) to confirm the GL plan. **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. @@ -169,16 +160,7 @@ def sync( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ReverseJournalEntryRequest): Reverse a posted journal entry. - - Creates a new entry whose line items flip the originals - (debits → credits, credits → debits), sets `reversal_of` on the new - entry to the original's id, marks the original as - `status='reversed'`, and posts the reversing entry immediately. - - This is how accountants correct posted entries — the original stays - in the audit trail, the reversal cancels its effect, and a - corrected entry can be created separately. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -200,14 +182,14 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: ReverseJournalEntryRequest, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Reverse Journal Entry + """Preview Event Block - Reverse a posted journal entry by creating a new offsetting entry (debits ↔ credits) and marking the - original as status='reversed'. Both entries stay in the ledger — the audit trail shows original + - reversal side by side. + Dry-run: resolve the matching handler and evaluate the transaction template without writing any + rows. Returns the matched handler + planned debit/credit lines + any validation errors. Use this + before create-event-block(apply_handlers=True) to confirm the GL plan. **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. @@ -215,16 +197,7 @@ async def asyncio_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ReverseJournalEntryRequest): Reverse a posted journal entry. - - Creates a new entry whose line items flip the originals - (debits → credits, credits → debits), sets `reversal_of` on the new - entry to the original's id, marks the original as - `status='reversed'`, and posts the reversing entry immediately. - - This is how accountants correct posted entries — the original stays - in the audit trail, the reversal cancels its effect, and a - corrected entry can be created separately. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -249,14 +222,14 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: ReverseJournalEntryRequest, + body: CreateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Reverse Journal Entry + """Preview Event Block - Reverse a posted journal entry by creating a new offsetting entry (debits ↔ credits) and marking the - original as status='reversed'. Both entries stay in the ledger — the audit trail shows original + - reversal side by side. + Dry-run: resolve the matching handler and evaluate the transaction template without writing any + rows. Returns the matched handler + planned debit/credit lines + any validation errors. Use this + before create-event-block(apply_handlers=True) to confirm the GL plan. **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. @@ -264,16 +237,7 @@ async def asyncio( Args: graph_id (str): idempotency_key (None | str | Unset): - body (ReverseJournalEntryRequest): Reverse a posted journal entry. - - Creates a new entry whose line items flip the originals - (debits → credits, credits → debits), sets `reversal_of` on the new - entry to the original's id, marks the original as - `status='reversed'`, and posts the reversing entry immediately. - - This is how accountants correct posted entries — the original stays - in the audit trail, the reversal cancels its effect, and a - corrected entry can be created separately. + body (CreateEventBlockRequest): Write surface for a single business event. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/extensions_robo_ledger/op_update_agent.py b/robosystems_client/api/extensions_robo_ledger/op_update_agent.py new file mode 100644 index 0000000..741cac4 --- /dev/null +++ b/robosystems_client/api/extensions_robo_ledger/op_update_agent.py @@ -0,0 +1,253 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.http_validation_error import HTTPValidationError +from ...models.operation_envelope import OperationEnvelope +from ...models.operation_error import OperationError +from ...models.update_agent_request import UpdateAgentRequest +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: UpdateAgentRequest, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/extensions/roboledger/{graph_id}/operations/update-agent".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = OperationError.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = OperationError.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = OperationError.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = cast(Any, None) + return response_429 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateAgentRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: + """Update Agent + + Patch counterparty fields. Only supplied fields are updated. Set is_active=false to deactivate + (agents are never deleted — they are reference data referenced by events and transactions). + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateAgentRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | HTTPValidationError | OperationEnvelope | OperationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateAgentRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: + """Update Agent + + Patch counterparty fields. Only supplied fields are updated. Set is_active=false to deactivate + (agents are never deleted — they are reference data referenced by events and transactions). + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateAgentRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | HTTPValidationError | OperationEnvelope | OperationError + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateAgentRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: + """Update Agent + + Patch counterparty fields. Only supplied fields are updated. Set is_active=false to deactivate + (agents are never deleted — they are reference data referenced by events and transactions). + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateAgentRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | HTTPValidationError | OperationEnvelope | OperationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateAgentRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: + """Update Agent + + Patch counterparty fields. Only supplied fields are updated. Set is_active=false to deactivate + (agents are never deleted — they are reference data referenced by events and transactions). + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateAgentRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | HTTPValidationError | OperationEnvelope | OperationError + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/extensions_robo_ledger/op_truncate_schedule.py b/robosystems_client/api/extensions_robo_ledger/op_update_event_block.py similarity index 66% rename from robosystems_client/api/extensions_robo_ledger/op_truncate_schedule.py rename to robosystems_client/api/extensions_robo_ledger/op_update_event_block.py index 146abb2..2708dac 100644 --- a/robosystems_client/api/extensions_robo_ledger/op_truncate_schedule.py +++ b/robosystems_client/api/extensions_robo_ledger/op_update_event_block.py @@ -9,14 +9,14 @@ from ...models.http_validation_error import HTTPValidationError from ...models.operation_envelope import OperationEnvelope from ...models.operation_error import OperationError -from ...models.truncate_schedule_operation import TruncateScheduleOperation +from ...models.update_event_block_request import UpdateEventBlockRequest from ...types import UNSET, Response, Unset def _get_kwargs( graph_id: str, *, - body: TruncateScheduleOperation, + body: UpdateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -25,7 +25,7 @@ def _get_kwargs( _kwargs: dict[str, Any] = { "method": "post", - "url": "/extensions/roboledger/{graph_id}/operations/truncate-schedule".format( + "url": "/extensions/roboledger/{graph_id}/operations/update-event-block".format( graph_id=quote(str(graph_id), safe=""), ), } @@ -103,14 +103,13 @@ def sync_detailed( graph_id: str, *, client: AuthenticatedClient, - body: TruncateScheduleOperation, + body: UpdateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Truncate Schedule (End Early) + """Update Event Block - End a schedule early by deleting forward facts and any stale draft closing entries past the cutoff. - Historical facts and posted entries are preserved. Use this when a business event (asset disposal, - contract cancellation) shortens the schedule's lifespan. + Apply a status transition (captured → committed | voided) and/or field corrections (description, + effective_at, metadata_patch) to an existing event block. Only supplied fields are updated. **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. @@ -118,13 +117,10 @@ def sync_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (TruncateScheduleOperation): CQRS-shaped body for `POST /operations/truncate- - schedule`. + body (UpdateEventBlockRequest): Status transitions and field corrections for an event + block. - Bundles the target schedule's `structure_id` with the update payload so - the single-body signature matches the registrar/MCP contract. The REST - handler, GraphQL resolver, and MCP tool all resolve to the same - `cmd_truncate_schedule(session, body, created_by=...)`. + All fields except event_id are optional — only supplied fields are updated. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -151,14 +147,13 @@ def sync( graph_id: str, *, client: AuthenticatedClient, - body: TruncateScheduleOperation, + body: UpdateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Truncate Schedule (End Early) + """Update Event Block - End a schedule early by deleting forward facts and any stale draft closing entries past the cutoff. - Historical facts and posted entries are preserved. Use this when a business event (asset disposal, - contract cancellation) shortens the schedule's lifespan. + Apply a status transition (captured → committed | voided) and/or field corrections (description, + effective_at, metadata_patch) to an existing event block. Only supplied fields are updated. **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. @@ -166,13 +161,10 @@ def sync( Args: graph_id (str): idempotency_key (None | str | Unset): - body (TruncateScheduleOperation): CQRS-shaped body for `POST /operations/truncate- - schedule`. + body (UpdateEventBlockRequest): Status transitions and field corrections for an event + block. - Bundles the target schedule's `structure_id` with the update payload so - the single-body signature matches the registrar/MCP contract. The REST - handler, GraphQL resolver, and MCP tool all resolve to the same - `cmd_truncate_schedule(session, body, created_by=...)`. + All fields except event_id are optional — only supplied fields are updated. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -194,14 +186,13 @@ async def asyncio_detailed( graph_id: str, *, client: AuthenticatedClient, - body: TruncateScheduleOperation, + body: UpdateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: - """Truncate Schedule (End Early) + """Update Event Block - End a schedule early by deleting forward facts and any stale draft closing entries past the cutoff. - Historical facts and posted entries are preserved. Use this when a business event (asset disposal, - contract cancellation) shortens the schedule's lifespan. + Apply a status transition (captured → committed | voided) and/or field corrections (description, + effective_at, metadata_patch) to an existing event block. Only supplied fields are updated. **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. @@ -209,13 +200,10 @@ async def asyncio_detailed( Args: graph_id (str): idempotency_key (None | str | Unset): - body (TruncateScheduleOperation): CQRS-shaped body for `POST /operations/truncate- - schedule`. + body (UpdateEventBlockRequest): Status transitions and field corrections for an event + block. - Bundles the target schedule's `structure_id` with the update payload so - the single-body signature matches the registrar/MCP contract. The REST - handler, GraphQL resolver, and MCP tool all resolve to the same - `cmd_truncate_schedule(session, body, created_by=...)`. + All fields except event_id are optional — only supplied fields are updated. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -240,14 +228,13 @@ async def asyncio( graph_id: str, *, client: AuthenticatedClient, - body: TruncateScheduleOperation, + body: UpdateEventBlockRequest, idempotency_key: None | str | Unset = UNSET, ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: - """Truncate Schedule (End Early) + """Update Event Block - End a schedule early by deleting forward facts and any stale draft closing entries past the cutoff. - Historical facts and posted entries are preserved. Use this when a business event (asset disposal, - contract cancellation) shortens the schedule's lifespan. + Apply a status transition (captured → committed | voided) and/or field corrections (description, + effective_at, metadata_patch) to an existing event block. Only supplied fields are updated. **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. @@ -255,13 +242,10 @@ async def asyncio( Args: graph_id (str): idempotency_key (None | str | Unset): - body (TruncateScheduleOperation): CQRS-shaped body for `POST /operations/truncate- - schedule`. + body (UpdateEventBlockRequest): Status transitions and field corrections for an event + block. - Bundles the target schedule's `structure_id` with the update payload so - the single-body signature matches the registrar/MCP contract. The REST - handler, GraphQL resolver, and MCP tool all resolve to the same - `cmd_truncate_schedule(session, body, created_by=...)`. + All fields except event_id are optional — only supplied fields are updated. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/extensions_robo_ledger/op_update_event_handler.py b/robosystems_client/api/extensions_robo_ledger/op_update_event_handler.py new file mode 100644 index 0000000..8ddcf29 --- /dev/null +++ b/robosystems_client/api/extensions_robo_ledger/op_update_event_handler.py @@ -0,0 +1,253 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.http_validation_error import HTTPValidationError +from ...models.operation_envelope import OperationEnvelope +from ...models.operation_error import OperationError +from ...models.update_event_handler_request import UpdateEventHandlerRequest +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: UpdateEventHandlerRequest, + idempotency_key: None | str | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(idempotency_key, Unset): + headers["Idempotency-Key"] = idempotency_key + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/extensions/roboledger/{graph_id}/operations/update-event-handler".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: + if response.status_code == 200: + response_200 = OperationEnvelope.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = OperationError.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = OperationError.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = OperationError.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = cast(Any, None) + return response_429 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateEventHandlerRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: + """Update Event Handler + + Patch an event handler's match criteria, template, priority, or active state. Pass approve=true to + approve an AI-suggested handler; approve=false to revoke approval. Only supplied fields are updated. + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateEventHandlerRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | HTTPValidationError | OperationEnvelope | OperationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateEventHandlerRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: + """Update Event Handler + + Patch an event handler's match criteria, template, priority, or active state. Pass approve=true to + approve an AI-suggested handler; approve=false to revoke approval. Only supplied fields are updated. + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateEventHandlerRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | HTTPValidationError | OperationEnvelope | OperationError + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateEventHandlerRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: + """Update Event Handler + + Patch an event handler's match criteria, template, priority, or active state. Pass approve=true to + approve an AI-suggested handler; approve=false to revoke approval. Only supplied fields are updated. + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateEventHandlerRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | HTTPValidationError | OperationEnvelope | OperationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + idempotency_key=idempotency_key, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: UpdateEventHandlerRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: + """Update Event Handler + + Patch an event handler's match criteria, template, priority, or active state. Pass approve=true to + approve an AI-suggested handler; approve=false to revoke approval. Only supplied fields are updated. + + **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. + + Args: + graph_id (str): + idempotency_key (None | str | Unset): + body (UpdateEventHandlerRequest): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | HTTPValidationError | OperationEnvelope | OperationError + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/api/extensions_robo_ledger/op_update_journal_entry.py b/robosystems_client/api/extensions_robo_ledger/op_update_journal_entry.py index 01068bf..331758f 100644 --- a/robosystems_client/api/extensions_robo_ledger/op_update_journal_entry.py +++ b/robosystems_client/api/extensions_robo_ledger/op_update_journal_entry.py @@ -108,9 +108,9 @@ def sync_detailed( ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: """Update Journal Entry - Update a draft journal entry. Posted entries are immutable and must be corrected via reverse- - journal-entry. If line_items is provided, existing line items are replaced atomically and the new - set must balance. + Update a draft journal entry. Posted entries are immutable and must be corrected via `create-event- + block(event_type='journal_entry_reversed')`. If line_items is provided, existing line items are + replaced atomically and the new set must balance. **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. @@ -157,9 +157,9 @@ def sync( ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: """Update Journal Entry - Update a draft journal entry. Posted entries are immutable and must be corrected via reverse- - journal-entry. If line_items is provided, existing line items are replaced atomically and the new - set must balance. + Update a draft journal entry. Posted entries are immutable and must be corrected via `create-event- + block(event_type='journal_entry_reversed')`. If line_items is provided, existing line items are + replaced atomically and the new set must balance. **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. @@ -201,9 +201,9 @@ async def asyncio_detailed( ) -> Response[Any | HTTPValidationError | OperationEnvelope | OperationError]: """Update Journal Entry - Update a draft journal entry. Posted entries are immutable and must be corrected via reverse- - journal-entry. If line_items is provided, existing line items are replaced atomically and the new - set must balance. + Update a draft journal entry. Posted entries are immutable and must be corrected via `create-event- + block(event_type='journal_entry_reversed')`. If line_items is provided, existing line items are + replaced atomically and the new set must balance. **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. @@ -248,9 +248,9 @@ async def asyncio( ) -> Any | HTTPValidationError | OperationEnvelope | OperationError | None: """Update Journal Entry - Update a draft journal entry. Posted entries are immutable and must be corrected via reverse- - journal-entry. If line_items is provided, existing line items are replaced atomically and the new - set must balance. + Update a draft journal entry. Posted entries are immutable and must be corrected via `create-event- + block(event_type='journal_entry_reversed')`. If line_items is provided, existing line items are + replaced atomically and the new set must balance. **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. diff --git a/robosystems_client/clients/ledger_client.py b/robosystems_client/clients/ledger_client.py index c6a7167..da301c9 100644 --- a/robosystems_client/clients/ledger_client.py +++ b/robosystems_client/clients/ledger_client.py @@ -35,11 +35,32 @@ from ..api.extensions_robo_ledger.op_close_period import ( sync_detailed as op_close_period, ) -from ..api.extensions_robo_ledger.op_create_closing_entry import ( - sync_detailed as op_create_closing_entry, +from ..api.extensions_robo_ledger.op_create_agent import ( + sync_detailed as op_create_agent, ) -from ..api.extensions_robo_ledger.op_create_manual_closing_entry import ( - sync_detailed as op_create_manual_closing_entry, +from ..api.extensions_robo_ledger.op_create_event_block import ( + sync_detailed as op_create_event_block, +) +from ..api.extensions_robo_ledger.op_create_event_handler import ( + sync_detailed as op_create_event_handler, +) +from ..api.extensions_robo_ledger.op_financial_statement_analysis import ( + sync_detailed as op_financial_statement_analysis, +) +from ..api.extensions_robo_ledger.op_live_financial_statement import ( + sync_detailed as op_live_financial_statement, +) +from ..api.extensions_robo_ledger.op_preview_event_block import ( + sync_detailed as op_preview_event_block, +) +from ..api.extensions_robo_ledger.op_update_agent import ( + sync_detailed as op_update_agent, +) +from ..api.extensions_robo_ledger.op_update_event_block import ( + sync_detailed as op_update_event_block, +) +from ..api.extensions_robo_ledger.op_update_event_handler import ( + sync_detailed as op_update_event_handler, ) from ..api.extensions_robo_ledger.op_create_mapping_association import ( sync_detailed as op_create_mapping_association, @@ -59,9 +80,6 @@ from ..api.extensions_robo_ledger.op_set_close_target import ( sync_detailed as op_set_close_target, ) -from ..api.extensions_robo_ledger.op_truncate_schedule import ( - sync_detailed as op_truncate_schedule, -) from ..api.extensions_robo_ledger.op_create_taxonomy_block import ( sync_detailed as op_create_taxonomy_block, ) @@ -71,9 +89,6 @@ from ..api.extensions_robo_ledger.op_delete_taxonomy_block import ( sync_detailed as op_delete_taxonomy_block, ) -from ..api.extensions_robo_ledger.op_dispose_schedule import ( - sync_detailed as op_dispose_schedule, -) from ..api.extensions_robo_ledger.op_evaluate_rules import ( sync_detailed as op_evaluate_rules, ) @@ -110,12 +125,6 @@ from ..api.extensions_robo_ledger.op_update_publish_list import ( sync_detailed as op_update_publish_list, ) -from ..api.extensions_robo_ledger.op_create_journal_entry import ( - sync_detailed as op_create_journal_entry, -) -from ..api.extensions_robo_ledger.op_create_transaction import ( - sync_detailed as op_create_transaction, -) from ..api.extensions_robo_ledger.op_link_entity_taxonomy import ( sync_detailed as op_link_entity_taxonomy, ) @@ -125,9 +134,6 @@ from ..api.extensions_robo_ledger.op_delete_information_block import ( sync_detailed as op_delete_information_block, ) -from ..api.extensions_robo_ledger.op_reverse_journal_entry import ( - sync_detailed as op_reverse_journal_entry, -) from ..api.extensions_robo_ledger.op_update_journal_entry import ( sync_detailed as op_update_journal_entry, ) @@ -197,27 +203,35 @@ ) from ..models.add_publish_list_members_operation import AddPublishListMembersOperation from ..models.auto_map_elements_operation import AutoMapElementsOperation -from ..models.create_journal_entry_request import CreateJournalEntryRequest -from ..models.create_transaction_request import CreateTransactionRequest +from ..models.create_agent_request import CreateAgentRequest +from ..models.create_event_block_request import CreateEventBlockRequest +from ..models.create_event_block_request_event_category import ( + CreateEventBlockRequestEventCategory, +) +from ..models.create_event_block_request_metadata import ( + CreateEventBlockRequestMetadata, +) +from ..models.create_event_handler_request import CreateEventHandlerRequest +from ..models.financial_statement_analysis_request import ( + FinancialStatementAnalysisRequest, +) +from ..models.live_financial_statement_request import LiveFinancialStatementRequest +from ..models.update_agent_request import UpdateAgentRequest +from ..models.update_event_block_request import UpdateEventBlockRequest +from ..models.update_event_handler_request import UpdateEventHandlerRequest from ..models.delete_journal_entry_request import DeleteJournalEntryRequest from ..models.delete_information_block_request import DeleteInformationBlockRequest from ..models.delete_information_block_request_payload import ( DeleteInformationBlockRequestPayload, ) from ..models.link_entity_taxonomy_request import LinkEntityTaxonomyRequest -from ..models.reverse_journal_entry_request import ReverseJournalEntryRequest from ..models.update_journal_entry_request import UpdateJournalEntryRequest from ..models.update_information_block_request import UpdateInformationBlockRequest from ..models.update_information_block_request_payload import ( UpdateInformationBlockRequestPayload, ) from ..models.close_period_operation import ClosePeriodOperation -from ..models.create_closing_entry_operation import CreateClosingEntryOperation from ..models.create_view_request import CreateViewRequest -from ..models.create_manual_closing_entry_request import CreateManualClosingEntryRequest -from ..models.create_manual_closing_entry_request_entry_type import ( - CreateManualClosingEntryRequestEntryType, -) from ..models.create_mapping_association_operation import ( CreateMappingAssociationOperation, ) @@ -229,7 +243,6 @@ DeleteMappingAssociationOperation, ) from ..models.initialize_ledger_request import InitializeLedgerRequest -from ..models.manual_line_item_request import ManualLineItemRequest from ..models.create_publish_list_request import CreatePublishListRequest from ..models.create_report_request import CreateReportRequest from ..models.delete_publish_list_operation import DeletePublishListOperation @@ -243,11 +256,9 @@ from ..models.update_publish_list_operation import UpdatePublishListOperation from ..models.reopen_period_operation import ReopenPeriodOperation from ..models.set_close_target_operation import SetCloseTargetOperation -from ..models.truncate_schedule_operation import TruncateScheduleOperation from ..models.create_taxonomy_block_request import CreateTaxonomyBlockRequest from ..models.update_taxonomy_block_request import UpdateTaxonomyBlockRequest from ..models.delete_taxonomy_block_request import DeleteTaxonomyBlockRequest -from ..models.dispose_schedule_request import DisposeScheduleRequest from ..models.evaluate_rules_request import EvaluateRulesRequest from ..models.update_entity_request import UpdateEntityRequest from ..types import UNSET @@ -341,6 +352,33 @@ def _call_op(self, label: str, response: Any) -> OperationEnvelope: envelope.result = envelope.result.to_dict() return envelope + def _build_event_block_request( + self, + *, + event_type: str, + event_category: str, + occurred_at: str, + metadata: dict[str, Any], + source: str = "native", + ) -> CreateEventBlockRequest: + """Build a ``CreateEventBlockRequest`` for one of the registered handlers. + + ``occurred_at`` accepts either a date string (``YYYY-MM-DD``) — which + is normalized to midnight UTC — or a full ISO-8601 timestamp. + """ + if "T" not in occurred_at: + occurred_dt = datetime.datetime.fromisoformat(f"{occurred_at}T00:00:00+00:00") + else: + occurred_dt = datetime.datetime.fromisoformat(occurred_at.replace("Z", "+00:00")) + return CreateEventBlockRequest( + event_type=event_type, + event_category=CreateEventBlockRequestEventCategory(event_category), + source=source, + occurred_at=occurred_dt, + apply_handlers=True, + metadata=CreateEventBlockRequestMetadata.from_dict(metadata), + ) + # ── Entity ────────────────────────────────────────────────────────── def get_entity(self, graph_id: str) -> dict[str, Any] | None: @@ -417,63 +455,6 @@ def get_account_rollups( # ── Transactions ──────────────────────────────────────────────────── - def create_transaction( - self, - graph_id: str, - *, - type: str, # noqa: A002 - date: str, - amount: int, - currency: str = "USD", - description: str | None = None, - merchant_name: str | None = None, - reference_number: str | None = None, - number: str | None = None, - category: str | None = None, - due_date: str | None = None, - status: str = "pending", - idempotency_key: str | None = None, - ) -> dict[str, Any]: - """Create a standalone business-event Transaction without entries. - - Returns a ``transaction_id`` that can be passed to - ``create_journal_entry`` to attach one or more journal entries to - this event. Useful when a single event (invoice, payment, deposit) - produces multiple entries over its lifecycle. - - ``amount`` is in minor currency units (cents). - ``type`` is free-form: invoice, payment, bill, expense, deposit, - transfer, journal_entry, etc. - """ - body_dict: dict[str, Any] = { - "type": type, - "date": date, - "amount": amount, - "currency": currency, - "status": status, - } - if description is not None: - body_dict["description"] = description - if merchant_name is not None: - body_dict["merchant_name"] = merchant_name - if reference_number is not None: - body_dict["reference_number"] = reference_number - if number is not None: - body_dict["number"] = number - if category is not None: - body_dict["category"] = category - if due_date is not None: - body_dict["due_date"] = due_date - body = CreateTransactionRequest.from_dict(body_dict) - response = op_create_transaction( - graph_id=graph_id, - body=body, - client=self._get_client(), - idempotency_key=idempotency_key if idempotency_key is not None else UNSET, - ) - envelope = self._call_op("Create transaction", response) - return envelope.result or {} - def list_transactions( self, graph_id: str, @@ -834,25 +815,6 @@ def create_schedule( envelope = self._call_op("Create schedule", response) return envelope.result or {} - def truncate_schedule( - self, - graph_id: str, - structure_id: str, - new_end_date: str, - reason: str, - ) -> dict[str, Any]: - """Truncate a schedule — end it early at `new_end_date`.""" - body = TruncateScheduleOperation( - structure_id=structure_id, - new_end_date=datetime.date.fromisoformat(new_end_date), - reason=reason, - ) - response = op_truncate_schedule( - graph_id=graph_id, body=body, client=self._get_client() - ) - envelope = self._call_op("Truncate schedule", response) - return envelope.result or {} - def dispose_schedule( self, graph_id: str, @@ -864,22 +826,31 @@ def dispose_schedule( proceeds_element_id: str | None = None, gain_loss_element_id: str | None = None, ) -> dict[str, Any]: - """Dispose of a schedule asset — post a disposal entry and delete forward facts.""" - body_dict: dict[str, Any] = { - "structure_id": structure_id, - "disposal_date": disposal_date, + """Dispose of a schedule asset — atomically truncates forward facts, + drops the SumEquals rule, and posts a balanced disposal entry. + + Routes through ``create-event-block`` with + ``event_type='asset_disposed'``. + """ + metadata: dict[str, Any] = { + "schedule_id": structure_id, "memo": memo, "reason": reason, } if sale_proceeds is not None: - body_dict["sale_proceeds"] = sale_proceeds + metadata["proceeds"] = sale_proceeds if proceeds_element_id is not None: - body_dict["proceeds_element_id"] = proceeds_element_id + metadata["proceeds_element_id"] = proceeds_element_id if gain_loss_element_id is not None: - body_dict["gain_loss_element_id"] = gain_loss_element_id - request = DisposeScheduleRequest.from_dict(body_dict) - response = op_dispose_schedule( - graph_id=graph_id, body=request, client=self._get_client() + metadata["gain_loss_element_id"] = gain_loss_element_id + body = self._build_event_block_request( + event_type="asset_disposed", + event_category="adjustment", + occurred_at=disposal_date, + metadata=metadata, + ) + response = op_create_event_block( + graph_id=graph_id, body=body, client=self._get_client() ) envelope = self._call_op("Dispose schedule", response) return envelope.result or {} @@ -963,55 +934,32 @@ def create_closing_entry( period_end: str, memo: str | None = None, ) -> dict[str, Any]: - """Idempotently create (or refresh) a draft closing entry from a schedule.""" - body = CreateClosingEntryOperation( - structure_id=structure_id, - posting_date=datetime.date.fromisoformat(posting_date), - period_start=datetime.date.fromisoformat(period_start), - period_end=datetime.date.fromisoformat(period_end), - memo=memo if memo is not None else UNSET, - ) - response = op_create_closing_entry( - graph_id=graph_id, body=body, client=self._get_client() - ) - envelope = self._call_op("Create closing entry", response) - return envelope.result or {} + """Idempotently create (or refresh) a draft closing entry from a schedule. - def create_manual_closing_entry( - self, - graph_id: str, - *, - posting_date: str, - memo: str, - line_items: list[dict[str, Any]], - entry_type: str | None = None, - ) -> dict[str, Any]: - """Create a manual balanced closing entry (not tied to a schedule).""" - items = [ - ManualLineItemRequest( - element_id=li["element_id"], - debit_amount=li.get("debit_amount", 0), - credit_amount=li.get("credit_amount", 0), - description=( - li.get("description") if li.get("description") is not None else UNSET - ), - ) - for li in line_items - ] - body = CreateManualClosingEntryRequest( - posting_date=datetime.date.fromisoformat(posting_date), - memo=memo, - line_items=items, - entry_type=( - CreateManualClosingEntryRequestEntryType(entry_type) - if entry_type is not None - else UNSET - ), - ) - response = op_create_manual_closing_entry( + Routes through ``create-event-block`` with + ``event_type='schedule_entry_due'`` — the underlying handler dispatches + one of created / unchanged / regenerated / removed / skipped internally. + Returns the EventBlockEnvelope. + """ + metadata: dict[str, Any] = { + "schedule_id": structure_id, + "posting_date": posting_date, + "period_start": period_start, + "period_end": period_end, + } + if memo is not None: + metadata["memo"] = memo + body = self._build_event_block_request( + event_type="schedule_entry_due", + event_category="recognition", + occurred_at=posting_date, + source="scheduled", + metadata=metadata, + ) + response = op_create_event_block( graph_id=graph_id, body=body, client=self._get_client() ) - envelope = self._call_op("Create manual closing entry", response) + envelope = self._call_op("Create closing entry", response) return envelope.result or {} # ── Journal entries (native accounting writes) ────────────────────── @@ -1030,6 +978,10 @@ def create_journal_entry( ) -> dict[str, Any]: """Create a journal entry with balanced line items (DR=CR enforced). + Routes through ``create-event-block`` with + ``event_type='journal_entry_recorded'`` — the Python handler forwards + to the internal journal-entry command. + Defaults to ``status='draft'`` for ongoing writes. Pass ``status='posted'`` for historical data import where entries represent already-happened business events. @@ -1037,8 +989,10 @@ def create_journal_entry( Supply ``idempotency_key`` to make the call safe to retry — replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409. + + Returns the EventBlockEnvelope (event row fields). """ - body_dict: dict[str, Any] = { + metadata: dict[str, Any] = { "posting_date": posting_date, "memo": memo, "line_items": line_items, @@ -1046,9 +1000,14 @@ def create_journal_entry( "status": status, } if transaction_id is not None: - body_dict["transaction_id"] = transaction_id - body = CreateJournalEntryRequest.from_dict(body_dict) - response = op_create_journal_entry( + metadata["transaction_id"] = transaction_id + body = self._build_event_block_request( + event_type="journal_entry_recorded", + event_category="adjustment", + occurred_at=posting_date, + metadata=metadata, + ) + response = op_create_event_block( graph_id=graph_id, body=body, client=self._get_client(), @@ -1081,21 +1040,182 @@ def reverse_journal_entry( entry_id: str, posting_date: str | None = None, memo: str | None = None, + reason: str | None = None, ) -> dict[str, Any]: - """Reverse a posted journal entry (creates offsetting entry, marks original as reversed).""" - body = ReverseJournalEntryRequest( - entry_id=entry_id, - posting_date=( - datetime.date.fromisoformat(posting_date) if posting_date else UNSET - ), - memo=memo if memo is not None else UNSET, - ) - response = op_reverse_journal_entry( + """Reverse a posted journal entry (creates offsetting entry, marks original as reversed). + + Routes through ``create-event-block`` with + ``event_type='journal_entry_reversed'``. Returns the EventBlockEnvelope. + """ + metadata: dict[str, Any] = {"entry_id": entry_id} + if posting_date is not None: + metadata["posting_date"] = posting_date + if memo is not None: + metadata["memo"] = memo + if reason is not None: + metadata["reason"] = reason + occurred_at = posting_date or datetime.date.today().isoformat() + body = self._build_event_block_request( + event_type="journal_entry_reversed", + event_category="adjustment", + occurred_at=occurred_at, + metadata=metadata, + ) + response = op_create_event_block( graph_id=graph_id, body=body, client=self._get_client() ) envelope = self._call_op("Reverse journal entry", response) return envelope.result or {} + # ── Event blocks (generic preview + status transitions) ────────────── + + def preview_event_block( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Dry-run an event block — resolve handler, evaluate metadata, return + the planned GL rows without writing anything. + + Companion to ``create_journal_entry`` / ``reverse_journal_entry`` / + ``create_closing_entry`` / ``dispose_schedule``: pass the same body + those methods would build (a ``CreateEventBlockRequest`` shape) and + inspect what the handler would do. + """ + request = CreateEventBlockRequest.from_dict(body) + response = op_preview_event_block( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Preview event block", response) + return envelope.result or {} + + def update_event_block( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Apply a status transition and/or field corrections to an event block. + + Use for posting drafts (``classified`` → ``committed`` → ``fulfilled``), + voiding, superseding (correction chains), or patching ``description``, + ``effective_at``, or ``metadata``. + """ + request = UpdateEventBlockRequest.from_dict(body) + response = op_update_event_block( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Update event block", response) + return envelope.result or {} + + # ── Agents (REA counterparties) ─────────────────────────────────────── + + def create_agent( + self, + graph_id: str, + body: dict[str, Any], + idempotency_key: str | None = None, + ) -> dict[str, Any]: + """Create an agent — REA counterparty (customer, vendor, employee, etc.) + referenced by event blocks via ``agent_id``. + + ``(source, external_id)`` is unique when ``external_id`` is provided, + so external-source ingestion is idempotent at the DB level. + """ + request = CreateAgentRequest.from_dict(body) + response = op_create_agent( + graph_id=graph_id, + body=request, + client=self._get_client(), + idempotency_key=idempotency_key if idempotency_key is not None else UNSET, + ) + envelope = self._call_op("Create agent", response) + return envelope.result or {} + + def update_agent( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Update an agent. ``metadata_patch`` is a partial merge into existing + metadata; all other fields replace. + """ + request = UpdateAgentRequest.from_dict(body) + response = op_update_agent( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Update agent", response) + return envelope.result or {} + + # ── Event handlers (DSL handler registry) ──────────────────────────── + + def create_event_handler( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Register a tenant-configurable event handler — DSL row in the + ``event_handlers`` table that drives ``create-event-block`` for event + types not covered by a Python handler. + """ + request = CreateEventHandlerRequest.from_dict(body) + response = op_create_event_handler( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Create event handler", response) + return envelope.result or {} + + def update_event_handler( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Update a registered event handler. Pass ``approve=True`` in the body + to flip an AI-suggested handler from unapproved to active. + """ + request = UpdateEventHandlerRequest.from_dict(body) + response = op_update_event_handler( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Update event handler", response) + return envelope.result or {} + + # ── Financial statements (graph-backed) ────────────────────────────── + + def live_financial_statement( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Live financial statement — pulls facts directly from the graph for + an explicit period window (or fiscal year) and returns the statement + shape without a persisted Report row. Useful for ad-hoc previews and + dashboards. + """ + request = LiveFinancialStatementRequest.from_dict(body) + response = op_live_financial_statement( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Live financial statement", response) + return envelope.result or {} + + def financial_statement_analysis( + self, + graph_id: str, + body: dict[str, Any], + ) -> dict[str, Any]: + """Run a financial statement analysis against an existing report. + + On shared-repo graphs (e.g. SEC), ``ticker`` is required; on tenant + graphs it's ignored. Either pass an explicit ``report_id`` or let the + server auto-resolve via ``fiscal_year`` + ``period_type``. + """ + request = FinancialStatementAnalysisRequest.from_dict(body) + response = op_financial_statement_analysis( + graph_id=graph_id, body=request, client=self._get_client() + ) + envelope = self._call_op("Financial statement analysis", response) + return envelope.result or {} + # ── Fact grid (graph-backed analytical query) ───────────────────── def build_fact_grid(self, graph_id: str, request: dict[str, Any]) -> dict[str, Any]: diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 0f3f6f3..6ccf497 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -57,25 +57,34 @@ from .connection_response_metadata import ConnectionResponseMetadata from .content_limits import ContentLimits from .copy_operation_limits import CopyOperationLimits +from .create_agent_request import CreateAgentRequest +from .create_agent_request_address_type_0 import CreateAgentRequestAddressType0 +from .create_agent_request_metadata import CreateAgentRequestMetadata from .create_api_key_request import CreateAPIKeyRequest from .create_api_key_response import CreateAPIKeyResponse from .create_checkout_request import CreateCheckoutRequest from .create_checkout_request_resource_config import CreateCheckoutRequestResourceConfig -from .create_closing_entry_operation import CreateClosingEntryOperation from .create_connection_request import CreateConnectionRequest from .create_connection_request_provider import CreateConnectionRequestProvider +from .create_event_block_request import CreateEventBlockRequest +from .create_event_block_request_event_category import ( + CreateEventBlockRequestEventCategory, +) +from .create_event_block_request_metadata import CreateEventBlockRequestMetadata +from .create_event_block_request_resource_type_type_0 import ( + CreateEventBlockRequestResourceTypeType0, +) +from .create_event_handler_request import CreateEventHandlerRequest +from .create_event_handler_request_match_metadata_expression_type_0 import ( + CreateEventHandlerRequestMatchMetadataExpressionType0, +) +from .create_event_handler_request_metadata import CreateEventHandlerRequestMetadata +from .create_event_handler_request_origin import CreateEventHandlerRequestOrigin from .create_graph_request import CreateGraphRequest from .create_information_block_request import CreateInformationBlockRequest from .create_information_block_request_payload import ( CreateInformationBlockRequestPayload, ) -from .create_journal_entry_request import CreateJournalEntryRequest -from .create_journal_entry_request_status import CreateJournalEntryRequestStatus -from .create_journal_entry_request_type import CreateJournalEntryRequestType -from .create_manual_closing_entry_request import CreateManualClosingEntryRequest -from .create_manual_closing_entry_request_entry_type import ( - CreateManualClosingEntryRequestEntryType, -) from .create_mapping_association_operation import CreateMappingAssociationOperation from .create_mapping_association_operation_association_type import ( CreateMappingAssociationOperationAssociationType, @@ -94,8 +103,6 @@ from .create_taxonomy_block_request_taxonomy_type import ( CreateTaxonomyBlockRequestTaxonomyType, ) -from .create_transaction_request import CreateTransactionRequest -from .create_transaction_request_status import CreateTransactionRequestStatus from .create_view_request import CreateViewRequest from .credit_limits import CreditLimits from .credit_summary import CreditSummary @@ -131,7 +138,6 @@ DetailedTransactionsResponseDateRange, ) from .detailed_transactions_response_summary import DetailedTransactionsResponseSummary -from .dispose_schedule_request import DisposeScheduleRequest from .document_detail_response import DocumentDetailResponse from .document_list_item import DocumentListItem from .document_list_response import DocumentListResponse @@ -208,7 +214,6 @@ from .live_financial_statement_request import LiveFinancialStatementRequest from .login_request import LoginRequest from .logout_user_response_logoutuser import LogoutUserResponseLogoutuser -from .manual_line_item_request import ManualLineItemRequest from .materialize_op import MaterializeOp from .mcp_tool_call import MCPToolCall from .mcp_tool_call_arguments import MCPToolCallArguments @@ -275,7 +280,6 @@ from .reset_password_validate_response import ResetPasswordValidateResponse from .response_mode import ResponseMode from .restore_backup_op import RestoreBackupOp -from .reverse_journal_entry_request import ReverseJournalEntryRequest from .schema_export_response import SchemaExportResponse from .schema_export_response_data_stats_type_0 import SchemaExportResponseDataStatsType0 from .schema_export_response_schema_definition_type_0 import ( @@ -355,10 +359,30 @@ from .tier_capacity import TierCapacity from .token_pricing import TokenPricing from .transaction_summary_response import TransactionSummaryResponse -from .truncate_schedule_operation import TruncateScheduleOperation +from .transaction_template import TransactionTemplate +from .transaction_template_entry import TransactionTemplateEntry +from .transaction_template_item import TransactionTemplateItem +from .transaction_template_leg import TransactionTemplateLeg from .upcoming_invoice import UpcomingInvoice +from .update_agent_request import UpdateAgentRequest +from .update_agent_request_address_type_0 import UpdateAgentRequestAddressType0 +from .update_agent_request_metadata_patch import UpdateAgentRequestMetadataPatch from .update_api_key_request import UpdateAPIKeyRequest from .update_entity_request import UpdateEntityRequest +from .update_event_block_request import UpdateEventBlockRequest +from .update_event_block_request_metadata_patch import ( + UpdateEventBlockRequestMetadataPatch, +) +from .update_event_block_request_transition_to_type_0 import ( + UpdateEventBlockRequestTransitionToType0, +) +from .update_event_handler_request import UpdateEventHandlerRequest +from .update_event_handler_request_match_metadata_expression_type_0 import ( + UpdateEventHandlerRequestMatchMetadataExpressionType0, +) +from .update_event_handler_request_metadata_patch import ( + UpdateEventHandlerRequestMetadataPatch, +) from .update_file_response_updatefile import UpdateFileResponseUpdatefile from .update_information_block_request import UpdateInformationBlockRequest from .update_information_block_request_payload import ( @@ -438,21 +462,26 @@ "ConnectionResponseMetadata", "ContentLimits", "CopyOperationLimits", + "CreateAgentRequest", + "CreateAgentRequestAddressType0", + "CreateAgentRequestMetadata", "CreateAPIKeyRequest", "CreateAPIKeyResponse", "CreateCheckoutRequest", "CreateCheckoutRequestResourceConfig", - "CreateClosingEntryOperation", "CreateConnectionRequest", "CreateConnectionRequestProvider", + "CreateEventBlockRequest", + "CreateEventBlockRequestEventCategory", + "CreateEventBlockRequestMetadata", + "CreateEventBlockRequestResourceTypeType0", + "CreateEventHandlerRequest", + "CreateEventHandlerRequestMatchMetadataExpressionType0", + "CreateEventHandlerRequestMetadata", + "CreateEventHandlerRequestOrigin", "CreateGraphRequest", "CreateInformationBlockRequest", "CreateInformationBlockRequestPayload", - "CreateJournalEntryRequest", - "CreateJournalEntryRequestStatus", - "CreateJournalEntryRequestType", - "CreateManualClosingEntryRequest", - "CreateManualClosingEntryRequestEntryType", "CreateMappingAssociationOperation", "CreateMappingAssociationOperationAssociationType", "CreatePortfolioRequest", @@ -467,8 +496,6 @@ "CreateTaxonomyBlockRequest", "CreateTaxonomyBlockRequestMetadata", "CreateTaxonomyBlockRequestTaxonomyType", - "CreateTransactionRequest", - "CreateTransactionRequestStatus", "CreateViewRequest", "CreditLimits", "CreditSummary", @@ -498,7 +525,6 @@ "DetailedTransactionsResponse", "DetailedTransactionsResponseDateRange", "DetailedTransactionsResponseSummary", - "DisposeScheduleRequest", "DocumentDetailResponse", "DocumentListItem", "DocumentListResponse", @@ -565,7 +591,6 @@ "LiveFinancialStatementRequest", "LoginRequest", "LogoutUserResponseLogoutuser", - "ManualLineItemRequest", "MaterializeOp", "MCPToolCall", "MCPToolCallArguments", @@ -626,7 +651,6 @@ "ResetPasswordValidateResponse", "ResponseMode", "RestoreBackupOp", - "ReverseJournalEntryRequest", "SchemaExportResponse", "SchemaExportResponseDataStatsType0", "SchemaExportResponseSchemaDefinitionType0", @@ -684,10 +708,22 @@ "TierCapacity", "TokenPricing", "TransactionSummaryResponse", - "TruncateScheduleOperation", + "TransactionTemplate", + "TransactionTemplateEntry", + "TransactionTemplateItem", + "TransactionTemplateLeg", "UpcomingInvoice", + "UpdateAgentRequest", + "UpdateAgentRequestAddressType0", + "UpdateAgentRequestMetadataPatch", "UpdateAPIKeyRequest", "UpdateEntityRequest", + "UpdateEventBlockRequest", + "UpdateEventBlockRequestMetadataPatch", + "UpdateEventBlockRequestTransitionToType0", + "UpdateEventHandlerRequest", + "UpdateEventHandlerRequestMatchMetadataExpressionType0", + "UpdateEventHandlerRequestMetadataPatch", "UpdateFileResponseUpdatefile", "UpdateInformationBlockRequest", "UpdateInformationBlockRequestPayload", diff --git a/robosystems_client/models/create_agent_request.py b/robosystems_client/models/create_agent_request.py new file mode 100644 index 0000000..7392ff8 --- /dev/null +++ b/robosystems_client/models/create_agent_request.py @@ -0,0 +1,323 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_agent_request_address_type_0 import ( + CreateAgentRequestAddressType0, + ) + from ..models.create_agent_request_metadata import CreateAgentRequestMetadata + + +T = TypeVar("T", bound="CreateAgentRequest") + + +@_attrs_define +class CreateAgentRequest: + """ + Attributes: + agent_type (str): 'customer' | 'vendor' | 'employee' | 'owner' | 'supplier' | 'government' | 'lender' | 'self' | + 'other' + name (str): + legal_name (None | str | Unset): + tax_id (None | str | Unset): + registration_number (None | str | Unset): + duns (None | str | Unset): + lei (None | str | Unset): + email (None | str | Unset): + phone (None | str | Unset): + address (CreateAgentRequestAddressType0 | None | Unset): + source (str | Unset): 'quickbooks' | 'xero' | 'plaid' | 'native' Default: 'native'. + external_id (None | str | Unset): + is_active (bool | Unset): Default: True. + is_1099_recipient (bool | Unset): Default: False. + metadata (CreateAgentRequestMetadata | Unset): + """ + + agent_type: str + name: str + legal_name: None | str | Unset = UNSET + tax_id: None | str | Unset = UNSET + registration_number: None | str | Unset = UNSET + duns: None | str | Unset = UNSET + lei: None | str | Unset = UNSET + email: None | str | Unset = UNSET + phone: None | str | Unset = UNSET + address: CreateAgentRequestAddressType0 | None | Unset = UNSET + source: str | Unset = "native" + external_id: None | str | Unset = UNSET + is_active: bool | Unset = True + is_1099_recipient: bool | Unset = False + metadata: CreateAgentRequestMetadata | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.create_agent_request_address_type_0 import ( + CreateAgentRequestAddressType0, + ) + + agent_type = self.agent_type + + name = self.name + + legal_name: None | str | Unset + if isinstance(self.legal_name, Unset): + legal_name = UNSET + else: + legal_name = self.legal_name + + tax_id: None | str | Unset + if isinstance(self.tax_id, Unset): + tax_id = UNSET + else: + tax_id = self.tax_id + + registration_number: None | str | Unset + if isinstance(self.registration_number, Unset): + registration_number = UNSET + else: + registration_number = self.registration_number + + duns: None | str | Unset + if isinstance(self.duns, Unset): + duns = UNSET + else: + duns = self.duns + + lei: None | str | Unset + if isinstance(self.lei, Unset): + lei = UNSET + else: + lei = self.lei + + email: None | str | Unset + if isinstance(self.email, Unset): + email = UNSET + else: + email = self.email + + phone: None | str | Unset + if isinstance(self.phone, Unset): + phone = UNSET + else: + phone = self.phone + + address: dict[str, Any] | None | Unset + if isinstance(self.address, Unset): + address = UNSET + elif isinstance(self.address, CreateAgentRequestAddressType0): + address = self.address.to_dict() + else: + address = self.address + + source = self.source + + external_id: None | str | Unset + if isinstance(self.external_id, Unset): + external_id = UNSET + else: + external_id = self.external_id + + is_active = self.is_active + + is_1099_recipient = self.is_1099_recipient + + metadata: dict[str, Any] | Unset = UNSET + if not isinstance(self.metadata, Unset): + metadata = self.metadata.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "agent_type": agent_type, + "name": name, + } + ) + if legal_name is not UNSET: + field_dict["legal_name"] = legal_name + if tax_id is not UNSET: + field_dict["tax_id"] = tax_id + if registration_number is not UNSET: + field_dict["registration_number"] = registration_number + if duns is not UNSET: + field_dict["duns"] = duns + if lei is not UNSET: + field_dict["lei"] = lei + if email is not UNSET: + field_dict["email"] = email + if phone is not UNSET: + field_dict["phone"] = phone + if address is not UNSET: + field_dict["address"] = address + if source is not UNSET: + field_dict["source"] = source + if external_id is not UNSET: + field_dict["external_id"] = external_id + if is_active is not UNSET: + field_dict["is_active"] = is_active + if is_1099_recipient is not UNSET: + field_dict["is_1099_recipient"] = is_1099_recipient + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.create_agent_request_address_type_0 import ( + CreateAgentRequestAddressType0, + ) + from ..models.create_agent_request_metadata import CreateAgentRequestMetadata + + d = dict(src_dict) + agent_type = d.pop("agent_type") + + name = d.pop("name") + + def _parse_legal_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + legal_name = _parse_legal_name(d.pop("legal_name", UNSET)) + + def _parse_tax_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + tax_id = _parse_tax_id(d.pop("tax_id", UNSET)) + + def _parse_registration_number(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + registration_number = _parse_registration_number( + d.pop("registration_number", UNSET) + ) + + def _parse_duns(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + duns = _parse_duns(d.pop("duns", UNSET)) + + def _parse_lei(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + lei = _parse_lei(d.pop("lei", UNSET)) + + def _parse_email(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + email = _parse_email(d.pop("email", UNSET)) + + def _parse_phone(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + phone = _parse_phone(d.pop("phone", UNSET)) + + def _parse_address(data: object) -> CreateAgentRequestAddressType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + address_type_0 = CreateAgentRequestAddressType0.from_dict(data) + + return address_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(CreateAgentRequestAddressType0 | None | Unset, data) + + address = _parse_address(d.pop("address", UNSET)) + + source = d.pop("source", UNSET) + + def _parse_external_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + external_id = _parse_external_id(d.pop("external_id", UNSET)) + + is_active = d.pop("is_active", UNSET) + + is_1099_recipient = d.pop("is_1099_recipient", UNSET) + + _metadata = d.pop("metadata", UNSET) + metadata: CreateAgentRequestMetadata | Unset + if isinstance(_metadata, Unset): + metadata = UNSET + else: + metadata = CreateAgentRequestMetadata.from_dict(_metadata) + + create_agent_request = cls( + agent_type=agent_type, + name=name, + legal_name=legal_name, + tax_id=tax_id, + registration_number=registration_number, + duns=duns, + lei=lei, + email=email, + phone=phone, + address=address, + source=source, + external_id=external_id, + is_active=is_active, + is_1099_recipient=is_1099_recipient, + metadata=metadata, + ) + + create_agent_request.additional_properties = d + return create_agent_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_agent_request_address_type_0.py b/robosystems_client/models/create_agent_request_address_type_0.py new file mode 100644 index 0000000..c9f6020 --- /dev/null +++ b/robosystems_client/models/create_agent_request_address_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CreateAgentRequestAddressType0") + + +@_attrs_define +class CreateAgentRequestAddressType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + create_agent_request_address_type_0 = cls() + + create_agent_request_address_type_0.additional_properties = d + return create_agent_request_address_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_agent_request_metadata.py b/robosystems_client/models/create_agent_request_metadata.py new file mode 100644 index 0000000..e95576d --- /dev/null +++ b/robosystems_client/models/create_agent_request_metadata.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CreateAgentRequestMetadata") + + +@_attrs_define +class CreateAgentRequestMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + create_agent_request_metadata = cls() + + create_agent_request_metadata.additional_properties = d + return create_agent_request_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_closing_entry_operation.py b/robosystems_client/models/create_closing_entry_operation.py deleted file mode 100644 index e0d5291..0000000 --- a/robosystems_client/models/create_closing_entry_operation.py +++ /dev/null @@ -1,113 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateClosingEntryOperation") - - -@_attrs_define -class CreateClosingEntryOperation: - """CQRS-shaped body for `POST /operations/create-closing-entry`. - - `structure_id` moves into the body so REST + MCP share a single body - type via the registrar. - - Attributes: - posting_date (datetime.date): Posting date for the entry - period_start (datetime.date): Period start - period_end (datetime.date): Period end - structure_id (str): Schedule structure the closing entry is derived from. - memo (None | str | Unset): Override memo - """ - - posting_date: datetime.date - period_start: datetime.date - period_end: datetime.date - structure_id: str - memo: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - posting_date = self.posting_date.isoformat() - - period_start = self.period_start.isoformat() - - period_end = self.period_end.isoformat() - - structure_id = self.structure_id - - memo: None | str | Unset - if isinstance(self.memo, Unset): - memo = UNSET - else: - memo = self.memo - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "posting_date": posting_date, - "period_start": period_start, - "period_end": period_end, - "structure_id": structure_id, - } - ) - if memo is not UNSET: - field_dict["memo"] = memo - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - posting_date = isoparse(d.pop("posting_date")).date() - - period_start = isoparse(d.pop("period_start")).date() - - period_end = isoparse(d.pop("period_end")).date() - - structure_id = d.pop("structure_id") - - def _parse_memo(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - memo = _parse_memo(d.pop("memo", UNSET)) - - create_closing_entry_operation = cls( - posting_date=posting_date, - period_start=period_start, - period_end=period_end, - structure_id=structure_id, - memo=memo, - ) - - create_closing_entry_operation.additional_properties = d - return create_closing_entry_operation - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/create_event_block_request.py b/robosystems_client/models/create_event_block_request.py new file mode 100644 index 0000000..501e0ff --- /dev/null +++ b/robosystems_client/models/create_event_block_request.py @@ -0,0 +1,339 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..models.create_event_block_request_event_category import ( + CreateEventBlockRequestEventCategory, +) +from ..models.create_event_block_request_resource_type_type_0 import ( + CreateEventBlockRequestResourceTypeType0, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_event_block_request_metadata import ( + CreateEventBlockRequestMetadata, + ) + + +T = TypeVar("T", bound="CreateEventBlockRequest") + + +@_attrs_define +class CreateEventBlockRequest: + """Write surface for a single business event. + + Attributes: + event_type (str): Open vocabulary: 'invoice_issued' | 'contract_signed' | 'bank_transaction' | ... + event_category (CreateEventBlockRequestEventCategory): REA economic classification. One of: sales, purchase, + financing, payroll, treasury, adjustment, recognition, other. + occurred_at (datetime.datetime): When the event happened in the real world + source (str): 'quickbooks' | 'xero' | 'plaid' | 'native' | 'scheduled' | ... + agent_id (None | str | Unset): Counterparty agent id + resource_type (CreateEventBlockRequestResourceTypeType0 | None | Unset): REA resource kind. One of: goods, + services, money, right, obligation, information, labor. + resource_element_id (None | str | Unset): Specific element being exchanged, if applicable + effective_at (datetime.datetime | None | Unset): Accounting recognition date, if different from occurred_at + external_id (None | str | Unset): Source-system dedup key. (source, external_id) is enforced unique when + external_id is provided, so retries from external adapters are idempotent at the DB level. + external_url (None | str | Unset): Deep link back to source-system record + amount (int | None | Unset): Cents, signed + currency (str | Unset): ISO 4217 currency code Default: 'USD'. + description (None | str | Unset): + metadata (CreateEventBlockRequestMetadata | Unset): Event-type-specific payload + dimension_ids (list[str] | Unset): + apply_handlers (bool | Unset): When True, resolves the event_type to a handler (Python registry first, then DSL) + and fires it atomically with event creation. Default: False. + """ + + event_type: str + event_category: CreateEventBlockRequestEventCategory + occurred_at: datetime.datetime + source: str + agent_id: None | str | Unset = UNSET + resource_type: CreateEventBlockRequestResourceTypeType0 | None | Unset = UNSET + resource_element_id: None | str | Unset = UNSET + effective_at: datetime.datetime | None | Unset = UNSET + external_id: None | str | Unset = UNSET + external_url: None | str | Unset = UNSET + amount: int | None | Unset = UNSET + currency: str | Unset = "USD" + description: None | str | Unset = UNSET + metadata: CreateEventBlockRequestMetadata | Unset = UNSET + dimension_ids: list[str] | Unset = UNSET + apply_handlers: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + event_type = self.event_type + + event_category = self.event_category.value + + occurred_at = self.occurred_at.isoformat() + + source = self.source + + agent_id: None | str | Unset + if isinstance(self.agent_id, Unset): + agent_id = UNSET + else: + agent_id = self.agent_id + + resource_type: None | str | Unset + if isinstance(self.resource_type, Unset): + resource_type = UNSET + elif isinstance(self.resource_type, CreateEventBlockRequestResourceTypeType0): + resource_type = self.resource_type.value + else: + resource_type = self.resource_type + + resource_element_id: None | str | Unset + if isinstance(self.resource_element_id, Unset): + resource_element_id = UNSET + else: + resource_element_id = self.resource_element_id + + effective_at: None | str | Unset + if isinstance(self.effective_at, Unset): + effective_at = UNSET + elif isinstance(self.effective_at, datetime.datetime): + effective_at = self.effective_at.isoformat() + else: + effective_at = self.effective_at + + external_id: None | str | Unset + if isinstance(self.external_id, Unset): + external_id = UNSET + else: + external_id = self.external_id + + external_url: None | str | Unset + if isinstance(self.external_url, Unset): + external_url = UNSET + else: + external_url = self.external_url + + amount: int | None | Unset + if isinstance(self.amount, Unset): + amount = UNSET + else: + amount = self.amount + + currency = self.currency + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + metadata: dict[str, Any] | Unset = UNSET + if not isinstance(self.metadata, Unset): + metadata = self.metadata.to_dict() + + dimension_ids: list[str] | Unset = UNSET + if not isinstance(self.dimension_ids, Unset): + dimension_ids = self.dimension_ids + + apply_handlers = self.apply_handlers + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "event_type": event_type, + "event_category": event_category, + "occurred_at": occurred_at, + "source": source, + } + ) + if agent_id is not UNSET: + field_dict["agent_id"] = agent_id + if resource_type is not UNSET: + field_dict["resource_type"] = resource_type + if resource_element_id is not UNSET: + field_dict["resource_element_id"] = resource_element_id + if effective_at is not UNSET: + field_dict["effective_at"] = effective_at + if external_id is not UNSET: + field_dict["external_id"] = external_id + if external_url is not UNSET: + field_dict["external_url"] = external_url + if amount is not UNSET: + field_dict["amount"] = amount + if currency is not UNSET: + field_dict["currency"] = currency + if description is not UNSET: + field_dict["description"] = description + if metadata is not UNSET: + field_dict["metadata"] = metadata + if dimension_ids is not UNSET: + field_dict["dimension_ids"] = dimension_ids + if apply_handlers is not UNSET: + field_dict["apply_handlers"] = apply_handlers + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.create_event_block_request_metadata import ( + CreateEventBlockRequestMetadata, + ) + + d = dict(src_dict) + event_type = d.pop("event_type") + + event_category = CreateEventBlockRequestEventCategory(d.pop("event_category")) + + occurred_at = isoparse(d.pop("occurred_at")) + + source = d.pop("source") + + def _parse_agent_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + agent_id = _parse_agent_id(d.pop("agent_id", UNSET)) + + def _parse_resource_type( + data: object, + ) -> CreateEventBlockRequestResourceTypeType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + resource_type_type_0 = CreateEventBlockRequestResourceTypeType0(data) + + return resource_type_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(CreateEventBlockRequestResourceTypeType0 | None | Unset, data) + + resource_type = _parse_resource_type(d.pop("resource_type", UNSET)) + + def _parse_resource_element_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + resource_element_id = _parse_resource_element_id( + d.pop("resource_element_id", UNSET) + ) + + def _parse_effective_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + effective_at_type_0 = isoparse(data) + + return effective_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + effective_at = _parse_effective_at(d.pop("effective_at", UNSET)) + + def _parse_external_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + external_id = _parse_external_id(d.pop("external_id", UNSET)) + + def _parse_external_url(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + external_url = _parse_external_url(d.pop("external_url", UNSET)) + + def _parse_amount(data: object) -> int | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(int | None | Unset, data) + + amount = _parse_amount(d.pop("amount", UNSET)) + + currency = d.pop("currency", UNSET) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + _metadata = d.pop("metadata", UNSET) + metadata: CreateEventBlockRequestMetadata | Unset + if isinstance(_metadata, Unset): + metadata = UNSET + else: + metadata = CreateEventBlockRequestMetadata.from_dict(_metadata) + + dimension_ids = cast(list[str], d.pop("dimension_ids", UNSET)) + + apply_handlers = d.pop("apply_handlers", UNSET) + + create_event_block_request = cls( + event_type=event_type, + event_category=event_category, + occurred_at=occurred_at, + source=source, + agent_id=agent_id, + resource_type=resource_type, + resource_element_id=resource_element_id, + effective_at=effective_at, + external_id=external_id, + external_url=external_url, + amount=amount, + currency=currency, + description=description, + metadata=metadata, + dimension_ids=dimension_ids, + apply_handlers=apply_handlers, + ) + + create_event_block_request.additional_properties = d + return create_event_block_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_event_block_request_event_category.py b/robosystems_client/models/create_event_block_request_event_category.py new file mode 100644 index 0000000..ee3b04d --- /dev/null +++ b/robosystems_client/models/create_event_block_request_event_category.py @@ -0,0 +1,15 @@ +from enum import Enum + + +class CreateEventBlockRequestEventCategory(str, Enum): + ADJUSTMENT = "adjustment" + FINANCING = "financing" + OTHER = "other" + PAYROLL = "payroll" + PURCHASE = "purchase" + RECOGNITION = "recognition" + SALES = "sales" + TREASURY = "treasury" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/create_event_block_request_metadata.py b/robosystems_client/models/create_event_block_request_metadata.py new file mode 100644 index 0000000..001dd2e --- /dev/null +++ b/robosystems_client/models/create_event_block_request_metadata.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CreateEventBlockRequestMetadata") + + +@_attrs_define +class CreateEventBlockRequestMetadata: + """Event-type-specific payload""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + create_event_block_request_metadata = cls() + + create_event_block_request_metadata.additional_properties = d + return create_event_block_request_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_event_block_request_resource_type_type_0.py b/robosystems_client/models/create_event_block_request_resource_type_type_0.py new file mode 100644 index 0000000..ed17a93 --- /dev/null +++ b/robosystems_client/models/create_event_block_request_resource_type_type_0.py @@ -0,0 +1,14 @@ +from enum import Enum + + +class CreateEventBlockRequestResourceTypeType0(str, Enum): + GOODS = "goods" + INFORMATION = "information" + LABOR = "labor" + MONEY = "money" + OBLIGATION = "obligation" + RIGHT = "right" + SERVICES = "services" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/create_event_handler_request.py b/robosystems_client/models/create_event_handler_request.py new file mode 100644 index 0000000..66e876c --- /dev/null +++ b/robosystems_client/models/create_event_handler_request.py @@ -0,0 +1,311 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_event_handler_request_origin import CreateEventHandlerRequestOrigin +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_event_handler_request_match_metadata_expression_type_0 import ( + CreateEventHandlerRequestMatchMetadataExpressionType0, + ) + from ..models.create_event_handler_request_metadata import ( + CreateEventHandlerRequestMetadata, + ) + from ..models.transaction_template import TransactionTemplate + + +T = TypeVar("T", bound="CreateEventHandlerRequest") + + +@_attrs_define +class CreateEventHandlerRequest: + """ + Attributes: + name (str): + event_type (str): + transaction_template (TransactionTemplate): The handler's output spec — one or more balanced entries to post. + + Wire shape:: + + { + "transactions": [{ + "entry_template": { + "debit": {"element_id": "elem_...", "amount": "{{ event.amount }}"}, + "credit": {"element_id": "elem_...", "amount": "{{ event.amount }}"} + } + }] + } + description (None | str | Unset): + event_category (None | str | Unset): + match_source (None | str | Unset): + match_agent_type (None | str | Unset): + match_resource_type (None | str | Unset): + match_metadata_expression (CreateEventHandlerRequestMatchMetadataExpressionType0 | None | Unset): JSONPath-style + equality map, e.g. {"metadata.category": "payroll"} + priority (int | Unset): Default: 0. + is_active (bool | Unset): Default: True. + origin (CreateEventHandlerRequestOrigin | Unset): Default: CreateEventHandlerRequestOrigin.TENANT. + metadata (CreateEventHandlerRequestMetadata | Unset): + """ + + name: str + event_type: str + transaction_template: TransactionTemplate + description: None | str | Unset = UNSET + event_category: None | str | Unset = UNSET + match_source: None | str | Unset = UNSET + match_agent_type: None | str | Unset = UNSET + match_resource_type: None | str | Unset = UNSET + match_metadata_expression: ( + CreateEventHandlerRequestMatchMetadataExpressionType0 | None | Unset + ) = UNSET + priority: int | Unset = 0 + is_active: bool | Unset = True + origin: CreateEventHandlerRequestOrigin | Unset = ( + CreateEventHandlerRequestOrigin.TENANT + ) + metadata: CreateEventHandlerRequestMetadata | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.create_event_handler_request_match_metadata_expression_type_0 import ( + CreateEventHandlerRequestMatchMetadataExpressionType0, + ) + + name = self.name + + event_type = self.event_type + + transaction_template = self.transaction_template.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + event_category: None | str | Unset + if isinstance(self.event_category, Unset): + event_category = UNSET + else: + event_category = self.event_category + + match_source: None | str | Unset + if isinstance(self.match_source, Unset): + match_source = UNSET + else: + match_source = self.match_source + + match_agent_type: None | str | Unset + if isinstance(self.match_agent_type, Unset): + match_agent_type = UNSET + else: + match_agent_type = self.match_agent_type + + match_resource_type: None | str | Unset + if isinstance(self.match_resource_type, Unset): + match_resource_type = UNSET + else: + match_resource_type = self.match_resource_type + + match_metadata_expression: dict[str, Any] | None | Unset + if isinstance(self.match_metadata_expression, Unset): + match_metadata_expression = UNSET + elif isinstance( + self.match_metadata_expression, + CreateEventHandlerRequestMatchMetadataExpressionType0, + ): + match_metadata_expression = self.match_metadata_expression.to_dict() + else: + match_metadata_expression = self.match_metadata_expression + + priority = self.priority + + is_active = self.is_active + + origin: str | Unset = UNSET + if not isinstance(self.origin, Unset): + origin = self.origin.value + + metadata: dict[str, Any] | Unset = UNSET + if not isinstance(self.metadata, Unset): + metadata = self.metadata.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "event_type": event_type, + "transaction_template": transaction_template, + } + ) + if description is not UNSET: + field_dict["description"] = description + if event_category is not UNSET: + field_dict["event_category"] = event_category + if match_source is not UNSET: + field_dict["match_source"] = match_source + if match_agent_type is not UNSET: + field_dict["match_agent_type"] = match_agent_type + if match_resource_type is not UNSET: + field_dict["match_resource_type"] = match_resource_type + if match_metadata_expression is not UNSET: + field_dict["match_metadata_expression"] = match_metadata_expression + if priority is not UNSET: + field_dict["priority"] = priority + if is_active is not UNSET: + field_dict["is_active"] = is_active + if origin is not UNSET: + field_dict["origin"] = origin + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.create_event_handler_request_match_metadata_expression_type_0 import ( + CreateEventHandlerRequestMatchMetadataExpressionType0, + ) + from ..models.create_event_handler_request_metadata import ( + CreateEventHandlerRequestMetadata, + ) + from ..models.transaction_template import TransactionTemplate + + d = dict(src_dict) + name = d.pop("name") + + event_type = d.pop("event_type") + + transaction_template = TransactionTemplate.from_dict(d.pop("transaction_template")) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + def _parse_event_category(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + event_category = _parse_event_category(d.pop("event_category", UNSET)) + + def _parse_match_source(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + match_source = _parse_match_source(d.pop("match_source", UNSET)) + + def _parse_match_agent_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + match_agent_type = _parse_match_agent_type(d.pop("match_agent_type", UNSET)) + + def _parse_match_resource_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + match_resource_type = _parse_match_resource_type( + d.pop("match_resource_type", UNSET) + ) + + def _parse_match_metadata_expression( + data: object, + ) -> CreateEventHandlerRequestMatchMetadataExpressionType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + match_metadata_expression_type_0 = ( + CreateEventHandlerRequestMatchMetadataExpressionType0.from_dict(data) + ) + + return match_metadata_expression_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + CreateEventHandlerRequestMatchMetadataExpressionType0 | None | Unset, data + ) + + match_metadata_expression = _parse_match_metadata_expression( + d.pop("match_metadata_expression", UNSET) + ) + + priority = d.pop("priority", UNSET) + + is_active = d.pop("is_active", UNSET) + + _origin = d.pop("origin", UNSET) + origin: CreateEventHandlerRequestOrigin | Unset + if isinstance(_origin, Unset): + origin = UNSET + else: + origin = CreateEventHandlerRequestOrigin(_origin) + + _metadata = d.pop("metadata", UNSET) + metadata: CreateEventHandlerRequestMetadata | Unset + if isinstance(_metadata, Unset): + metadata = UNSET + else: + metadata = CreateEventHandlerRequestMetadata.from_dict(_metadata) + + create_event_handler_request = cls( + name=name, + event_type=event_type, + transaction_template=transaction_template, + description=description, + event_category=event_category, + match_source=match_source, + match_agent_type=match_agent_type, + match_resource_type=match_resource_type, + match_metadata_expression=match_metadata_expression, + priority=priority, + is_active=is_active, + origin=origin, + metadata=metadata, + ) + + create_event_handler_request.additional_properties = d + return create_event_handler_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_event_handler_request_match_metadata_expression_type_0.py b/robosystems_client/models/create_event_handler_request_match_metadata_expression_type_0.py new file mode 100644 index 0000000..8465496 --- /dev/null +++ b/robosystems_client/models/create_event_handler_request_match_metadata_expression_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CreateEventHandlerRequestMatchMetadataExpressionType0") + + +@_attrs_define +class CreateEventHandlerRequestMatchMetadataExpressionType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + create_event_handler_request_match_metadata_expression_type_0 = cls() + + create_event_handler_request_match_metadata_expression_type_0.additional_properties = d + return create_event_handler_request_match_metadata_expression_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_event_handler_request_metadata.py b/robosystems_client/models/create_event_handler_request_metadata.py new file mode 100644 index 0000000..403f67c --- /dev/null +++ b/robosystems_client/models/create_event_handler_request_metadata.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CreateEventHandlerRequestMetadata") + + +@_attrs_define +class CreateEventHandlerRequestMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + create_event_handler_request_metadata = cls() + + create_event_handler_request_metadata.additional_properties = d + return create_event_handler_request_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/create_event_handler_request_origin.py b/robosystems_client/models/create_event_handler_request_origin.py new file mode 100644 index 0000000..8c11eda --- /dev/null +++ b/robosystems_client/models/create_event_handler_request_origin.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CreateEventHandlerRequestOrigin(str, Enum): + HUB = "hub" + TENANT = "tenant" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/create_journal_entry_request.py b/robosystems_client/models/create_journal_entry_request.py deleted file mode 100644 index 8f21353..0000000 --- a/robosystems_client/models/create_journal_entry_request.py +++ /dev/null @@ -1,161 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..models.create_journal_entry_request_status import CreateJournalEntryRequestStatus -from ..models.create_journal_entry_request_type import CreateJournalEntryRequestType -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.journal_entry_line_item_input import JournalEntryLineItemInput - - -T = TypeVar("T", bound="CreateJournalEntryRequest") - - -@_attrs_define -class CreateJournalEntryRequest: - """Create a new journal entry with balanced line items. - - Defaults to `status='draft'` for ongoing native writes (the normal - workflow: draft → review → post via close-period). Pass - `status='posted'` for historical data import where entries represent - already-happened business events that don't need review. - - Total debit amount must equal total credit amount or the request - is rejected with 422. `line_items` must contain at least two rows - (at least one debit, at least one credit). - - Attributes: - posting_date (datetime.date): - memo (str): - line_items (list[JournalEntryLineItemInput]): - type_ (CreateJournalEntryRequestType | Unset): Default: CreateJournalEntryRequestType.STANDARD. - status (CreateJournalEntryRequestStatus | Unset): Default: CreateJournalEntryRequestStatus.DRAFT. - transaction_id (None | str | Unset): - """ - - posting_date: datetime.date - memo: str - line_items: list[JournalEntryLineItemInput] - type_: CreateJournalEntryRequestType | Unset = CreateJournalEntryRequestType.STANDARD - status: CreateJournalEntryRequestStatus | Unset = ( - CreateJournalEntryRequestStatus.DRAFT - ) - transaction_id: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - posting_date = self.posting_date.isoformat() - - memo = self.memo - - line_items = [] - for line_items_item_data in self.line_items: - line_items_item = line_items_item_data.to_dict() - line_items.append(line_items_item) - - type_: str | Unset = UNSET - if not isinstance(self.type_, Unset): - type_ = self.type_.value - - status: str | Unset = UNSET - if not isinstance(self.status, Unset): - status = self.status.value - - transaction_id: None | str | Unset - if isinstance(self.transaction_id, Unset): - transaction_id = UNSET - else: - transaction_id = self.transaction_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "posting_date": posting_date, - "memo": memo, - "line_items": line_items, - } - ) - if type_ is not UNSET: - field_dict["type"] = type_ - if status is not UNSET: - field_dict["status"] = status - if transaction_id is not UNSET: - field_dict["transaction_id"] = transaction_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.journal_entry_line_item_input import JournalEntryLineItemInput - - d = dict(src_dict) - posting_date = isoparse(d.pop("posting_date")).date() - - memo = d.pop("memo") - - line_items = [] - _line_items = d.pop("line_items") - for line_items_item_data in _line_items: - line_items_item = JournalEntryLineItemInput.from_dict(line_items_item_data) - - line_items.append(line_items_item) - - _type_ = d.pop("type", UNSET) - type_: CreateJournalEntryRequestType | Unset - if isinstance(_type_, Unset): - type_ = UNSET - else: - type_ = CreateJournalEntryRequestType(_type_) - - _status = d.pop("status", UNSET) - status: CreateJournalEntryRequestStatus | Unset - if isinstance(_status, Unset): - status = UNSET - else: - status = CreateJournalEntryRequestStatus(_status) - - def _parse_transaction_id(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - transaction_id = _parse_transaction_id(d.pop("transaction_id", UNSET)) - - create_journal_entry_request = cls( - posting_date=posting_date, - memo=memo, - line_items=line_items, - type_=type_, - status=status, - transaction_id=transaction_id, - ) - - create_journal_entry_request.additional_properties = d - return create_journal_entry_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/create_journal_entry_request_status.py b/robosystems_client/models/create_journal_entry_request_status.py deleted file mode 100644 index 1fe3522..0000000 --- a/robosystems_client/models/create_journal_entry_request_status.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class CreateJournalEntryRequestStatus(str, Enum): - DRAFT = "draft" - POSTED = "posted" - - def __str__(self) -> str: - return str(self.value) diff --git a/robosystems_client/models/create_journal_entry_request_type.py b/robosystems_client/models/create_journal_entry_request_type.py deleted file mode 100644 index 907e30f..0000000 --- a/robosystems_client/models/create_journal_entry_request_type.py +++ /dev/null @@ -1,11 +0,0 @@ -from enum import Enum - - -class CreateJournalEntryRequestType(str, Enum): - ADJUSTING = "adjusting" - CLOSING = "closing" - REVERSING = "reversing" - STANDARD = "standard" - - def __str__(self) -> str: - return str(self.value) diff --git a/robosystems_client/models/create_manual_closing_entry_request.py b/robosystems_client/models/create_manual_closing_entry_request.py deleted file mode 100644 index a2cc68b..0000000 --- a/robosystems_client/models/create_manual_closing_entry_request.py +++ /dev/null @@ -1,117 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..models.create_manual_closing_entry_request_entry_type import ( - CreateManualClosingEntryRequestEntryType, -) -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.manual_line_item_request import ManualLineItemRequest - - -T = TypeVar("T", bound="CreateManualClosingEntryRequest") - - -@_attrs_define -class CreateManualClosingEntryRequest: - """ - Attributes: - posting_date (datetime.date): Posting date for the entry - memo (str): Memo describing the business event (e.g., 'Sale of computer to Vendor X on 3/15') - line_items (list[ManualLineItemRequest]): Line items; must balance (total DR = total CR) - entry_type (CreateManualClosingEntryRequestEntryType | Unset): Entry type: 'closing' (default), 'adjusting', - 'standard', 'reversing' Default: CreateManualClosingEntryRequestEntryType.CLOSING. - """ - - posting_date: datetime.date - memo: str - line_items: list[ManualLineItemRequest] - entry_type: CreateManualClosingEntryRequestEntryType | Unset = ( - CreateManualClosingEntryRequestEntryType.CLOSING - ) - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - posting_date = self.posting_date.isoformat() - - memo = self.memo - - line_items = [] - for line_items_item_data in self.line_items: - line_items_item = line_items_item_data.to_dict() - line_items.append(line_items_item) - - entry_type: str | Unset = UNSET - if not isinstance(self.entry_type, Unset): - entry_type = self.entry_type.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "posting_date": posting_date, - "memo": memo, - "line_items": line_items, - } - ) - if entry_type is not UNSET: - field_dict["entry_type"] = entry_type - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.manual_line_item_request import ManualLineItemRequest - - d = dict(src_dict) - posting_date = isoparse(d.pop("posting_date")).date() - - memo = d.pop("memo") - - line_items = [] - _line_items = d.pop("line_items") - for line_items_item_data in _line_items: - line_items_item = ManualLineItemRequest.from_dict(line_items_item_data) - - line_items.append(line_items_item) - - _entry_type = d.pop("entry_type", UNSET) - entry_type: CreateManualClosingEntryRequestEntryType | Unset - if isinstance(_entry_type, Unset): - entry_type = UNSET - else: - entry_type = CreateManualClosingEntryRequestEntryType(_entry_type) - - create_manual_closing_entry_request = cls( - posting_date=posting_date, - memo=memo, - line_items=line_items, - entry_type=entry_type, - ) - - create_manual_closing_entry_request.additional_properties = d - return create_manual_closing_entry_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/create_manual_closing_entry_request_entry_type.py b/robosystems_client/models/create_manual_closing_entry_request_entry_type.py deleted file mode 100644 index fbfbc62..0000000 --- a/robosystems_client/models/create_manual_closing_entry_request_entry_type.py +++ /dev/null @@ -1,11 +0,0 @@ -from enum import Enum - - -class CreateManualClosingEntryRequestEntryType(str, Enum): - ADJUSTING = "adjusting" - CLOSING = "closing" - REVERSING = "reversing" - STANDARD = "standard" - - def __str__(self) -> str: - return str(self.value) diff --git a/robosystems_client/models/create_transaction_request.py b/robosystems_client/models/create_transaction_request.py deleted file mode 100644 index aafeaa3..0000000 --- a/robosystems_client/models/create_transaction_request.py +++ /dev/null @@ -1,248 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..models.create_transaction_request_status import CreateTransactionRequestStatus -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateTransactionRequest") - - -@_attrs_define -class CreateTransactionRequest: - """Create a standalone business-event Transaction. - - Use this when you want to record a real-world event (invoice, payment, - deposit, expense) first and then attach one or more journal entries to - it via `create-journal-entry` with the returned `transaction_id`. - - `amount` is in minor currency units (cents). `type` is free-form but - common values are: invoice, payment, bill, expense, deposit, transfer, - journal_entry. - - Attributes: - type_ (str): - date (datetime.date): - amount (int): - currency (str | Unset): Default: 'USD'. - description (None | str | Unset): - merchant_name (None | str | Unset): - reference_number (None | str | Unset): - number (None | str | Unset): - category (None | str | Unset): - due_date (datetime.date | None | Unset): - status (CreateTransactionRequestStatus | Unset): Default: CreateTransactionRequestStatus.PENDING. - """ - - type_: str - date: datetime.date - amount: int - currency: str | Unset = "USD" - description: None | str | Unset = UNSET - merchant_name: None | str | Unset = UNSET - reference_number: None | str | Unset = UNSET - number: None | str | Unset = UNSET - category: None | str | Unset = UNSET - due_date: datetime.date | None | Unset = UNSET - status: CreateTransactionRequestStatus | Unset = ( - CreateTransactionRequestStatus.PENDING - ) - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - type_ = self.type_ - - date = self.date.isoformat() - - amount = self.amount - - currency = self.currency - - description: None | str | Unset - if isinstance(self.description, Unset): - description = UNSET - else: - description = self.description - - merchant_name: None | str | Unset - if isinstance(self.merchant_name, Unset): - merchant_name = UNSET - else: - merchant_name = self.merchant_name - - reference_number: None | str | Unset - if isinstance(self.reference_number, Unset): - reference_number = UNSET - else: - reference_number = self.reference_number - - number: None | str | Unset - if isinstance(self.number, Unset): - number = UNSET - else: - number = self.number - - category: None | str | Unset - if isinstance(self.category, Unset): - category = UNSET - else: - category = self.category - - due_date: None | str | Unset - if isinstance(self.due_date, Unset): - due_date = UNSET - elif isinstance(self.due_date, datetime.date): - due_date = self.due_date.isoformat() - else: - due_date = self.due_date - - status: str | Unset = UNSET - if not isinstance(self.status, Unset): - status = self.status.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "type": type_, - "date": date, - "amount": amount, - } - ) - if currency is not UNSET: - field_dict["currency"] = currency - if description is not UNSET: - field_dict["description"] = description - if merchant_name is not UNSET: - field_dict["merchant_name"] = merchant_name - if reference_number is not UNSET: - field_dict["reference_number"] = reference_number - if number is not UNSET: - field_dict["number"] = number - if category is not UNSET: - field_dict["category"] = category - if due_date is not UNSET: - field_dict["due_date"] = due_date - if status is not UNSET: - field_dict["status"] = status - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - type_ = d.pop("type") - - date = isoparse(d.pop("date")).date() - - amount = d.pop("amount") - - currency = d.pop("currency", UNSET) - - def _parse_description(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - description = _parse_description(d.pop("description", UNSET)) - - def _parse_merchant_name(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - merchant_name = _parse_merchant_name(d.pop("merchant_name", UNSET)) - - def _parse_reference_number(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - reference_number = _parse_reference_number(d.pop("reference_number", UNSET)) - - def _parse_number(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - number = _parse_number(d.pop("number", UNSET)) - - def _parse_category(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - category = _parse_category(d.pop("category", UNSET)) - - def _parse_due_date(data: object) -> datetime.date | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - due_date_type_0 = isoparse(data).date() - - return due_date_type_0 - except (TypeError, ValueError, AttributeError, KeyError): - pass - return cast(datetime.date | None | Unset, data) - - due_date = _parse_due_date(d.pop("due_date", UNSET)) - - _status = d.pop("status", UNSET) - status: CreateTransactionRequestStatus | Unset - if isinstance(_status, Unset): - status = UNSET - else: - status = CreateTransactionRequestStatus(_status) - - create_transaction_request = cls( - type_=type_, - date=date, - amount=amount, - currency=currency, - description=description, - merchant_name=merchant_name, - reference_number=reference_number, - number=number, - category=category, - due_date=due_date, - status=status, - ) - - create_transaction_request.additional_properties = d - return create_transaction_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/create_transaction_request_status.py b/robosystems_client/models/create_transaction_request_status.py deleted file mode 100644 index a0c5df4..0000000 --- a/robosystems_client/models/create_transaction_request_status.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class CreateTransactionRequestStatus(str, Enum): - PENDING = "pending" - POSTED = "posted" - - def __str__(self) -> str: - return str(self.value) diff --git a/robosystems_client/models/dispose_schedule_request.py b/robosystems_client/models/dispose_schedule_request.py deleted file mode 100644 index cd1c5a8..0000000 --- a/robosystems_client/models/dispose_schedule_request.py +++ /dev/null @@ -1,162 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DisposeScheduleRequest") - - -@_attrs_define -class DisposeScheduleRequest: - """Dispose a schedule early — combines truncation with a disposal closing entry. - - Computes net book value from the schedule's own facts, truncates forward - periods, and creates a balanced disposal entry in one atomic operation. - Use when an asset is sold or abandoned before the schedule runs to completion. - - Attributes: - structure_id (str): Target schedule structure ID. - disposal_date (datetime.date): Last day of the final period (month-end). Forward facts past this date are - deleted; the disposal entry is posted on this date. - memo (str): Memo for the disposal closing entry. - reason (str): Reason for disposal (audit trail). - sale_proceeds (int | None | Unset): Cash received from the sale in cents. None or 0 for abandonment (no cash - received). If provided, `proceeds_element_id` is required. - proceeds_element_id (None | str | Unset): Element to debit for sale proceeds (e.g., Cash or AR). Required when - sale_proceeds > 0. - gain_loss_element_id (None | str | Unset): Element for gain or loss on disposal. Required when net book value > - 0 after applying sale proceeds. Optional when asset is fully depreciated (NBV = 0, no gain/loss line needed). - """ - - structure_id: str - disposal_date: datetime.date - memo: str - reason: str - sale_proceeds: int | None | Unset = UNSET - proceeds_element_id: None | str | Unset = UNSET - gain_loss_element_id: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - structure_id = self.structure_id - - disposal_date = self.disposal_date.isoformat() - - memo = self.memo - - reason = self.reason - - sale_proceeds: int | None | Unset - if isinstance(self.sale_proceeds, Unset): - sale_proceeds = UNSET - else: - sale_proceeds = self.sale_proceeds - - proceeds_element_id: None | str | Unset - if isinstance(self.proceeds_element_id, Unset): - proceeds_element_id = UNSET - else: - proceeds_element_id = self.proceeds_element_id - - gain_loss_element_id: None | str | Unset - if isinstance(self.gain_loss_element_id, Unset): - gain_loss_element_id = UNSET - else: - gain_loss_element_id = self.gain_loss_element_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "structure_id": structure_id, - "disposal_date": disposal_date, - "memo": memo, - "reason": reason, - } - ) - if sale_proceeds is not UNSET: - field_dict["sale_proceeds"] = sale_proceeds - if proceeds_element_id is not UNSET: - field_dict["proceeds_element_id"] = proceeds_element_id - if gain_loss_element_id is not UNSET: - field_dict["gain_loss_element_id"] = gain_loss_element_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - structure_id = d.pop("structure_id") - - disposal_date = isoparse(d.pop("disposal_date")).date() - - memo = d.pop("memo") - - reason = d.pop("reason") - - def _parse_sale_proceeds(data: object) -> int | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(int | None | Unset, data) - - sale_proceeds = _parse_sale_proceeds(d.pop("sale_proceeds", UNSET)) - - def _parse_proceeds_element_id(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - proceeds_element_id = _parse_proceeds_element_id( - d.pop("proceeds_element_id", UNSET) - ) - - def _parse_gain_loss_element_id(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - gain_loss_element_id = _parse_gain_loss_element_id( - d.pop("gain_loss_element_id", UNSET) - ) - - dispose_schedule_request = cls( - structure_id=structure_id, - disposal_date=disposal_date, - memo=memo, - reason=reason, - sale_proceeds=sale_proceeds, - proceeds_element_id=proceeds_element_id, - gain_loss_element_id=gain_loss_element_id, - ) - - dispose_schedule_request.additional_properties = d - return dispose_schedule_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/manual_line_item_request.py b/robosystems_client/models/manual_line_item_request.py deleted file mode 100644 index 2c5e920..0000000 --- a/robosystems_client/models/manual_line_item_request.py +++ /dev/null @@ -1,101 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="ManualLineItemRequest") - - -@_attrs_define -class ManualLineItemRequest: - """ - Attributes: - element_id (str): Element ID (chart of accounts) - debit_amount (int | Unset): Debit in cents Default: 0. - credit_amount (int | Unset): Credit in cents Default: 0. - description (None | str | Unset): - """ - - element_id: str - debit_amount: int | Unset = 0 - credit_amount: int | Unset = 0 - description: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - element_id = self.element_id - - debit_amount = self.debit_amount - - credit_amount = self.credit_amount - - description: None | str | Unset - if isinstance(self.description, Unset): - description = UNSET - else: - description = self.description - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "element_id": element_id, - } - ) - if debit_amount is not UNSET: - field_dict["debit_amount"] = debit_amount - if credit_amount is not UNSET: - field_dict["credit_amount"] = credit_amount - if description is not UNSET: - field_dict["description"] = description - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - element_id = d.pop("element_id") - - debit_amount = d.pop("debit_amount", UNSET) - - credit_amount = d.pop("credit_amount", UNSET) - - def _parse_description(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - description = _parse_description(d.pop("description", UNSET)) - - manual_line_item_request = cls( - element_id=element_id, - debit_amount=debit_amount, - credit_amount=credit_amount, - description=description, - ) - - manual_line_item_request.additional_properties = d - return manual_line_item_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/reverse_journal_entry_request.py b/robosystems_client/models/reverse_journal_entry_request.py deleted file mode 100644 index ae9d530..0000000 --- a/robosystems_client/models/reverse_journal_entry_request.py +++ /dev/null @@ -1,125 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="ReverseJournalEntryRequest") - - -@_attrs_define -class ReverseJournalEntryRequest: - """Reverse a posted journal entry. - - Creates a new entry whose line items flip the originals - (debits → credits, credits → debits), sets `reversal_of` on the new - entry to the original's id, marks the original as - `status='reversed'`, and posts the reversing entry immediately. - - This is how accountants correct posted entries — the original stays - in the audit trail, the reversal cancels its effect, and a - corrected entry can be created separately. - - Attributes: - entry_id (str): - posting_date (datetime.date | None | Unset): - memo (None | str | Unset): - """ - - entry_id: str - posting_date: datetime.date | None | Unset = UNSET - memo: None | str | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - entry_id = self.entry_id - - posting_date: None | str | Unset - if isinstance(self.posting_date, Unset): - posting_date = UNSET - elif isinstance(self.posting_date, datetime.date): - posting_date = self.posting_date.isoformat() - else: - posting_date = self.posting_date - - memo: None | str | Unset - if isinstance(self.memo, Unset): - memo = UNSET - else: - memo = self.memo - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "entry_id": entry_id, - } - ) - if posting_date is not UNSET: - field_dict["posting_date"] = posting_date - if memo is not UNSET: - field_dict["memo"] = memo - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - entry_id = d.pop("entry_id") - - def _parse_posting_date(data: object) -> datetime.date | None | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - posting_date_type_0 = isoparse(data).date() - - return posting_date_type_0 - except (TypeError, ValueError, AttributeError, KeyError): - pass - return cast(datetime.date | None | Unset, data) - - posting_date = _parse_posting_date(d.pop("posting_date", UNSET)) - - def _parse_memo(data: object) -> None | str | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(None | str | Unset, data) - - memo = _parse_memo(d.pop("memo", UNSET)) - - reverse_journal_entry_request = cls( - entry_id=entry_id, - posting_date=posting_date, - memo=memo, - ) - - reverse_journal_entry_request.additional_properties = d - return reverse_journal_entry_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/transaction_template.py b/robosystems_client/models/transaction_template.py new file mode 100644 index 0000000..f295937 --- /dev/null +++ b/robosystems_client/models/transaction_template.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.transaction_template_item import TransactionTemplateItem + + +T = TypeVar("T", bound="TransactionTemplate") + + +@_attrs_define +class TransactionTemplate: + """The handler's output spec — one or more balanced entries to post. + + Wire shape:: + + { + "transactions": [{ + "entry_template": { + "debit": {"element_id": "elem_...", "amount": "{{ event.amount }}"}, + "credit": {"element_id": "elem_...", "amount": "{{ event.amount }}"} + } + }] + } + + Attributes: + transactions (list[TransactionTemplateItem]): At least one debit/credit entry pair + """ + + transactions: list[TransactionTemplateItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + transactions = [] + for transactions_item_data in self.transactions: + transactions_item = transactions_item_data.to_dict() + transactions.append(transactions_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "transactions": transactions, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.transaction_template_item import TransactionTemplateItem + + d = dict(src_dict) + transactions = [] + _transactions = d.pop("transactions") + for transactions_item_data in _transactions: + transactions_item = TransactionTemplateItem.from_dict(transactions_item_data) + + transactions.append(transactions_item) + + transaction_template = cls( + transactions=transactions, + ) + + transaction_template.additional_properties = d + return transaction_template + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/transaction_template_entry.py b/robosystems_client/models/transaction_template_entry.py new file mode 100644 index 0000000..1c16f96 --- /dev/null +++ b/robosystems_client/models/transaction_template_entry.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.transaction_template_leg import TransactionTemplateLeg + + +T = TypeVar("T", bound="TransactionTemplateEntry") + + +@_attrs_define +class TransactionTemplateEntry: + """One balanced entry (debit + credit pair) — the inner shape of entry_template. + + Attributes: + debit (TransactionTemplateLeg): One side of a journal entry leg (debit or credit). + credit (TransactionTemplateLeg): One side of a journal entry leg (debit or credit). + """ + + debit: TransactionTemplateLeg + credit: TransactionTemplateLeg + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + debit = self.debit.to_dict() + + credit = self.credit.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "debit": debit, + "credit": credit, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.transaction_template_leg import TransactionTemplateLeg + + d = dict(src_dict) + debit = TransactionTemplateLeg.from_dict(d.pop("debit")) + + credit = TransactionTemplateLeg.from_dict(d.pop("credit")) + + transaction_template_entry = cls( + debit=debit, + credit=credit, + ) + + transaction_template_entry.additional_properties = d + return transaction_template_entry + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/transaction_template_item.py b/robosystems_client/models/transaction_template_item.py new file mode 100644 index 0000000..ac642be --- /dev/null +++ b/robosystems_client/models/transaction_template_item.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.transaction_template_entry import TransactionTemplateEntry + + +T = TypeVar("T", bound="TransactionTemplateItem") + + +@_attrs_define +class TransactionTemplateItem: + """One item in the transactions list — wraps entry_template to match the DSL shape. + + Attributes: + entry_template (TransactionTemplateEntry): One balanced entry (debit + credit pair) — the inner shape of + entry_template. + """ + + entry_template: TransactionTemplateEntry + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entry_template = self.entry_template.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entry_template": entry_template, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.transaction_template_entry import TransactionTemplateEntry + + d = dict(src_dict) + entry_template = TransactionTemplateEntry.from_dict(d.pop("entry_template")) + + transaction_template_item = cls( + entry_template=entry_template, + ) + + transaction_template_item.additional_properties = d + return transaction_template_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/transaction_template_leg.py b/robosystems_client/models/transaction_template_leg.py new file mode 100644 index 0000000..2aee296 --- /dev/null +++ b/robosystems_client/models/transaction_template_leg.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="TransactionTemplateLeg") + + +@_attrs_define +class TransactionTemplateLeg: + """One side of a journal entry leg (debit or credit). + + Attributes: + element_id (str): Element ULID (elem_ prefixed) identifying the account to post to + amount (str): Amount expression. Supports: '{{ event.amount }}' — raw event amount (cents); '{{ event.amount }} + / 2' — half of event amount; '{{ event.metadata.fee_cents }}' — field from event metadata + """ + + element_id: str + amount: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + element_id = self.element_id + + amount = self.amount + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "element_id": element_id, + "amount": amount, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + element_id = d.pop("element_id") + + amount = d.pop("amount") + + transaction_template_leg = cls( + element_id=element_id, + amount=amount, + ) + + transaction_template_leg.additional_properties = d + return transaction_template_leg + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/truncate_schedule_operation.py b/robosystems_client/models/truncate_schedule_operation.py deleted file mode 100644 index b001e2a..0000000 --- a/robosystems_client/models/truncate_schedule_operation.py +++ /dev/null @@ -1,86 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -T = TypeVar("T", bound="TruncateScheduleOperation") - - -@_attrs_define -class TruncateScheduleOperation: - """CQRS-shaped body for `POST /operations/truncate-schedule`. - - Bundles the target schedule's `structure_id` with the update payload so - the single-body signature matches the registrar/MCP contract. The REST - handler, GraphQL resolver, and MCP tool all resolve to the same - `cmd_truncate_schedule(session, body, created_by=...)`. - - Attributes: - new_end_date (datetime.date): New last-covered date for the schedule. Facts with period_start > this date are - deleted (along with any stale draft entries they produced). Historical facts (already posted) are preserved. - reason (str): Required reason for the truncation (captured in audit log). - structure_id (str): Target schedule structure ID. - """ - - new_end_date: datetime.date - reason: str - structure_id: str - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - new_end_date = self.new_end_date.isoformat() - - reason = self.reason - - structure_id = self.structure_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "new_end_date": new_end_date, - "reason": reason, - "structure_id": structure_id, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - new_end_date = isoparse(d.pop("new_end_date")).date() - - reason = d.pop("reason") - - structure_id = d.pop("structure_id") - - truncate_schedule_operation = cls( - new_end_date=new_end_date, - reason=reason, - structure_id=structure_id, - ) - - truncate_schedule_operation.additional_properties = d - return truncate_schedule_operation - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/robosystems_client/models/update_agent_request.py b/robosystems_client/models/update_agent_request.py new file mode 100644 index 0000000..57cbf16 --- /dev/null +++ b/robosystems_client/models/update_agent_request.py @@ -0,0 +1,331 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.update_agent_request_address_type_0 import ( + UpdateAgentRequestAddressType0, + ) + from ..models.update_agent_request_metadata_patch import ( + UpdateAgentRequestMetadataPatch, + ) + + +T = TypeVar("T", bound="UpdateAgentRequest") + + +@_attrs_define +class UpdateAgentRequest: + """ + Attributes: + agent_id (str): + name (None | str | Unset): + legal_name (None | str | Unset): + tax_id (None | str | Unset): + registration_number (None | str | Unset): + duns (None | str | Unset): + lei (None | str | Unset): + email (None | str | Unset): + phone (None | str | Unset): + address (None | Unset | UpdateAgentRequestAddressType0): + is_active (bool | None | Unset): + is_1099_recipient (bool | None | Unset): + metadata_patch (UpdateAgentRequestMetadataPatch | Unset): + """ + + agent_id: str + name: None | str | Unset = UNSET + legal_name: None | str | Unset = UNSET + tax_id: None | str | Unset = UNSET + registration_number: None | str | Unset = UNSET + duns: None | str | Unset = UNSET + lei: None | str | Unset = UNSET + email: None | str | Unset = UNSET + phone: None | str | Unset = UNSET + address: None | Unset | UpdateAgentRequestAddressType0 = UNSET + is_active: bool | None | Unset = UNSET + is_1099_recipient: bool | None | Unset = UNSET + metadata_patch: UpdateAgentRequestMetadataPatch | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.update_agent_request_address_type_0 import ( + UpdateAgentRequestAddressType0, + ) + + agent_id = self.agent_id + + name: None | str | Unset + if isinstance(self.name, Unset): + name = UNSET + else: + name = self.name + + legal_name: None | str | Unset + if isinstance(self.legal_name, Unset): + legal_name = UNSET + else: + legal_name = self.legal_name + + tax_id: None | str | Unset + if isinstance(self.tax_id, Unset): + tax_id = UNSET + else: + tax_id = self.tax_id + + registration_number: None | str | Unset + if isinstance(self.registration_number, Unset): + registration_number = UNSET + else: + registration_number = self.registration_number + + duns: None | str | Unset + if isinstance(self.duns, Unset): + duns = UNSET + else: + duns = self.duns + + lei: None | str | Unset + if isinstance(self.lei, Unset): + lei = UNSET + else: + lei = self.lei + + email: None | str | Unset + if isinstance(self.email, Unset): + email = UNSET + else: + email = self.email + + phone: None | str | Unset + if isinstance(self.phone, Unset): + phone = UNSET + else: + phone = self.phone + + address: dict[str, Any] | None | Unset + if isinstance(self.address, Unset): + address = UNSET + elif isinstance(self.address, UpdateAgentRequestAddressType0): + address = self.address.to_dict() + else: + address = self.address + + is_active: bool | None | Unset + if isinstance(self.is_active, Unset): + is_active = UNSET + else: + is_active = self.is_active + + is_1099_recipient: bool | None | Unset + if isinstance(self.is_1099_recipient, Unset): + is_1099_recipient = UNSET + else: + is_1099_recipient = self.is_1099_recipient + + metadata_patch: dict[str, Any] | Unset = UNSET + if not isinstance(self.metadata_patch, Unset): + metadata_patch = self.metadata_patch.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "agent_id": agent_id, + } + ) + if name is not UNSET: + field_dict["name"] = name + if legal_name is not UNSET: + field_dict["legal_name"] = legal_name + if tax_id is not UNSET: + field_dict["tax_id"] = tax_id + if registration_number is not UNSET: + field_dict["registration_number"] = registration_number + if duns is not UNSET: + field_dict["duns"] = duns + if lei is not UNSET: + field_dict["lei"] = lei + if email is not UNSET: + field_dict["email"] = email + if phone is not UNSET: + field_dict["phone"] = phone + if address is not UNSET: + field_dict["address"] = address + if is_active is not UNSET: + field_dict["is_active"] = is_active + if is_1099_recipient is not UNSET: + field_dict["is_1099_recipient"] = is_1099_recipient + if metadata_patch is not UNSET: + field_dict["metadata_patch"] = metadata_patch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.update_agent_request_address_type_0 import ( + UpdateAgentRequestAddressType0, + ) + from ..models.update_agent_request_metadata_patch import ( + UpdateAgentRequestMetadataPatch, + ) + + d = dict(src_dict) + agent_id = d.pop("agent_id") + + def _parse_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + name = _parse_name(d.pop("name", UNSET)) + + def _parse_legal_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + legal_name = _parse_legal_name(d.pop("legal_name", UNSET)) + + def _parse_tax_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + tax_id = _parse_tax_id(d.pop("tax_id", UNSET)) + + def _parse_registration_number(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + registration_number = _parse_registration_number( + d.pop("registration_number", UNSET) + ) + + def _parse_duns(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + duns = _parse_duns(d.pop("duns", UNSET)) + + def _parse_lei(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + lei = _parse_lei(d.pop("lei", UNSET)) + + def _parse_email(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + email = _parse_email(d.pop("email", UNSET)) + + def _parse_phone(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + phone = _parse_phone(d.pop("phone", UNSET)) + + def _parse_address(data: object) -> None | Unset | UpdateAgentRequestAddressType0: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + address_type_0 = UpdateAgentRequestAddressType0.from_dict(data) + + return address_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | Unset | UpdateAgentRequestAddressType0, data) + + address = _parse_address(d.pop("address", UNSET)) + + def _parse_is_active(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_active = _parse_is_active(d.pop("is_active", UNSET)) + + def _parse_is_1099_recipient(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_1099_recipient = _parse_is_1099_recipient(d.pop("is_1099_recipient", UNSET)) + + _metadata_patch = d.pop("metadata_patch", UNSET) + metadata_patch: UpdateAgentRequestMetadataPatch | Unset + if isinstance(_metadata_patch, Unset): + metadata_patch = UNSET + else: + metadata_patch = UpdateAgentRequestMetadataPatch.from_dict(_metadata_patch) + + update_agent_request = cls( + agent_id=agent_id, + name=name, + legal_name=legal_name, + tax_id=tax_id, + registration_number=registration_number, + duns=duns, + lei=lei, + email=email, + phone=phone, + address=address, + is_active=is_active, + is_1099_recipient=is_1099_recipient, + metadata_patch=metadata_patch, + ) + + update_agent_request.additional_properties = d + return update_agent_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_agent_request_address_type_0.py b/robosystems_client/models/update_agent_request_address_type_0.py new file mode 100644 index 0000000..aa47262 --- /dev/null +++ b/robosystems_client/models/update_agent_request_address_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateAgentRequestAddressType0") + + +@_attrs_define +class UpdateAgentRequestAddressType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + update_agent_request_address_type_0 = cls() + + update_agent_request_address_type_0.additional_properties = d + return update_agent_request_address_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_agent_request_metadata_patch.py b/robosystems_client/models/update_agent_request_metadata_patch.py new file mode 100644 index 0000000..9e804b1 --- /dev/null +++ b/robosystems_client/models/update_agent_request_metadata_patch.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateAgentRequestMetadataPatch") + + +@_attrs_define +class UpdateAgentRequestMetadataPatch: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + update_agent_request_metadata_patch = cls() + + update_agent_request_metadata_patch.additional_properties = d + return update_agent_request_metadata_patch + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_event_block_request.py b/robosystems_client/models/update_event_block_request.py new file mode 100644 index 0000000..7708ad6 --- /dev/null +++ b/robosystems_client/models/update_event_block_request.py @@ -0,0 +1,205 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..models.update_event_block_request_transition_to_type_0 import ( + UpdateEventBlockRequestTransitionToType0, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.update_event_block_request_metadata_patch import ( + UpdateEventBlockRequestMetadataPatch, + ) + + +T = TypeVar("T", bound="UpdateEventBlockRequest") + + +@_attrs_define +class UpdateEventBlockRequest: + """Status transitions and field corrections for an event block. + + All fields except event_id are optional — only supplied fields are updated. + + Attributes: + event_id (str): + transition_to (None | Unset | UpdateEventBlockRequestTransitionToType0): Status transition. Valid moves depend + on current status: captured → committed | voided; classified → committed | pending | fulfilled | voided; + committed → pending | fulfilled | voided; pending → fulfilled | voided. Terminal states (fulfilled, voided, + superseded) accept no further transitions. Note: classified and fulfilled are usually set by handlers, not by + callers, but the transition is allowed for corrections. + superseded_by_id (None | str | Unset): New event id that replaces this one. Required when + transition_to='superseded'. + description (None | str | Unset): + effective_at (datetime.datetime | None | Unset): + metadata_patch (UpdateEventBlockRequestMetadataPatch | Unset): Key-value pairs merged into existing metadata + (additive patch, not replace). + """ + + event_id: str + transition_to: None | Unset | UpdateEventBlockRequestTransitionToType0 = UNSET + superseded_by_id: None | str | Unset = UNSET + description: None | str | Unset = UNSET + effective_at: datetime.datetime | None | Unset = UNSET + metadata_patch: UpdateEventBlockRequestMetadataPatch | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + event_id = self.event_id + + transition_to: None | str | Unset + if isinstance(self.transition_to, Unset): + transition_to = UNSET + elif isinstance(self.transition_to, UpdateEventBlockRequestTransitionToType0): + transition_to = self.transition_to.value + else: + transition_to = self.transition_to + + superseded_by_id: None | str | Unset + if isinstance(self.superseded_by_id, Unset): + superseded_by_id = UNSET + else: + superseded_by_id = self.superseded_by_id + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + effective_at: None | str | Unset + if isinstance(self.effective_at, Unset): + effective_at = UNSET + elif isinstance(self.effective_at, datetime.datetime): + effective_at = self.effective_at.isoformat() + else: + effective_at = self.effective_at + + metadata_patch: dict[str, Any] | Unset = UNSET + if not isinstance(self.metadata_patch, Unset): + metadata_patch = self.metadata_patch.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "event_id": event_id, + } + ) + if transition_to is not UNSET: + field_dict["transition_to"] = transition_to + if superseded_by_id is not UNSET: + field_dict["superseded_by_id"] = superseded_by_id + if description is not UNSET: + field_dict["description"] = description + if effective_at is not UNSET: + field_dict["effective_at"] = effective_at + if metadata_patch is not UNSET: + field_dict["metadata_patch"] = metadata_patch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.update_event_block_request_metadata_patch import ( + UpdateEventBlockRequestMetadataPatch, + ) + + d = dict(src_dict) + event_id = d.pop("event_id") + + def _parse_transition_to( + data: object, + ) -> None | Unset | UpdateEventBlockRequestTransitionToType0: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + transition_to_type_0 = UpdateEventBlockRequestTransitionToType0(data) + + return transition_to_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | Unset | UpdateEventBlockRequestTransitionToType0, data) + + transition_to = _parse_transition_to(d.pop("transition_to", UNSET)) + + def _parse_superseded_by_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + superseded_by_id = _parse_superseded_by_id(d.pop("superseded_by_id", UNSET)) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + def _parse_effective_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + effective_at_type_0 = isoparse(data) + + return effective_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + effective_at = _parse_effective_at(d.pop("effective_at", UNSET)) + + _metadata_patch = d.pop("metadata_patch", UNSET) + metadata_patch: UpdateEventBlockRequestMetadataPatch | Unset + if isinstance(_metadata_patch, Unset): + metadata_patch = UNSET + else: + metadata_patch = UpdateEventBlockRequestMetadataPatch.from_dict(_metadata_patch) + + update_event_block_request = cls( + event_id=event_id, + transition_to=transition_to, + superseded_by_id=superseded_by_id, + description=description, + effective_at=effective_at, + metadata_patch=metadata_patch, + ) + + update_event_block_request.additional_properties = d + return update_event_block_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_event_block_request_metadata_patch.py b/robosystems_client/models/update_event_block_request_metadata_patch.py new file mode 100644 index 0000000..8a49a56 --- /dev/null +++ b/robosystems_client/models/update_event_block_request_metadata_patch.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateEventBlockRequestMetadataPatch") + + +@_attrs_define +class UpdateEventBlockRequestMetadataPatch: + """Key-value pairs merged into existing metadata (additive patch, not replace).""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + update_event_block_request_metadata_patch = cls() + + update_event_block_request_metadata_patch.additional_properties = d + return update_event_block_request_metadata_patch + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_event_block_request_transition_to_type_0.py b/robosystems_client/models/update_event_block_request_transition_to_type_0.py new file mode 100644 index 0000000..49cdbfc --- /dev/null +++ b/robosystems_client/models/update_event_block_request_transition_to_type_0.py @@ -0,0 +1,12 @@ +from enum import Enum + + +class UpdateEventBlockRequestTransitionToType0(str, Enum): + COMMITTED = "committed" + FULFILLED = "fulfilled" + PENDING = "pending" + SUPERSEDED = "superseded" + VOIDED = "voided" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/update_event_handler_request.py b/robosystems_client/models/update_event_handler_request.py new file mode 100644 index 0000000..4ed2346 --- /dev/null +++ b/robosystems_client/models/update_event_handler_request.py @@ -0,0 +1,359 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.transaction_template import TransactionTemplate + from ..models.update_event_handler_request_match_metadata_expression_type_0 import ( + UpdateEventHandlerRequestMatchMetadataExpressionType0, + ) + from ..models.update_event_handler_request_metadata_patch import ( + UpdateEventHandlerRequestMetadataPatch, + ) + + +T = TypeVar("T", bound="UpdateEventHandlerRequest") + + +@_attrs_define +class UpdateEventHandlerRequest: + """ + Attributes: + event_handler_id (str): + name (None | str | Unset): + description (None | str | Unset): + event_category (None | str | Unset): + match_source (None | str | Unset): + match_agent_type (None | str | Unset): + match_resource_type (None | str | Unset): + match_metadata_expression (None | Unset | UpdateEventHandlerRequestMatchMetadataExpressionType0): + transaction_template (None | TransactionTemplate | Unset): + priority (int | None | Unset): + is_active (bool | None | Unset): + approve (bool | None | Unset): + metadata_patch (UpdateEventHandlerRequestMetadataPatch | Unset): + """ + + event_handler_id: str + name: None | str | Unset = UNSET + description: None | str | Unset = UNSET + event_category: None | str | Unset = UNSET + match_source: None | str | Unset = UNSET + match_agent_type: None | str | Unset = UNSET + match_resource_type: None | str | Unset = UNSET + match_metadata_expression: ( + None | Unset | UpdateEventHandlerRequestMatchMetadataExpressionType0 + ) = UNSET + transaction_template: None | TransactionTemplate | Unset = UNSET + priority: int | None | Unset = UNSET + is_active: bool | None | Unset = UNSET + approve: bool | None | Unset = UNSET + metadata_patch: UpdateEventHandlerRequestMetadataPatch | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.transaction_template import TransactionTemplate + from ..models.update_event_handler_request_match_metadata_expression_type_0 import ( + UpdateEventHandlerRequestMatchMetadataExpressionType0, + ) + + event_handler_id = self.event_handler_id + + name: None | str | Unset + if isinstance(self.name, Unset): + name = UNSET + else: + name = self.name + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + event_category: None | str | Unset + if isinstance(self.event_category, Unset): + event_category = UNSET + else: + event_category = self.event_category + + match_source: None | str | Unset + if isinstance(self.match_source, Unset): + match_source = UNSET + else: + match_source = self.match_source + + match_agent_type: None | str | Unset + if isinstance(self.match_agent_type, Unset): + match_agent_type = UNSET + else: + match_agent_type = self.match_agent_type + + match_resource_type: None | str | Unset + if isinstance(self.match_resource_type, Unset): + match_resource_type = UNSET + else: + match_resource_type = self.match_resource_type + + match_metadata_expression: dict[str, Any] | None | Unset + if isinstance(self.match_metadata_expression, Unset): + match_metadata_expression = UNSET + elif isinstance( + self.match_metadata_expression, + UpdateEventHandlerRequestMatchMetadataExpressionType0, + ): + match_metadata_expression = self.match_metadata_expression.to_dict() + else: + match_metadata_expression = self.match_metadata_expression + + transaction_template: dict[str, Any] | None | Unset + if isinstance(self.transaction_template, Unset): + transaction_template = UNSET + elif isinstance(self.transaction_template, TransactionTemplate): + transaction_template = self.transaction_template.to_dict() + else: + transaction_template = self.transaction_template + + priority: int | None | Unset + if isinstance(self.priority, Unset): + priority = UNSET + else: + priority = self.priority + + is_active: bool | None | Unset + if isinstance(self.is_active, Unset): + is_active = UNSET + else: + is_active = self.is_active + + approve: bool | None | Unset + if isinstance(self.approve, Unset): + approve = UNSET + else: + approve = self.approve + + metadata_patch: dict[str, Any] | Unset = UNSET + if not isinstance(self.metadata_patch, Unset): + metadata_patch = self.metadata_patch.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "event_handler_id": event_handler_id, + } + ) + if name is not UNSET: + field_dict["name"] = name + if description is not UNSET: + field_dict["description"] = description + if event_category is not UNSET: + field_dict["event_category"] = event_category + if match_source is not UNSET: + field_dict["match_source"] = match_source + if match_agent_type is not UNSET: + field_dict["match_agent_type"] = match_agent_type + if match_resource_type is not UNSET: + field_dict["match_resource_type"] = match_resource_type + if match_metadata_expression is not UNSET: + field_dict["match_metadata_expression"] = match_metadata_expression + if transaction_template is not UNSET: + field_dict["transaction_template"] = transaction_template + if priority is not UNSET: + field_dict["priority"] = priority + if is_active is not UNSET: + field_dict["is_active"] = is_active + if approve is not UNSET: + field_dict["approve"] = approve + if metadata_patch is not UNSET: + field_dict["metadata_patch"] = metadata_patch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.transaction_template import TransactionTemplate + from ..models.update_event_handler_request_match_metadata_expression_type_0 import ( + UpdateEventHandlerRequestMatchMetadataExpressionType0, + ) + from ..models.update_event_handler_request_metadata_patch import ( + UpdateEventHandlerRequestMetadataPatch, + ) + + d = dict(src_dict) + event_handler_id = d.pop("event_handler_id") + + def _parse_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + name = _parse_name(d.pop("name", UNSET)) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + def _parse_event_category(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + event_category = _parse_event_category(d.pop("event_category", UNSET)) + + def _parse_match_source(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + match_source = _parse_match_source(d.pop("match_source", UNSET)) + + def _parse_match_agent_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + match_agent_type = _parse_match_agent_type(d.pop("match_agent_type", UNSET)) + + def _parse_match_resource_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + match_resource_type = _parse_match_resource_type( + d.pop("match_resource_type", UNSET) + ) + + def _parse_match_metadata_expression( + data: object, + ) -> None | Unset | UpdateEventHandlerRequestMatchMetadataExpressionType0: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + match_metadata_expression_type_0 = ( + UpdateEventHandlerRequestMatchMetadataExpressionType0.from_dict(data) + ) + + return match_metadata_expression_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + None | Unset | UpdateEventHandlerRequestMatchMetadataExpressionType0, data + ) + + match_metadata_expression = _parse_match_metadata_expression( + d.pop("match_metadata_expression", UNSET) + ) + + def _parse_transaction_template(data: object) -> None | TransactionTemplate | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + transaction_template_type_0 = TransactionTemplate.from_dict(data) + + return transaction_template_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | TransactionTemplate | Unset, data) + + transaction_template = _parse_transaction_template( + d.pop("transaction_template", UNSET) + ) + + def _parse_priority(data: object) -> int | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(int | None | Unset, data) + + priority = _parse_priority(d.pop("priority", UNSET)) + + def _parse_is_active(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_active = _parse_is_active(d.pop("is_active", UNSET)) + + def _parse_approve(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + approve = _parse_approve(d.pop("approve", UNSET)) + + _metadata_patch = d.pop("metadata_patch", UNSET) + metadata_patch: UpdateEventHandlerRequestMetadataPatch | Unset + if isinstance(_metadata_patch, Unset): + metadata_patch = UNSET + else: + metadata_patch = UpdateEventHandlerRequestMetadataPatch.from_dict(_metadata_patch) + + update_event_handler_request = cls( + event_handler_id=event_handler_id, + name=name, + description=description, + event_category=event_category, + match_source=match_source, + match_agent_type=match_agent_type, + match_resource_type=match_resource_type, + match_metadata_expression=match_metadata_expression, + transaction_template=transaction_template, + priority=priority, + is_active=is_active, + approve=approve, + metadata_patch=metadata_patch, + ) + + update_event_handler_request.additional_properties = d + return update_event_handler_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_event_handler_request_match_metadata_expression_type_0.py b/robosystems_client/models/update_event_handler_request_match_metadata_expression_type_0.py new file mode 100644 index 0000000..ddd568e --- /dev/null +++ b/robosystems_client/models/update_event_handler_request_match_metadata_expression_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateEventHandlerRequestMatchMetadataExpressionType0") + + +@_attrs_define +class UpdateEventHandlerRequestMatchMetadataExpressionType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + update_event_handler_request_match_metadata_expression_type_0 = cls() + + update_event_handler_request_match_metadata_expression_type_0.additional_properties = d + return update_event_handler_request_match_metadata_expression_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/update_event_handler_request_metadata_patch.py b/robosystems_client/models/update_event_handler_request_metadata_patch.py new file mode 100644 index 0000000..7c3ffaf --- /dev/null +++ b/robosystems_client/models/update_event_handler_request_metadata_patch.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateEventHandlerRequestMetadataPatch") + + +@_attrs_define +class UpdateEventHandlerRequestMetadataPatch: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + update_event_handler_request_metadata_patch = cls() + + update_event_handler_request_metadata_patch.additional_properties = d + return update_event_handler_request_metadata_patch + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/tests/test_ledger_client.py b/tests/test_ledger_client.py index 172dbb1..9a40c80 100644 --- a/tests/test_ledger_client.py +++ b/tests/test_ledger_client.py @@ -345,15 +345,14 @@ def test_auto_map_elements_returns_ack(self, mock_op, mock_config, graph_id): assert ack["operation_id"].startswith("op_") assert ack["status"] == OperationEnvelopeStatus.PENDING - @patch("robosystems_client.clients.ledger_client.op_create_closing_entry") + @patch("robosystems_client.clients.ledger_client.op_create_event_block") def test_create_closing_entry(self, mock_op, mock_config, graph_id): envelope = _envelope( - "create-closing-entry", + "create-event-block", { - "outcome": "created", - "entry_id": "entry_1", - "status": "draft", - "amount": 100000, + "id": "evt_1", + "event_type": "schedule_entry_due", + "status": "classified", }, ) mock_op.return_value = _mock_response(envelope) @@ -361,27 +360,18 @@ def test_create_closing_entry(self, mock_op, mock_config, graph_id): result = client.create_closing_entry( graph_id, "str_1", "2026-03-31", "2026-03-01", "2026-03-31", memo="Depr" ) - assert result["outcome"] == "created" + assert result["event_type"] == "schedule_entry_due" body = mock_op.call_args.kwargs["body"] - assert body.memo == "Depr" - - @patch("robosystems_client.clients.ledger_client.op_truncate_schedule") - def test_truncate_schedule(self, mock_op, mock_config, graph_id): - envelope = _envelope( - "truncate-schedule", - { - "structure_id": "str_1", - "new_end_date": "2026-06-30", - "facts_deleted": 6, - "reason": "asset disposed", - }, - ) - mock_op.return_value = _mock_response(envelope) - client = LedgerClient(mock_config) - result = client.truncate_schedule( - graph_id, "str_1", new_end_date="2026-06-30", reason="asset disposed" - ) - assert result["facts_deleted"] == 6 + assert body.event_type == "schedule_entry_due" + assert body.event_category.value == "recognition" + assert body.source == "scheduled" + assert body.apply_handlers is True + metadata = body.metadata.to_dict() + assert metadata["schedule_id"] == "str_1" + assert metadata["period_start"] == "2026-03-01" + assert metadata["period_end"] == "2026-03-31" + assert metadata["posting_date"] == "2026-03-31" + assert metadata["memo"] == "Depr" @patch("robosystems_client.clients.ledger_client.op_build_fact_grid") def test_build_fact_grid_dispatches_via_operations( @@ -427,11 +417,15 @@ class TestJournalEntries: {"element_id": "elem_revenue", "debit_amount": 0, "credit_amount": 50000}, ] - @patch("robosystems_client.clients.ledger_client.op_create_journal_entry") + @patch("robosystems_client.clients.ledger_client.op_create_event_block") def test_create_journal_entry_basic(self, mock_op, mock_config, graph_id): envelope = _envelope( - "create-journal-entry", - {"entry_id": "je_1", "status": "draft", "memo": "Q1 revenue"}, + "create-event-block", + { + "id": "evt_1", + "event_type": "journal_entry_recorded", + "status": "classified", + }, ) mock_op.return_value = _mock_response(envelope) client = LedgerClient(mock_config) @@ -441,22 +435,29 @@ def test_create_journal_entry_basic(self, mock_op, mock_config, graph_id): memo="Q1 revenue", line_items=self._LINE_ITEMS, ) - assert result["entry_id"] == "je_1" - assert result["status"] == "draft" + assert result["event_type"] == "journal_entry_recorded" call_kwargs = mock_op.call_args.kwargs assert call_kwargs["graph_id"] == graph_id assert call_kwargs["idempotency_key"] is UNSET body = call_kwargs["body"] - assert body.memo == "Q1 revenue" - assert len(body.line_items) == 2 - - @patch("robosystems_client.clients.ledger_client.op_create_journal_entry") + assert body.event_type == "journal_entry_recorded" + assert body.event_category.value == "adjustment" + assert body.source == "native" + assert body.apply_handlers is True + metadata = body.metadata.to_dict() + assert metadata["memo"] == "Q1 revenue" + assert metadata["posting_date"] == "2026-03-31" + assert len(metadata["line_items"]) == 2 + assert metadata["type"] == "standard" + assert metadata["status"] == "draft" + + @patch("robosystems_client.clients.ledger_client.op_create_event_block") def test_create_journal_entry_idempotency_key_forwarded( self, mock_op, mock_config, graph_id ): envelope = _envelope( - "create-journal-entry", - {"entry_id": "je_2", "status": "draft", "memo": "retry-safe write"}, + "create-event-block", + {"id": "evt_2", "event_type": "journal_entry_recorded"}, ) mock_op.return_value = _mock_response(envelope) client = LedgerClient(mock_config) @@ -469,11 +470,11 @@ def test_create_journal_entry_idempotency_key_forwarded( ) assert mock_op.call_args.kwargs["idempotency_key"] == "idem-key-abc123" - @patch("robosystems_client.clients.ledger_client.op_create_journal_entry") + @patch("robosystems_client.clients.ledger_client.op_create_event_block") def test_create_journal_entry_posted_status(self, mock_op, mock_config, graph_id): envelope = _envelope( - "create-journal-entry", - {"entry_id": "je_3", "status": "posted"}, + "create-event-block", + {"id": "evt_3", "event_type": "journal_entry_recorded", "status": "fulfilled"}, ) mock_op.return_value = _mock_response(envelope) client = LedgerClient(mock_config) @@ -484,8 +485,8 @@ def test_create_journal_entry_posted_status(self, mock_op, mock_config, graph_id line_items=self._LINE_ITEMS, status="posted", ) - body = mock_op.call_args.kwargs["body"] - assert body.status.value == "posted" + metadata = mock_op.call_args.kwargs["body"].metadata.to_dict() + assert metadata["status"] == "posted" @patch("robosystems_client.clients.ledger_client.op_update_journal_entry") def test_update_journal_entry(self, mock_op, mock_config, graph_id): @@ -523,14 +524,14 @@ def test_delete_journal_entry_returns_result_when_present( result = client.delete_journal_entry(graph_id, "je_1") assert result["entry_id"] == "je_1" - @patch("robosystems_client.clients.ledger_client.op_reverse_journal_entry") + @patch("robosystems_client.clients.ledger_client.op_create_event_block") def test_reverse_journal_entry(self, mock_op, mock_config, graph_id): envelope = _envelope( - "reverse-journal-entry", + "create-event-block", { - "original_entry_id": "je_1", - "reversal_entry_id": "je_2", - "posting_date": "2026-04-01", + "id": "evt_1", + "event_type": "journal_entry_reversed", + "status": "fulfilled", }, ) mock_op.return_value = _mock_response(envelope) @@ -538,10 +539,14 @@ def test_reverse_journal_entry(self, mock_op, mock_config, graph_id): result = client.reverse_journal_entry( graph_id, "je_1", posting_date="2026-04-01", memo="Reversal of Q1 entry" ) - assert result["reversal_entry_id"] == "je_2" + assert result["event_type"] == "journal_entry_reversed" body = mock_op.call_args.kwargs["body"] - assert body.entry_id == "je_1" - assert body.memo == "Reversal of Q1 entry" + assert body.event_type == "journal_entry_reversed" + assert body.event_category.value == "adjustment" + metadata = body.metadata.to_dict() + assert metadata["entry_id"] == "je_1" + assert metadata["memo"] == "Reversal of Q1 entry" + assert metadata["posting_date"] == "2026-04-01" # ── Taxonomy / entity linking ─────────────────────────────────────────── @@ -1261,15 +1266,21 @@ def test_reopen_period(self, mock_op, mock_config, graph_id): assert body.reason == "Correction required" assert body.note == "Found error in entry" - @patch("robosystems_client.clients.ledger_client.op_create_manual_closing_entry") - def test_create_manual_closing_entry(self, mock_op, mock_config, graph_id): + @patch("robosystems_client.clients.ledger_client.op_create_event_block") + def test_create_journal_entry_with_adjusting_type( + self, mock_op, mock_config, graph_id + ): + """create_manual_closing_entry was retired — create_journal_entry covers + the same shape (free-form line items + entry type) via the event-block + surface. + """ envelope = _envelope( - "create-manual-closing-entry", - {"entry_id": "je_manual_1", "status": "draft", "total_amount": 25000}, + "create-event-block", + {"id": "evt_manual_1", "event_type": "journal_entry_recorded"}, ) mock_op.return_value = _mock_response(envelope) client = LedgerClient(mock_config) - result = client.create_manual_closing_entry( + result = client.create_journal_entry( graph_id, posting_date="2026-03-31", memo="Manual accrual", @@ -1277,15 +1288,16 @@ def test_create_manual_closing_entry(self, mock_op, mock_config, graph_id): {"element_id": "elem_exp", "debit_amount": 25000, "credit_amount": 0}, {"element_id": "elem_accrued", "debit_amount": 0, "credit_amount": 25000}, ], - entry_type="adjusting", + type="adjusting", ) - assert result["entry_id"] == "je_manual_1" + assert result["event_type"] == "journal_entry_recorded" body = mock_op.call_args.kwargs["body"] - assert body.memo == "Manual accrual" - assert len(body.line_items) == 2 - assert body.line_items[0].element_id == "elem_exp" - assert body.line_items[0].debit_amount == 25000 - assert body.entry_type.value == "adjusting" + metadata = body.metadata.to_dict() + assert metadata["memo"] == "Manual accrual" + assert len(metadata["line_items"]) == 2 + assert metadata["line_items"][0]["element_id"] == "elem_exp" + assert metadata["line_items"][0]["debit_amount"] == 25000 + assert metadata["type"] == "adjusting" # ── Variable-stripping behaviour in _query ──────────────────────────── @@ -1325,3 +1337,334 @@ def test_list_accounts_keeps_explicitly_set_filters( client.list_accounts(graph_id, is_active=False) variables = mock_execute.call_args[0][2] assert variables["isActive"] is False + + +# ── Event blocks (preview + status transitions) ────────────────────────── + + +@pytest.mark.unit +class TestEventBlockOps: + _PREVIEW_BODY = { + "event_type": "journal_entry_recorded", + "event_category": "adjustment", + "source": "native", + "occurred_at": "2026-03-31T00:00:00+00:00", + "apply_handlers": True, + "metadata": { + "posting_date": "2026-03-31", + "memo": "preview", + "line_items": [ + {"element_id": "elem_a", "debit_amount": 100, "credit_amount": 0}, + {"element_id": "elem_b", "debit_amount": 0, "credit_amount": 100}, + ], + "type": "standard", + "status": "draft", + }, + } + + @patch("robosystems_client.clients.ledger_client.op_preview_event_block") + def test_preview_event_block_returns_planned_rows( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope( + "preview-event-block", + {"would_succeed": True, "planned_transactions": [], "validation_errors": []}, + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.preview_event_block(graph_id, self._PREVIEW_BODY) + assert result["would_succeed"] is True + body = mock_op.call_args.kwargs["body"] + assert body.event_type == "journal_entry_recorded" + + @patch("robosystems_client.clients.ledger_client.op_preview_event_block") + def test_preview_event_block_surfaces_validation_errors( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope( + "preview-event-block", + {"would_succeed": False, "validation_errors": ["Line items unbalanced"]}, + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.preview_event_block(graph_id, self._PREVIEW_BODY) + assert result["would_succeed"] is False + assert "unbalanced" in result["validation_errors"][0] + + @patch("robosystems_client.clients.ledger_client.op_update_event_block") + def test_update_event_block_status_transition(self, mock_op, mock_config, graph_id): + envelope = _envelope("update-event-block", {"id": "evt_1", "status": "committed"}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.update_event_block( + graph_id, {"event_id": "evt_1", "transition_to": "committed"} + ) + assert result["status"] == "committed" + body = mock_op.call_args.kwargs["body"] + assert body.event_id == "evt_1" + assert body.transition_to.value == "committed" + + @patch("robosystems_client.clients.ledger_client.op_update_event_block") + def test_update_event_block_supersede_with_successor( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope("update-event-block", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.update_event_block( + graph_id, + { + "event_id": "evt_1", + "transition_to": "superseded", + "superseded_by_id": "evt_2", + }, + ) + body = mock_op.call_args.kwargs["body"] + assert body.superseded_by_id == "evt_2" + + @patch("robosystems_client.clients.ledger_client.op_update_event_block") + def test_update_event_block_metadata_patch(self, mock_op, mock_config, graph_id): + envelope = _envelope("update-event-block", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.update_event_block( + graph_id, + { + "event_id": "evt_1", + "description": "Updated description", + "metadata_patch": {"reason": "duplicate"}, + }, + ) + body = mock_op.call_args.kwargs["body"] + assert body.description == "Updated description" + assert body.metadata_patch.to_dict() == {"reason": "duplicate"} + + +# ── Agents ──────────────────────────────────────────────────────────────── + + +@pytest.mark.unit +class TestAgentOps: + @patch("robosystems_client.clients.ledger_client.op_create_agent") + def test_create_agent_basic(self, mock_op, mock_config, graph_id): + envelope = _envelope( + "create-agent", {"id": "agt_1", "agent_type": "customer", "name": "ACME"} + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.create_agent(graph_id, {"agent_type": "customer", "name": "ACME"}) + assert result["id"] == "agt_1" + call_kwargs = mock_op.call_args.kwargs + assert call_kwargs["graph_id"] == graph_id + assert call_kwargs["idempotency_key"] is UNSET + body = call_kwargs["body"] + assert str(body.agent_type) == "customer" + assert body.name == "ACME" + + @patch("robosystems_client.clients.ledger_client.op_create_agent") + def test_create_agent_with_optional_fields(self, mock_op, mock_config, graph_id): + envelope = _envelope("create-agent", {"id": "agt_1"}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.create_agent( + graph_id, + { + "agent_type": "vendor", + "name": "Office Supplier", + "legal_name": "Office Supplier Inc.", + "tax_id": "12-3456789", + "email": "ap@supplier.com", + "is_1099_recipient": True, + "source": "quickbooks", + "external_id": "qb_vendor_42", + }, + ) + body = mock_op.call_args.kwargs["body"] + assert body.tax_id == "12-3456789" + assert body.is_1099_recipient is True + assert body.external_id == "qb_vendor_42" + + @patch("robosystems_client.clients.ledger_client.op_create_agent") + def test_create_agent_forwards_idempotency_key(self, mock_op, mock_config, graph_id): + envelope = _envelope("create-agent", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.create_agent( + graph_id, + {"agent_type": "customer", "name": "X"}, + idempotency_key="idem-agent-1", + ) + assert mock_op.call_args.kwargs["idempotency_key"] == "idem-agent-1" + + @patch("robosystems_client.clients.ledger_client.op_update_agent") + def test_update_agent_basic(self, mock_op, mock_config, graph_id): + envelope = _envelope("update-agent", {"id": "agt_1", "name": "New Name"}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.update_agent(graph_id, {"agent_id": "agt_1", "name": "New Name"}) + assert result["name"] == "New Name" + body = mock_op.call_args.kwargs["body"] + assert body.agent_id == "agt_1" + assert body.name == "New Name" + + @patch("robosystems_client.clients.ledger_client.op_update_agent") + def test_update_agent_metadata_patch(self, mock_op, mock_config, graph_id): + envelope = _envelope("update-agent", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.update_agent( + graph_id, + {"agent_id": "agt_1", "metadata_patch": {"region": "us-west"}}, + ) + body = mock_op.call_args.kwargs["body"] + assert body.metadata_patch.to_dict() == {"region": "us-west"} + + +# ── Event handlers ──────────────────────────────────────────────────────── + + +@pytest.mark.unit +class TestEventHandlerOps: + _HANDLER_BODY = { + "name": "Stripe charge -> revenue", + "event_type": "invoice_paid", + "event_category": "sales", + "match_source": "stripe", + "transaction_template": { + "transactions": [ + { + "entry_template": { + "debit": {"element_id": "elem_cash", "amount": "{{ event.amount }}"}, + "credit": { + "element_id": "elem_revenue", + "amount": "{{ event.amount }}", + }, + } + } + ] + }, + "priority": 100, + } + + @patch("robosystems_client.clients.ledger_client.op_create_event_handler") + def test_create_event_handler_returns_handler(self, mock_op, mock_config, graph_id): + envelope = _envelope( + "create-event-handler", + {"id": "eh_1", "name": self._HANDLER_BODY["name"]}, + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.create_event_handler(graph_id, self._HANDLER_BODY) + assert result["id"] == "eh_1" + body = mock_op.call_args.kwargs["body"] + assert body.event_type == "invoice_paid" + assert body.match_source == "stripe" + assert body.priority == 100 + + @patch("robosystems_client.clients.ledger_client.op_update_event_handler") + def test_update_event_handler_basic(self, mock_op, mock_config, graph_id): + envelope = _envelope("update-event-handler", {"id": "eh_1", "is_active": False}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.update_event_handler( + graph_id, {"event_handler_id": "eh_1", "is_active": False} + ) + assert result["is_active"] is False + body = mock_op.call_args.kwargs["body"] + assert body.event_handler_id == "eh_1" + assert body.is_active is False + + @patch("robosystems_client.clients.ledger_client.op_update_event_handler") + def test_update_event_handler_approve_flag(self, mock_op, mock_config, graph_id): + envelope = _envelope("update-event-handler", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.update_event_handler(graph_id, {"event_handler_id": "eh_1", "approve": True}) + body = mock_op.call_args.kwargs["body"] + assert body.approve is True + + +# ── Financial statements ────────────────────────────────────────────────── + + +@pytest.mark.unit +class TestFinancialStatementOps: + @patch("robosystems_client.clients.ledger_client.op_live_financial_statement") + def test_live_financial_statement_with_period_window( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope( + "live-financial-statement", + { + "statement_type": "income_statement", + "rows": [{"element": "us-gaap:Revenues", "value": 1000000}], + }, + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.live_financial_statement( + graph_id, + { + "statement_type": "income_statement", + "period_start": "2026-01-01", + "period_end": "2026-03-31", + }, + ) + assert result["statement_type"] == "income_statement" + body = mock_op.call_args.kwargs["body"] + assert str(body.statement_type) == "income_statement" + + @patch("robosystems_client.clients.ledger_client.op_live_financial_statement") + def test_live_financial_statement_with_fiscal_year( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope("live-financial-statement", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.live_financial_statement( + graph_id, + {"statement_type": "balance_sheet", "fiscal_year": 2026, "limit": 50}, + ) + body = mock_op.call_args.kwargs["body"] + assert body.fiscal_year == 2026 + assert body.limit == 50 + + @patch("robosystems_client.clients.ledger_client.op_financial_statement_analysis") + def test_financial_statement_analysis_with_report_id( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope( + "financial-statement-analysis", + { + "statement_type": "income_statement", + "analysis": {"gross_margin": 0.42}, + }, + ) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + result = client.financial_statement_analysis( + graph_id, + {"statement_type": "income_statement", "report_id": "rep_1"}, + ) + assert result["analysis"]["gross_margin"] == 0.42 + body = mock_op.call_args.kwargs["body"] + assert body.report_id == "rep_1" + + @patch("robosystems_client.clients.ledger_client.op_financial_statement_analysis") + def test_financial_statement_analysis_with_ticker( + self, mock_op, mock_config, graph_id + ): + envelope = _envelope("financial-statement-analysis", {}) + mock_op.return_value = _mock_response(envelope) + client = LedgerClient(mock_config) + client.financial_statement_analysis( + "sec", + { + "statement_type": "balance_sheet", + "ticker": "NVDA", + "fiscal_year": 2025, + }, + ) + body = mock_op.call_args.kwargs["body"] + assert body.ticker == "NVDA" + assert body.fiscal_year == 2025