uncloud-mravi/uncloud/uncloud_pay/helpers.py

84 lines
2.9 KiB
Python
Raw Normal View History

from functools import reduce
2020-02-29 08:08:30 +00:00
from datetime import datetime
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
2020-02-29 08:08:30 +00:00
from django.db.models import Q
from .models import Bill, Payment, PaymentMethod, Order
from django.utils import timezone
from django.core.exceptions import ObjectDoesNotExist
from dateutil.relativedelta import relativedelta
def sum_amounts(entries):
return reduce(lambda acc, entry: acc + entry.amount, entries, 0)
def get_balance_for(user):
bills = sum_amounts(Bill.objects.filter(owner=user))
payments = sum_amounts(Payment.objects.filter(owner=user))
return payments - bills
def get_payment_method_for(user):
methods = PaymentMethod.objects.filter(owner=user)
for method in methods:
# Do we want to do something with non-primary method?
if method.primary:
return method
return None
2020-02-29 08:08:30 +00:00
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,
mixins.ListModelMixin,
GenericViewSet):
"""
A customer-facing viewset that provides default `create()`, `retrieve()`
and `list()`.
"""
pass