diff options
| -rw-r--r-- | generalresearch/managers/thl/ledger_manager/thl_ledger.py | 8 | ||||
| -rw-r--r-- | generalresearch/managers/thl/virtual_incentives_api.py | 2 | ||||
| -rw-r--r-- | test_utils/managers/conftest.py | 32 | ||||
| -rw-r--r-- | tests/managers/thl/test_wallet/test_user_payout.py | 220 |
4 files changed, 256 insertions, 6 deletions
diff --git a/generalresearch/managers/thl/ledger_manager/thl_ledger.py b/generalresearch/managers/thl/ledger_manager/thl_ledger.py index 13a79ec..85e60d1 100644 --- a/generalresearch/managers/thl/ledger_manager/thl_ledger.py +++ b/generalresearch/managers/thl/ledger_manager/thl_ledger.py @@ -1151,6 +1151,7 @@ class ThlLedgerManager(LedgerManager): PayoutType.PAYPAL: f"User Payout Paypal Complete {amt_str}", PayoutType.CASH_IN_MAIL: f"User Payout Cash Complete {amt_str}", PayoutType.TANGO: f"User Payout Tango Complete {amt_str}", + PayoutType.VIRTUAL_INCENTIVES: f"User Payout VI Complete {amt_str}", } description = descriptions[payout_event.payout_type] bp_wallet_account = self.get_account_or_create_bp_wallet(user.product) @@ -1189,6 +1190,13 @@ class ThlLedgerManager(LedgerManager): ) if fee_amount is None: fee_amount = (amount_usd * Decimal("0.035")).quantize(Decimal("0.01")) + elif payout_event.payout_type == PayoutType.VIRTUAL_INCENTIVES: + bp_expense_account = self.get_account_or_create_bp_expense( + product=user.product, expense_name="virtual_incentives" + ) + if fee_amount is None: + # todo: What is the fee????? On the website it says 0, which I don't really believe. + fee_amount = (amount_usd * Decimal("0.029")).quantize(Decimal("0.01")) else: raise NotImplementedError() diff --git a/generalresearch/managers/thl/virtual_incentives_api.py b/generalresearch/managers/thl/virtual_incentives_api.py index 25d9d5f..56127a1 100644 --- a/generalresearch/managers/thl/virtual_incentives_api.py +++ b/generalresearch/managers/thl/virtual_incentives_api.py @@ -262,10 +262,8 @@ class VirtualIncentivesManager(PostgresManagerWithRedis): order_data=order, ) - # todo: What is the fee?? ledger_manager.create_tx_user_payout_complete( user, payout_event=payout_event, - fee_amount=Decimal('0.10'), ) return payout_event diff --git a/test_utils/managers/conftest.py b/test_utils/managers/conftest.py index a9f92a2..d78332e 100644 --- a/test_utils/managers/conftest.py +++ b/test_utils/managers/conftest.py @@ -31,6 +31,7 @@ from generalresearch.models.definitions import Source from generalresearch.models.thl.wallet.cashout_method import ( CashoutMethod, TangoCashoutMethodData, + VICashoutMethodData, ) from generalresearch.models.thl.wallet.definitions import Currency, PayoutType @@ -177,12 +178,13 @@ def setup_cashoutmethod_db( cashout_method_manager: CashoutMethodManager, delete_cashoutmethod_db: Callable[..., None], example_tango_cashout_methods: list[CashoutMethod], + example_vi_cashout_methods: list[CashoutMethod], ) -> Callable[..., None]: def _inner(): delete_cashoutmethod_db() - for x in example_tango_cashout_methods: + for x in example_tango_cashout_methods + example_vi_cashout_methods: cashout_method_manager.create(x) return _inner @@ -199,8 +201,7 @@ def random_ext_id_factory(base: str = "U02") -> Callable[..., str]: @pytest.fixture(scope="session") -def example_tango_cashout_methods( -) -> list[CashoutMethod]: +def example_tango_cashout_methods() -> list[CashoutMethod]: return [ CashoutMethod( id=uuid4().hex, @@ -237,6 +238,31 @@ def example_tango_cashout_methods( ] +@pytest.fixture(scope="session") +def example_vi_cashout_methods() -> list[CashoutMethod]: + return [ + CashoutMethod( + id=uuid4().hex, + type=PayoutType.VIRTUAL_INCENTIVES, + ext_id="AMAZON-US", + name="Amazon.com Gift Card", + description="Amazon.com Gift Card", + data=VICashoutMethodData( + sku="AMAZON-US", + value_type="variable", + marketing="Amazon marketing copy", + terms="Amazon terms", + ), + user=None, + image_url="https://example.com/amazon.png", + currency=Currency.USD, + original_currency=Currency.USD, + min_value=500, + max_value=25_000, + ) + ] + + # === THL: Marketplaces === diff --git a/tests/managers/thl/test_wallet/test_user_payout.py b/tests/managers/thl/test_wallet/test_user_payout.py index 2a89c97..1ef080a 100644 --- a/tests/managers/thl/test_wallet/test_user_payout.py +++ b/tests/managers/thl/test_wallet/test_user_payout.py @@ -12,6 +12,11 @@ from generalresearch.managers.thl.cashout_method import CashoutMethodManager from generalresearch.managers.thl.ipinfo import GeoIpInfoManager from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager from generalresearch.managers.thl.userhealth import UserIpHistoryManager +from generalresearch.managers.thl.virtual_incentives_api import ( + VirtualIncentivesClient, + VirtualIncentivesManager, +) +from generalresearch.managers.thl.wallet import manage_pending_cashout from generalresearch.managers.thl.wallet.tango import TangoManager from generalresearch.managers.thl.wallet.user_payout import ( UserPayoutEventManager, @@ -19,6 +24,7 @@ from generalresearch.managers.thl.wallet.user_payout import ( ) from generalresearch.models.thl.definitions import PayoutStatus from generalresearch.models.thl.payout import UserPayoutEvent +from generalresearch.models.thl.product import UserWalletConfig from generalresearch.models.thl.user import User from generalresearch.models.thl.wallet.cashout_method import ( CashMailCashoutMethodData, @@ -318,7 +324,7 @@ class TestUserRequestRedeem: user_ip_history_manager=user_iphistory_manager, redis_client=thl_redis_client, ) - assert payout.request_data["amount"] == '1.74' + assert payout.request_data["amount"] == "1.74" assert payout.request_data["externalRefID"] == payout.uuid user_payout_event_manager.update( @@ -365,6 +371,218 @@ class TestUserRequestRedeem: ) assert thl_ledger_manager.get_account_balance(bp_expense) == -7 + def test_user_request_redeem_virtual_incentives( + self, + product_factory, + payout_config, + user_factory, + user_payout_event_manager: UserPayoutEventManager, + cashout_method_manager: CashoutMethodManager, + thl_ledger_manager: ThlLedgerManager, + user_iphistory_manager: UserIpHistoryManager, + ip_record_factory, + thl_redis_client, + setup_cashoutmethod_db, + example_vi_cashout_methods, + ): + setup_cashoutmethod_db() + cm = example_vi_cashout_methods[0] + product = product_factory( + payout_config=payout_config, + user_wallet_config=UserWalletConfig( + enabled=True, supported_payout_types={PayoutType.VIRTUAL_INCENTIVES} + ), + ) + user = user_factory(product=product) + + ip_record_factory(user=user, ip="8.8.8.8") + bonus_ref = uuid4().hex + thl_ledger_manager.create_tx_user_bonus( + user=user, + amount=Decimal("10.00"), + ref_uuid=bonus_ref, + description="Fund Virtual Incentives redemption test", + ) + tango_manager = Mock(spec=TangoManager) + tango_manager.get_exchange_rates.return_value = {} + virtual_incentives_manager = VirtualIncentivesManager.__new__( + VirtualIncentivesManager + ) + + payout = user_payout_event_manager.user_request_redeem( + user=user, + cashout_method_id=cm.id, + amount=USDCent(600), + tango_manager=tango_manager, + virtual_incentives_manager=virtual_incentives_manager, + cashout_method_manager=cashout_method_manager, + ledger_manager=thl_ledger_manager, + user_ip_history_manager=user_iphistory_manager, + redis_client=thl_redis_client, + ) + + assert payout.status == PayoutStatus.PENDING + assert payout.payout_type == PayoutType.VIRTUAL_INCENTIVES + assert payout.amount == 600 + assert payout.request_data == { + "sku": "AMAZON-US", + "amount": "6.00", + "cashout_request_id": payout.uuid, + } + assert payout.cashout_method_uuid == cm.id + assert thl_ledger_manager.get_user_wallet_balance(user) == 400 + assert user_payout_event_manager.get_by_uuid(payout.uuid) == payout + + bonus_tag = f"test:user_bonus:{bonus_ref}" + request_tag = f"test:user_payout:{payout.uuid}:request" + assert len(thl_ledger_manager.get_tx_ids_by_tag(bonus_tag)) == 1 + assert len(thl_ledger_manager.get_tx_ids_by_tag(request_tag)) == 1 + + user_wallet = thl_ledger_manager.get_account_or_create_user_wallet(user) + bp_wallet = thl_ledger_manager.get_account_or_create_bp_wallet(product) + pending_payout = thl_ledger_manager.get_or_create_bp_pending_payout_account( + product + ) + assert thl_ledger_manager.get_account_balance(user_wallet) == 400 + assert thl_ledger_manager.get_account_balance(bp_wallet) == -1_000 + assert thl_ledger_manager.get_account_balance(pending_payout) == 600 + assert ( + thl_ledger_manager.get_account_filtered_balance( + account=user_wallet, + metadata_key="payoutevent", + metadata_value=payout.uuid, + ) + == -600 + ) + assert ( + thl_ledger_manager.get_account_filtered_balance( + account=pending_payout, + metadata_key="payoutevent", + metadata_value=payout.uuid, + ) + == 600 + ) + + detail = user_payout_event_manager.get_payout_detail(payout.uuid) + assert detail.status == PayoutStatus.PENDING + assert detail.description == "Amazon.com Gift Card" + assert not detail.transaction_info + + +class TestManagePendingCashout: + def test_approve_virtual_incentives( + self, + product_factory, + payout_config, + user_factory, + user_manager, + user_payout_event_manager: UserPayoutEventManager, + cashout_method_manager: CashoutMethodManager, + thl_ledger_manager: ThlLedgerManager, + user_iphistory_manager: UserIpHistoryManager, + ip_record_factory, + thl_redis_client, + setup_cashoutmethod_db, + example_vi_cashout_methods, + create_main_accounts, + ): + create_main_accounts() + setup_cashoutmethod_db() + cashout_method = example_vi_cashout_methods[0] + product = product_factory( + payout_config=payout_config, + user_wallet_config=UserWalletConfig( + enabled=True, + supported_payout_types={PayoutType.VIRTUAL_INCENTIVES}, + ), + ) + user = user_factory(product=product) + ip_record_factory(user=user, ip="8.8.8.8") + thl_ledger_manager.create_tx_user_bonus( + user=user, + amount=Decimal("10.00"), + ref_uuid=uuid4().hex, + description="Fund Virtual Incentives approval test", + ) + tango_manager = Mock(spec=TangoManager) + tango_manager.get_exchange_rates.return_value = {} + virtual_incentives_manager = VirtualIncentivesManager.__new__( + VirtualIncentivesManager + ) + virtual_incentives_manager.client = Mock(spec=VirtualIncentivesClient) + + payout = user_payout_event_manager.user_request_redeem( + user=user, + cashout_method_id=cashout_method.id, + amount=USDCent(600), + tango_manager=tango_manager, + virtual_incentives_manager=virtual_incentives_manager, + cashout_method_manager=cashout_method_manager, + ledger_manager=thl_ledger_manager, + user_ip_history_manager=user_iphistory_manager, + redis_client=thl_redis_client, + ) + + pending_payout = thl_ledger_manager.get_or_create_bp_pending_payout_account( + product + ) + user_wallet = thl_ledger_manager.get_account_or_create_user_wallet(user) + + assert thl_ledger_manager.get_account_balance(user_wallet) == 400 + assert thl_ledger_manager.get_account_balance(pending_payout) == 600 + + order = { + "status": PayoutStatus.COMPLETE, + "number": "vi-order-1", + "accounts": [{"sku": "AMAZON-US", "amount": "6.00"}], + } + virtual_incentives_manager.client.create_order.return_value = order + + result = manage_pending_cashout( + payout_id=payout.uuid, + new_status=PayoutStatus.APPROVED, + user_payout_event_manager=user_payout_event_manager, + user_ip_history_manager=user_iphistory_manager, + user_manager=user_manager, + ledger_manager=thl_ledger_manager, + virtual_incentives_manager=virtual_incentives_manager, + ) + + assert result.uuid == payout.uuid + assert result.status == PayoutStatus.COMPLETE + assert result.ext_ref_id == "vi-order-1" + assert result.order_data == order + virtual_incentives_manager.client.create_order.assert_called_once_with( + cashout_request_id=payout.uuid, + sku="AMAZON-US", + amount=Decimal("6.00"), + ) + + stored_payout = user_payout_event_manager.get_by_uuid(payout.uuid) + assert stored_payout.status == PayoutStatus.COMPLETE + assert stored_payout.ext_ref_id == "vi-order-1" + assert stored_payout.order_data == order + + request_tag = f"test:user_payout:{payout.uuid}:request" + complete_tag = f"test:user_payout:{payout.uuid}:complete" + assert len(thl_ledger_manager.get_tx_ids_by_tag(request_tag)) == 1 + assert len(thl_ledger_manager.get_tx_ids_by_tag(complete_tag)) == 1 + + bp_wallet = thl_ledger_manager.get_account_or_create_bp_wallet(product) + + cash = thl_ledger_manager.get_account_cash() + vi_expense = thl_ledger_manager.get_account_or_create_bp_expense_by_uuid( + product_uuid=product.uuid, + expense_name="virtual_incentives", + ) + assert thl_ledger_manager.get_account_balance(user_wallet) == 400 + assert thl_ledger_manager.get_account_balance(pending_payout) == 0 + assert thl_ledger_manager.get_account_balance(cash) == -600 + # $10 bribe, 17c expense (2.9% x $6) + assert thl_ledger_manager.get_account_balance(bp_wallet) == -10_17 + assert thl_ledger_manager.get_account_balance(vi_expense) == -17 + assert thl_ledger_manager.check_ledger_balanced() + def test_user_request_redeem_paypal_insufficient_balance( self, user_with_wallet: User, |
