from datetime import datetime from decimal import Decimal import typing from typing import Dict, List from pydantic import BaseModel, computed_field, ConfigDict, Field, TypeAdapter from src.constants import DECIMAL_ZERO, RevenueTransactionTypes class Event(BaseModel): model_config = ConfigDict(populate_by_name=True) event_name: str = Field(alias='eventName') statement_period_id: int = Field(alias='statementPeriodId') abacus_event_id: int = Field(alias='abacusEventId') target_type: str = Field(alias='targetType') target_id: int = Field(alias='targetId') is_retry: bool = Field(alias='isRetry', default=False) class LambdaResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) status_code: int = Field(alias='statusCode') status_description: str = Field(alias='statusDescription') headers: Dict[str, str] = Field({'Content-Type': 'application/json'}) class PaymentGroup(BaseModel): payment_group_id: int group_name: str is_reusable: bool group_criteria: dict[str, typing.Any] class PaymentGroupPayment(BaseModel): payment_group_id: int payment_name: str class PaymentGroupPaymentAccount(BaseModel): account_id: int last_statement_period_id: typing.Optional[int] class PaymentGroupPaymentAccountsResponse(BaseModel): """Payment group payments accounts response.""" items: typing.List[PaymentGroupPaymentAccount] total_count: int class AccountPayableContract(BaseModel): contract_id: int currency_code: str current_balance: Decimal class Account(BaseModel): account_id: int # TODO: this field is not needed here, # as we anyway fetch account tax info later # and this field ia absent in the generic list endpoint. # This should be refactored to support both generic and eligible endpoints. country_of_tax_residence: typing.Optional[str] = None currency_code: typing.Optional[str] = None class GetAccountsResponse(BaseModel): items: List[Account] total_count: int class AccountPaymentHold(BaseModel): payment_hold_id: int account_id: int is_on_hold: bool start_date: str reason: str class PaymentHoldList(BaseModel): items: List[AccountPaymentHold] total_count: int class AccountTaxInfo(BaseModel): account_tax_info_id: int country_of_tax_residence: str account_id: int is_sba_signed: bool is_vat_exempt: bool is_tax_treaty_claimed: bool class GetAccountTaxInfoResponse(BaseModel): items: List[AccountTaxInfo] total_count: int class ContractCloseBalance(BaseModel): worksheet_account_contract_closing_balance_id: int contract_id: int account_id: int amount: Decimal reference_payment_entity_id: int currency_code: str statement_period_id: int class PaginatedContractCloseBalances(BaseModel): items: List[ContractCloseBalance] total_count: int class ReferenceTaxWithholding(BaseModel): reference_tax_withholding_id: int country_of_withholding: str country_of_tax_residence: typing.Optional[str] tax_rate: Decimal is_resource_provisioned: typing.Optional[bool] class PaymentEntity(BaseModel): reference_payment_entity_id: int payment_entity_name: str country_of_tax_reporting: str class TaxCorrection(BaseModel): """Tax correction.""" worksheet_tax_correction_id: int account_id: int contract_id: int correction_statement_period_id: int payable_detail_type_id: int amount: Decimal currency_code: str note: typing.Optional[str] class GetTaxCorrectionsResponse(BaseModel): """Get tax corrections response.""" items: typing.List[TaxCorrection] total_count: int class TaxCorrectionVAT(BaseModel): """Tax correction VAT.""" worksheet_tax_correction_vat_id: int correction_statement_period_id: int account_id: int contract_id: int payable_detail_type_id: int payee_currency_code: str vat_currency_code: str base_amount_payee_currency: Decimal vat_rate: Decimal vat_amount_payee_currency: Decimal vat_amount_vat_currency: Decimal net_amount_payee_currency: Decimal note: typing.Optional[str] @computed_field # type: ignore @property def amount(self) -> Decimal: return self.vat_amount_payee_currency @computed_field # type: ignore @property def currency_code(self) -> str: return self.payee_currency_code class GetTaxCorrectionsVATResponse(BaseModel): """Get tax corrections VAT response.""" items: typing.List[TaxCorrectionVAT] total_count: int class PayableBalanceAfterTaxEntry(BaseModel): """Model to represent the microservice data.""" model_config = ConfigDict(populate_by_name=True) worksheet_account_contract_payable_after_tax_id: int worksheet_account_contract_closing_balance_id: int contract_id: int account_id: int payable_amount_pre_tax: Decimal tax_withholding_amount: typing.Optional[Decimal] = None vat_amount: typing.Optional[Decimal] = None payable_amount_post_tax: Decimal currency_code: str country_of_tax_residence: str country_of_tax_policy: str class PaginatedPayableBalanceAfterTaxEntries(BaseModel): items: List[PayableBalanceAfterTaxEntry] total_count: int class PayableDetailEntry(BaseModel): """Worksheet account contract payable detail entry (microservice data).""" worksheet_account_contract_payable_after_tax_id: int payable_detail_type_id: typing.Optional[int] = None amount_payable: Decimal class PaginatedPayableDetailEntries(BaseModel): items: List[PayableDetailEntry] total_count: int class PayableBalanceAfterTaxBulkUpdate(BaseModel): """Body entry for bulk updating worksheet payable balance after tax amounts.""" worksheet_account_contract_payable_after_tax_id: int tax_withholding_amount: typing.Optional[Decimal] = None vat_amount: typing.Optional[Decimal] = None payable_amount_post_tax: Decimal class ContractPayableDetails(BaseModel): model_config = ConfigDict(populate_by_name=True) worksheet_account_contract_payable_after_tax_id: int contract_id: int account_id: int amount_payable: Decimal currency: str target_table: str target_id: int reference_target_table: typing.Optional[str] = None reference_target_id: typing.Optional[int] = None payable_detail_type_id: int class AbacusState(BaseModel): action_name: str abacus_state_id: int action_status: str parent_table_id: int parent_table_name: str class AbacusStateBulkQueryResponse(BaseModel): items: List[AbacusState] limit: int offset: int total: int class TaxableRevenue(BaseModel): model_config = ConfigDict(populate_by_name=True) account_contract_taxable_revenue_id: int worksheet_account_contract_closing_balance_id: typing.Optional[int] account_id: int contract_id: int reference_payment_entity_id: int statement_period_id: int amount: Decimal currency_code: str revenue_transaction_type: RevenueTransactionTypes is_us_revenue: bool def __eq__(self, other: typing.Any) -> bool: if isinstance(other, TaxableRevenue): return ( self.account_contract_taxable_revenue_id == other.account_contract_taxable_revenue_id ) return NotImplemented class TaxableRevenueCatchupDetail(BaseModel): """Taxable revenue wrapper.""" model_config = ConfigDict(populate_by_name=True) taxable_revenue: TaxableRevenue ref_wht: ReferenceTaxWithholding catchup_wht_amount: Decimal class PayableBalanceAfterTax(BaseModel): """Model for the related data manipulation.""" model_config = ConfigDict(populate_by_name=True) worksheet_account_contract_closing_balance_id: int contract_id: int account_id: int payable_amount_pre_tax: Decimal tax_withholding_amount: typing.Optional[Decimal] vat_amount: typing.Optional[Decimal] payable_amount_post_tax: Decimal currency_code: str country_of_tax_residence: str country_of_tax_policy: str # Non-serializable fields worksheet_account_contract_payable_after_tax_id: typing.Optional[int] = Field( exclude=True, default=None ) account_contract_taxable_revenue_id: typing.Optional[int] = Field( exclude=True, default=None ) reference_vat_rate_id: typing.Optional[int] = Field(exclude=True, default=None) reference_tax_withholding_id: typing.Optional[int] = Field( exclude=True, default=None ) wht_corrections: List[TaxCorrection] = Field(exclude=True, default=[]) tax_withholding_amount_pre_correction: typing.Optional[Decimal] = Field( exclude=True, default=DECIMAL_ZERO ) vat_corrections: List[TaxCorrectionVAT] = Field(exclude=True, default=[]) vat_amount_pre_correction: typing.Optional[Decimal] = Field( exclude=True, default=DECIMAL_ZERO ) taxable_revenues_catchup_details: List[TaxableRevenueCatchupDetail] = Field( exclude=True, default=[] ) class AccountPaymentTerm(BaseModel): """Model for AccountPaymentTerm data.""" account_payment_term_id: int account_id: int currency_code: str payment_schedule: str class AccountPaymentTermDataloaderItem(BaseModel): """Model for dataloader response items.""" data: typing.Optional[AccountPaymentTerm] = None @classmethod def list_validate( cls, data: typing.List[typing.Mapping[str, typing.Any]] ) -> typing.List[typing.Self]: """Validate the list of items.""" return TypeAdapter( typing.List[cls] # type: ignore ).validate_python(data) class AccountPayee(BaseModel): """Model for Account Payee.""" account_payee_id: int account_id: int class AccountPayeeDataLoaderItem(BaseModel): data: AccountPayee | None class AccountPayeeDataLoaderResponse(BaseModel): items: List[AccountPayeeDataLoaderItem] class FlowthroughAllocation(BaseModel): """Model for flowthrough allocation.""" payment_allocation_id: int contract_id: int statement_period_id: int amount_to_payment: Decimal currency_code: str class GetFlowThroughAllocationResponse(BaseModel): """Model for flowthrough allocation response.""" items: List[FlowthroughAllocation] total_count: int