feature/pricelist add server pagination for balance #17
|
@ -175,8 +175,8 @@ def register(data):
|
|||
allowed_keys = User().serialize().keys()
|
||||
values = {key: value for key, value in data.items() if key in allowed_keys}
|
||||
roles = values.pop("roles", [])
|
||||
if "birthday" in values:
|
||||
values["birthday"] = from_iso_format(values["birthday"]).date()
|
||||
if "birthday" in data:
|
||||
values["birthday"] = from_iso_format(data["birthday"]).date()
|
||||
user = User(**values)
|
||||
set_roles(user, roles)
|
||||
|
||||
|
@ -195,6 +195,8 @@ def register(data):
|
|||
)
|
||||
messageController.send_message(messageController.Message(user, text, subject))
|
||||
|
||||
find_user(user.userid)
|
||||
|
||||
return user
|
||||
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
# English: Debit -> from account
|
||||
# Credit -> to account
|
||||
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import func, case, and_
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from datetime import datetime
|
||||
from werkzeug.exceptions import BadRequest, NotFound, Conflict
|
||||
|
||||
from flaschengeist.database import db
|
||||
from flaschengeist.models.user import User
|
||||
from flaschengeist.models.user import User, _UserAttribute
|
||||
|
||||
from .models import Transaction
|
||||
from . import permissions, BalancePlugin
|
||||
|
@ -38,27 +39,114 @@ def get_balance(user, start: datetime = None, end: datetime = None):
|
|||
return credit, debit, credit - debit
|
||||
|
||||
|
||||
def get_balances(start: datetime = None, end: datetime = None):
|
||||
debit = db.session.query(Transaction.sender_id, func.sum(Transaction.amount)).filter(Transaction.sender_ != None)
|
||||
credit = db.session.query(Transaction.receiver_id, func.sum(Transaction.amount)).filter(
|
||||
Transaction.receiver_ != None
|
||||
)
|
||||
if start:
|
||||
debit = debit.filter(start <= Transaction.time)
|
||||
credit = credit.filter(start <= Transaction.time)
|
||||
if end:
|
||||
debit = debit.filter(Transaction.time <= end)
|
||||
credit = credit.filter(Transaction.time <= end)
|
||||
def get_balances(start: datetime = None, end: datetime = None, limit=None, offset=None, descending=None, sortBy=None):
|
||||
class _User(User):
|
||||
_debit = db.relationship(Transaction, back_populates="sender_", foreign_keys=[Transaction._sender_id])
|
||||
_credit = db.relationship(Transaction, back_populates="receiver_", foreign_keys=[Transaction._receiver_id])
|
||||
|
||||
debit = debit.group_by(Transaction._sender_id).all()
|
||||
credit = credit.group_by(Transaction._receiver_id).all()
|
||||
@hybrid_property
|
||||
def debit(self):
|
||||
return sum([cred.amount for cred in self._debit])
|
||||
|
||||
@debit.expression
|
||||
def debit(cls):
|
||||
a = (
|
||||
db.select(func.sum(Transaction.amount))
|
||||
.where(cls.id_ == Transaction._sender_id, Transaction.amount)
|
||||
.scalar_subquery()
|
||||
)
|
||||
return case([(a, a)], else_=0)
|
||||
|
||||
@hybrid_property
|
||||
def credit(self):
|
||||
return sum([cred.amount for cred in self._credit])
|
||||
|
||||
@credit.expression
|
||||
def credit(cls):
|
||||
b = (
|
||||
db.select(func.sum(Transaction.amount))
|
||||
.where(cls.id_ == Transaction._receiver_id, Transaction.amount)
|
||||
.scalar_subquery()
|
||||
)
|
||||
return case([(b, b)], else_=0)
|
||||
|
||||
@hybrid_property
|
||||
def limit(self):
|
||||
return self.get_attribute("balance_limit", None)
|
||||
|
||||
@limit.expression
|
||||
def limit(cls):
|
||||
return (
|
||||
db.select(_UserAttribute.value)
|
||||
.where(and_(cls.id_ == _UserAttribute.user, _UserAttribute.name == "balance_limit"))
|
||||
.scalar_subquery()
|
||||
)
|
||||
|
||||
def get_debit(self, start: datetime = None, end: datetime = None):
|
||||
if start and end:
|
||||
return sum([deb.amount for deb in self._debit if start <= deb.time and deb.time <= end])
|
||||
if start:
|
||||
return sum([deb.amount for deb in self._dedit if start <= deb.time])
|
||||
if end:
|
||||
return sum([deb.amount for deb in self._dedit if deb.time <= end])
|
||||
return self.debit
|
||||
|
||||
def get_credit(self, start: datetime = None, end: datetime = None):
|
||||
if start and end:
|
||||
return sum([cred.amount for cred in self._credit if start <= cred.time and cred.time <= end])
|
||||
if start:
|
||||
return sum([cred.amount for cred in self._credit if start <= cred.time])
|
||||
if end:
|
||||
return sum([cred.amount for cred in self._credit if cred.time <= end])
|
||||
return self.credit
|
||||
|
||||
query = _User.query
|
||||
|
||||
if start:
|
||||
q1 = query.join(_User._credit).filter(start <= Transaction.time)
|
||||
q2 = query.join(_User._debit).filter(start <= Transaction.time)
|
||||
query = q1.union(q2)
|
||||
if end:
|
||||
q1 = query.join(_User._credit).filter(Transaction.time <= end)
|
||||
q2 = query.join(_User._debit).filter(Transaction.time <= end)
|
||||
query = q1.union(q2)
|
||||
|
||||
if sortBy == "balance":
|
||||
if descending:
|
||||
query = query.order_by((_User.credit - _User.debit).desc(), _User.lastname.asc(), _User.firstname.asc())
|
||||
else:
|
||||
query = query.order_by((_User.credit - _User.debit).asc(), _User.lastname.asc(), _User.firstname.asc())
|
||||
elif sortBy == "limit":
|
||||
if descending:
|
||||
query = query.order_by(_User.limit.desc(), User.lastname.asc(), User.firstname.asc())
|
||||
else:
|
||||
query = query.order_by(_User.limit.asc(), User.lastname.asc(), User.firstname.asc())
|
||||
elif sortBy == "firstname":
|
||||
if descending:
|
||||
query = query.order_by(User.firstname.desc(), User.lastname.desc())
|
||||
else:
|
||||
query = query.order_by(User.firstname.asc(), User.lastname.asc())
|
||||
elif sortBy == "lastname":
|
||||
if descending:
|
||||
query = query.order_by(User.lastname.desc(), User.firstname.desc())
|
||||
else:
|
||||
query = query.order_by(User.lastname.asc(), User.firstname.asc())
|
||||
|
||||
count = None
|
||||
if limit:
|
||||
count = query.count()
|
||||
query = query.limit(limit)
|
||||
if offset:
|
||||
query = query.offset(offset)
|
||||
users = query
|
||||
all = {}
|
||||
for uid, cred in credit:
|
||||
all[uid] = [cred, 0]
|
||||
for uid, deb in debit:
|
||||
all.setdefault(uid, [0, 0])
|
||||
all[uid][1] = deb
|
||||
return all
|
||||
|
||||
for user in users:
|
||||
|
||||
all[user.userid] = [user.get_credit(start, end), 0]
|
||||
all[user.userid][1] = user.get_debit(start, end)
|
||||
|
||||
return all, count
|
||||
|
||||
|
||||
def send(sender: User, receiver, amount: float, author: User):
|
||||
|
|
|
@ -110,7 +110,6 @@ def limits(current_session: Session):
|
|||
Returns:
|
||||
JSON encoded array of userid with limit or HTTP-error
|
||||
"""
|
||||
|
||||
users = userController.get_users()
|
||||
if request.method == "GET":
|
||||
return jsonify([{"userid": user.userid, "limit": user.get_attribute("balance_limit")} for user in users])
|
||||
|
@ -311,5 +310,14 @@ def get_balances(current_session: Session):
|
|||
Returns:
|
||||
JSON Array containing credit, debit and userid for each user or HTTP error
|
||||
"""
|
||||
balances = balance_controller.get_balances()
|
||||
return jsonify([{"userid": u, "credit": v[0], "debit": v[1]} for u, v in balances.items()])
|
||||
limit = request.args.get("limit", type=int)
|
||||
offset = request.args.get("offset", type=int)
|
||||
descending = request.args.get("descending", False, type=bool)
|
||||
sortBy = request.args.get("sortBy", type=str)
|
||||
balances, count = balance_controller.get_balances(limit=limit, offset=offset, descending=descending, sortBy=sortBy)
|
||||
return jsonify(
|
||||
{
|
||||
"balances": [{"userid": u, "credit": v[0], "debit": v[1]} for u, v in balances.items()],
|
||||
"count": count,
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue