diff --git a/crud.py b/crud.py index 4b04ef2..c4c413d 100644 --- a/crud.py +++ b/crud.py @@ -260,7 +260,9 @@ async def get_client_balance_summary(client_id: str, as_of_time: Optional[dateti # 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") + # Verify timezone consistency for temporal filtering + tz_info = "UTC" if as_of_time.tzinfo == timezone.utc else f"TZ: {as_of_time.tzinfo}" + logger.info(f"Client {client_id[:8]}... balance as of {as_of_time} ({tz_info}): {total_deposits - total_payments} centavos remaining") return ClientBalanceSummary( client_id=client_id, diff --git a/transaction_processor.py b/transaction_processor.py index f842911..58d251d 100644 --- a/transaction_processor.py +++ b/transaction_processor.py @@ -503,7 +503,16 @@ class LamassuTransactionProcessor: processed_row[key] = float(value) if value else 0.0 elif key == 'transaction_time': from datetime import datetime - processed_row[key] = datetime.fromisoformat(value.replace('Z', '+00:00')) + # Parse timestamp and ensure it's in UTC for consistency + dt = datetime.fromisoformat(value.replace('Z', '+00:00')) + # Convert to UTC if not already + if dt.tzinfo is None: + # Assume UTC if no timezone info + dt = dt.replace(tzinfo=timezone.utc) + elif dt.tzinfo != timezone.utc: + # Convert to UTC + dt = dt.astimezone(timezone.utc) + processed_row[key] = dt else: processed_row[key] = value results.append(processed_row) @@ -610,6 +619,18 @@ class LamassuTransactionProcessor: discount = transaction.get("discount") # Discount percentage transaction_time = transaction.get("transaction_time") # ATM transaction timestamp for temporal accuracy + # Normalize transaction_time to UTC if present + if transaction_time is not None: + if transaction_time.tzinfo is None: + # Assume UTC if no timezone info + transaction_time = transaction_time.replace(tzinfo=timezone.utc) + logger.warning("Transaction time was timezone-naive, assuming UTC") + elif transaction_time.tzinfo != timezone.utc: + # Convert to UTC + original_tz = transaction_time.tzinfo + transaction_time = transaction_time.astimezone(timezone.utc) + logger.info(f"Converted transaction time from {original_tz} to UTC") + # Validate required fields if crypto_atoms is None: logger.error(f"Missing crypto_amount in transaction: {transaction}") @@ -718,7 +739,7 @@ class LamassuTransactionProcessor: exchange_rate=distribution["exchange_rate"], transaction_type="flow", lamassu_transaction_id=transaction_id, - transaction_time=transaction.get("transaction_time") # Original ATM transaction time + transaction_time=transaction_time # Normalized UTC timestamp ) # Record the payment in our database @@ -893,7 +914,7 @@ class LamassuTransactionProcessor: crypto_code=transaction.get("crypto_code", "BTC"), fiat_code=transaction.get("fiat_code", "GTQ"), device_id=transaction.get("device_id"), - transaction_time=transaction.get("transaction_time") + transaction_time=transaction_time # Normalized UTC timestamp ) # Store in database