import requests from fastapi import HTTPException, status from generalresearch.currency import USDCent from generalresearch.models.thl.definitions import PayoutStatus from generalresearch.models.thl.payout import UserPayoutEvent from generalresearch.models.thl.task_status import TaskStatusResponse from generalresearch.models.thl.wallet.cashout_method import ( CashoutMethodOut, CashoutRequestDetail, CashoutRequestResponse, ) from jb.config import settings def get_task_status(tsid: str) -> TaskStatusResponse | None: url = f"{settings.fsb_host}{settings.product_id}/status/{tsid}/" d = requests.get(url).json() if d.get("msg") == "invalid tsid": return None return TaskStatusResponse.model_validate(d) def user_cashout_request( product_user_id: str, amount: USDCent, cashout_method_id: str ) -> CashoutRequestDetail: assert isinstance(amount, USDCent) assert USDCent(0) < amount <= USDCent(100_00) url = f"{settings.fsb_host}{settings.product_id}/cashout/" body: dict[str, str | int] = { "bpuid": product_user_id, "amount": int(amount), "cashout_method_id": cashout_method_id, } res = requests.post(url, json=body) if res.status_code == status.HTTP_400_BAD_REQUEST: try: message = res.json().get("msg") except (ValueError, AttributeError): message = None raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=message or "Cashout request failed", ) res.raise_for_status() d = res.json() return CashoutRequestResponse.model_validate(d).cashout def manage_pending_cashout( cashout_id: str, payout_status: PayoutStatus ) -> UserPayoutEvent: url = f"{settings.fsb_host}{settings.fsb_host_private_route}/thl/manage_cashout/" body = { "payout_id": cashout_id, "new_status": payout_status.value, } res = requests.post(url, json=body) d = res.json() return UserPayoutEvent.model_validate(d) def get_paypal_cashout_method_if_exists( product_user_id: str, client_ip: str ) -> str | None: """ Make sure a paypal cashout method exists for this user. Use their login email. We check if it exists first, so that once a user can change their paypal email, we do not overwrite it. """ url = f"{settings.fsb_host}{settings.product_id}/cashout_methods/" params = {"bpuid": product_user_id, "ip": client_ip} res = requests.get(url, params=params) assert res.status_code == status.HTTP_200_OK, res.text cms = res.json()["cashout_methods"] res = next(filter(lambda x: x["type"] == "PAYPAL", cms), None) if res: return res["id"] return None def create_paypal_cashout_method(product_user_id: str, email: str) -> dict: url = f"{settings.fsb_host}{settings.product_id}/cashout_methods/" body = {"bpuid": product_user_id, "type": "PAYPAL", "email": email} res = requests.post(url, json=body) assert res.status_code == status.HTTP_200_OK, res.text return res.json()["cashout_method"] def create_paypal_cashout_method_if_not_exists( product_user_id: str, email: str, client_ip: str ) -> None: if not get_paypal_cashout_method_if_exists(product_user_id, client_ip=client_ip): create_paypal_cashout_method(product_user_id, email) def get_cashout_method(cashout_method_id: str) -> CashoutMethodOut: url = ( f"{settings.fsb_host}{settings.product_id}/cashout_methods/{cashout_method_id}/" ) res = requests.get(url) assert res.status_code == status.HTTP_200_OK, res.text return CashoutMethodOut.model_validate(res.json()["cashout_method"]) def get_wallet_balance(amt_worker_id: str) -> USDCent: # This will raise an Exception if wallet balance is negative url = f"{settings.fsb_host}{settings.product_id}/wallet/" params = {"bpuid": amt_worker_id} return USDCent(requests.get(url, params=params).json()["wallet"]["amount"]) def get_wallet_balance_if_non_negative(amt_worker_id: str) -> USDCent | None: url = f"{settings.fsb_host}{settings.product_id}/wallet/" params = {"bpuid": amt_worker_id} amt = requests.get(url, params=params).json()["wallet"]["amount"] if amt >= 0: return USDCent(amt) return None def get_cashout_detail(cashout_id: str) -> CashoutRequestDetail: url = f"{settings.fsb_host}{settings.product_id}/cashout/{cashout_id}/" res = requests.get(url) assert res.status_code == status.HTTP_200_OK, res.text return CashoutRequestDetail.model_validate(res.json()["cashout"])