diff options
| author | Max Nanis | 2026-08-21 01:38:27 -0700 |
|---|---|---|
| committer | Max Nanis | 2026-08-21 01:38:27 -0700 |
| commit | 05102628a7dc85a5a19a32415a7ec41ea7a91812 (patch) | |
| tree | f5253ad2f57a9f05776eaf8f5dfb21bedbd08c7e /test_utils/managers/ledger | |
| parent | 0c10237223829818752ab4fc431957c0b22a0e23 (diff) | |
| download | generalresearch-05102628a7dc85a5a19a32415a7ec41ea7a91812.tar.gz generalresearch-05102628a7dc85a5a19a32415a7ec41ea7a91812.zip | |
moving create_dummy, organizing test_utils, working on django config for any repos
Diffstat (limited to 'test_utils/managers/ledger')
| -rw-r--r-- | test_utils/managers/ledger/conftest.py | 778 |
1 files changed, 66 insertions, 712 deletions
diff --git a/test_utils/managers/ledger/conftest.py b/test_utils/managers/ledger/conftest.py index 0aa6cb3..ce8348e 100644 --- a/test_utils/managers/ledger/conftest.py +++ b/test_utils/managers/ledger/conftest.py @@ -1,740 +1,94 @@ -from datetime import datetime -from decimal import Decimal -from random import randint -from typing import TYPE_CHECKING, Callable, Dict, Optional -from uuid import uuid4 +from __future__ import annotations import pytest -from generalresearch.currency import USDCent -from generalresearch.managers.base import PostgresManager -from test_utils.models.conftest import ( - payout_config, - product_amt_true, - product_user_wallet_no, - product_user_wallet_yes, - session, - session_factory, - user_factory, - wall, - wall_factory, +from generalresearch.managers.base import Permission +from generalresearch.managers.thl.ledger_manager.ledger import ( + LedgerAccountManager, + LedgerManager, + LedgerTransactionManager, ) - -_ = ( - user_factory, - product_user_wallet_no, - wall, - product_amt_true, - product_user_wallet_yes, - session_factory, - session, - wall_factory, - payout_config, +from generalresearch.managers.thl.ledger_manager.thl_ledger import ( + ThlLedgerManager, ) +from generalresearch.pg_helper import PostgresConfig +from generalresearch.redis_helper import RedisConfig -if TYPE_CHECKING: - - from generalresearch.currency import LedgerCurrency - from generalresearch.managers.thl.ledger_manager.ledger import LedgerManager - from generalresearch.managers.thl.ledger_manager.thl_ledger import ( - ThlLedgerManager, - ) - from generalresearch.managers.thl.payout import ( - BrokerageProductPayoutEventManager, - BusinessPayoutEventManager, - ) - from generalresearch.managers.thl.session import SessionManager - from generalresearch.managers.thl.wall import WallManager - from generalresearch.models.thl.ledger import ( - LedgerAccount, - LedgerTransaction, - ) - from generalresearch.models.thl.payout import ( - BrokerageProductPayoutEvent, - ) - from generalresearch.models.thl.product import Product - from generalresearch.models.thl.session import Session - from generalresearch.models.thl.user import User - - -@pytest.fixture -def ledger_account( - request, lm: "LedgerManager", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) +# --- Ledger --- - account_type = getattr(request, "account_type", AccountType.CASH) - direction = getattr(request, "direction", Direction.CREDIT) - acct_uuid = uuid4().hex - qn = ":".join([currency, account_type, acct_uuid]) +@pytest.fixture(scope="session") +def ledger_manager( + thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig +) -> LedgerManager: - acct_model = LedgerAccount( - uuid=acct_uuid, - display_name=f"test-{acct_uuid}", - currency=currency, - qualified_name=qn, - account_type=account_type, - normal_balance=direction, + return LedgerManager( + pg_config=thl_web_rw, + permissions=[ + Permission.CREATE, + Permission.READ, + Permission.UPDATE, + Permission.DELETE, + ], + testing=True, + redis_config=thl_redis_config, ) - return lm.create_account(account=acct_model) - - -@pytest.fixture -def ledger_account_factory( - request, thl_lm: "ThlLedgerManager", lm: "LedgerManager", currency: "LedgerCurrency" -) -> Callable[..., "LedgerAccount"]: - - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - def _inner( - product: "Product", - account_type: AccountType = AccountType.CASH, - direction: Direction = Direction.CREDIT, - ) -> "LedgerAccount": - thl_lm.get_account_or_create_bp_wallet(product=product) - acct_uuid = uuid4().hex - qn = ":".join([currency, account_type, acct_uuid]) - - acct_model = LedgerAccount( - uuid=acct_uuid, - display_name=f"test-{acct_uuid}", - currency=currency, - qualified_name=qn, - account_type=account_type, - normal_balance=direction, - ) - return lm.create_account(account=acct_model) - - return _inner - -@pytest.fixture -def ledger_account_credit( - request, lm: "LedgerManager", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import AccountType, Direction - account_type = AccountType.REVENUE - acct_uuid = uuid4().hex +@pytest.fixture(scope="session") +def ledger_tx_manager( + thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig +) -> LedgerTransactionManager: + assert thl_web_rw.dsn.path + assert "/unittest-" in thl_web_rw.dsn.path - qn = ":".join([currency, account_type, acct_uuid]) - from generalresearch.models.thl.ledger import LedgerAccount - - acct_model = LedgerAccount( - uuid=acct_uuid, - display_name=f"test-{acct_uuid}", - currency=currency, - qualified_name=qn, - account_type=account_type, - normal_balance=Direction.CREDIT, + from generalresearch.managers.thl.ledger_manager.ledger import ( + LedgerTransactionManager, ) - return lm.create_account(account=acct_model) - - -@pytest.fixture -def ledger_account_debit( - request, lm: "LedgerManager", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import AccountType, Direction - - account_type = AccountType.EXPENSE - acct_uuid = uuid4().hex - - qn = ":".join([currency, account_type, acct_uuid]) - from generalresearch.models.thl.ledger import LedgerAccount - acct_model = LedgerAccount( - uuid=acct_uuid, - display_name=f"test-{acct_uuid}", - currency=currency, - qualified_name=qn, - account_type=account_type, - normal_balance=Direction.DEBIT, + return LedgerTransactionManager( + pg_config=thl_web_rw, + permissions=[Permission.CREATE, Permission.READ], + testing=True, + redis_config=thl_redis_config, ) - return lm.create_account(account=acct_model) -@pytest.fixture -def tag(request, lm: "LedgerManager") -> str: - from generalresearch.currency import LedgerCurrency +@pytest.fixture(scope="session") +def ledger_account_manager( + thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig +) -> LedgerAccountManager: + assert thl_web_rw.dsn.path + assert "/unittest-" in thl_web_rw.dsn.path - return ( - request.param - if hasattr(request, "tag") - else f"{LedgerCurrency.TEST}:{uuid4().hex}" + from generalresearch.managers.thl.ledger_manager.ledger import ( + LedgerAccountManager, ) - -@pytest.fixture -def usd_cent(request) -> USDCent: - amount = randint(99, 9_999) - return request.param if hasattr(request, "usd_cent") else USDCent(amount) - - -@pytest.fixture -def bp_payout_event( - product: "Product", - usd_cent: "USDCent", - business_payout_event_manager: "BusinessPayoutEventManager", - thl_lm: "ThlLedgerManager", -) -> "BrokerageProductPayoutEvent": - - return business_payout_event_manager.create_bp_payout_event( - thl_ledger_manager=thl_lm, - product=product, - amount=usd_cent, - skip_wallet_balance_check=True, - skip_one_per_day_check=True, + return LedgerAccountManager( + pg_config=thl_web_rw, + permissions=[Permission.CREATE, Permission.READ], + testing=True, + redis_config=thl_redis_config, ) -@pytest.fixture -def bp_payout_event_factory( - brokerage_product_payout_event_manager: "BrokerageProductPayoutEventManager", - thl_lm: "ThlLedgerManager", -) -> Callable[..., "BrokerageProductPayoutEvent"]: +# --- THL Ledger --- - from generalresearch.currency import USDCent - from generalresearch.models.thl.product import Product - - def _inner( - product: Product, usd_cent: USDCent, ext_ref_id: Optional[str] = None - ) -> "BrokerageProductPayoutEvent": - - return brokerage_product_payout_event_manager.create_bp_payout_event( - thl_ledger_manager=thl_lm, - product=product, - amount=usd_cent, - ext_ref_id=ext_ref_id, - skip_wallet_balance_check=True, - skip_one_per_day_check=True, - ) - - return _inner - - -@pytest.fixture -def currency(lm: "LedgerManager") -> "LedgerCurrency": - # return request.param if hasattr(request, "currency") else LedgerCurrency.TEST - assert lm.currency, "LedgerManager must have a currency specified for these tests" - return lm.currency - - -@pytest.fixture -def tx_metadata(request) -> Optional[Dict[str, str]]: - return ( - request.param - if hasattr(request, "tx_metadata") - else {f"key-{uuid4().hex[:10]}": uuid4().hex} - ) - - -@pytest.fixture -def ledger_tx( - request, - ledger_account_credit: "LedgerAccount", - ledger_account_debit: "LedgerAccount", - tag: str, - currency: "LedgerCurrency", - tx_metadata: Optional[Dict[str, str]], - lm: "LedgerManager", -) -> "LedgerTransaction": - from generalresearch.models.thl.ledger import Direction, LedgerEntry - - amount = int(Decimal("1.00") * 100) - - entries = [ - LedgerEntry( - direction=Direction.CREDIT, - account_uuid=ledger_account_credit.uuid, - amount=amount, - ), - LedgerEntry( - direction=Direction.DEBIT, - account_uuid=ledger_account_debit.uuid, - amount=amount, - ), - ] - - return lm.create_tx(entries=entries, tag=tag, metadata=tx_metadata) - - -@pytest.fixture -def create_main_accounts( - lm: "LedgerManager", currency: "LedgerCurrency" -) -> Callable[..., None]: - - def _inner() -> None: - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - account = LedgerAccount( - display_name="Cash flow task complete", - qualified_name=f"{currency.value}:revenue:task_complete", - normal_balance=Direction.CREDIT, - account_type=AccountType.REVENUE, - currency=lm.currency, - ) - lm.get_account_or_create(account=account) - - account = LedgerAccount( - display_name="Operating Cash Account", - qualified_name=f"{currency.value}:cash", - normal_balance=Direction.DEBIT, - account_type=AccountType.CASH, - currency=currency, - ) - - lm.get_account_or_create(account=account) - - return None - - return _inner - - -@pytest.fixture -def delete_ledger_db(thl_web_rw: "PostgresManager") -> Callable[..., None]: - - def _inner(): - for table in [ - "ledger_transactionmetadata", - "ledger_entry", - "ledger_transaction", - "ledger_account", - ]: - thl_web_rw.execute_write( - query=f"DELETE FROM {table};", - ) - - return _inner - - -@pytest.fixture -def wipe_main_accounts( - thl_web_rw: "PostgresManager", lm: "LedgerManager", currency: "LedgerCurrency" -) -> Callable[..., None]: - - def _inner() -> None: - db_table = thl_web_rw.db_name - qual_names = [ - f"{currency.value}:revenue:task_complete", - f"{currency.value}:cash", - ] - - res = thl_web_rw.execute_sql_query( - query=f""" - SELECT lt.id as ltid, le.id as leid, tmd.id as tmdid, la.uuid as lauuid - FROM `{db_table}`.`ledger_transaction` AS lt - LEFT JOIN `{db_table}`.ledger_entry le - ON lt.id = le.transaction_id - LEFT JOIN `{db_table}`.ledger_account la - ON la.uuid = le.account_id - LEFT JOIN `{db_table}`.ledger_transactionmetadata tmd - ON lt.id = tmd.transaction_id - WHERE la.qualified_name IN %s - """, - params=[qual_names], - ) - - lt = {x["ltid"] for x in res if x["ltid"]} - le = {x["leid"] for x in res if x["leid"]} - tmd = {x["tmdid"] for x in res if x["tmdid"]} - la = {x["lauuid"] for x in res if x["lauuid"]} - - thl_web_rw.execute_sql_query( - query=f""" - DELETE FROM `{db_table}`.`ledger_transactionmetadata` - WHERE id IN %s - """, - params=[tmd], - commit=True, - ) - - thl_web_rw.execute_sql_query( - query=f""" - DELETE FROM `{db_table}`.`ledger_entry` - WHERE id IN %s - """, - params=[le], - commit=True, - ) - - thl_web_rw.execute_sql_query( - query=f""" - DELETE FROM `{db_table}`.`ledger_transaction` - WHERE id IN %s - """, - params=[lt], - commit=True, - ) - - thl_web_rw.execute_sql_query( - query=f""" - DELETE FROM `{db_table}`.`ledger_account` - WHERE uuid IN %s - """, - params=[la], - commit=True, - ) - - return None - - return _inner - - -@pytest.fixture -def account_cash(lm: "LedgerManager", currency: "LedgerCurrency") -> "LedgerAccount": - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - account = LedgerAccount( - display_name="Operating Cash Account", - qualified_name=f"{currency.value}:cash", - normal_balance=Direction.DEBIT, - account_type=AccountType.CASH, - currency=currency, - ) - return lm.get_account_or_create(account=account) +@pytest.fixture(scope="session") +def thl_ledger_manager( + thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig +) -> ThlLedgerManager: -@pytest.fixture -def account_revenue_task_complete( - lm: "LedgerManager", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, + return ThlLedgerManager( + pg_config=thl_web_rw, + permissions=[ + Permission.CREATE, + Permission.READ, + Permission.UPDATE, + Permission.DELETE, + ], + testing=True, + redis_config=thl_redis_config, ) - - account = LedgerAccount( - display_name="Cash flow task complete", - qualified_name=f"{currency.value}:revenue:task_complete", - normal_balance=Direction.CREDIT, - account_type=AccountType.REVENUE, - currency=currency, - ) - return lm.get_account_or_create(account=account) - - -@pytest.fixture -def account_expense_tango( - lm: "LedgerManager", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - account = LedgerAccount( - display_name="Tango Fee", - qualified_name=f"{currency.value}:expense:tango_fee", - normal_balance=Direction.DEBIT, - account_type=AccountType.EXPENSE, - currency=currency, - ) - return lm.get_account_or_create(account=account) - - -@pytest.fixture -def user_account_user_wallet( - lm: "LedgerManager", user: "User", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - account = LedgerAccount( - display_name=f"{user.uuid} Wallet", - qualified_name=f"{currency.value}:user_wallet:{user.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.USER_WALLET, - reference_type="user", - reference_uuid=user.uuid, - currency=currency, - ) - return lm.get_account_or_create(account=account) - - -@pytest.fixture -def product_account_bp_wallet( - lm: "LedgerManager", product: "Product", currency: "LedgerCurrency" -) -> "LedgerAccount": - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - account = LedgerAccount.model_validate( - dict( - display_name=f"{product.name} Wallet", - qualified_name=f"{currency.value}:bp_wallet:{product.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.BP_WALLET, - reference_type="bp", - reference_uuid=product.uuid, - currency=currency, - ) - ) - return lm.get_account_or_create(account=account) - - -@pytest.fixture -def setup_accounts( - product_factory: Callable[..., "Product"], - lm: "LedgerManager", - user: "User", - currency: "LedgerCurrency", -) -> None: - from generalresearch.models.thl.ledger import ( - AccountType, - Direction, - LedgerAccount, - ) - - # BP's wallet and a revenue from their commissions account. - p1 = product_factory() - - account = LedgerAccount( - display_name=f"Revenue from {p1.name} commission", - qualified_name=f"{currency.value}:revenue:bp_commission:{p1.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.REVENUE, - reference_type="bp", - reference_uuid=p1.uuid, - currency=currency, - ) - lm.get_account_or_create(account=account) - - account = LedgerAccount.model_validate( - dict( - display_name=f"{p1.name} Wallet", - qualified_name=f"{currency.value}:bp_wallet:{p1.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.BP_WALLET, - reference_type="bp", - reference_uuid=p1.uuid, - currency=currency, - ) - ) - lm.get_account_or_create(account=account) - - # BP's wallet, user's wallet, and a revenue from their commissions account. - p2 = product_factory() - account = LedgerAccount( - display_name=f"Revenue from {p2.name} commission", - qualified_name=f"{currency.value}:revenue:bp_commission:{p2.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.REVENUE, - reference_type="bp", - reference_uuid=p2.uuid, - currency=currency, - ) - lm.get_account_or_create(account) - - account = LedgerAccount( - display_name=f"{p2.name} Wallet", - qualified_name=f"{currency.value}:bp_wallet:{p2.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.BP_WALLET, - reference_type="bp", - reference_uuid=p2.uuid, - currency=currency, - ) - lm.get_account_or_create(account) - - account = LedgerAccount( - display_name=f"{user.uuid} Wallet", - qualified_name=f"{currency.value}:user_wallet:{user.uuid}", - normal_balance=Direction.CREDIT, - account_type=AccountType.USER_WALLET, - reference_type="user", - reference_uuid=user.uuid, - currency="test", - ) - lm.get_account_or_create(account=account) - - -@pytest.fixture -def session_with_tx_factory( - user_factory: Callable[..., "User"], - product: "Product", - session_factory: Callable[..., "Session"], - session_manager: "SessionManager", - wall_manager: "WallManager", - utc_hour_ago: datetime, - thl_lm: "ThlLedgerManager", -) -> Callable[..., "Session"]: - - from generalresearch.models.thl.session import ( - Status, - StatusCode1, - ) - from generalresearch.models.thl.user import User - - def _inner( - user: User, - final_status: Status = Status.COMPLETE, - wall_req_cpi: Decimal = Decimal(".50"), - started: datetime = utc_hour_ago, - ) -> Session: - s: Session = session_factory( - user=user, - wall_count=2, - final_status=final_status, - wall_req_cpi=wall_req_cpi, - started=started, - ) - last_wall = s.wall_events[-1] - - wall_manager.finish( - wall=last_wall, - status=Status.COMPLETE, - status_code_1=StatusCode1.COMPLETE, - finished=last_wall.finished, - ) - - status, status_code_1 = s.determine_session_status() - _, _, bp_pay, user_pay = s.determine_payments() - session_manager.finish_with_status( - session=s, - finished=last_wall.finished, - payout=bp_pay, - user_payout=user_pay, - status=status, - status_code_1=status_code_1, - ) - - thl_lm.create_tx_task_complete( - wall=last_wall, - user=user, - created=last_wall.finished, - force=True, - ) - - thl_lm.create_tx_bp_payment(session=s, created=last_wall.finished, force=True) - - return s - - return _inner - - -@pytest.fixture -def adj_to_fail_with_tx_factory( - session_manager: "SessionManager", - wall_manager: "WallManager", - thl_lm: "ThlLedgerManager", -) -> Callable[..., None]: - from datetime import datetime, timedelta - - from generalresearch.models.thl.definitions import WallAdjustedStatus - from generalresearch.models.thl.session import ( - Session, - ) - - def _inner( - session: Session, - created: datetime, - ) -> None: - w1 = wall_manager.get_wall_events(session_id=session.id)[-1] - - # This is defined in `thl-grpc/thl/user_quality_history/recons.py:150` - # so we can't use it as part of this test anyway to add rows to the - # thl_taskadjustment table anyway.. until we created a - # TaskAdjustment Manager to put into generalresearch! - - # create_task_adjustment_event( - # wall, - # user, - # adjusted_status, - # amount_usd=amount_usd, - # alert_time=alert_time, - # ext_status_code=ext_status_code, - # ) - - wall_manager.adjust_status( - wall=w1, - adjusted_status=WallAdjustedStatus.ADJUSTED_TO_FAIL, - adjusted_cpi=Decimal("0.00"), - adjusted_timestamp=created, - ) - - thl_lm.create_tx_task_adjustment( - wall=w1, - user=session.user, - created=created + timedelta(milliseconds=1), - ) - - session.wall_events = wall_manager.get_wall_events(session_id=session.id) - session_manager.adjust_status(session=session) - - thl_lm.create_tx_bp_adjustment( - session=session, created=created + timedelta(milliseconds=2) - ) - - return None - - return _inner - - -@pytest.fixture -def adj_to_complete_with_tx_factory( - session_manager: "SessionManager", - wall_manager: "WallManager", - thl_lm: "ThlLedgerManager", -) -> Callable[..., None]: - from datetime import timedelta - - from generalresearch.models.thl.definitions import WallAdjustedStatus - from generalresearch.models.thl.session import ( - Session, - ) - - def _inner( - session: Session, - created: datetime, - ) -> None: - w1 = wall_manager.get_wall_events(session_id=session.id)[-1] - - wall_manager.adjust_status( - wall=w1, - adjusted_status=WallAdjustedStatus.ADJUSTED_TO_COMPLETE, - adjusted_cpi=w1.req_cpi, - adjusted_timestamp=created, - ) - - thl_lm.create_tx_task_adjustment( - wall=w1, - user=session.user, - created=created + timedelta(milliseconds=1), - ) - - session.wall_events = wall_manager.get_wall_events(session_id=session.id) - session_manager.adjust_status(session=session) - - thl_lm.create_tx_bp_adjustment( - session=session, created=created + timedelta(milliseconds=2) - ) - - return None - - return _inner |
