Django расчет повторяющихся записей/платежей

У меня есть таблица "ожидаемых платежей", которые либо являются единовременным платежом, либо повторяются ежемесячно, ежеквартально или ежегодно. Цель - рассчитать общую сумму ожидаемых платежей за каждый из предстоящих 12 месяцев.

Модель выглядит следующим образом:

class ExpectedPayment(models.Model):
    id = models.BigIntegerField(primary_key=True)
    period = models.BigIntegerField()
    date_start = models.DateField(blank=True, null=True)
    date_end = models.DateField(blank=True, null=True)
    amount = models.DecimalField(max_digits=1000, decimal_places=1000)

Период 1 = Ежемесячно повторяющийся
Период 2 = Каждый квартал - после даты начала. (То есть, начался в феврале, следующий квартал - май)
. Период 3 = Ежегодное повторение - также после даты начала
. Период 4 = Единовременная оплата

Как правильно рассчитать общую "сумму" за каждый месяц, учитывая при этом, когда должен состояться платеж? Особенно это касается квартальных платежей..

Я не могу понять, как учитывать время начала и окончания платежа, так как он мог быть начат на полпути в течение года, закончен 3 месяца спустя или уже был закончен изначально. Как мне узнать, какой месяц квартала следует считать ожидаемым платежом, если он всегда относительно даты начала_даты.

Пример для одного месяца: (каждый ежемесячный платеж, который активен в текущем месяце)

start_of_current_month = datetime.today().replace(day=1)
current_month_expected_monthly_payments = ExpectedPayment.objects.filter(period=1, date_start__lte=start_of_current_month, date_end__gte=start_of_current_month).aggregate(total=Sum("amount"))

Предполагается, что для каждого данного периода платеж собирается в начале периода. Например - Для квартального платежа, начинающегося в феврале, сумма за февраль, март и апрель собирается в феврале. Для отчетности вы хотите представить сумму как amount/3, так как вы хотите отчитываться на ежемесячной основе. Вот что я думаю. Для каждого периода вы можете рассчитать сумму, используя аннотацию -

ExpectedPayment.objects.filter(
    date_start__lte=start_of_current_month,
    date_end__gte=start_of_current_month
    ).annotate(
         monthly_amount = Case(
             When(period=2, then=F('amount')/3,
             When(period=3, then=F('amount')/12,
             default=F('amount')
    )).aggregate(monthly_sum = Sum(F('monthly_amount'))

Для ежемесячных платежей вам не понадобится отдельный случай, поскольку вы сообщаете сумму ежемесячно. Для разовых платежей сумма будет считаться, если операция произошла в этом месяце. Следовательно, для этих случаев не нужны отдельные дела.

Я ссылался на документацию здесь:

Вот выпуск, в котором используется аннотация и агрегация, которые, как мне кажется, могут быть вам полезны.

Вернуться на верх