aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--generalresearch/managers/thl/payout.py110
-rw-r--r--tests/managers/thl/test_payout.py168
2 files changed, 74 insertions, 204 deletions
diff --git a/generalresearch/managers/thl/payout.py b/generalresearch/managers/thl/payout.py
index 4409a63..551758f 100644
--- a/generalresearch/managers/thl/payout.py
+++ b/generalresearch/managers/thl/payout.py
@@ -16,6 +16,10 @@ from generalresearch.currency import USDCent
from generalresearch.decorators import LOG
from generalresearch.managers.base import (
PostgresManagerWithRedis,
+ Permission,
+)
+from generalresearch.managers.thl.ledger_manager.exceptions import (
+ LedgerTransactionConditionFailedError,
)
from generalresearch.managers.thl.ledger_manager.thl_ledger import (
ThlLedgerManager,
@@ -41,6 +45,8 @@ from generalresearch.models.thl.wallet.cashout_method import (
CashMailOrderData,
CashoutRequestInfo,
)
+from generalresearch.pg_helper import PostgresConfig
+from generalresearch.redis_helper import RedisConfig
class PayoutEventManager(PostgresManagerWithRedis):
@@ -51,27 +57,6 @@ class PayoutEventManager(PostgresManagerWithRedis):
"""
- def set_account_lookup_table(self, thl_lm: ThlLedgerManager) -> None:
- """This needs to run from grl-flow or from somewhere that has thl-redis
- access
- """
-
- res = self.pg_config.execute_sql_query(
- query=f"""
- SELECT uuid, reference_uuid
- FROM ledger_account
- WHERE qualified_name LIKE '{thl_lm.currency.value}:bp_wallet:%'
- """
- )
- account_to_product = {i["uuid"]: i["reference_uuid"] for i in res}
- product_to_account = {i["reference_uuid"]: i["uuid"] for i in res}
-
- rc = self.redis_client
- rc.hset(name="pem:account_to_product", mapping=account_to_product)
- rc.hset(name="pem:product_to_account", mapping=product_to_account)
-
- return None
-
def get_by_uuid(self, pe_uuid: UUIDStr) -> PayoutEvent:
res = self.pg_config.execute_sql_query(
query="""
@@ -316,7 +301,7 @@ class UserPayoutEventManager(PayoutEventManager):
request_data=request_data or {},
order_data=order_data,
)
- d = payout_event.model_dump_mysql()
+ d = payout_event.model_dump_postgres()
with self.pg_config.make_connection() as conn:
with conn.cursor() as c:
@@ -593,54 +578,18 @@ class BrokerageProductPayoutEventManager(PayoutEventManager):
self.update(payout_event=bp_pe, status=PayoutStatus.COMPLETE)
return bp_pe
- return self._create_tx_bp_payout_from_payout_event(
+ return self.create_tx_bp_payout_from_payout_event(
thl_ledger_manager=thl_ledger_manager,
bp_pe=bp_pe,
product=product,
- skip_one_per_day_check=True,
- skip_wallet_balance_check=True,
)
- def create_pending_bp_payout_events(
- self,
- product: Product,
- amount: USDCent,
- payout_type: PayoutType = PayoutType.ACH,
- ext_ref_id: str | None = None,
- created: AwareDatetime | None = None,
- ):
- pass
-
- # def create_bp_payout_event(
- # self,
- # thl_ledger_manager: ThlLedgerManager,
- # product: Product,
- # amount: USDCent,
- # payout_type: PayoutType = PayoutType.ACH,
- # ext_ref_id: str | None = None,
- # created: AwareDatetime | None = None,
- # skip_wallet_balance_check: bool = False,
- # skip_one_per_day_check: bool = False,
- # ) -> BrokerageProductPayoutEvent:
- #
- # return self._create_tx_bp_payout_from_payout_event(
- # thl_ledger_manager=thl_ledger_manager,
- # bp_pe=bp_pe,
- # product=product,
- # amount=amount,
- # created=created,
- # skip_one_per_day_check=skip_one_per_day_check,
- # skip_wallet_balance_check=skip_wallet_balance_check,
- # )
-
- def _create_tx_bp_payout_from_payout_event(
+ def create_tx_bp_payout_from_payout_event(
self,
thl_ledger_manager: ThlLedgerManager,
bp_pe: BrokerageProductPayoutEvent,
product: Product,
created: AwareDatetime | None = None,
- skip_wallet_balance_check: bool = False,
- skip_one_per_day_check: bool = False,
) -> BrokerageProductPayoutEvent:
"""
This should not be called directly.
@@ -655,22 +604,25 @@ class BrokerageProductPayoutEventManager(PayoutEventManager):
amount=USDCent(bp_pe.amount),
payoutevent_uuid=bp_pe.uuid,
created=created,
- skip_wallet_balance_check=skip_wallet_balance_check,
- skip_one_per_day_check=skip_one_per_day_check,
+ skip_wallet_balance_check=True,
+ skip_one_per_day_check=True,
)
+ except LedgerTransactionConditionFailedError as e:
+ if e.args[0] == "duplicate tag":
+ raise ValueError(
+ f"""Payout event already exists! {e}
+ You are trying to create a tx that already exists. We can't know
+ if this is a new payout event with the same ref id, or you're
+ trying to run the same one twice ... So not setting the existing
+ payout event to FAILED, b/c the existing one is not failed!
+ Doing nothing ...
+ """
+ ) from e
+ self.update(payout_event=bp_pe, status=PayoutStatus.FAILED)
+ raise
except Exception as e:
- e.pe_uuid = bp_pe.uuid
- if self.check_for_ledger_tx(
- thl_ledger_manager=thl_ledger_manager,
- payout_event=bp_pe,
- ):
- LOG.warning(f"Got exception {e} but ledger tx exists! Continuing ... ")
- self.update(payout_event=bp_pe, status=PayoutStatus.COMPLETE)
- return bp_pe
- else:
- LOG.warning(f"Got exception {e}. No ledger tx was created.")
- self.update(payout_event=bp_pe, status=PayoutStatus.FAILED)
- raise e
+ self.update(payout_event=bp_pe, status=PayoutStatus.FAILED)
+ raise
self.update(payout_event=bp_pe, status=PayoutStatus.COMPLETE)
return bp_pe
@@ -701,6 +653,10 @@ class BrokerageProductPayoutEventManager(PayoutEventManager):
class BusinessPayoutEventManager(PostgresManagerWithRedis):
+ def __init__(self, *arg, **kwargs):
+ super().__init__(*arg, **kwargs)
+ self.bp_pe_manager = BrokerageProductPayoutEventManager(*arg, **kwargs)
+
def get_by_ext_ref_id(self, ext_ref_id: str) -> BusinessPayoutEvent:
res = self.pg_config.execute_sql_query(
"""
@@ -1145,7 +1101,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis):
amount=USDCent(item["issue_amount"]),
ext_ref_id=transaction_id,
product_id=product.uuid,
- cashout_method_uuid=self.CASHOUT_METHOD_UUID,
+ cashout_method_uuid=self.bp_pe_manager.CASHOUT_METHOD_UUID,
debit_account_uuid=wallet_lookup[product_id],
)
)
@@ -1159,12 +1115,10 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis):
# from the BrokerageProductPayoutEvents
for bp_pe in bpe.bp_payouts:
product = product_lookup[bp_pe.product_id]
- self._create_tx_bp_payout_from_payout_event(
+ self.bp_pe_manager.create_tx_bp_payout_from_payout_event(
thl_ledger_manager=thl_lm,
bp_pe=bp_pe,
product=product,
- skip_one_per_day_check=True,
- skip_wallet_balance_check=True,
)
self.update_business_payout_event(pk=bpe.id, status=PayoutStatus.COMPLETE)
diff --git a/tests/managers/thl/test_payout.py b/tests/managers/thl/test_payout.py
index 000f425..03cd441 100644
--- a/tests/managers/thl/test_payout.py
+++ b/tests/managers/thl/test_payout.py
@@ -11,6 +11,7 @@ import pandas as pd
import pytest
from generalresearch import pg_helper
+from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
from generalresearch.models.thl.product import Product
from generalresearch.models.thl.user import User
from generalresearch.currency import USDCent
@@ -106,82 +107,43 @@ class TestPayout:
delete_ledger_db,
create_main_accounts,
):
- delete_ledger_db()
- create_main_accounts()
- from generalresearch.models.thl.ledger import LedgerAccount
-
- thl_lm.get_account_or_create_bp_wallet(product=product)
- brokerage_product_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
-
- with pytest.raises(expected_exception=LedgerTransactionConditionFailedError):
- # wallet balance failure
- brokerage_product_payout_event_manager.create_bp_payout_event(
- thl_ledger_manager=thl_lm,
- product=product,
- amount=USDCent(100),
- skip_wallet_balance_check=False,
- skip_one_per_day_check=False,
- )
+ # create_bp_payout_event does not get called directly. We have tests
+ # for the ledger methods already
+ pass
- # (we don't have a special method for this) Put money in the BP's account
- amount_cents = 100
- cash_account: LedgerAccount = thl_lm.get_account_cash()
- bp_wallet: LedgerAccount = thl_lm.get_account_or_create_bp_wallet(
- product=product
- )
-
- entries = [
- LedgerEntry(
- direction=Direction.DEBIT,
- account_uuid=cash_account.uuid,
- amount=amount_cents,
- ),
- LedgerEntry(
- direction=Direction.CREDIT,
- account_uuid=bp_wallet.uuid,
- amount=amount_cents,
- ),
- ]
-
- lm.create_tx(entries=entries)
- assert 100 == lm.get_account_balance(account=bp_wallet)
-
- # Then run it again for $1.00
- brokerage_product_payout_event_manager.create_bp_payout_event(
- thl_ledger_manager=thl_lm,
- product=product,
- amount=USDCent(100),
- skip_wallet_balance_check=False,
- skip_one_per_day_check=False,
- )
- assert 0 == lm.get_account_balance(account=bp_wallet)
-
- # Run again should without balance check, should still fail due to day check
- with pytest.raises(LedgerTransactionConditionFailedError):
- brokerage_product_payout_event_manager.create_bp_payout_event(
- thl_ledger_manager=thl_lm,
- product=product,
- amount=USDCent(100),
- skip_wallet_balance_check=True,
- skip_one_per_day_check=False,
- )
-
- # And then we can run again skip both checks
- pe = brokerage_product_payout_event_manager.create_bp_payout_event(
- thl_ledger_manager=thl_lm,
- product=product,
+ @pytest.fixture
+ def pending_bp_pe(
+ self,
+ thl_web_rw,
+ product,
+ thl_lm: ThlLedgerManager,
+ brokerage_product_payout_event_manager,
+ utc_now
+ ) -> BrokerageProductPayoutEvent:
+ account = thl_lm.get_account_or_create_bp_wallet(product=product)
+ bp_pe = BrokerageProductPayoutEvent(
+ product_id=product.uuid,
amount=USDCent(100),
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
- )
- assert -100 == lm.get_account_balance(account=bp_wallet)
-
- pe = brokerage_product_payout_event_manager.get_by_uuid(pe.uuid)
- txs = lm.get_tx_filtered_by_metadata(
- metadata_key="event_payout", metadata_value=pe.uuid
- )
-
- assert 1 == len(txs)
+ payout_type=PayoutType.ACH,
+ debit_account_uuid=account.uuid,
+ cashout_method_uuid=brokerage_product_payout_event_manager.CASHOUT_METHOD_UUID,
+ created=utc_now
+ )
+ params = bp_pe.model_dump_postgres()
+ # This shouldn't exist. For testing only, so no supplier_payout
+ params['supplier_payout_id'] = None
+ thl_web_rw.execute_write("""
+ INSERT INTO event_payout (
+ uuid, debit_account_uuid, created, cashout_method_uuid,
+ amount, status, ext_ref_id, payout_type, order_data,
+ request_data, supplier_payout_id
+ ) VALUES (
+ %(uuid)s, %(debit_account_uuid)s, %(created)s, %(cashout_method_uuid)s,
+ %(amount)s, %(status)s, %(ext_ref_id)s, %(payout_type)s, %(order_data)s,
+ %(request_data)s, %(supplier_payout_id)s
+ );
+ """, params)
+ return bp_pe
def test_create_bp_payout_quick_dupe(
self,
@@ -193,26 +155,22 @@ class TestPayout:
lm,
utc_now,
create_main_accounts,
+ pending_bp_pe,
):
thl_lm.get_account_or_create_bp_wallet(product=product)
- brokerage_product_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
- brokerage_product_payout_event_manager.create_bp_payout_event(
+ brokerage_product_payout_event_manager.create_tx_bp_payout_from_payout_event(
thl_ledger_manager=thl_lm,
+ bp_pe=pending_bp_pe,
product=product,
- amount=USDCent(100),
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
created=utc_now,
)
with pytest.raises(ValueError) as cm:
- brokerage_product_payout_event_manager.create_bp_payout_event(
+ brokerage_product_payout_event_manager.create_tx_bp_payout_from_payout_event(
thl_ledger_manager=thl_lm,
product=product,
- amount=USDCent(100),
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
+ bp_pe=pending_bp_pe,
created=utc_now,
)
assert "Payout event already exists!" in str(cm.value)
@@ -297,44 +255,7 @@ class TestPayout:
class TestPayoutEventManager:
- def test_set_account_lookup_table(
- self, payout_event_manager, thl_redis_config, thl_lm, delete_ledger_db
- ):
- delete_ledger_db()
- rc = thl_redis_config.create_redis_client()
- rc.delete("pem:account_to_product")
- rc.delete("pem:product_to_account")
- N = 5
-
- for idx in range(N):
- thl_lm.get_account_or_create_bp_wallet_by_uuid(product_uuid=uuid4().hex)
-
- res = rc.hgetall(name="pem:account_to_product")
- assert len(res.items()) == 0
-
- res = rc.hgetall(name="pem:product_to_account")
- assert len(res.items()) == 0
-
- payout_event_manager.set_account_lookup_table(
- thl_lm=thl_lm,
- )
-
- res = rc.hgetall(name="pem:account_to_product")
- assert len(res.items()) == N
-
- res = rc.hgetall(name="pem:product_to_account")
- assert len(res.items()) == N
-
- thl_lm.get_account_or_create_bp_wallet_by_uuid(product_uuid=uuid4().hex)
- payout_event_manager.set_account_lookup_table(
- thl_lm=thl_lm,
- )
-
- res = rc.hgetall(name="pem:account_to_product")
- assert len(res.items()) == N + 1
-
- res = rc.hgetall(name="pem:product_to_account")
- assert len(res.items()) == N + 1
+ pass
class TestBusinessPayoutEventManager:
@@ -368,7 +289,6 @@ class TestBusinessPayoutEventManager:
p1: Product = product_factory(business=business)
thl_lm.get_account_or_create_bp_wallet(product=p1)
- business_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
ach_id1 = uuid4().hex
ach_id2 = uuid4().hex
@@ -406,8 +326,6 @@ class TestBusinessPayoutEventManager:
)
business.prebuild_payouts(
- thl_pg_config=thl_web_rr,
- thl_lm=thl_lm,
bpem=business_payout_event_manager,
)
@@ -1213,8 +1131,6 @@ class TestBusinessPayoutEventManager:
pop_ledger=pop_ledger_merge,
)
business.prebuild_payouts(
- thl_pg_config=thl_web_rr,
- thl_lm=thl_lm,
bpem=business_payout_event_manager,
)