From 33368dcb94ac9719150ecfe3658870ca6d265dab Mon Sep 17 00:00:00 2001 From: "Joseph T. French" Date: Mon, 5 Oct 2026 21:24:32 -0500 Subject: [PATCH] feat: add setSelectedGraph and mark selectGraph deprecated Regenerated from robosystems#1706: PUT /v1/user/selected-graph under the User tag, the graph-scoped select deprecated. Drift since the last regeneration is docstring-only. --- robosystems_client/api/graphs/select_graph.py | 12 + .../api/operations/stream_operation_events.py | 20 +- .../execute_event_block.py | 88 ++++---- .../api/user/set_selected_graph.py | 213 ++++++++++++++++++ robosystems_client/graphql/schema.graphql | 2 +- robosystems_client/models/__init__.py | 2 + .../models/execute_event_block_request.py | 11 +- .../models/fiscal_calendar_response.py | 2 +- .../models/set_selected_graph_request.py | 62 +++++ 9 files changed, 357 insertions(+), 55 deletions(-) create mode 100644 robosystems_client/api/user/set_selected_graph.py create mode 100644 robosystems_client/models/set_selected_graph_request.py diff --git a/robosystems_client/api/graphs/select_graph.py b/robosystems_client/api/graphs/select_graph.py index 95930f2a..b24d2039 100644 --- a/robosystems_client/api/graphs/select_graph.py +++ b/robosystems_client/api/graphs/select_graph.py @@ -93,6 +93,9 @@ def sync_detailed( ) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: """Select Graph + Deprecated: use `PUT /v1/user/selected-graph`, which writes the same selection. Remembers the graph + as the caller's current one. + Args: graph_id (str): @@ -122,6 +125,9 @@ def sync( ) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: """Select Graph + Deprecated: use `PUT /v1/user/selected-graph`, which writes the same selection. Remembers the graph + as the caller's current one. + Args: graph_id (str): @@ -146,6 +152,9 @@ async def asyncio_detailed( ) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: """Select Graph + Deprecated: use `PUT /v1/user/selected-graph`, which writes the same selection. Remembers the graph + as the caller's current one. + Args: graph_id (str): @@ -173,6 +182,9 @@ async def asyncio( ) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: """Select Graph + Deprecated: use `PUT /v1/user/selected-graph`, which writes the same selection. Remembers the graph + as the caller's current one. + Args: graph_id (str): diff --git a/robosystems_client/api/operations/stream_operation_events.py b/robosystems_client/api/operations/stream_operation_events.py index fc616118..3d6c6c5d 100644 --- a/robosystems_client/api/operations/stream_operation_events.py +++ b/robosystems_client/api/operations/stream_operation_events.py @@ -121,8 +121,9 @@ def sync_detailed( Args: operation_id (str): Operation identifier from initial submission - from_sequence (int | Unset): Start streaming from this sequence number (0 = from - beginning) Default: 0. + from_sequence (int | Unset): Replay stored events from this sequence number, then stream + live ones. A running operation replays nothing at 0 (live events only); a settled one + replays its history from here (0 = all) and closes. Default: 0. token (None | str | Unset): JWT token for SSE authentication authorization (None | str | Unset): @@ -163,8 +164,9 @@ def sync( Args: operation_id (str): Operation identifier from initial submission - from_sequence (int | Unset): Start streaming from this sequence number (0 = from - beginning) Default: 0. + from_sequence (int | Unset): Replay stored events from this sequence number, then stream + live ones. A running operation replays nothing at 0 (live events only); a settled one + replays its history from here (0 = all) and closes. Default: 0. token (None | str | Unset): JWT token for SSE authentication authorization (None | str | Unset): @@ -200,8 +202,9 @@ async def asyncio_detailed( Args: operation_id (str): Operation identifier from initial submission - from_sequence (int | Unset): Start streaming from this sequence number (0 = from - beginning) Default: 0. + from_sequence (int | Unset): Replay stored events from this sequence number, then stream + live ones. A running operation replays nothing at 0 (live events only); a settled one + replays its history from here (0 = all) and closes. Default: 0. token (None | str | Unset): JWT token for SSE authentication authorization (None | str | Unset): @@ -240,8 +243,9 @@ async def asyncio( Args: operation_id (str): Operation identifier from initial submission - from_sequence (int | Unset): Start streaming from this sequence number (0 = from - beginning) Default: 0. + from_sequence (int | Unset): Replay stored events from this sequence number, then stream + live ones. A running operation replays nothing at 0 (live events only); a settled one + replays its history from here (0 = all) and closes. Default: 0. token (None | str | Unset): JWT token for SSE authentication authorization (None | str | Unset): diff --git a/robosystems_client/api/robo_ledger_ledger_events/execute_event_block.py b/robosystems_client/api/robo_ledger_ledger_events/execute_event_block.py index 5598c1c5..40eee223 100644 --- a/robosystems_client/api/robo_ledger_ledger_events/execute_event_block.py +++ b/robosystems_client/api/robo_ledger_ledger_events/execute_event_block.py @@ -113,11 +113,12 @@ def sync_detailed( ) -> Response[ErrorResponse | OperationEnvelopeExecuteEventBlockResponse]: """Execute Event Block - For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the captured GL - plan to the source-of-truth system (QuickBooks). Captures qb_txn_id on - event.metadata.qb_external_id, transitions status to 'fulfilled' (or 'pending' on rejection), and - promotes draft GL rows to 'posted'. Native-policy events fast-path through with no QB write — - RoboSystems is the system of record. + For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the event's + draft GL entries to the source-of-truth system (QuickBooks), each as its own JournalEntry. Records + the QuickBooks ids per entry on event.metadata.qb_entry_ids and promotes the published entries to + 'posted'; the event goes 'fulfilled' once no draft remains, or 'pending' on rejection (what landed + is kept). Native-policy events fast-path through with no QB write — RoboSystems is the system of + record. **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. @@ -129,11 +130,12 @@ def sync_detailed( system. For events on a connection with `write_policy='qb_authoritative'` - (or `'hybrid'`), this triggers a synchronous write to QuickBooks - via the QB API. The returned `qb_txn_id` lands on - `event.metadata.qb_external_id` and the event transitions to - `committed` (in flight) → `fulfilled` (QB accepted) or `pending` - (QB rejected). + (or `'hybrid'`), this triggers a synchronous write to QuickBooks: + each draft entry posts as its own JournalEntry, with the entry id as + the RequestId, and its QuickBooks id is recorded per entry on + `event.metadata.qb_entry_ids`. The event goes `fulfilled` once no + draft remains, or `pending` when QuickBooks rejects an entry (what + landed is kept). `'native'`-policy events fast-path through with no QB write — RoboSystems IS the source of truth, no outbound publish needed. @@ -168,11 +170,12 @@ def sync( ) -> ErrorResponse | OperationEnvelopeExecuteEventBlockResponse | None: """Execute Event Block - For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the captured GL - plan to the source-of-truth system (QuickBooks). Captures qb_txn_id on - event.metadata.qb_external_id, transitions status to 'fulfilled' (or 'pending' on rejection), and - promotes draft GL rows to 'posted'. Native-policy events fast-path through with no QB write — - RoboSystems is the system of record. + For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the event's + draft GL entries to the source-of-truth system (QuickBooks), each as its own JournalEntry. Records + the QuickBooks ids per entry on event.metadata.qb_entry_ids and promotes the published entries to + 'posted'; the event goes 'fulfilled' once no draft remains, or 'pending' on rejection (what landed + is kept). Native-policy events fast-path through with no QB write — RoboSystems is the system of + record. **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. @@ -184,11 +187,12 @@ def sync( system. For events on a connection with `write_policy='qb_authoritative'` - (or `'hybrid'`), this triggers a synchronous write to QuickBooks - via the QB API. The returned `qb_txn_id` lands on - `event.metadata.qb_external_id` and the event transitions to - `committed` (in flight) → `fulfilled` (QB accepted) or `pending` - (QB rejected). + (or `'hybrid'`), this triggers a synchronous write to QuickBooks: + each draft entry posts as its own JournalEntry, with the entry id as + the RequestId, and its QuickBooks id is recorded per entry on + `event.metadata.qb_entry_ids`. The event goes `fulfilled` once no + draft remains, or `pending` when QuickBooks rejects an entry (what + landed is kept). `'native'`-policy events fast-path through with no QB write — RoboSystems IS the source of truth, no outbound publish needed. @@ -218,11 +222,12 @@ async def asyncio_detailed( ) -> Response[ErrorResponse | OperationEnvelopeExecuteEventBlockResponse]: """Execute Event Block - For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the captured GL - plan to the source-of-truth system (QuickBooks). Captures qb_txn_id on - event.metadata.qb_external_id, transitions status to 'fulfilled' (or 'pending' on rejection), and - promotes draft GL rows to 'posted'. Native-policy events fast-path through with no QB write — - RoboSystems is the system of record. + For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the event's + draft GL entries to the source-of-truth system (QuickBooks), each as its own JournalEntry. Records + the QuickBooks ids per entry on event.metadata.qb_entry_ids and promotes the published entries to + 'posted'; the event goes 'fulfilled' once no draft remains, or 'pending' on rejection (what landed + is kept). Native-policy events fast-path through with no QB write — RoboSystems is the system of + record. **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. @@ -234,11 +239,12 @@ async def asyncio_detailed( system. For events on a connection with `write_policy='qb_authoritative'` - (or `'hybrid'`), this triggers a synchronous write to QuickBooks - via the QB API. The returned `qb_txn_id` lands on - `event.metadata.qb_external_id` and the event transitions to - `committed` (in flight) → `fulfilled` (QB accepted) or `pending` - (QB rejected). + (or `'hybrid'`), this triggers a synchronous write to QuickBooks: + each draft entry posts as its own JournalEntry, with the entry id as + the RequestId, and its QuickBooks id is recorded per entry on + `event.metadata.qb_entry_ids`. The event goes `fulfilled` once no + draft remains, or `pending` when QuickBooks rejects an entry (what + landed is kept). `'native'`-policy events fast-path through with no QB write — RoboSystems IS the source of truth, no outbound publish needed. @@ -271,11 +277,12 @@ async def asyncio( ) -> ErrorResponse | OperationEnvelopeExecuteEventBlockResponse | None: """Execute Event Block - For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the captured GL - plan to the source-of-truth system (QuickBooks). Captures qb_txn_id on - event.metadata.qb_external_id, transitions status to 'fulfilled' (or 'pending' on rejection), and - promotes draft GL rows to 'posted'. Native-policy events fast-path through with no QB write — - RoboSystems is the system of record. + For events on a connection with write_policy='qb_authoritative' or 'hybrid', publish the event's + draft GL entries to the source-of-truth system (QuickBooks), each as its own JournalEntry. Records + the QuickBooks ids per entry on event.metadata.qb_entry_ids and promotes the published entries to + 'posted'; the event goes 'fulfilled' once no draft remains, or 'pending' on rejection (what landed + is kept). Native-policy events fast-path through with no QB write — RoboSystems is the system of + record. **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. @@ -287,11 +294,12 @@ async def asyncio( system. For events on a connection with `write_policy='qb_authoritative'` - (or `'hybrid'`), this triggers a synchronous write to QuickBooks - via the QB API. The returned `qb_txn_id` lands on - `event.metadata.qb_external_id` and the event transitions to - `committed` (in flight) → `fulfilled` (QB accepted) or `pending` - (QB rejected). + (or `'hybrid'`), this triggers a synchronous write to QuickBooks: + each draft entry posts as its own JournalEntry, with the entry id as + the RequestId, and its QuickBooks id is recorded per entry on + `event.metadata.qb_entry_ids`. The event goes `fulfilled` once no + draft remains, or `pending` when QuickBooks rejects an entry (what + landed is kept). `'native'`-policy events fast-path through with no QB write — RoboSystems IS the source of truth, no outbound publish needed. diff --git a/robosystems_client/api/user/set_selected_graph.py b/robosystems_client/api/user/set_selected_graph.py new file mode 100644 index 00000000..aa92d7e8 --- /dev/null +++ b/robosystems_client/api/user/set_selected_graph.py @@ -0,0 +1,213 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.set_selected_graph_request import SetSelectedGraphRequest +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + *, + body: SetSelectedGraphRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/v1/user/selected-graph", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + 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[ErrorResponse | HTTPValidationError | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, + body: SetSelectedGraphRequest, +) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: + """Set Selected Graph + + Remembers the graph as the caller's current one: `GET /v1/graphs` then reports it as + `selectedGraphId`, and the apps open on it. One graph per user, replacing the previous selection. + Only a graph the caller belongs to can be selected; shared repositories cannot be. + + Args: + body (SetSelectedGraphRequest): Request model for setting the user's selected graph. + + 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[ErrorResponse | HTTPValidationError | SuccessResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, + body: SetSelectedGraphRequest, +) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: + """Set Selected Graph + + Remembers the graph as the caller's current one: `GET /v1/graphs` then reports it as + `selectedGraphId`, and the apps open on it. One graph per user, replacing the previous selection. + Only a graph the caller belongs to can be selected; shared repositories cannot be. + + Args: + body (SetSelectedGraphRequest): Request model for setting the user's selected graph. + + 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: + ErrorResponse | HTTPValidationError | SuccessResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + body: SetSelectedGraphRequest, +) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: + """Set Selected Graph + + Remembers the graph as the caller's current one: `GET /v1/graphs` then reports it as + `selectedGraphId`, and the apps open on it. One graph per user, replacing the previous selection. + Only a graph the caller belongs to can be selected; shared repositories cannot be. + + Args: + body (SetSelectedGraphRequest): Request model for setting the user's selected graph. + + 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[ErrorResponse | HTTPValidationError | SuccessResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, + body: SetSelectedGraphRequest, +) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: + """Set Selected Graph + + Remembers the graph as the caller's current one: `GET /v1/graphs` then reports it as + `selectedGraphId`, and the apps open on it. One graph per user, replacing the previous selection. + Only a graph the caller belongs to can be selected; shared repositories cannot be. + + Args: + body (SetSelectedGraphRequest): Request model for setting the user's selected graph. + + 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: + ErrorResponse | HTTPValidationError | SuccessResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/graphql/schema.graphql b/robosystems_client/graphql/schema.graphql index 372b3c2b..134b868a 100644 --- a/robosystems_client/graphql/schema.graphql +++ b/robosystems_client/graphql/schema.graphql @@ -2319,7 +2319,7 @@ type FiscalCalendar { closeableNow: Boolean! """ - Structured blocker codes when closeable_now is False: 'sequence_violation', 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations', 'stranded_obligations' + Structured blocker codes when closeable_now is False: 'sequence_violation', 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations', 'stranded_obligations', 'reconciling_items', 'unposted_source_events', 'unreconciled_accounts' """ blockers: [String!]! diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 304928ac..2dff6541 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -933,6 +933,7 @@ from .service_offerings_response import ServiceOfferingsResponse from .set_close_target_operation import SetCloseTargetOperation from .set_reconciliation_policy_request import SetReconciliationPolicyRequest +from .set_selected_graph_request import SetSelectedGraphRequest from .set_write_policy_request import SetWritePolicyRequest from .set_write_policy_request_write_policy import SetWritePolicyRequestWritePolicy from .share_report_operation import ShareReportOperation @@ -1721,6 +1722,7 @@ "ServiceOfferingSummary", "SetCloseTargetOperation", "SetReconciliationPolicyRequest", + "SetSelectedGraphRequest", "SetWritePolicyRequest", "SetWritePolicyRequestWritePolicy", "ShareReportOperation", diff --git a/robosystems_client/models/execute_event_block_request.py b/robosystems_client/models/execute_event_block_request.py index 2f0e2ed0..be59c16f 100644 --- a/robosystems_client/models/execute_event_block_request.py +++ b/robosystems_client/models/execute_event_block_request.py @@ -16,11 +16,12 @@ class ExecuteEventBlockRequest: """Request to publish an event to the source-of-truth system. For events on a connection with `write_policy='qb_authoritative'` - (or `'hybrid'`), this triggers a synchronous write to QuickBooks - via the QB API. The returned `qb_txn_id` lands on - `event.metadata.qb_external_id` and the event transitions to - `committed` (in flight) → `fulfilled` (QB accepted) or `pending` - (QB rejected). + (or `'hybrid'`), this triggers a synchronous write to QuickBooks: + each draft entry posts as its own JournalEntry, with the entry id as + the RequestId, and its QuickBooks id is recorded per entry on + `event.metadata.qb_entry_ids`. The event goes `fulfilled` once no + draft remains, or `pending` when QuickBooks rejects an entry (what + landed is kept). `'native'`-policy events fast-path through with no QB write — RoboSystems IS the source of truth, no outbound publish needed. diff --git a/robosystems_client/models/fiscal_calendar_response.py b/robosystems_client/models/fiscal_calendar_response.py index c51e0985..73232a26 100644 --- a/robosystems_client/models/fiscal_calendar_response.py +++ b/robosystems_client/models/fiscal_calendar_response.py @@ -35,7 +35,7 @@ class FiscalCalendarResponse: Default: False. blockers (list[str] | Unset): Structured blocker codes when closeable_now is False: 'sequence_violation', 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations', - 'stranded_obligations' + 'stranded_obligations', 'reconciling_items', 'unposted_source_events', 'unreconciled_accounts' pending_obligation_count (int | Unset): Number of pending schedule_entry_due events blocking close. Non-zero only when `pending_obligations` is in `blockers`. Default: 0. pending_obligation_sample (list[PendingObligationDetailResponse] | Unset): Sample of up to 5 pending obligations diff --git a/robosystems_client/models/set_selected_graph_request.py b/robosystems_client/models/set_selected_graph_request.py new file mode 100644 index 00000000..7a314eb1 --- /dev/null +++ b/robosystems_client/models/set_selected_graph_request.py @@ -0,0 +1,62 @@ +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="SetSelectedGraphRequest") + + +@_attrs_define +class SetSelectedGraphRequest: + """Request model for setting the user's selected graph. + + Attributes: + graph_id (str): The graph the apps open on the caller's next load + """ + + graph_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + graph_id = self.graph_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "graph_id": graph_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + graph_id = d.pop("graph_id") + + set_selected_graph_request = cls( + graph_id=graph_id, + ) + + set_selected_graph_request.additional_properties = d + return set_selected_graph_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