WIP revamped bill logic

This commit is contained in:
fnux 2020-02-29 09:08:30 +01:00
commit e319d1d151
7 changed files with 152 additions and 69 deletions

View file

@ -1,7 +1,10 @@
from functools import reduce
from datetime import datetime
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from .models import Bill, Payment, PaymentMethod
from django.db.models import Q
from .models import Bill, Payment, PaymentMethod, Order
from django.utils import timezone
def sum_amounts(entries):
return reduce(lambda acc, entry: acc + entry.amount, entries, 0)
@ -20,6 +23,52 @@ def get_payment_method_for(user):
return None
def beginning_of_month(date):
return datetime(year=date.year, date=now.month, day=0)
def generate_bills_for(year, month, user, allowed_delay):
# /!\ We exclusively work on the specified year and month.
# Default values for next bill (if any). Only saved at the end of
# this method, if relevant.
tz = timezone.get_current_timezone()
next_bill = Bill(owner=user,
starting_date=datetime(year=year, month=month, day=1, tzinfo=tz),
ending_date=datetime(year=year, month=month, day=28, tzinfo=tz),
creation_date=timezone.now(),
due_date=timezone.now() + allowed_delay)
# Select all orders active on the request period.
orders = Order.objects.filter(
Q(ending_date__gt=next_bill.starting_date) | Q(ending_date__isnull=True),
owner=user)
# Check if there is already a bill covering the order and period pair:
# * Get latest bill by ending_date: previous_bill.ending_date
# * If previous_bill.ending_date is before next_bill.ending_date, a new
# bill has to be generated.
unpaid_orders = []
for order in orders:
try:
previous_bill = order.bill.latest('-ending_date')
except ObjectDoesNotExist:
previous_bill = None
if previous_bill == None or previous_bill.ending_date < next_bill.ending_date:
unpaid_orders.append(order)
# Commit next_bill if it there are 'unpaid' orders.
if len(unpaid_orders) > 0:
next_bill.save()
# It is not possible to register many-to-many relationship before
# the two end-objects are saved in database.
for order in unpaid_orders:
order.bill.add(next_bill)
return next_bill
# Return None if no bill was created.
class ProductViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,