74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import select, and_, func
|
|
from app.core.logger import make_log
|
|
from app.core.models import Memory, User, UserBalance, Asset, InternalTransaction
|
|
from app.core.storage import db_session
|
|
|
|
|
|
async def get_user_balance(session, user: User, asset: Asset) -> UserBalance:
|
|
assert user, "No user"
|
|
assert asset, "No asset"
|
|
result = await session.execute(select(UserBalance).where(
|
|
and_(UserBalance.user_id == user.id, UserBalance.asset_id == asset.id)
|
|
))
|
|
row = result.scalars().first()
|
|
if not row:
|
|
user_balance = UserBalance(
|
|
user_id=user.id,
|
|
asset_id=asset.id,
|
|
balance=0,
|
|
created=datetime.now(),
|
|
)
|
|
session.add(user_balance)
|
|
await session.commit()
|
|
return await get_user_balance(session, user, asset)
|
|
return row
|
|
|
|
|
|
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)
|
|
async with db_session(auto_commit=False) as session:
|
|
async with memory.transaction():
|
|
user = (await session.execute(select(User).where(User.id == user_id))).scalars().first()
|
|
assert user, "No user"
|
|
asset = (await session.execute(select(Asset).where(Asset.id == asset_id))).scalars().first()
|
|
assert asset, "No asset"
|
|
user_balance = await 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)
|
|
await session.commit()
|
|
|
|
make_log(user, f"Made internal transaction: {'-' if is_spent else ''}{abs_amount} {asset.symbol}, type: {type}")
|