Enhance client balance summary retrieval: Updated the get_client_balance_summary function to accept an optional as_of_time parameter for temporal accuracy in balance calculations. Adjusted SQL queries to filter results based on the specified time, ensuring accurate balance summaries. Added logging for cases where as_of_time is utilized. Updated transaction processing to leverage this new functionality for improved accuracy in client balance calculations.
This commit is contained in:
parent
8871f24cec
commit
7e39bb160a
2 changed files with 35 additions and 10 deletions
33
crud.py
33
crud.py
|
|
@ -221,32 +221,47 @@ async def get_payments_by_lamassu_transaction(lamassu_transaction_id: str) -> Li
|
||||||
|
|
||||||
|
|
||||||
# Balance and Summary Operations
|
# Balance and Summary Operations
|
||||||
async def get_client_balance_summary(client_id: str) -> ClientBalanceSummary:
|
async def get_client_balance_summary(client_id: str, as_of_time: Optional[datetime] = None) -> ClientBalanceSummary:
|
||||||
# Get total confirmed deposits
|
"""Get client balance summary, optionally as of a specific point in time"""
|
||||||
|
|
||||||
|
# Build time filter for temporal accuracy
|
||||||
|
time_filter = ""
|
||||||
|
params = {"client_id": client_id}
|
||||||
|
|
||||||
|
if as_of_time is not None:
|
||||||
|
time_filter = "AND confirmed_at <= :as_of_time"
|
||||||
|
params["as_of_time"] = as_of_time
|
||||||
|
|
||||||
|
# Get total confirmed deposits (only those confirmed before the cutoff time)
|
||||||
total_deposits_result = await db.fetchone(
|
total_deposits_result = await db.fetchone(
|
||||||
"""
|
f"""
|
||||||
SELECT COALESCE(SUM(amount), 0) as total, currency
|
SELECT COALESCE(SUM(amount), 0) as total, currency
|
||||||
FROM satoshimachine.dca_deposits
|
FROM satoshimachine.dca_deposits
|
||||||
WHERE client_id = :client_id AND status = 'confirmed'
|
WHERE client_id = :client_id AND status = 'confirmed' {time_filter}
|
||||||
GROUP BY currency
|
GROUP BY currency
|
||||||
""",
|
""",
|
||||||
{"client_id": client_id}
|
params
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get total payments made
|
# Get total payments made (only those created before the cutoff time)
|
||||||
total_payments_result = await db.fetchone(
|
total_payments_result = await db.fetchone(
|
||||||
"""
|
f"""
|
||||||
SELECT COALESCE(SUM(amount_fiat), 0) as total
|
SELECT COALESCE(SUM(amount_fiat), 0) as total
|
||||||
FROM satoshimachine.dca_payments
|
FROM satoshimachine.dca_payments
|
||||||
WHERE client_id = :client_id AND status = 'confirmed'
|
WHERE client_id = :client_id AND status = 'confirmed' {time_filter}
|
||||||
""",
|
""",
|
||||||
{"client_id": client_id}
|
params
|
||||||
)
|
)
|
||||||
|
|
||||||
total_deposits = total_deposits_result["total"] if total_deposits_result else 0
|
total_deposits = total_deposits_result["total"] if total_deposits_result else 0
|
||||||
total_payments = total_payments_result["total"] if total_payments_result else 0
|
total_payments = total_payments_result["total"] if total_payments_result else 0
|
||||||
currency = total_deposits_result["currency"] if total_deposits_result else "GTQ"
|
currency = total_deposits_result["currency"] if total_deposits_result else "GTQ"
|
||||||
|
|
||||||
|
# Log temporal filtering if as_of_time was used
|
||||||
|
if as_of_time is not None:
|
||||||
|
from lnbits.core.services import logger
|
||||||
|
logger.info(f"Client {client_id[:8]}... balance as of {as_of_time}: {total_deposits - total_payments} centavos remaining")
|
||||||
|
|
||||||
return ClientBalanceSummary(
|
return ClientBalanceSummary(
|
||||||
client_id=client_id,
|
client_id=client_id,
|
||||||
total_deposits=total_deposits,
|
total_deposits=total_deposits,
|
||||||
|
|
|
||||||
|
|
@ -608,6 +608,7 @@ class LamassuTransactionProcessor:
|
||||||
fiat_amount = transaction.get("fiat_amount") # Actual fiat dispensed (principal only)
|
fiat_amount = transaction.get("fiat_amount") # Actual fiat dispensed (principal only)
|
||||||
commission_percentage = transaction.get("commission_percentage") # Already stored as decimal (e.g., 0.045)
|
commission_percentage = transaction.get("commission_percentage") # Already stored as decimal (e.g., 0.045)
|
||||||
discount = transaction.get("discount") # Discount percentage
|
discount = transaction.get("discount") # Discount percentage
|
||||||
|
transaction_time = transaction.get("transaction_time") # ATM transaction timestamp for temporal accuracy
|
||||||
|
|
||||||
# Validate required fields
|
# Validate required fields
|
||||||
if crypto_atoms is None:
|
if crypto_atoms is None:
|
||||||
|
|
@ -622,6 +623,10 @@ class LamassuTransactionProcessor:
|
||||||
if discount is None:
|
if discount is None:
|
||||||
logger.info(f"Missing discount in transaction: {transaction}, defaulting to 0")
|
logger.info(f"Missing discount in transaction: {transaction}, defaulting to 0")
|
||||||
discount = 0.0
|
discount = 0.0
|
||||||
|
if transaction_time is None:
|
||||||
|
logger.warning(f"Missing transaction_time in transaction: {transaction}")
|
||||||
|
# Could use current time as fallback, but this indicates a data issue
|
||||||
|
# transaction_time = datetime.now(timezone.utc)
|
||||||
|
|
||||||
# Calculate effective commission percentage after discount (following the reference logic)
|
# Calculate effective commission percentage after discount (following the reference logic)
|
||||||
if commission_percentage > 0:
|
if commission_percentage > 0:
|
||||||
|
|
@ -642,13 +647,18 @@ class LamassuTransactionProcessor:
|
||||||
logger.info(f"Transaction - Total crypto: {crypto_atoms} sats")
|
logger.info(f"Transaction - Total crypto: {crypto_atoms} sats")
|
||||||
logger.info(f"Commission: {commission_percentage*100:.1f}% - {discount:.1f}% discount = {effective_commission*100:.1f}% effective ({commission_amount_sats} sats)")
|
logger.info(f"Commission: {commission_percentage*100:.1f}% - {discount:.1f}% discount = {effective_commission*100:.1f}% effective ({commission_amount_sats} sats)")
|
||||||
logger.info(f"Base for DCA: {base_crypto_atoms} sats, Fiat dispensed: {fiat_amount}, Exchange rate: {exchange_rate:.2f} sats/fiat_unit")
|
logger.info(f"Base for DCA: {base_crypto_atoms} sats, Fiat dispensed: {fiat_amount}, Exchange rate: {exchange_rate:.2f} sats/fiat_unit")
|
||||||
|
if transaction_time:
|
||||||
|
logger.info(f"Calculating balances as of transaction time: {transaction_time}")
|
||||||
|
else:
|
||||||
|
logger.warning("No transaction time available - using current balances (may be inaccurate)")
|
||||||
|
|
||||||
# Get balance summaries for all clients to calculate proportions
|
# Get balance summaries for all clients to calculate proportions
|
||||||
client_balances = {}
|
client_balances = {}
|
||||||
total_confirmed_deposits = 0
|
total_confirmed_deposits = 0
|
||||||
|
|
||||||
for client in flow_clients:
|
for client in flow_clients:
|
||||||
balance = await get_client_balance_summary(client.id)
|
# Get balance as of the transaction time for temporal accuracy
|
||||||
|
balance = await get_client_balance_summary(client.id, as_of_time=transaction_time)
|
||||||
if balance.remaining_balance > 0: # Only include clients with remaining balance
|
if balance.remaining_balance > 0: # Only include clients with remaining balance
|
||||||
client_balances[client.id] = balance.remaining_balance
|
client_balances[client.id] = balance.remaining_balance
|
||||||
total_confirmed_deposits += balance.remaining_balance
|
total_confirmed_deposits += balance.remaining_balance
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue