Update commodity and transaction details and list
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user