"""Account Handler.""" from fastapi import APIRouter from moneyhub.constants.constants import ONE_MONTH from moneyhub.constants.constants import OrderDirection from moneyhub.logic import account as account_logic from moneyhub.logic import account_statement_period as account_statement_period_logic from moneyhub.schemas.account import ArtistDataloaderSchema from moneyhub.schemas.account_statement_period import AccountActivityPeriodSchema from moneyhub.schemas.account_statement_period import AccountActivityPeriodsDataloaderSchema from moneyhub.schemas.account_statement_period import AccountActivitySchema from moneyhub.schemas.account_statement_period import AccountArtistSchema from moneyhub.schemas.account_statement_period import AccountContractsDataloaderSchema from moneyhub.schemas.account_statement_period import AccountContractsSchema from moneyhub.schemas.account_statement_period import AccountImprintSchema from moneyhub.schemas.account_statement_period import AccountImprintsDataloaderSchema from moneyhub.schemas.account_statement_period import AccountProductSchema from moneyhub.schemas.account_statement_period import AccountProjectSchema from moneyhub.schemas.account_statement_period import AccountRecordingSchema from moneyhub.schemas.account_statement_period import AccountStatementPeriodBalanceSchema from moneyhub.schemas.account_statement_period import AccountStatementPeriodDetailSchema from moneyhub.schemas.account_statement_period import AccountStatementPeriodPaymentDetailSchema from moneyhub.schemas.account_statement_period import AccountStatementPeriodSchema from moneyhub.schemas.account_statement_period import AccountStatementPeriodVatDetailSchema from moneyhub.schemas.account_statement_period import AccountTrackSchema from moneyhub.schemas.account_statement_period import PaginatedAccountStatementPeriodDetailSchema from moneyhub.schemas.recording import RecordingDataloaderSchema from moneyhub.schemas.recording import RecordingSchema from moneyhub.schemas.revenue_analysis import StoreSchema from moneyhub.schemas.revenue_analysis import TransactionTypeSchema from moneyhub.utils.cache import cache from moneyhub.utils.request import extract_json_body account_router = APIRouter(prefix='/account', tags=['account']) @account_router.get( '/{account_id}/activity-periods', status_code=200 ) @cache(ttl=ONE_MONTH) def get_activity_periods_by_account( account_id: int, subaccount_id: int | None = None, is_subaccount: bool = False, ) -> list[AccountActivityPeriodSchema]: """GET activity periods for a specified account. Args: account_id (int): Account to get periods for subaccount_id (int): Optional subaccount to filter by is_subaccount (bool): Whether the request is made by a subaccount Returns: list: list of activity periods """ return account_logic.get_activity_periods_by_account( account_id, subaccount_id, None) @account_router.get( '/{account_id}/statement-periods', status_code=200 ) def get_account_statements_by_account_id( account_id: int, contract_id: int | None = None, order_dir: OrderDirection = OrderDirection.ASC ) -> list[AccountStatementPeriodDetailSchema]: """GET ledger info per statement period for a specified account. Args: account_id (int): The id of an account contract_id (int): the id of a contract order_dir (OrderDirection): Sort direction for statement IDs Returns: list: list of account statement periods details """ result = account_statement_period_logic.get_account_statement_periods_by_account( account_id, contract_id, None, None, order_dir) return result['items'] @account_router.get( '/{account_id}/statements', status_code=200 ) def get_statements_by_account_id( account_id: int, contract_id: int | None = None, limit: int = 50, offset: int = 0, order_dir: OrderDirection = OrderDirection.ASC, ) -> PaginatedAccountStatementPeriodDetailSchema: """GET statements info per statement period for a specified account. Args: account_id (int): The id of an account contract_id (int | None): The id of a contract limit (int): Number of records to return (pagination) offset (int): Number of records to skip (pagination) order_dir (OrderDirection): Sort direction (ASC or DESC) Returns: PaginatedAccountStatementPeriodDetailSchema: paginated statement periods details """ return account_statement_period_logic.get_account_statement_periods_by_account( account_id=account_id, contract_id=contract_id, limit=limit, offset=offset, order_dir=order_dir ) @account_router.get( '/{account_id}/statement-period/{statement_period_id}/payments', status_code=200 ) def get_account_statement_period_payments( account_id: int, statement_period_id: int, contract_id: int | None = None ) -> list[AccountStatementPeriodPaymentDetailSchema]: """Get payments by an account_id and statement_period_id. Args: account_id (int): The id of an account statement_period_id (int): The id of statement period contract_id (int): the id of a contract Returns: list: list of statement period payments """ return account_statement_period_logic.get_payments_by_account_and_statement_periods( account_id, contract_id, [statement_period_id] ) @account_router.get( '/{account_id}/statement-period/{statement_period_id}/vat', status_code=200 ) def get_account_statement_period_vat( account_id: int, statement_period_id: int, contract_id: int | None = None ) -> AccountStatementPeriodVatDetailSchema | None: """Get the VAT numbers for a given account and statement period. Args: account_id (int): The ID of an account statement_period_id (int): The ID of statement period contract_id (int): the id of a contract Returns: AccountStatementPeriodVatDetailSchema: list vat objects """ results = account_statement_period_logic.get_vat_by_account_and_statement_periods( account_id, contract_id, [statement_period_id] ) return results[0] if results else None @account_router.get( '/{account_id}/statement-period/{statement_period_id}/balance', status_code=200 ) def get_account_statement_period_balance( account_id: int, statement_period_id: int, contract_id: int | None = None ) -> AccountStatementPeriodBalanceSchema | None: """Get the balance numbers for a given account and statement period. Args: account_id (int): The ID of an account statement_period_id (int): The ID of statement period contract_id (int): the id of a contract Returns: AccountStatementPeriodbalanceSchema: balance object """ result = account_statement_period_logic.get_balance_by_account_statement_periods( account_id, [statement_period_id], contract_id ) return result[0] if result else None @account_router.get( '/{account_id}/stores', status_code=200 ) @cache(ttl=ONE_MONTH) def get_stores_by_account_id( account_id: int, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[StoreSchema]: """GET a list of stores for a specified account. Args: account_id (int): the id of an account subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool): whether to not a subaccount is making the request Returns: list[StoreSchema]: Response schema """ return account_logic.get_stores_by_account_id(account_id, subaccount_id) @account_router.get( '/{account_id}/transaction-types', status_code=200 ) @cache(ttl=ONE_MONTH) def get_transaction_types_by_account( account_id: int, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[TransactionTypeSchema]: """Get transaction types for a specified account and optionally subaccount. Args: account_id (int): ID of the account subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: TransactionTypeSchema: response schema """ return account_logic.get_transaction_types_by_account_id( account_id, subaccount_id ) @account_router.get( '/{account_id}/projects', status_code=200 ) @cache(ttl=ONE_MONTH) def get_projects_by_account( account_id: int, limit: int = 50, search_term: str | int | None = None, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[AccountProjectSchema]: """Get projects for a specified account with optional search and limit. Args: account_id (int): ID of the account limit (int): maximum number of projects to return search_term (str): search term to filter projects by name subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: list[AccountImprintSchema]: list of project options """ return account_logic.get_projects_by_account_id( account_id, limit, search_term, subaccount_id, ) @account_router.get( '/{account_id}/imprints', status_code=200 ) @cache(ttl=ONE_MONTH) def get_imprints_by_account( account_id: int, limit: int = 50, search_term: str | int | None = None, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[AccountImprintSchema]: """Get imprints for a specified account with optional search and limit. Args: account_id (int): ID of the account limit (int): maximum number of imprints to return search_term (str): search term to filter imprints by name subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: list[AccountImprintSchema]: list of imprint options """ return account_logic.get_imprints_by_account_id( account_id, limit, search_term, subaccount_id, None, ) @account_router.get( '/{account_id}/products', status_code=200 ) @cache(ttl=ONE_MONTH) def get_products_by_account( account_id: int, limit: int = 50, search_term: str | None = None, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[AccountProductSchema]: """Get products for a specified account with optional search and limit. Args: account_id (int): ID of the account limit (int): maximum number of products to return search_term (str): search term to filter products by name, UPC, or exact ID subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: list[AccountProductSchema]: list of product options """ return account_logic.get_products_by_account_id( account_id, limit, search_term, subaccount_id, ) @account_router.get( '/{account_id}/artists', status_code=200 ) @cache(ttl=ONE_MONTH) def get_artists_by_account( account_id: int, limit: int = 50, search_term: str | int | None = None, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[AccountArtistSchema]: """Get artists for a specified account with optional search and limit. Args: account_id (int): ID of the account limit (int): maximum number of artists to return search_term (str): search term to filter artists by name subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: list[AccountArtistSchema]: list of artist options """ return account_logic.get_artists_by_account_id( account_id, limit, search_term, subaccount_id, ) @account_router.get( '/{account_id}/tracks', status_code=200 ) @cache(ttl=ONE_MONTH) def get_tracks_by_account( account_id: int, limit: int = 50, search_term: str | int | None = None, subaccount_id: int | None = None, is_subaccount: bool = False ) -> list[AccountTrackSchema]: """Get tracks for a specified account with optional search and limit. Args: account_id (int): ID of the account limit (int): maximum number of tracks to return search_term (str): search term to filter tracks by name or ISRC subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: list[AccountTrackSchema]: list of track options """ return account_logic.get_tracks_by_account_id( account_id, limit, search_term, subaccount_id, ) @account_router.get( '/{account_id}/recordings', status_code=200 ) @cache(ttl=ONE_MONTH) def get_recordings_by_account( account_id: int, limit: int = 50, search_term: str | None = None, contract_id: int | None = None, ) -> list[AccountRecordingSchema]: """Get recordings for a specified account with optional search and limit. Args: account_id (int): ID of the account limit (int): maximum number of recordings to return search_term (str): search term to filter recordings by title contract_id (int): the id of a contract to filter by Returns: list[AccountRecordingSchema]: list of recording options """ return account_logic.get_recordings_by_account_id( account_id, limit, search_term, contract_id, ) @account_router.post( '/{account_id}/dataloader/artists', status_code=200 ) def load_artists( account_id: int, payload: ArtistDataloaderSchema, is_subaccount: bool | None = None, subaccount_id: int | None = None, ) -> list[AccountArtistSchema]: """Dataload artist names for a specified artist IDs. Args: account_id (int): The id of an account (for permissions checking only) subaccount_id (int): The id of a subaccount (for permissions checking only) is_subaccount (bool): a boolean flag to check if the resource is a subaccount (for permissions checking only) payload (ArtistDataloaderSchema): JSON body payload with artist_ids Returns: list: list of artists with ids and names """ if not payload.artist_ids: return [] return account_logic.get_artists_by_ids(payload.artist_ids) @account_router.get( '/{account_id}/account-statement-periods', status_code=200 ) def get_statement_periods_by_account_id( account_id: int, contract_id: int | None = None, order_dir: OrderDirection = OrderDirection.ASC ) -> list[AccountStatementPeriodSchema]: """GET statement periods for a specified account. Args: account_id (int): The id of an account contract_id (int): the id of a contract order_dir (OrderDirection): Sort direction order Returns: list: list of statement periods """ return account_logic.get_statement_periods_by_account(account_id, contract_id, order_dir) @account_router.get( '/{account_id}/activity', status_code=200 ) def get_account_activity( account_id: int, subaccount_id: int | None = None, is_subaccount: bool = False ) -> AccountActivitySchema: """Get the activity for a given account - whether it has any adjustments, expenses, or revenue. Args: account_id (int): The id of an account subaccount_id (int): the id of a subaccount to filter by is_subaccount (bool): Whether the request is made by a subaccount Returns: AccountActivitySchema: Account activity """ return account_logic.get_account_activity(account_id, subaccount_id, is_subaccount) @account_router.post( '/{account_id}/dataloader/contracts', status_code=200 ) def load_account_contracts( account_id: int, payload: AccountContractsDataloaderSchema, ) -> list[AccountContractsSchema]: """Dataload contracts info for a specified account. Args: account_id (int): The id of an account payload (AccountContractsDataloaderSchema): JSON body payload Returns: list: list contracts """ body = extract_json_body(payload) return account_logic.get_contracts_info( account_id, body['contract_ids'] ) @account_router.post( '/{account_id}/dataloader/imprints', status_code=200 ) def load_imprints_by_account( account_id: int, payload: AccountImprintsDataloaderSchema, subaccount_id: int | None = None, is_subaccount: bool = False, ) -> list[AccountImprintSchema]: """Dataload imprints for a given account. Args: account_id (int): ID of the account payload (AccountImprintsDataloaderSchema): Request body subaccount_id (int | None): Optional ID of a subaccount to filter by is_subaccount (bool | None): Whether a subaccount is making the request Returns: list[AccountImprintSchema]: list of imprints """ if not payload.imprint_ids: return [] return account_logic.get_imprints_by_account_id( account_id, None, None, subaccount_id, payload.imprint_ids, ) @account_router.post( '/{account_id}/dataloader/recordings', status_code=200 ) def load_account_recordings( account_id: int, payload: RecordingDataloaderSchema, ) -> list[RecordingSchema]: """Dataload recording names for a specified account. Args: account_id (int): The id of an account payload (RecordingDataloaderSchema): JSON body payload with recording_ids Returns: list: list of recordings with id, title and isrc """ if not payload.recording_ids: return [] return account_logic.get_recording_names( account_id, payload.recording_ids ) @account_router.post( '/{account_id}/dataloader/activity-periods', status_code=200 ) def load_activity_periods_by_account( account_id: int, payload: AccountActivityPeriodsDataloaderSchema, subaccount_id: int | None = None, is_subaccount: bool = False, ) -> list[AccountActivityPeriodSchema]: """Load activity periods for a specified account. Args: account_id (int): Account to get periods for payload (AccountActivityPeriodsDataloaderSchema): JSON body payload subaccount_id (int): Optional ID of a subaccount to filter by is_subaccount (bool): Whether the request is made by a subaccount Returns: list: list of activity periods """ if not payload.activity_period_ids: return [] return account_logic.get_activity_periods_by_account( account_id, subaccount_id, payload.activity_period_ids)