diff options
| author | stuppie | 2026-08-20 16:01:07 -0600 |
|---|---|---|
| committer | stuppie | 2026-08-20 16:01:07 -0600 |
| commit | 85cfaf5a7bcf49e225d01eba3f07978ece7248c8 (patch) | |
| tree | a1ea528a7f509f96b89b0651b1a4c1ef1222a3bd | |
| parent | 8e0d9c60f237fc0e0d763751650c609b93fb3db6 (diff) | |
| download | generalresearch-85cfaf5a7bcf49e225d01eba3f07978ece7248c8.tar.gz generalresearch-85cfaf5a7bcf49e225d01eba3f07978ece7248c8.zip | |
tests for prev commits. working on cleaning up Business.prebuild_* stuff
| -rw-r--r-- | generalresearch/managers/thl/payout.py | 81 | ||||
| -rw-r--r-- | generalresearch/models/gr/business.py | 13 | ||||
| -rw-r--r-- | tests/managers/thl/test_payout.py | 51 |
3 files changed, 93 insertions, 52 deletions
diff --git a/generalresearch/managers/thl/payout.py b/generalresearch/managers/thl/payout.py index 0e44926..4409a63 100644 --- a/generalresearch/managers/thl/payout.py +++ b/generalresearch/managers/thl/payout.py @@ -699,7 +699,7 @@ class BrokerageProductPayoutEventManager(PayoutEventManager): return self.get_bp_payout_events_for_accounts(accounts=accounts) -class BusinessPayoutEventManager(BrokerageProductPayoutEventManager): +class BusinessPayoutEventManager(PostgresManagerWithRedis): def get_by_ext_ref_id(self, ext_ref_id: str) -> BusinessPayoutEvent: res = self.pg_config.execute_sql_query( @@ -735,6 +735,54 @@ class BusinessPayoutEventManager(BrokerageProductPayoutEventManager): ), "No BP payouts found for this Business Payout Event. This shouldn't happen!" return bpe + def filter_by( + self, + business_uuids: Collection[UUIDStr] | None = None, + ) -> list[BusinessPayoutEvent]: + + params = dict() + filters = [] + if business_uuids is not None: + filters.append("business_id = ANY(%(business_uuids)s)") + params["business_uuids"] = business_uuids + + assert len(filters) > 0, "must pass at least 1 filter" + filter_str = " AND ".join(filters) + + res = self.pg_config.execute_sql_query( + f""" + SELECT + sp.*, + ep.bp_payouts + FROM supplier_payout sp + JOIN ( + SELECT + ep_inner.supplier_payout_id, + jsonb_agg( + to_jsonb(ep_inner) + || jsonb_build_object('product_id', la.reference_uuid) + ORDER BY ep_inner.created + ) AS bp_payouts + FROM event_payout ep_inner + JOIN ledger_account la + ON ep_inner.debit_account_uuid = la.uuid + GROUP BY ep_inner.supplier_payout_id + ) ep ON sp.id = ep.supplier_payout_id + WHERE {filter_str} + """, + params, + ) + bpes = [] + for row in res: + for bp_payout in row["bp_payouts"]: + bp_payout["created"] = datetime.fromisoformat(bp_payout["created"]) + bpe = BusinessPayoutEvent.model_validate(row) + assert ( + bpe.bp_payouts is not None and len(bpe.bp_payouts) > 0 + ), "No BP payouts found for this Business Payout Event. This shouldn't happen!" + bpes.append(bpe) + return bpes + def validate_business_payout_in_ledger( self, ext_ref_id: str, thl_lm: ThlLedgerManager ): @@ -807,34 +855,17 @@ class BusinessPayoutEventManager(BrokerageProductPayoutEventManager): return None - def get_business_payout_events_for_products( + def get_business_payout_events_for_business( self, - product_uuids: Collection[UUIDStr], + business_uuid: UUIDStr, order_by: OrderBy | None = OrderBy.ASC, ) -> list[BusinessPayoutEvent]: - res = self.get_bp_bp_payout_events_for_products( - product_uuids=product_uuids, - order_by=order_by, + order_by = order_by or OrderBy.ASC + bpes = self.filter_by( + business_uuids=[business_uuid], ) - - return self.from_bp_payout_events(bp_payout_events=res) - - @staticmethod - def from_bp_payout_events( - bp_payout_events: Collection[BrokerageProductPayoutEvent], - ) -> list[BusinessPayoutEvent]: - if len(bp_payout_events) == 0: - return [] - - grouped = defaultdict(list) - for bp_pe in bp_payout_events: - grouped[bp_pe.ext_ref_id].append(bp_pe) - - res = [] - for _, members in grouped.items(): - res.append(BusinessPayoutEvent.model_validate({"bp_payouts": members})) - - return res + bpes = sorted(bpes, key=lambda x: x.created, reverse=order_by == OrderBy.DESC) + return bpes @staticmethod def recoup_proportional( diff --git a/generalresearch/models/gr/business.py b/generalresearch/models/gr/business.py index bd66fbf..a842757 100644 --- a/generalresearch/models/gr/business.py +++ b/generalresearch/models/gr/business.py @@ -434,27 +434,22 @@ class Business(BaseModel): def prebuild_payouts( self, - thl_pg_config: PostgresConfig, - thl_lm: ThlLedgerManager, bpem: BusinessPayoutEventManager, ) -> None: LOG.debug(f"Business.prebuild_payouts({self.uuid=})") - self.prefetch_products(thl_pg_config=thl_pg_config) - - self.payouts = bpem.get_business_payout_events_for_products( - product_uuids=self.product_uuids, + self.payouts = bpem.get_business_payout_events_for_business( + business_uuid=self.uuid, order_by=OrderBy.DESC, ) - self.prebuild_payouts_total() + return None def prebuild_payouts_total(self): assert self.payouts is not None self.payouts_total = USDCent(sum([po.amount for po in self.payouts])) self.payouts_total_str = self.payouts_total.to_usd_str() - - return + return None def prebuild_pop_financial( self, diff --git a/tests/managers/thl/test_payout.py b/tests/managers/thl/test_payout.py index d586ba2..000f425 100644 --- a/tests/managers/thl/test_payout.py +++ b/tests/managers/thl/test_payout.py @@ -9,6 +9,8 @@ import io import pandas as pd import pytest + +from generalresearch import pg_helper from generalresearch.models.thl.product import Product from generalresearch.models.thl.user import User from generalresearch.currency import USDCent @@ -865,26 +867,19 @@ class TestBusinessPayoutEventManager: ach_id1 = uuid4().hex ach_id2 = uuid4().hex - # Product 1: Complete, Payout, Recon.. - s1 = session_with_tx_factory( - user=u1, - wall_req_cpi=Decimal("5.00"), - started=start + timedelta(days=1), - ) - - # Product 2: Complete x10 - for idx in range(15): + # Product 1: Complete $10 x 20 + for idx in range(20): session_with_tx_factory( user=u2, - wall_req_cpi=Decimal("7.50"), + wall_req_cpi=Decimal("10.00"), started=start + timedelta(days=1, hours=2, minutes=1 + idx), ) - # Product 3: Complete x5 - for idx in range(10): + # Product 2: Complete $10 x 30 + for idx in range(30): session_with_tx_factory( user=u3, - wall_req_cpi=Decimal("7.50"), + wall_req_cpi=Decimal("10.00"), started=start + timedelta(days=1, hours=3, minutes=1 + idx), ) @@ -899,12 +894,12 @@ class TestBusinessPayoutEventManager: ) bb = business.balance - assert bb.payout == 25 * 712 + 475 # $7.50 * .95% = $7.125 = $7.12 - assert bb.net == (25 * 7.12 + 4.75) * 100 + assert bb.payout == 475_00 # $500 * .95% = $475 + assert bb.net == 475_00 bp1 = business_payout_event_manager.create_from_ach_or_wire( business=business, - amount=USDCent(bb.available_balance), + amount=USDCent(100_00), pm=product_manager, thl_lm=thl_lm, created=start + timedelta(days=1, hours=5), @@ -912,7 +907,19 @@ class TestBusinessPayoutEventManager: ) print(f"{bp1=}") assert isinstance(bp1, BusinessPayoutEvent) - assert len(bp1.bp_payouts) == 3 + assert len(bp1.bp_payouts) == 2 + + bp2 = business_payout_event_manager.create_from_ach_or_wire( + business=business, + amount=USDCent(bb.available_balance), + pm=product_manager, + thl_lm=thl_lm, + created=start + timedelta(days=2, hours=5), + transaction_id=ach_id2, + ) + print(f"{bp2=}") + assert isinstance(bp2, BusinessPayoutEvent) + assert len(bp2.bp_payouts) == 2 with caplog.at_level(logging.WARNING): business_payout_event_manager.resume_failed_business_payout( @@ -920,7 +927,15 @@ class TestBusinessPayoutEventManager: ) assert "Nothing to do!" in caplog.text - bpe = business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id1) + # bpe = business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id1) + # bp_pe = bpe.bp_payouts[0] + # thl_web_rr.execute_write( + # """ + # UPDATE event_payout + # SET status = %(status)s + # WHERE uuid = %(uuid)s""", + # {"uuid": bp_pe.uuid, "status": PayoutStatus.FAILED}, + # ) assert 1 == 0 return None |
