783 lines
20 KiB
Python
783 lines
20 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date, datetime
|
|
from decimal import Decimal
|
|
from typing import Any
|
|
|
|
from mousehold_domain import (
|
|
AccountType,
|
|
EventObservationRelation,
|
|
FinancialEventStatus,
|
|
FinancialEventType,
|
|
ImportConnectionStatus,
|
|
ImportConnectionType,
|
|
ObservationStatus,
|
|
PaymentLineStatus,
|
|
PaymentStatus,
|
|
PlanningStatus,
|
|
ProjectStatus,
|
|
ReconciliationStatus,
|
|
RecurringCommitmentStatus,
|
|
RecurringInterval,
|
|
RelationType,
|
|
SettlementStatus,
|
|
SourceType,
|
|
VisibilityMode,
|
|
)
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class ApiModel(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class HouseholdCreate(ApiModel):
|
|
name: str
|
|
default_currency: str = "EUR"
|
|
|
|
|
|
class HouseholdUpdate(ApiModel):
|
|
name: str | None = None
|
|
default_currency: str | None = None
|
|
|
|
|
|
class HouseholdRead(ApiModel):
|
|
id: str
|
|
name: str
|
|
default_currency: str
|
|
created_at: datetime
|
|
|
|
|
|
class UserCreate(ApiModel):
|
|
household_id: str
|
|
display_name: str
|
|
email: str | None = None
|
|
|
|
|
|
class UserUpdate(ApiModel):
|
|
display_name: str | None = None
|
|
email: str | None = None
|
|
|
|
|
|
class UserRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
display_name: str
|
|
email: str | None
|
|
created_at: datetime
|
|
|
|
|
|
class LoginIdentityCreate(ApiModel):
|
|
user_id: str
|
|
provider: str
|
|
provider_subject: str
|
|
email: str | None = None
|
|
display_name: str | None = None
|
|
|
|
|
|
class LoginIdentityRead(ApiModel):
|
|
id: str
|
|
user_id: str
|
|
provider: str
|
|
provider_subject: str
|
|
email: str | None
|
|
display_name: str | None
|
|
created_at: datetime
|
|
|
|
|
|
class LocalLoginRequest(ApiModel):
|
|
user_id: str
|
|
|
|
|
|
class LocalSessionRead(ApiModel):
|
|
id: str
|
|
user_id: str
|
|
household_id: str
|
|
created_at: datetime
|
|
last_seen_at: datetime
|
|
expires_at: datetime
|
|
|
|
|
|
class AuthSessionRead(ApiModel):
|
|
session: LocalSessionRead
|
|
user: UserRead
|
|
household: HouseholdRead
|
|
|
|
|
|
class AccountCreate(ApiModel):
|
|
household_id: str
|
|
owner_user_id: str | None = None
|
|
name: str
|
|
account_type: AccountType
|
|
institution_name: str | None = None
|
|
currency: str = "EUR"
|
|
visibility_mode: VisibilityMode = VisibilityMode.PRIVATE
|
|
is_active: bool = True
|
|
|
|
|
|
class AccountUpdate(ApiModel):
|
|
owner_user_id: str | None = None
|
|
name: str | None = None
|
|
account_type: AccountType | None = None
|
|
institution_name: str | None = None
|
|
currency: str | None = None
|
|
visibility_mode: VisibilityMode | None = None
|
|
is_active: bool | None = None
|
|
|
|
|
|
class AccountRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
owner_user_id: str | None
|
|
name: str
|
|
account_type: AccountType
|
|
institution_name: str | None
|
|
currency: str
|
|
visibility_mode: VisibilityMode
|
|
is_active: bool
|
|
created_at: datetime
|
|
|
|
|
|
class SplitLineCreate(ApiModel):
|
|
user_id: str
|
|
share_amount: Decimal
|
|
share_percent: Decimal | None = None
|
|
reason: str = "manual"
|
|
|
|
|
|
class SplitLineRead(ApiModel):
|
|
id: str
|
|
event_id: str
|
|
user_id: str
|
|
share_amount: Decimal
|
|
share_percent: Decimal | None
|
|
reason: str
|
|
created_at: datetime
|
|
|
|
|
|
class ManualObservationCreate(ApiModel):
|
|
household_id: str
|
|
source_type: SourceType = SourceType.MANUAL
|
|
source_account_id: str | None = None
|
|
owner_user_id: str | None = None
|
|
observed_at: datetime | None = None
|
|
source_reference: str | None = None
|
|
provider_transaction_id: str | None = None
|
|
message_id: str | None = None
|
|
raw_text: str | None = None
|
|
raw_payload_json: dict[str, Any] | None = None
|
|
amount: Decimal
|
|
currency: str = "EUR"
|
|
event_date: date
|
|
booking_date: date | None = None
|
|
due_date: date | None = None
|
|
merchant: str | None = None
|
|
counterparty: str | None = None
|
|
description: str | None = None
|
|
event_type: FinancialEventType = FinancialEventType.EXPENSE
|
|
status: FinancialEventStatus | None = None
|
|
payer_user_id: str | None = None
|
|
payment_account_id: str | None = None
|
|
category_id: str | None = None
|
|
project_id: str | None = None
|
|
split_lines: list[SplitLineCreate] = Field(default_factory=list)
|
|
|
|
|
|
class ObservationImportCreate(ManualObservationCreate):
|
|
source_type: SourceType
|
|
|
|
|
|
class RawObservationRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
source_type: SourceType
|
|
source_account_id: str | None
|
|
owner_user_id: str | None
|
|
observed_at: datetime | None
|
|
received_at: datetime
|
|
raw_hash: str
|
|
source_reference: str | None
|
|
provider_transaction_id: str | None
|
|
message_id: str | None
|
|
raw_text: str | None
|
|
raw_file_path: str | None
|
|
raw_payload_json: dict[str, Any] | None
|
|
parsed_json: dict[str, Any] | None
|
|
parser_name: str | None
|
|
parser_version: str | None
|
|
confidence: Decimal
|
|
status: ObservationStatus
|
|
created_at: datetime
|
|
|
|
|
|
class EventObservationLinkRead(ApiModel):
|
|
id: str
|
|
event_id: str
|
|
observation_id: str
|
|
relation: EventObservationRelation
|
|
confidence: Decimal
|
|
created_at: datetime
|
|
|
|
|
|
class EventCreate(ApiModel):
|
|
household_id: str
|
|
source_account_id: str | None = None
|
|
payment_account_id: str | None = None
|
|
payer_user_id: str | None = None
|
|
event_type: FinancialEventType = FinancialEventType.EXPENSE
|
|
status: FinancialEventStatus = FinancialEventStatus.CANDIDATE
|
|
event_date: date
|
|
booking_date: date | None = None
|
|
due_date: date | None = None
|
|
amount: Decimal
|
|
currency: str = "EUR"
|
|
merchant: str | None = None
|
|
counterparty: str | None = None
|
|
description: str | None = None
|
|
category_id: str | None = None
|
|
project_id: str | None = None
|
|
created_by_user_id: str | None = None
|
|
split_lines: list[SplitLineCreate] = Field(default_factory=list)
|
|
|
|
|
|
class EventUpdate(ApiModel):
|
|
source_account_id: str | None = None
|
|
payment_account_id: str | None = None
|
|
payer_user_id: str | None = None
|
|
event_type: FinancialEventType | None = None
|
|
status: FinancialEventStatus | None = None
|
|
event_date: date | None = None
|
|
booking_date: date | None = None
|
|
due_date: date | None = None
|
|
amount: Decimal | None = None
|
|
currency: str | None = None
|
|
merchant: str | None = None
|
|
counterparty: str | None = None
|
|
description: str | None = None
|
|
category_id: str | None = None
|
|
project_id: str | None = None
|
|
|
|
|
|
class EventRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
source_account_id: str | None
|
|
payment_account_id: str | None
|
|
payer_user_id: str | None
|
|
event_type: FinancialEventType
|
|
status: FinancialEventStatus
|
|
event_date: date
|
|
booking_date: date | None
|
|
due_date: date | None
|
|
amount: Decimal
|
|
currency: str
|
|
merchant: str | None
|
|
counterparty: str | None
|
|
description: str | None
|
|
category_id: str | None
|
|
project_id: str | None
|
|
created_by_user_id: str | None
|
|
fingerprint: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
split_lines: list[SplitLineRead] = Field(default_factory=list)
|
|
tag_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class EventRelationCreate(ApiModel):
|
|
to_event_id: str
|
|
relation_type: RelationType
|
|
confidence: Decimal = Decimal("1.00")
|
|
created_by: str = "user"
|
|
|
|
|
|
class EventRelationRead(ApiModel):
|
|
id: str
|
|
from_event_id: str
|
|
to_event_id: str
|
|
relation_type: RelationType
|
|
confidence: Decimal
|
|
created_by: str
|
|
created_at: datetime
|
|
|
|
|
|
class CategoryCreate(ApiModel):
|
|
household_id: str
|
|
name: str
|
|
parent_id: str | None = None
|
|
path: str | None = None
|
|
is_active: bool = True
|
|
|
|
|
|
class CategoryUpdate(ApiModel):
|
|
name: str | None = None
|
|
parent_id: str | None = None
|
|
path: str | None = None
|
|
is_active: bool | None = None
|
|
|
|
|
|
class CategoryRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
parent_id: str | None
|
|
name: str
|
|
path: str
|
|
is_active: bool
|
|
|
|
|
|
class TagCreate(ApiModel):
|
|
household_id: str
|
|
name: str
|
|
|
|
|
|
class TagUpdate(ApiModel):
|
|
name: str | None = None
|
|
|
|
|
|
class TagRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
name: str
|
|
|
|
|
|
class EventTagsUpdate(ApiModel):
|
|
tag_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class EventDetailRead(ApiModel):
|
|
event: EventRead
|
|
category: CategoryRead | None = None
|
|
tags: list[TagRead] = Field(default_factory=list)
|
|
observation_links: list[EventObservationLinkRead] = Field(default_factory=list)
|
|
observations: list[RawObservationRead] = Field(default_factory=list)
|
|
relations: list[EventRelationRead] = Field(default_factory=list)
|
|
related_events: list[EventRead] = Field(default_factory=list)
|
|
|
|
|
|
class ObservationReviewItem(ApiModel):
|
|
observation: RawObservationRead
|
|
events: list[EventRead] = Field(default_factory=list)
|
|
action_required: bool = True
|
|
suggested_action: str = "review"
|
|
|
|
|
|
class ObservationAcceptRequest(ApiModel):
|
|
event_status: FinancialEventStatus | None = None
|
|
create_event_if_missing: bool = True
|
|
|
|
|
|
class ObservationUpdateRequest(ApiModel):
|
|
source_account_id: str | None = None
|
|
owner_user_id: str | None = None
|
|
raw_text: str | None = None
|
|
amount: Decimal | None = None
|
|
currency: str | None = None
|
|
event_date: date | None = None
|
|
booking_date: date | None = None
|
|
due_date: date | None = None
|
|
merchant: str | None = None
|
|
counterparty: str | None = None
|
|
description: str | None = None
|
|
event_type: FinancialEventType | None = None
|
|
status: FinancialEventStatus | None = None
|
|
sync_linked_events: bool = True
|
|
|
|
|
|
class ObservationIgnoreRequest(ApiModel):
|
|
ignore_linked_events: bool = False
|
|
reason: str | None = None
|
|
|
|
|
|
class ObservationLinkRequest(ApiModel):
|
|
event_id: str
|
|
relation: EventObservationRelation = EventObservationRelation.EVIDENCE_FOR
|
|
|
|
|
|
class ObservationBatchRequest(ApiModel):
|
|
observation_ids: list[str]
|
|
action: str
|
|
event_status: FinancialEventStatus | None = None
|
|
ignore_linked_events: bool = False
|
|
|
|
|
|
class ObservationBatchResponse(ApiModel):
|
|
updated_count: int
|
|
items: list[ObservationReviewItem]
|
|
|
|
|
|
class SettlementTransfer(ApiModel):
|
|
from_user_id: str
|
|
to_user_id: str
|
|
amount: Decimal
|
|
currency: str
|
|
|
|
|
|
class SettlementUserBalance(ApiModel):
|
|
user_id: str
|
|
paid: Decimal
|
|
share: Decimal
|
|
net: Decimal
|
|
|
|
|
|
class SettlementSummary(ApiModel):
|
|
household_id: str
|
|
project_id: str | None
|
|
currency: str
|
|
included_event_ids: list[str]
|
|
excluded_event_ids: list[str]
|
|
balances: list[SettlementUserBalance]
|
|
suggested_transfers: list[SettlementTransfer]
|
|
explanation: list[str]
|
|
|
|
|
|
class ProjectCreate(ApiModel):
|
|
household_id: str
|
|
name: str
|
|
description: str | None = None
|
|
start_date: date | None = None
|
|
end_date: date | None = None
|
|
default_split_rule_id: str | None = None
|
|
status: ProjectStatus = ProjectStatus.PLANNING
|
|
currency: str = "EUR"
|
|
participant_user_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class ProjectRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
name: str
|
|
description: str | None
|
|
start_date: date | None
|
|
end_date: date | None
|
|
default_split_rule_id: str | None
|
|
status: ProjectStatus
|
|
currency: str
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ProjectParticipantCreate(ApiModel):
|
|
user_id: str
|
|
role: str = "participant"
|
|
default_share_percent: Decimal | None = None
|
|
|
|
|
|
class ProjectParticipantRead(ApiModel):
|
|
id: str
|
|
project_id: str
|
|
user_id: str
|
|
role: str
|
|
default_share_percent: Decimal | None
|
|
|
|
|
|
class ProjectBudgetLineCreate(ApiModel):
|
|
category_id: str | None = None
|
|
name: str
|
|
budgeted_amount: Decimal = Decimal("0.00")
|
|
sort_order: int = 0
|
|
notes: str | None = None
|
|
|
|
|
|
class ProjectBudgetLineRead(ApiModel):
|
|
id: str
|
|
project_id: str
|
|
category_id: str | None
|
|
name: str
|
|
budgeted_amount: Decimal
|
|
committed_amount_cached: Decimal | None
|
|
paid_amount_cached: Decimal | None
|
|
sort_order: int
|
|
notes: str | None
|
|
|
|
|
|
class ProjectPlannedItemCreate(ApiModel):
|
|
budget_line_id: str | None = None
|
|
description: str
|
|
estimated_amount: Decimal = Decimal("0.00")
|
|
committed_amount: Decimal | None = None
|
|
expected_date: date | None = None
|
|
due_date: date | None = None
|
|
expected_payer_account_id: str | None = None
|
|
split_rule_id: str | None = None
|
|
planning_status: PlanningStatus = PlanningStatus.IDEA
|
|
payment_status: PaymentStatus = PaymentStatus.UNPAID
|
|
reconciliation_status: ReconciliationStatus = ReconciliationStatus.NO_EVIDENCE
|
|
settlement_status: SettlementStatus = SettlementStatus.UNSETTLED
|
|
notes: str | None = None
|
|
|
|
|
|
class ProjectPlannedItemRead(ApiModel):
|
|
id: str
|
|
project_id: str
|
|
budget_line_id: str | None
|
|
description: str
|
|
estimated_amount: Decimal
|
|
committed_amount: Decimal | None
|
|
expected_date: date | None
|
|
due_date: date | None
|
|
expected_payer_account_id: str | None
|
|
split_rule_id: str | None
|
|
planning_status: PlanningStatus
|
|
payment_status: PaymentStatus
|
|
reconciliation_status: ReconciliationStatus
|
|
settlement_status: SettlementStatus
|
|
notes: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class PaymentLineCreate(ApiModel):
|
|
planned_item_id: str | None = None
|
|
event_id: str | None = None
|
|
amount: Decimal
|
|
currency: str = "EUR"
|
|
date: date
|
|
paid_by_user_id: str | None = None
|
|
payment_account_id: str | None = None
|
|
source_observation_id: str | None = None
|
|
status: PaymentLineStatus = PaymentLineStatus.EXPECTED
|
|
|
|
|
|
class PaymentLineRead(ApiModel):
|
|
id: str
|
|
planned_item_id: str | None
|
|
event_id: str | None
|
|
amount: Decimal
|
|
currency: str
|
|
date: date
|
|
paid_by_user_id: str | None
|
|
payment_account_id: str | None
|
|
source_observation_id: str | None
|
|
status: PaymentLineStatus
|
|
created_at: datetime
|
|
|
|
|
|
class ProjectSummary(ApiModel):
|
|
project_id: str
|
|
currency: str
|
|
budgeted_total: Decimal
|
|
committed_total: Decimal
|
|
paid_total: Decimal
|
|
reconciled_total: Decimal
|
|
settled_total: Decimal
|
|
due_later_total: Decimal
|
|
remaining_uncommitted_budget: Decimal
|
|
open_actions: list[str]
|
|
|
|
|
|
class ImportConnectionCreate(ApiModel):
|
|
household_id: str
|
|
owner_user_id: str
|
|
connection_type: ImportConnectionType
|
|
display_name: str
|
|
status: ImportConnectionStatus = ImportConnectionStatus.NEEDS_AUTH
|
|
secret_storage_ref: str | None = None
|
|
runs_locally: bool = True
|
|
connector_config_json: dict[str, Any] | None = None
|
|
|
|
|
|
class ImportConnectionUpdate(ApiModel):
|
|
owner_user_id: str | None = None
|
|
connection_type: ImportConnectionType | None = None
|
|
display_name: str | None = None
|
|
status: ImportConnectionStatus | None = None
|
|
secret_storage_ref: str | None = None
|
|
runs_locally: bool | None = None
|
|
connector_config_json: dict[str, Any] | None = None
|
|
|
|
|
|
class ImportConnectionRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
owner_user_id: str
|
|
connection_type: ImportConnectionType
|
|
display_name: str
|
|
status: ImportConnectionStatus
|
|
last_sync_at: datetime | None
|
|
last_error: str | None
|
|
secret_storage_ref: str | None
|
|
runs_locally: bool
|
|
connector_config_json: dict[str, Any] | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ImportRunRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
connection_id: str | None
|
|
actor_user_id: str | None
|
|
source_type: str | None
|
|
status: str
|
|
imported_count: int
|
|
duplicate_count: int
|
|
created_event_count: int
|
|
skipped_count: int
|
|
error: str | None
|
|
summary_json: dict[str, Any] | None
|
|
started_at: datetime
|
|
finished_at: datetime | None
|
|
|
|
|
|
class ImportRunDetailRead(ApiModel):
|
|
run: ImportRunRead
|
|
observations: list[RawObservationRead] = Field(default_factory=list)
|
|
events: list[EventRead] = Field(default_factory=list)
|
|
|
|
|
|
class LocalAgentRegister(ApiModel):
|
|
household_id: str
|
|
owner_user_id: str
|
|
display_name: str = "Local connector agent"
|
|
|
|
|
|
class LocalAgentHeartbeat(ApiModel):
|
|
connection_id: str
|
|
status: ImportConnectionStatus = ImportConnectionStatus.ACTIVE
|
|
last_error: str | None = None
|
|
|
|
|
|
class SyncObservationsRequest(ApiModel):
|
|
connection_id: str
|
|
observations: list[ObservationImportCreate]
|
|
|
|
|
|
class SyncObservationsResponse(ApiModel):
|
|
imported_observation_ids: list[str]
|
|
created_event_ids: list[str]
|
|
duplicate_observation_ids: list[str]
|
|
connection_id: str | None = None
|
|
imported_count: int = 0
|
|
duplicate_count: int = 0
|
|
created_event_count: int = 0
|
|
run: ImportRunRead | None = None
|
|
|
|
|
|
class BackupResult(ApiModel):
|
|
file_path: str
|
|
size_bytes: int
|
|
created_at: datetime
|
|
|
|
|
|
class HouseholdExport(ApiModel):
|
|
household: dict[str, Any]
|
|
exported_at: datetime
|
|
counts: dict[str, int]
|
|
data: dict[str, list[dict[str, Any]]]
|
|
|
|
|
|
class RecurringCommitmentCreate(ApiModel):
|
|
household_id: str
|
|
provider: str
|
|
description: str | None = None
|
|
amount_expected: Decimal
|
|
amount_min: Decimal | None = None
|
|
amount_max: Decimal | None = None
|
|
currency: str = "EUR"
|
|
interval: RecurringInterval
|
|
next_due_date: date
|
|
payer_account_id: str | None = None
|
|
category_id: str | None = None
|
|
project_id: str | None = None
|
|
notice_period: str | None = None
|
|
renewal_date: date | None = None
|
|
status: RecurringCommitmentStatus = RecurringCommitmentStatus.ACTIVE
|
|
matching_rule_json: dict[str, Any] | None = None
|
|
|
|
|
|
class RecurringCommitmentUpdate(ApiModel):
|
|
provider: str | None = None
|
|
description: str | None = None
|
|
amount_expected: Decimal | None = None
|
|
amount_min: Decimal | None = None
|
|
amount_max: Decimal | None = None
|
|
currency: str | None = None
|
|
interval: RecurringInterval | None = None
|
|
next_due_date: date | None = None
|
|
payer_account_id: str | None = None
|
|
category_id: str | None = None
|
|
project_id: str | None = None
|
|
notice_period: str | None = None
|
|
renewal_date: date | None = None
|
|
status: RecurringCommitmentStatus | None = None
|
|
matching_rule_json: dict[str, Any] | None = None
|
|
|
|
|
|
class RecurringCommitmentRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
provider: str
|
|
description: str | None
|
|
amount_expected: Decimal
|
|
amount_min: Decimal | None
|
|
amount_max: Decimal | None
|
|
currency: str
|
|
interval: RecurringInterval
|
|
next_due_date: date
|
|
payer_account_id: str | None
|
|
category_id: str | None
|
|
project_id: str | None
|
|
notice_period: str | None
|
|
renewal_date: date | None
|
|
status: RecurringCommitmentStatus
|
|
matching_rule_json: dict[str, Any] | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ReconciliationEventSummary(ApiModel):
|
|
id: str
|
|
source_type: str | None
|
|
event_type: str
|
|
status: str
|
|
event_date: date
|
|
amount: Decimal
|
|
currency: str
|
|
merchant: str | None
|
|
counterparty: str | None
|
|
description: str | None
|
|
source_reference: str | None
|
|
provider_transaction_id: str | None
|
|
observation_id: str | None
|
|
|
|
|
|
class ReconciliationSuggestionRead(ApiModel):
|
|
id: str
|
|
kind: str
|
|
relation_type: RelationType
|
|
primary_event: ReconciliationEventSummary
|
|
confirming_event: ReconciliationEventSummary
|
|
confidence: Decimal
|
|
reasons: list[str]
|
|
action: str
|
|
|
|
|
|
class ReconciliationAcceptResponse(ApiModel):
|
|
accepted: ReconciliationSuggestionRead
|
|
|
|
|
|
class ReconciliationIgnoreRequest(ApiModel):
|
|
actor_user_id: str | None = None
|
|
reason: str | None = None
|
|
|
|
|
|
class ReconciliationDecisionRead(ApiModel):
|
|
id: str
|
|
household_id: str
|
|
suggestion_id: str
|
|
decision: str
|
|
kind: str
|
|
relation_type: RelationType
|
|
primary_event_id: str
|
|
confirming_event_id: str
|
|
confidence: Decimal
|
|
actor_user_id: str | None
|
|
reason: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ReconciliationIgnoreResponse(ApiModel):
|
|
ignored: ReconciliationSuggestionRead
|
|
decision: ReconciliationDecisionRead
|