diff --git a/robosystems_client/api/robo_ledger_ledger_events/record_deconsolidation.py b/robosystems_client/api/robo_ledger_ledger_events/record_deconsolidation.py new file mode 100644 index 0000000..5c8beb0 --- /dev/null +++ b/robosystems_client/api/robo_ledger_ledger_events/record_deconsolidation.py @@ -0,0 +1,314 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.operation_envelope_deconsolidation_response import ( + OperationEnvelopeDeconsolidationResponse, +) +from ...models.record_deconsolidation_request import RecordDeconsolidationRequest +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + graph_id: str, + *, + body: RecordDeconsolidationRequest, + 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/record-deconsolidation".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 +) -> ErrorResponse | OperationEnvelopeDeconsolidationResponse | None: + if response.status_code == 200: + response_200 = OperationEnvelopeDeconsolidationResponse.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 == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = ErrorResponse.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 | OperationEnvelopeDeconsolidationResponse]: + 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: RecordDeconsolidationRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelopeDeconsolidationResponse]: + """Record Deconsolidation + + Record a member's leaving the group, once `left_on` is set on it: what the parent received for its + shares in cents (0 for a dissolution) and the basis. It writes a draft in the consolidation entity, + dated the first day of the month after the member's last, that its close posts: what the + consolidation entity still holds for the member on its balance-sheet accounts and as the outside + owners' interest is taken off (goodwill, step-ups, the price above book of the investment, the + outside owners' accumulated share), a member in full has the results it earned in the group put back + into the group's equity as they leave with its books, and the difference is the gain or loss on its + leaving: the group's adjustment to the gain the parent's own books took, so the consolidated gain is + the consideration less the carrying amount of what left (ASC 810). The investment and intercompany + eliminations go back on their own in that month's proposals. The parent's own sale entry stays on + its books. Recording again replaces the draft; a posted deconsolidation is reversed first. A + retained interest is not supported yet. + + **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 (RecordDeconsolidationRequest): A member has left the group (`left_on` set): what the + parent received + for its shares, and the basis. The entry derecognizes what the + consolidation entity still holds for the member and takes the gain or + loss on its leaving; the parent's own sale entry stays on its books. + + 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 | OperationEnvelopeDeconsolidationResponse] + """ + + 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: RecordDeconsolidationRequest, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelopeDeconsolidationResponse | None: + """Record Deconsolidation + + Record a member's leaving the group, once `left_on` is set on it: what the parent received for its + shares in cents (0 for a dissolution) and the basis. It writes a draft in the consolidation entity, + dated the first day of the month after the member's last, that its close posts: what the + consolidation entity still holds for the member on its balance-sheet accounts and as the outside + owners' interest is taken off (goodwill, step-ups, the price above book of the investment, the + outside owners' accumulated share), a member in full has the results it earned in the group put back + into the group's equity as they leave with its books, and the difference is the gain or loss on its + leaving: the group's adjustment to the gain the parent's own books took, so the consolidated gain is + the consideration less the carrying amount of what left (ASC 810). The investment and intercompany + eliminations go back on their own in that month's proposals. The parent's own sale entry stays on + its books. Recording again replaces the draft; a posted deconsolidation is reversed first. A + retained interest is not supported yet. + + **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 (RecordDeconsolidationRequest): A member has left the group (`left_on` set): what the + parent received + for its shares, and the basis. The entry derecognizes what the + consolidation entity still holds for the member and takes the gain or + loss on its leaving; the parent's own sale entry stays on its books. + + 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 | OperationEnvelopeDeconsolidationResponse + """ + + 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: RecordDeconsolidationRequest, + idempotency_key: None | str | Unset = UNSET, +) -> Response[ErrorResponse | OperationEnvelopeDeconsolidationResponse]: + """Record Deconsolidation + + Record a member's leaving the group, once `left_on` is set on it: what the parent received for its + shares in cents (0 for a dissolution) and the basis. It writes a draft in the consolidation entity, + dated the first day of the month after the member's last, that its close posts: what the + consolidation entity still holds for the member on its balance-sheet accounts and as the outside + owners' interest is taken off (goodwill, step-ups, the price above book of the investment, the + outside owners' accumulated share), a member in full has the results it earned in the group put back + into the group's equity as they leave with its books, and the difference is the gain or loss on its + leaving: the group's adjustment to the gain the parent's own books took, so the consolidated gain is + the consideration less the carrying amount of what left (ASC 810). The investment and intercompany + eliminations go back on their own in that month's proposals. The parent's own sale entry stays on + its books. Recording again replaces the draft; a posted deconsolidation is reversed first. A + retained interest is not supported yet. + + **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 (RecordDeconsolidationRequest): A member has left the group (`left_on` set): what the + parent received + for its shares, and the basis. The entry derecognizes what the + consolidation entity still holds for the member and takes the gain or + loss on its leaving; the parent's own sale entry stays on its books. + + 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 | OperationEnvelopeDeconsolidationResponse] + """ + + 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: RecordDeconsolidationRequest, + idempotency_key: None | str | Unset = UNSET, +) -> ErrorResponse | OperationEnvelopeDeconsolidationResponse | None: + """Record Deconsolidation + + Record a member's leaving the group, once `left_on` is set on it: what the parent received for its + shares in cents (0 for a dissolution) and the basis. It writes a draft in the consolidation entity, + dated the first day of the month after the member's last, that its close posts: what the + consolidation entity still holds for the member on its balance-sheet accounts and as the outside + owners' interest is taken off (goodwill, step-ups, the price above book of the investment, the + outside owners' accumulated share), a member in full has the results it earned in the group put back + into the group's equity as they leave with its books, and the difference is the gain or loss on its + leaving: the group's adjustment to the gain the parent's own books took, so the consolidated gain is + the consideration less the carrying amount of what left (ASC 810). The investment and intercompany + eliminations go back on their own in that month's proposals. The parent's own sale entry stays on + its books. Recording again replaces the draft; a posted deconsolidation is reversed first. A + retained interest is not supported yet. + + **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 (RecordDeconsolidationRequest): A member has left the group (`left_on` set): what the + parent received + for its shares, and the basis. The entry derecognizes what the + consolidation entity still holds for the member and takes the gain or + loss on its leaving; the parent's own sale entry stays on its books. + + 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 | OperationEnvelopeDeconsolidationResponse + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + idempotency_key=idempotency_key, + ) + ).parsed diff --git a/robosystems_client/graphql/schema.graphql b/robosystems_client/graphql/schema.graphql index bfe7d4e..4e5fb02 100644 --- a/robosystems_client/graphql/schema.graphql +++ b/robosystems_client/graphql/schema.graphql @@ -1816,6 +1816,11 @@ type LedgerEntity { """ leftOn: Date + """ + True once the month this entity left the group is over: its months in the group are history, readable under it, and it is no longer current. False for a member still in, and through the month it leaves. + """ + isFormer: Boolean! + """Provenance: 'native' | 'sec' | 'quickbooks' | 'xero' | 'plaid'.""" source: String! diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 15ce9c2..fbdb1d8 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -179,6 +179,7 @@ from .database_health_response import DatabaseHealthResponse from .database_info_response import DatabaseInfoResponse from .database_storage_entry import DatabaseStorageEntry +from .deconsolidation_response import DeconsolidationResponse from .delete_connection_disposition import DeleteConnectionDisposition from .delete_document_op import DeleteDocumentOp from .delete_file_op import DeleteFileOp @@ -202,6 +203,7 @@ from .delete_subgraph_op import DeleteSubgraphOp from .delete_taxonomy_block_request import DeleteTaxonomyBlockRequest from .delete_taxonomy_block_response import DeleteTaxonomyBlockResponse +from .derecognized_balance import DerecognizedBalance from .describe_filing_request import DescribeFilingRequest from .describe_filing_response import DescribeFilingResponse from .describe_filing_response_counts_type_0 import DescribeFilingResponseCountsType0 @@ -552,6 +554,12 @@ from .operation_envelope_consolidation_worksheet_response_status import ( OperationEnvelopeConsolidationWorksheetResponseStatus, ) +from .operation_envelope_deconsolidation_response import ( + OperationEnvelopeDeconsolidationResponse, +) +from .operation_envelope_deconsolidation_response_status import ( + OperationEnvelopeDeconsolidationResponseStatus, +) from .operation_envelope_delete_information_block_response import ( OperationEnvelopeDeleteInformationBlockResponse, ) @@ -961,6 +969,7 @@ ) from .reconciling_item_regenerated import ReconcilingItemRegenerated from .record_acquisition_request import RecordAcquisitionRequest +from .record_deconsolidation_request import RecordDeconsolidationRequest from .record_opening_balance_request import RecordOpeningBalanceRequest from .record_ownership_change_request import RecordOwnershipChangeRequest from .record_statement_balance_request import RecordStatementBalanceRequest @@ -1388,6 +1397,7 @@ "DatabaseHealthResponse", "DatabaseInfoResponse", "DatabaseStorageEntry", + "DeconsolidationResponse", "DeleteConnectionDisposition", "DeleteDocumentOp", "DeleteFileOp", @@ -1411,6 +1421,7 @@ "DeleteSubgraphOp", "DeleteTaxonomyBlockRequest", "DeleteTaxonomyBlockResponse", + "DerecognizedBalance", "DescribeFilingRequest", "DescribeFilingResponse", "DescribeFilingResponseCountsType0", @@ -1647,6 +1658,8 @@ "OperationEnvelopeComputeMetricsResponseStatus", "OperationEnvelopeConsolidationWorksheetResponse", "OperationEnvelopeConsolidationWorksheetResponseStatus", + "OperationEnvelopeDeconsolidationResponse", + "OperationEnvelopeDeconsolidationResponseStatus", "OperationEnvelopeDeleteInformationBlockResponse", "OperationEnvelopeDeleteInformationBlockResponseStatus", "OperationEnvelopeDeletePortfolioBlockResponse", @@ -1858,6 +1871,7 @@ "ReconcilingItemPlanDefaultDisposition", "ReconcilingItemRegenerated", "RecordAcquisitionRequest", + "RecordDeconsolidationRequest", "RecordOpeningBalanceRequest", "RecordOwnershipChangeRequest", "RecordStatementBalanceRequest", diff --git a/robosystems_client/models/deconsolidation_response.py b/robosystems_client/models/deconsolidation_response.py new file mode 100644 index 0000000..571df2a --- /dev/null +++ b/robosystems_client/models/deconsolidation_response.py @@ -0,0 +1,166 @@ +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 ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.derecognized_balance import DerecognizedBalance + from ..models.journal_entry_response import JournalEntryResponse + + +T = TypeVar("T", bound="DeconsolidationResponse") + + +@_attrs_define +class DeconsolidationResponse: + """A member's leaving as recorded: the draft in the consolidation entity + its close posts, dated the first day of the month after the member's + last. + + Attributes: + entity_id (str): The member that left. + entity_name (str): The member's name. + left_on (datetime.date): The day it left, as the entity records. + period (str): The month the entry is dated in, as YYYY-MM: the first the group reads without the member. + consideration (int): Cents the parent received. + gain_loss (int): Cents, a gain positive: the group's adjustment to the parent's own gain or loss on the sale, so + the consolidated gain is the consideration less the carrying amount of what left (ASC 810). + entry (JournalEntryResponse): The common response shape for journal entry write operations. + derecognized (list[DerecognizedBalance] | Unset): What the consolidation entity held for the member beyond the + eliminations its leaving reverses on their own, each taken off. + earnings_restored (int | Unset): Cents: the member's results since it joined, credited to the group's equity as + they leave with its books; they were the group's income. Zero for an equity-method member, whose books were + never summed. Default: 0. + replaced (bool | Unset): True when it replaced an earlier draft of the deconsolidation. Default: False. + """ + + entity_id: str + entity_name: str + left_on: datetime.date + period: str + consideration: int + gain_loss: int + entry: JournalEntryResponse + derecognized: list[DerecognizedBalance] | Unset = UNSET + earnings_restored: int | Unset = 0 + replaced: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + entity_name = self.entity_name + + left_on = self.left_on.isoformat() + + period = self.period + + consideration = self.consideration + + gain_loss = self.gain_loss + + entry = self.entry.to_dict() + + derecognized: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.derecognized, Unset): + derecognized = [] + for derecognized_item_data in self.derecognized: + derecognized_item = derecognized_item_data.to_dict() + derecognized.append(derecognized_item) + + earnings_restored = self.earnings_restored + + replaced = self.replaced + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "entity_name": entity_name, + "left_on": left_on, + "period": period, + "consideration": consideration, + "gain_loss": gain_loss, + "entry": entry, + } + ) + if derecognized is not UNSET: + field_dict["derecognized"] = derecognized + if earnings_restored is not UNSET: + field_dict["earnings_restored"] = earnings_restored + if replaced is not UNSET: + field_dict["replaced"] = replaced + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.derecognized_balance import DerecognizedBalance + from ..models.journal_entry_response import JournalEntryResponse + + d = dict(src_dict) + entity_id = d.pop("entity_id") + + entity_name = d.pop("entity_name") + + left_on = datetime.date.fromisoformat(d.pop("left_on")) + + period = d.pop("period") + + consideration = d.pop("consideration") + + gain_loss = d.pop("gain_loss") + + entry = JournalEntryResponse.from_dict(d.pop("entry")) + + _derecognized = d.pop("derecognized", UNSET) + derecognized: list[DerecognizedBalance] | Unset = UNSET + if _derecognized is not UNSET: + derecognized = [] + for derecognized_item_data in _derecognized: + derecognized_item = DerecognizedBalance.from_dict(derecognized_item_data) + + derecognized.append(derecognized_item) + + earnings_restored = d.pop("earnings_restored", UNSET) + + replaced = d.pop("replaced", UNSET) + + deconsolidation_response = cls( + entity_id=entity_id, + entity_name=entity_name, + left_on=left_on, + period=period, + consideration=consideration, + gain_loss=gain_loss, + entry=entry, + derecognized=derecognized, + earnings_restored=earnings_restored, + replaced=replaced, + ) + + deconsolidation_response.additional_properties = d + return deconsolidation_response + + @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/derecognized_balance.py b/robosystems_client/models/derecognized_balance.py new file mode 100644 index 0000000..7c34865 --- /dev/null +++ b/robosystems_client/models/derecognized_balance.py @@ -0,0 +1,72 @@ +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="DerecognizedBalance") + + +@_attrs_define +class DerecognizedBalance: + """A balance the consolidation entity held for a member that left, taken + off by the deconsolidation. + + Attributes: + concept (str): The rs-gaap concept. + amount (int): Cents as held: positive a debit (goodwill, a step-up), negative a credit (the outside owners' + interest, the price above book of the parent's investment). + """ + + concept: str + amount: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + concept = self.concept + + amount = self.amount + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "concept": concept, + "amount": amount, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + concept = d.pop("concept") + + amount = d.pop("amount") + + derecognized_balance = cls( + concept=concept, + amount=amount, + ) + + derecognized_balance.additional_properties = d + return derecognized_balance + + @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/ledger_entity_response.py b/robosystems_client/models/ledger_entity_response.py index 5c45c11..bd478e6 100644 --- a/robosystems_client/models/ledger_entity_response.py +++ b/robosystems_client/models/ledger_entity_response.py @@ -66,6 +66,9 @@ class LedgerEntityResponse: member still. The consolidated statements include it through that month and leave it out after. Membership is by month: a period column wider than a month that overlaps the interval is summed whole, so a member's books in this graph should hold only the months it belonged. + is_former (bool | Unset): True once the month this entity left the group is over: its months in the group are + history, readable under it, and it is no longer current. False for a member still in, and through the month it + leaves. Default: False. source (str | Unset): Provenance: 'native' | 'sec' | 'quickbooks' | 'xero' | 'plaid'. Default: 'native'. source_id (None | str | Unset): Source-system primary key for sync reconciliation. source_graph_id (None | str | Unset): Origin graph for received entities (cross-graph linking, e.g. RoboInvestor @@ -107,6 +110,7 @@ class LedgerEntityResponse: entity_role: str | Unset = "operating" joined_on: datetime.date | None | Unset = UNSET left_on: datetime.date | None | Unset = UNSET + is_former: bool | Unset = False source: str | Unset = "native" source_id: None | str | Unset = UNSET source_graph_id: None | str | Unset = UNSET @@ -263,6 +267,8 @@ def to_dict(self) -> dict[str, Any]: else: left_on = self.left_on + is_former = self.is_former + source = self.source source_id: None | str | Unset @@ -383,6 +389,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["joined_on"] = joined_on if left_on is not UNSET: field_dict["left_on"] = left_on + if is_former is not UNSET: + field_dict["is_former"] = is_former if source is not UNSET: field_dict["source"] = source if source_id is not UNSET: @@ -630,6 +638,8 @@ def _parse_left_on(data: object) -> datetime.date | None | Unset: left_on = _parse_left_on(d.pop("left_on", UNSET)) + is_former = d.pop("is_former", UNSET) + source = d.pop("source", UNSET) def _parse_source_id(data: object) -> None | str | Unset: @@ -752,6 +762,7 @@ def _parse_updated_at(data: object) -> None | str | Unset: entity_role=entity_role, joined_on=joined_on, left_on=left_on, + is_former=is_former, source=source, source_id=source_id, source_graph_id=source_graph_id, diff --git a/robosystems_client/models/operation_envelope_deconsolidation_response.py b/robosystems_client/models/operation_envelope_deconsolidation_response.py new file mode 100644 index 0000000..3c94e2b --- /dev/null +++ b/robosystems_client/models/operation_envelope_deconsolidation_response.py @@ -0,0 +1,158 @@ +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.operation_envelope_deconsolidation_response_status import ( + OperationEnvelopeDeconsolidationResponseStatus, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.deconsolidation_response import DeconsolidationResponse + + +T = TypeVar("T", bound="OperationEnvelopeDeconsolidationResponse") + + +@_attrs_define +class OperationEnvelopeDeconsolidationResponse: + """ + Attributes: + operation (str): Kebab-case operation name + operation_id (str): op_-prefixed ULID for audit and SSE correlation + status (OperationEnvelopeDeconsolidationResponseStatus): Operation lifecycle state + at (str): ISO-8601 UTC timestamp + result (DeconsolidationResponse | None | Unset): Command-specific result payload + created_by (None | str | Unset): User ID that initiated the operation + idempotent_replay (bool | Unset): True when this envelope came from the idempotency cache — the underlying + command did not execute again. False on fresh executions. Default: False. + """ + + operation: str + operation_id: str + status: OperationEnvelopeDeconsolidationResponseStatus + at: str + result: DeconsolidationResponse | None | Unset = UNSET + created_by: None | str | Unset = UNSET + idempotent_replay: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.deconsolidation_response import DeconsolidationResponse + + operation = self.operation + + operation_id = self.operation_id + + status = self.status.value + + at = self.at + + result: dict[str, Any] | None | Unset + if isinstance(self.result, Unset): + result = UNSET + elif isinstance(self.result, DeconsolidationResponse): + result = self.result.to_dict() + else: + result = self.result + + created_by: None | str | Unset + if isinstance(self.created_by, Unset): + created_by = UNSET + else: + created_by = self.created_by + + idempotent_replay = self.idempotent_replay + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "operation": operation, + "operationId": operation_id, + "status": status, + "at": at, + } + ) + if result is not UNSET: + field_dict["result"] = result + if created_by is not UNSET: + field_dict["createdBy"] = created_by + if idempotent_replay is not UNSET: + field_dict["idempotentReplay"] = idempotent_replay + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.deconsolidation_response import DeconsolidationResponse + + d = dict(src_dict) + operation = d.pop("operation") + + operation_id = d.pop("operationId") + + status = OperationEnvelopeDeconsolidationResponseStatus(d.pop("status")) + + at = d.pop("at") + + def _parse_result(data: object) -> DeconsolidationResponse | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + result_type_0 = DeconsolidationResponse.from_dict(data) + + return result_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(DeconsolidationResponse | None | Unset, data) + + result = _parse_result(d.pop("result", UNSET)) + + def _parse_created_by(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + created_by = _parse_created_by(d.pop("createdBy", UNSET)) + + idempotent_replay = d.pop("idempotentReplay", UNSET) + + operation_envelope_deconsolidation_response = cls( + operation=operation, + operation_id=operation_id, + status=status, + at=at, + result=result, + created_by=created_by, + idempotent_replay=idempotent_replay, + ) + + operation_envelope_deconsolidation_response.additional_properties = d + return operation_envelope_deconsolidation_response + + @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/operation_envelope_deconsolidation_response_status.py b/robosystems_client/models/operation_envelope_deconsolidation_response_status.py new file mode 100644 index 0000000..6669b42 --- /dev/null +++ b/robosystems_client/models/operation_envelope_deconsolidation_response_status.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class OperationEnvelopeDeconsolidationResponseStatus(str, Enum): + COMPLETED = "completed" + FAILED = "failed" + PENDING = "pending" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/ownership_change_response.py b/robosystems_client/models/ownership_change_response.py index e1ceb10..58f88ae 100644 --- a/robosystems_client/models/ownership_change_response.py +++ b/robosystems_client/models/ownership_change_response.py @@ -34,6 +34,8 @@ class OwnershipChangeResponse: equity_adjustment (int): Cents taken from the parent's equity: the price above the carrying amount of what was bought (negative when it paid less). entry (JournalEntryResponse): The common response shape for journal entry write operations. + premium_transferred (int | Unset): Cents: the share bought of the outside owners' interest beyond their share of + book value (from the acquisition at fair value, or its step-ups), moved to the parent. Default: 0. replaced (bool | Unset): True when it replaced an earlier draft for the month. Default: False. """ @@ -47,6 +49,7 @@ class OwnershipChangeResponse: earnings_transferred: int equity_adjustment: int entry: JournalEntryResponse + premium_transferred: int | Unset = 0 replaced: bool | Unset = False additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -71,6 +74,8 @@ def to_dict(self) -> dict[str, Any]: entry = self.entry.to_dict() + premium_transferred = self.premium_transferred + replaced = self.replaced field_dict: dict[str, Any] = {} @@ -89,6 +94,8 @@ def to_dict(self) -> dict[str, Any]: "entry": entry, } ) + if premium_transferred is not UNSET: + field_dict["premium_transferred"] = premium_transferred if replaced is not UNSET: field_dict["replaced"] = replaced @@ -119,6 +126,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: entry = JournalEntryResponse.from_dict(d.pop("entry")) + premium_transferred = d.pop("premium_transferred", UNSET) + replaced = d.pop("replaced", UNSET) ownership_change_response = cls( @@ -132,6 +141,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: earnings_transferred=earnings_transferred, equity_adjustment=equity_adjustment, entry=entry, + premium_transferred=premium_transferred, replaced=replaced, ) diff --git a/robosystems_client/models/record_deconsolidation_request.py b/robosystems_client/models/record_deconsolidation_request.py new file mode 100644 index 0000000..2f8ab70 --- /dev/null +++ b/robosystems_client/models/record_deconsolidation_request.py @@ -0,0 +1,83 @@ +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="RecordDeconsolidationRequest") + + +@_attrs_define +class RecordDeconsolidationRequest: + """A member has left the group (`left_on` set): what the parent received + for its shares, and the basis. The entry derecognizes what the + consolidation entity still holds for the member and takes the gain or + loss on its leaving; the parent's own sale entry stays on its books. + + Attributes: + entity_id (str): The member that left: its `left_on` is set. + consideration (int): Cents the parent received for its shares; 0 for a dissolution or an abandonment. Recorded + with the entry for the record: the parent's own books hold the sale, cash against its investment and its own + gain or loss, which this entry adjusts to the group's. + basis (str): The sale agreement, the dissolution, or what sets the price. + """ + + entity_id: str + consideration: int + basis: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + consideration = self.consideration + + basis = self.basis + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "consideration": consideration, + "basis": basis, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + entity_id = d.pop("entity_id") + + consideration = d.pop("consideration") + + basis = d.pop("basis") + + record_deconsolidation_request = cls( + entity_id=entity_id, + consideration=consideration, + basis=basis, + ) + + record_deconsolidation_request.additional_properties = d + return record_deconsolidation_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