126 lines
4.3 KiB
Python
126 lines
4.3 KiB
Python
import datetime
|
|
from collections import defaultdict
|
|
from django.utils import timezone as tz
|
|
from django.db import models
|
|
|
|
# Create your models here.
|
|
|
|
class Etiquette(models.Model):
|
|
nom = models.CharField(max_length=128, unique=True)
|
|
|
|
def __str__(self):
|
|
return "%s" % self.nom
|
|
|
|
|
|
class MonthManager(models.Manager):
|
|
|
|
|
|
def get_queryset_for_month(self, month, year):
|
|
return super().get_queryset().filter(date__month=month,
|
|
date__year=year)
|
|
|
|
def get_queryset(self, month=None, year=None):
|
|
""" Add custom 'month' and 'year' keyword arguments, used as filters.
|
|
Without argument, simply proxy to parent method.
|
|
|
|
This method checks if month is newly created (first access). If
|
|
so, it spawns recursive records for this month.
|
|
"""
|
|
# Generic call
|
|
if not month and not year:
|
|
return super().get_queryset()
|
|
# Custom call
|
|
elif month and year:
|
|
recursifs = EnregistrementRecursif.objects.all()
|
|
if (not self.get_queryset_for_month(month, year).exists()
|
|
and recursifs.exists()):
|
|
print("LOG: Month is created so we populated it...")
|
|
for r in recursifs:
|
|
r.spawn(month, year)
|
|
return self.get_queryset_for_month(month, year)
|
|
# Invalid call
|
|
else:
|
|
raise TypeError(
|
|
"You must call with either none or \
|
|
both 'month' and 'year' keyword arguments")
|
|
|
|
def _populate_data(self, qs, data):
|
|
|
|
def somme_par_etiquette(qs):
|
|
sommes = defaultdict(lambda:0)
|
|
for el in qs:
|
|
sommes[el.etiquette.nom] += el.montant
|
|
return dict(sommes)
|
|
|
|
data['balance'] = sum(map(lambda t: t[0], qs.values_list('montant')))
|
|
data['par_etiquette'] = somme_par_etiquette(qs)
|
|
|
|
return data
|
|
|
|
def calculate_data(self, qs):
|
|
#TODO: cached results
|
|
return self._populate_data(qs, {})
|
|
|
|
def get_month_with_data(self, month, year):
|
|
""" Retrieve the queryset for given month and year, plus
|
|
some data calculated on the set """
|
|
|
|
qs = self.get_queryset(month=month, year=year)
|
|
data = self.calculate_data(qs)
|
|
return qs, data
|
|
|
|
|
|
class Enregistrement(models.Model):
|
|
objects = MonthManager()
|
|
|
|
date = models.DateField()
|
|
montant = models.FloatField()
|
|
etiquette = models.ForeignKey(Etiquette)
|
|
description = models.CharField(max_length=512)
|
|
|
|
def __str__(self):
|
|
return "<Depense: %s>" % self.etiquette
|
|
|
|
|
|
class EnregistrementRecursif(models.Model):
|
|
jour = models.IntegerField()
|
|
montant = models.FloatField()
|
|
etiquette = models.ForeignKey(Etiquette)
|
|
description = models.CharField(max_length=512)
|
|
created_date = models.DateField()
|
|
|
|
def is_older(self, month, year):
|
|
return (self.created_date.month <= month
|
|
and self.created_date.year <= year)
|
|
|
|
def spawn(self, month, year, commit=True):
|
|
""" Spawn a new Enregistrement for given month and year. """
|
|
|
|
# Do not spawn for dates older than this instance creation date
|
|
if not self.is_older(month, year):
|
|
return None
|
|
# Create new Enregistrement from this instance values
|
|
date = datetime.date(year, month, self.jour)
|
|
new_object, created = Enregistrement.objects.get_or_create(date=date,
|
|
montant=self.montant,
|
|
etiquette=self.etiquette,
|
|
description=self.description)
|
|
if created and commit:
|
|
new_object.save()
|
|
return new_object
|
|
|
|
def save(self, **kwargs):
|
|
""" Update 'created_date' on each save, this avoids conflict with older
|
|
spawned instances.
|
|
"""
|
|
self.created_date = tz.now().date()
|
|
return super().save(**kwargs)
|
|
|
|
def __str__(self):
|
|
return "<[%i] %s (%s) : %s {%s}>" % (self.jour,
|
|
self.description,
|
|
self.etiquette,
|
|
self.montant,
|
|
self.created_date)
|
|
|