diff options
Diffstat (limited to 'generalresearch/managers/thl/wallet/__init__.py')
| -rw-r--r-- | generalresearch/managers/thl/wallet/__init__.py | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/generalresearch/managers/thl/wallet/__init__.py b/generalresearch/managers/thl/wallet/__init__.py new file mode 100644 index 0000000..3b34756 --- /dev/null +++ b/generalresearch/managers/thl/wallet/__init__.py @@ -0,0 +1,147 @@ +from decimal import Decimal +from typing import Optional, Dict + +from generalresearch.managers.thl.ledger_manager.thl_ledger import ( + ThlLedgerManager, +) +from generalresearch.managers.thl.payout import ( + UserPayoutEventManager, + PayoutEventManager, +) +from generalresearch.managers.thl.user_manager.user_manager import ( + UserManager, +) +from generalresearch.managers.thl.userhealth import UserIpHistoryManager +from generalresearch.managers.thl.wallet.approve import ( + approve_paypal_order, + approve_amt_cashout, +) +from generalresearch.models.thl.definitions import PayoutStatus +from generalresearch.models.thl.payout import UserPayoutEvent +from generalresearch.models.thl.wallet import PayoutType +from generalresearch.models.thl.wallet.cashout_method import ( + CashMailOrderData, +) + + +def manage_pending_cashout( + payout_id: str, + new_status: PayoutStatus, + user_payout_event_manager: UserPayoutEventManager, + user_ip_history_manager: UserIpHistoryManager, + user_manager: UserManager, + ledger_manager: ThlLedgerManager, + order_data: Optional[Dict | CashMailOrderData] = None, +) -> UserPayoutEvent: + """ + Called by a UI actions performed by Todd. This rejects/approves/cancels + a payout event. We're calling this "cashout" because that is the + terminology used in generalresearch, even though the cashouts are stored + in the payoutevent table + + :param payout_id: the payoutevent pk hex + :param new_status: + :param user_payout_event_manager + :param user_ip_history_manager + :param user_manager + :param ledger_manager + :param order_data: For Cash_in_mail, pass this in. + + :returns: PayoutEvent object + """ + pe: UserPayoutEvent = user_payout_event_manager.get_by_uuid(payout_id) + pe.check_status_change_allowed(status=new_status) + assert pe.account_reference_type == "user" + user = user_manager.get_user(user_uuid=pe.account_reference_uuid) + user.prefetch_product(user_manager.mysql_user_manager.pg_config) + + assert ( + user.product.user_wallet_enabled + ), "manage_pending_cashout called on user without managed wallet" + assert not user.blocked, "manage_pending_cashout: Blocked user" + assert not user_ip_history_manager.is_user_anonymous( + user + ), "manage_pending_cashout: Anonymous user" + + # Just assign it with direct casting/type annotation + payout_event_manager: PayoutEventManager = user_payout_event_manager + + if new_status == PayoutStatus.APPROVED: + if pe.payout_type == PayoutType.TANGO: + from generalresearch.managers.thl.wallet.tango import ( + complete_tango_order, + ) + + complete_tango_order( + user=user, + payout_event=pe, + payout_event_manager=payout_event_manager, + ledger_manager=ledger_manager, + ) + + elif pe.payout_type == PayoutType.PAYPAL: + approve_paypal_order( + payout_event=pe, payout_event_manager=payout_event_manager + ) + + elif pe.payout_type in {PayoutType.AMT_BONUS, PayoutType.AMT_HIT}: + approve_amt_cashout( + user=user, + payout_event=pe, + payout_event_manager=payout_event_manager, + ledger_manager=ledger_manager, + ) + + elif pe.payout_type == PayoutType.CASH_IN_MAIL: + assert order_data, "must pass order_data" + payout_event_manager.update( + pe, status=PayoutStatus.APPROVED, order_data=order_data + ) + ledger_manager.create_tx_user_payout_complete( + user, + payout_event=pe, + fee_amount=Decimal(order_data.shipping_cost) / 100, + ) + + else: + raise ValueError(f"unsupported payout_type: {pe.payout_type}") + + return pe + + elif new_status == PayoutStatus.COMPLETE: + # Used only for AMT/dummy cashouts that are actually paid out not + # by us. They are informing us that the cashout was successfully + # sent to the user + if pe.payout_type in {PayoutType.AMT_BONUS, PayoutType.AMT_HIT}: + # We already do this under approve_amt_cashout() + pass + + elif pe.payout_type == PayoutType.PAYPAL: + # This is an issue here in that we actually don't know what the + # fee is until it is sent and we read it back from paypal's csv + # result. We have to just run this with a custom script, which + # uses manual_complete_paypal_order() + raise ValueError("user custom paypal script for this") + + payout_event_manager.update(pe, status=new_status) + + return pe + + elif new_status == PayoutStatus.REJECTED: + # They lose the money in their wallet at this point, no ledger txs occur. + payout_event_manager.update(pe, status=new_status) + return pe + + elif new_status == PayoutStatus.CANCELLED: + # create another ledger item putting the money back into their wallet. + payout_event_manager.update(pe, status=new_status) + ledger_manager.create_tx_user_payout_cancelled(user, payout_event=pe) + return pe + + elif new_status == PayoutStatus.FAILED: + # We just update the status (like in PayoutStatus.REJECTED). No ledger xs + payout_event_manager.update(pe, status=new_status) + return pe + + else: + raise ValueError(f"unsupported status: {new_status}") |
