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'))
Для ежемесячных платежей вам не понадобится отдельный случай, поскольку вы сообщаете сумму ежемесячно. Для разовых платежей сумма будет считаться, если операция произошла в этом месяце. Следовательно, для этих случаев не нужны отдельные дела.
Я ссылался на документацию здесь:
Вот выпуск, в котором используется аннотация и агрегация, которые, как мне кажется, могут быть вам полезны.