Update commodity and transaction details and list

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-03-26 15:18:41 -04:00
parent c320f81181
commit cf2b4ab06d
9 changed files with 211 additions and 31 deletions

View File

@@ -1,11 +1,12 @@
from datetime import date
from datetime import datetime
from typing import Mapping, Optional, Sequence
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.db import models
from django.db.models import Q
from django.db.models import Q, Sum
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from frozendict import frozendict
from guardian.shortcuts import assign_perm
@@ -75,8 +76,6 @@ class User(PermissionsMixin, AbstractBaseUser):
return self.balances().get(commodity, 0)
def balances(self) -> Mapping["Commodity", int]:
from django.db.models import Sum
# We are the source, receiving from the destination
credits_sent = {
row["dest_sends"]: row["dest_amount__sum"]
@@ -172,24 +171,82 @@ class Commodity(models.Model):
id = HashidAutoField(primary_key=True)
name = models.CharField(
blank=False, unique=True, max_length=100, verbose_name=_("commodity name")
blank=False,
unique=True,
editable=False,
max_length=100,
verbose_name=_("commodity name"),
)
symbol = models.CharField(
blank=False, unique=True, editable=False, max_length=6, verbose_name=_("symbol")
)
in_circulation = models.PositiveIntegerField()
created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
symbol = models.CharField(blank=True, max_length=6, verbose_name=_("symbol"))
class Meta:
verbose_name = _("commodity")
verbose_name_plural = _("commodities")
def get_absolute_url(self):
return "/c/detail/%s" % self.pk
def trading_volume(self, since: Optional[datetime] = None) -> int:
"""
Gets the amount of this commodity traded since the given cutoff, inclusive.
def html_symbol(self) -> str:
if self.symbol:
return f"<span>{self.symbol}</span>"
else:
return f"<span>units of {self.name}</span>"
If no cutoff is given, then it returns the volume of all transactions.
"""
source_filt = {"source_sends": self, "status": TxRequest.ACCEPTED}
dest_filt = {"dest_sends": self, "status": TxRequest.ACCEPTED}
if since is not None:
source_filt["update_time__gte"] = since
dest_filt["update_time__gte"] = since
source_query = (
TxRequest.objects.filter(**source_filt)
.annotate(Sum("source_amount"))
.values("source_amount__sum")
.first()
)
dest_query = (
TxRequest.objects.filter(**dest_filt)
.annotate(Sum("dest_amount"))
.values("dest_amount__sum")
.first()
)
source_amount = source_query["source_amount__sum"] if source_query else 0
dest_amount = dest_query["dest_amount__sum"] if dest_query else 0
return source_amount + dest_amount
@property
def market_spread(self) -> int:
count = 0
for user in User.objects.all():
if not user.is_active:
continue
if user.balance_of(self) > 0:
count += 1
return count
@property
def market_spread_ratio(self) -> float:
user_count = len(User.objects.all())
if user_count == 0:
return 0.0
return self.market_spread / user_count
@property
def amount_pending(self) -> int:
"""
Gets the amount of this commodity that is currently being held in pending transactions.
"""
pending = (
TxRequest.objects.filter(source_sends=self, status=TxRequest.OPEN)
.annotate(Sum("source_amount"))
.values("source_amount__sum")
.first()
)
return pending["source_amount__sum"] if pending else 0
@property
def url(self) -> str:
return f'<a href="{reverse("trading:commodity_detail", args=[self.id])}">{self.symbol}</a>'
class MaxCommodityError(Exception):
@@ -230,6 +287,9 @@ class TxRequest(models.Model):
# related_name="revised_request",
# )
create_time = models.DateTimeField(auto_now_add=True, editable=False)
update_time = models.DateTimeField(auto_now=True)
source = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="tx_sent", editable=False,
)