aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--generalresearch/managers/thl/ledger_manager/ledger.py18
-rw-r--r--generalresearch/managers/thl/ledger_manager/thl_ledger.py37
-rw-r--r--generalresearch/models/thl/ledger.py42
3 files changed, 83 insertions, 14 deletions
diff --git a/generalresearch/managers/thl/ledger_manager/ledger.py b/generalresearch/managers/thl/ledger_manager/ledger.py
index 3a02cdf..d027bd5 100644
--- a/generalresearch/managers/thl/ledger_manager/ledger.py
+++ b/generalresearch/managers/thl/ledger_manager/ledger.py
@@ -869,6 +869,24 @@ class LedgerAccountManager(LedgerManagerBasePostgres):
)
return res[0] if len(res) == 1 else None
+ def get_account_by_uuid(
+ self, account_uuid: UUIDStr, raise_on_error: bool = True
+ ) -> LedgerAccount | None:
+ check_valid_uuid(account_uuid)
+ res = self.pg_config.execute_sql_query(
+ query="""
+ SELECT
+ uuid, display_name, qualified_name, account_type,
+ normal_balance, reference_type, reference_uuid, currency
+ FROM ledger_account
+ WHERE uuid = %s;
+ """,
+ params=[account_uuid],
+ )
+ if raise_on_error and len(res) != 1:
+ raise LedgerAccountDoesntExistError
+ return LedgerAccount.model_validate(res[0]) if len(res) == 1 else None
+
def get_account_many_(
self, qualified_names: list[str], raise_on_error: bool = True
) -> list[dict[str, Any]]:
diff --git a/generalresearch/managers/thl/ledger_manager/thl_ledger.py b/generalresearch/managers/thl/ledger_manager/thl_ledger.py
index 2fef50f..5210189 100644
--- a/generalresearch/managers/thl/ledger_manager/thl_ledger.py
+++ b/generalresearch/managers/thl/ledger_manager/thl_ledger.py
@@ -2234,12 +2234,39 @@ class ThlLedgerManager(LedgerManager):
page: int = 1,
size: int = 50,
order_by: str | None = "created,tag",
+ account_uuid: UUIDStr | None = None,
+ qualified_name: str | None = None,
) -> UserLedgerTransactions:
+ """Return user-facing transactions for one of the user's ledger accounts.
+
+ The account can be selected by UUID or qualified name. If neither is
+ supplied, this defaults to the user's primary wallet.
+ """
+ assert user.product_id is not None
user.prefetch_product(self.pg_config)
- user_account = self.get_account_or_create_user_wallet(user)
+ assert account_uuid is None or qualified_name is None, (
+ "Pass either account_uuid or qualified_name, not both"
+ )
+
+ if account_uuid is not None:
+ user_account = self.get_account_by_uuid(account_uuid)
+ elif qualified_name is not None:
+ user_account = self.get_account(qualified_name)
+ else:
+ user_account = self.get_account_or_create_user_wallet(user)
+
+ assert user_account is not None
+ assert user_account.reference_type == "user", (
+ "Account must be a user ledger account"
+ )
+ assert user_account.reference_uuid == user.uuid, "Account must be owned by user"
exclude_txs_before = None
- if user.product_id == JAMES_BILLINGS_BPID:
+ if (
+ user.product_id == JAMES_BILLINGS_BPID
+ and user_account.account_type == AccountType.USER_WALLET
+ and user_account.currency == self.currency.value
+ ):
time_start = (
max([JAMES_BILLINGS_TX_CUTOFF, time_start])
if time_start is not None
@@ -2263,7 +2290,11 @@ class ThlLedgerManager(LedgerManager):
user_account=user_account,
txs=txs,
product_id=user.product_id,
- payout_format=user.product.payout_config.payout_format,
+ payout_format=(
+ user.product.payout_config.payout_format
+ if user_account.currency == self.currency.value
+ else None
+ ),
summary=summary,
page=page,
size=size,
diff --git a/generalresearch/models/thl/ledger.py b/generalresearch/models/thl/ledger.py
index 613d16e..4160e98 100644
--- a/generalresearch/models/thl/ledger.py
+++ b/generalresearch/models/thl/ledger.py
@@ -352,7 +352,7 @@ class LedgerTransaction(BaseModel):
return d
def to_user_tx(
- self, user_account: LedgerAccount, product_id: str, payout_format: str
+ self, user_account: LedgerAccount, product_id: str, payout_format: str | None
):
from generalresearch.models.thl.wallet.definitions import PayoutType
@@ -386,10 +386,15 @@ class LedgerTransaction(BaseModel):
raise ValueError(payout_type)
return UserLedgerTransactionUserPayout.model_validate(d)
elif d["tx_type"] == TransactionType.BP_PAYMENT.value:
+ assert len(debits) == 1 or len(credits) == 1
+ d["amount"] = credits[0].amount if credits else debits[0].amount * -1
+ d["tsid"] = self.metadata.get("thl_session")
+ return UserLedgerTransactionTaskComplete.model_validate(d)
+ elif d["tx_type"] == TransactionType.USER_ATTEMPT_CREDIT.value:
assert len(credits) == 1
d["amount"] = credits[0].amount
d["tsid"] = self.metadata.get("thl_session")
- return UserLedgerTransactionTaskComplete.model_validate(d)
+ return UserLedgerTransactionAttemptCredit.model_validate(d)
elif d["tx_type"] == TransactionType.USER_BONUS.value:
assert len(credits) == 1
d["amount"] = credits[0].amount
@@ -546,11 +551,6 @@ class UserLedgerTransactionTaskComplete(UserLedgerTransaction):
def create_url(self, product_id: str) -> str | None:
return f"https://fsb.generalresearch.com/{product_id}/status/{self.tsid}/"
- @model_validator(mode="after")
- def validate_amount(self):
- assert self.amount >= 0, f"UserLedgerTransactionTaskComplete: {self.amount=}"
- return self
-
class UserLedgerTransactionTaskAdjustment(UserLedgerTransaction):
model_config = ConfigDict(
@@ -578,11 +578,28 @@ class UserLedgerTransactionTaskAdjustment(UserLedgerTransaction):
return f"https://fsb.generalresearch.com/{product_id}/status/{self.tsid}/"
+class UserLedgerTransactionAttemptCredit(UserLedgerTransaction):
+ tx_type: Literal[TransactionType.USER_ATTEMPT_CREDIT] = Field(
+ default=TransactionType.USER_ATTEMPT_CREDIT
+ )
+ description: str = Field(default="Attempt Credit", max_length=255)
+ tsid: UUIDStr
+
+ def create_url(self, product_id: str) -> str | None:
+ return f"https://fsb.generalresearch.com/{product_id}/status/{self.tsid}/"
+
+ @model_validator(mode="after")
+ def validate_amount(self):
+ assert self.amount > 0, f"UserLedgerTransactionAttemptCredit: {self.amount=}"
+ return self
+
+
UserLedgerTransactionType = Annotated[
UserLedgerTransactionUserPayout
| UserLedgerTransactionUserBonus
| UserLedgerTransactionTaskAdjustment
- | UserLedgerTransactionTaskComplete,
+ | UserLedgerTransactionTaskComplete
+ | UserLedgerTransactionAttemptCredit,
Field(discriminator="tx_type"),
]
@@ -611,6 +628,9 @@ class UserLedgerTransactionTypesSummary(BaseModel):
user_bonus: UserLedgerTransactionTypeSummary = Field(
default_factory=UserLedgerTransactionTypeSummary
)
+ user_attempt_credit: UserLedgerTransactionTypeSummary = Field(
+ default_factory=UserLedgerTransactionTypeSummary
+ )
user_payout_request: UserLedgerTransactionTypeSummary = Field(
default_factory=UserLedgerTransactionTypeSummary
)
@@ -623,8 +643,8 @@ class UserLedgerTransactions(Page):
transactions: list[UserLedgerTransactionType] = Field(default_factory=list)
# The summary is w.r.t an optional time-filter. The transactions are
- # paginated so the counts won't necesarily match. In other words, the
- # summary is across all transaction in all pages, not this the transactions
+ # paginated so the counts won't necessarily match. In other words, the
+ # summary is across all transactions in all pages, not this the transactions
# in this page.
summary: UserLedgerTransactionTypesSummary = Field()
@@ -634,7 +654,7 @@ class UserLedgerTransactions(Page):
user_account: LedgerAccount,
txs: list[LedgerTransaction],
product_id: str,
- payout_format: str,
+ payout_format: PayoutFormatType | None,
summary: UserLedgerTransactionTypesSummary,
page: int,
size: int,