from datetime import datetime from app.core.logger import make_log from app.core.models import Memory, User, UserBalance, Asset, InternalTransaction from app.core.storage import db_session def get_user_balance(session, user: User, asset: Asset) -> UserBalance: assert user, "No user" assert asset, "No asset" result = session.query(UserBalance).filter( UserBalance.user_id == user.id, UserBalance.asset_id == asset.id ) results_count = result.count() if results_count == 0: user_balance = UserBalance( user_id=user.id, asset_id=asset.id, balance=0, created=datetime.now(), ) session.add(user_balance) session.commit() return get_user_balance(session, user, asset) elif results_count == 1: return result.first() else: raise Exception(f"Multiple user balances found: {results_count}") async def make_internal_transaction( memory: Memory, user_id: int, asset_id: int, amount: float, is_spent: bool, type: str = "NOT_SPECIFIED", spent_transaction_id: int = None ) -> InternalTransaction: amount = float(amount) is_spent = bool(is_spent) type = str(type)[:256] if amount < 0: if not is_spent: raise Exception(f"Invalid is_spent: {is_spent}, amount: {amount}") elif amount > 0: if is_spent: raise Exception(f"Invalid is_spent: {is_spent}, amount: {amount}") else: raise Exception(f"Invalid amount: {amount}") abs_amount = abs(amount) with db_session(auto_commit=False) as session: async with memory.transaction(): user = session.query(User).filter_by(id=user_id).first() assert user, "No user" asset = session.query(Asset).filter_by(id=asset_id).first() assert asset, "No asset" user_balance = get_user_balance(session, user, asset) assert user_balance, "No user balance" if is_spent is True: if abs_amount > user_balance.balance: raise Exception(f"Insufficient balance: {user_balance.balance} < {abs_amount}") user_balance.balance = float(user_balance.balance) + amount user_balance.updated = datetime.now() internal_transaction = InternalTransaction( user_id=user.id, asset_id=asset.id, amount=abs_amount, is_spent=is_spent, type=type, spent_transaction_id=spent_transaction_id, created=datetime.now(), ) session.add(internal_transaction) session.commit() make_log(user, f"Made internal transaction: {'-' if is_spent else ''}{abs_amount} {asset.symbol}, type: {type}")