Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd7a72f3c0 | |||
| d1242e5cd2 |
1 changed files with 32 additions and 17 deletions
|
|
@ -493,14 +493,26 @@ class LamassuTransactionProcessor:
|
||||||
# Convert string values to appropriate types
|
# Convert string values to appropriate types
|
||||||
processed_row = {}
|
processed_row = {}
|
||||||
for key, value in row.items():
|
for key, value in row.items():
|
||||||
if value == '':
|
# Handle None/empty values consistently at data ingestion boundary
|
||||||
processed_row[key] = None
|
if value == '' or value is None:
|
||||||
|
if key in ['fiat_amount', 'crypto_amount']:
|
||||||
|
processed_row[key] = 0 # Default numeric fields to 0
|
||||||
|
elif key in ['commission_percentage', 'discount']:
|
||||||
|
processed_row[key] = 0.0 # Default percentage fields to 0.0
|
||||||
|
else:
|
||||||
|
processed_row[key] = None # Keep None for non-numeric fields
|
||||||
elif key in ['transaction_id', 'device_id', 'crypto_code', 'fiat_code']:
|
elif key in ['transaction_id', 'device_id', 'crypto_code', 'fiat_code']:
|
||||||
processed_row[key] = str(value)
|
processed_row[key] = str(value)
|
||||||
elif key in ['fiat_amount', 'crypto_amount']:
|
elif key in ['fiat_amount', 'crypto_amount']:
|
||||||
processed_row[key] = int(float(value)) if value else 0
|
try:
|
||||||
|
processed_row[key] = int(float(value))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
processed_row[key] = 0 # Fallback to 0 for invalid values
|
||||||
elif key in ['commission_percentage', 'discount']:
|
elif key in ['commission_percentage', 'discount']:
|
||||||
processed_row[key] = float(value) if value else 0.0
|
try:
|
||||||
|
processed_row[key] = float(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
processed_row[key] = 0.0 # Fallback to 0.0 for invalid values
|
||||||
elif key == 'transaction_time':
|
elif key == 'transaction_time':
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
# Parse PostgreSQL timestamp format and ensure it's in UTC for consistency
|
# Parse PostgreSQL timestamp format and ensure it's in UTC for consistency
|
||||||
|
|
@ -628,11 +640,11 @@ class LamassuTransactionProcessor:
|
||||||
logger.info("No Flow Mode clients found - skipping distribution")
|
logger.info("No Flow Mode clients found - skipping distribution")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Extract transaction details with None-safe defaults
|
# Extract transaction details - guaranteed clean from data ingestion
|
||||||
crypto_atoms = transaction.get("crypto_amount") # Total sats with commission baked in
|
crypto_atoms = transaction.get("crypto_amount", 0) # Total sats with commission baked in
|
||||||
fiat_amount = transaction.get("fiat_amount") # Actual fiat dispensed (principal only)
|
fiat_amount = transaction.get("fiat_amount", 0) # 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", 0.0) # Already stored as decimal (e.g., 0.045)
|
||||||
discount = transaction.get("discount") # Discount percentage
|
discount = transaction.get("discount", 0.0) # Discount percentage
|
||||||
transaction_time = transaction.get("transaction_time") # ATM transaction timestamp for temporal accuracy
|
transaction_time = transaction.get("transaction_time") # ATM transaction timestamp for temporal accuracy
|
||||||
|
|
||||||
# Normalize transaction_time to UTC if present
|
# Normalize transaction_time to UTC if present
|
||||||
|
|
@ -837,10 +849,13 @@ class LamassuTransactionProcessor:
|
||||||
logger.error(f"CRITICAL: Client {client_id[:8]}... has negative balance ({current_balance.remaining_balance:.2f} GTQ) - REFUSING payment of {distribution['sats_amount']} sats")
|
logger.error(f"CRITICAL: Client {client_id[:8]}... has negative balance ({current_balance.remaining_balance:.2f} GTQ) - REFUSING payment of {distribution['sats_amount']} sats")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Verify balance is sufficient for this distribution
|
# Verify balance is sufficient for this distribution (round to 2 decimal places to match DECIMAL(10,2) precision)
|
||||||
fiat_equivalent = distribution["fiat_amount"] # Amount in GTQ
|
fiat_equivalent = distribution["fiat_amount"] # Amount in GTQ
|
||||||
if current_balance.remaining_balance < fiat_equivalent:
|
# Round both values to 2 decimal places to match database precision and avoid floating point comparison issues
|
||||||
logger.error(f"CRITICAL: Client {client_id[:8]}... insufficient balance ({current_balance.remaining_balance:.2f} < {fiat_equivalent:.2f} GTQ) - REFUSING payment")
|
balance_rounded = round(current_balance.remaining_balance, 2)
|
||||||
|
amount_rounded = round(fiat_equivalent, 2)
|
||||||
|
if balance_rounded < amount_rounded:
|
||||||
|
logger.error(f"CRITICAL: Client {client_id[:8]}... insufficient balance ({balance_rounded:.2f} < {amount_rounded:.2f} GTQ) - REFUSING payment")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info(f"Client {client_id[:8]}... pre-payment balance check: {current_balance.remaining_balance:.2f} GTQ - SUFFICIENT for {fiat_equivalent:.2f} GTQ payment")
|
logger.info(f"Client {client_id[:8]}... pre-payment balance check: {current_balance.remaining_balance:.2f} GTQ - SUFFICIENT for {fiat_equivalent:.2f} GTQ payment")
|
||||||
|
|
@ -995,11 +1010,11 @@ class LamassuTransactionProcessor:
|
||||||
async def store_lamassu_transaction(self, transaction: Dict[str, Any]) -> Optional[str]:
|
async def store_lamassu_transaction(self, transaction: Dict[str, Any]) -> Optional[str]:
|
||||||
"""Store the Lamassu transaction in our database for audit and UI"""
|
"""Store the Lamassu transaction in our database for audit and UI"""
|
||||||
try:
|
try:
|
||||||
# Extract and validate transaction data
|
# Extract transaction data - guaranteed clean from data ingestion boundary
|
||||||
crypto_atoms = transaction.get("crypto_amount", 0)
|
crypto_atoms = transaction.get("crypto_amount", 0)
|
||||||
fiat_amount = transaction.get("fiat_amount", 0)
|
fiat_amount = transaction.get("fiat_amount", 0)
|
||||||
commission_percentage = transaction.get("commission_percentage") or 0.0
|
commission_percentage = transaction.get("commission_percentage", 0.0)
|
||||||
discount = transaction.get("discount") or 0.0
|
discount = transaction.get("discount", 0.0)
|
||||||
transaction_time = transaction.get("transaction_time")
|
transaction_time = transaction.get("transaction_time")
|
||||||
|
|
||||||
# Normalize transaction_time to UTC if present
|
# Normalize transaction_time to UTC if present
|
||||||
|
|
@ -1145,8 +1160,8 @@ class LamassuTransactionProcessor:
|
||||||
|
|
||||||
# Calculate commission amount for sending to commission wallet
|
# Calculate commission amount for sending to commission wallet
|
||||||
crypto_atoms = transaction.get("crypto_amount", 0)
|
crypto_atoms = transaction.get("crypto_amount", 0)
|
||||||
commission_percentage = transaction.get("commission_percentage") or 0.0
|
commission_percentage = transaction.get("commission_percentage", 0.0)
|
||||||
discount = transaction.get("discount") or 0.0
|
discount = transaction.get("discount", 0.0)
|
||||||
|
|
||||||
if commission_percentage and commission_percentage > 0:
|
if commission_percentage and commission_percentage > 0:
|
||||||
effective_commission = commission_percentage * (100 - discount) / 100
|
effective_commission = commission_percentage * (100 - discount) / 100
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue