2
0

[ENH] account_spread_cost_revenue: add calculate by days feature

This commit is contained in:
ps-tubtim 2023-02-08 11:57:36 +07:00 committed by Andrea Stirpe
parent fb9f29fc0c
commit 0fdbf6f02c
4 changed files with 77 additions and 5 deletions

View File

@ -3,6 +3,7 @@
import calendar
import time
from datetime import timedelta
from dateutil.relativedelta import relativedelta
@ -44,6 +45,11 @@ class AccountSpread(models.Model):
help="Period length for the entries",
required=True,
)
days_calc = fields.Boolean(
string="Calculate by days",
default=False,
help="Use number of days to calculate amount",
)
use_invoice_line_account = fields.Boolean()
credit_account_id = fields.Many2one(
"account.account",
@ -242,6 +248,7 @@ class AccountSpread(models.Model):
self.period_type = self.template_id.period_type
if self.template_id.start_date:
self.spread_date = self.template_id.start_date
self.days_calc = self.template_id.days_calc
@api.depends("invoice_type", "company_id")
def _compute_journal_id(self):
@ -368,8 +375,9 @@ class AccountSpread(models.Model):
for x in range(len(posted_line_ids), number_of_periods):
sequence = x + 1
date = self._get_last_day_of_month(spread_date)
amount = self._compute_board_amount(
sequence, unposted_amount, number_of_periods
sequence, unposted_amount, number_of_periods, date
)
amount = self.currency_id.round(amount)
rounding = self.currency_id.rounding
@ -380,7 +388,7 @@ class AccountSpread(models.Model):
"amount": amount,
"spread_id": self.id,
"name": self._get_spread_entry_name(sequence),
"date": self._get_last_day_of_month(spread_date),
"date": date,
}
commands.append((0, False, vals))
@ -398,22 +406,78 @@ class AccountSpread(models.Model):
self.ensure_one()
return self.period_number + 1 if month_day != 1 else self.period_number
@staticmethod
def _get_first_day_of_month(spread_date):
return spread_date + relativedelta(day=1)
@staticmethod
def _get_last_day_of_month(spread_date):
return spread_date + relativedelta(day=31)
def _compute_board_amount(self, sequence, amount, number_of_periods):
def _get_spread_start_date(self, period_type, spread_end_date):
self.ensure_one()
spread_start_date = spread_end_date + relativedelta(days=1)
if period_type == "month":
spread_start_date = spread_end_date + relativedelta(day=1)
elif period_type == "quarter":
spread_start_date = spread_start_date - relativedelta(months=3)
elif period_type == "year":
spread_start_date = spread_start_date - relativedelta(years=1)
spread_start_date = self._get_first_day_of_month(spread_start_date)
spread_start_date = max(spread_start_date, self.spread_date)
return spread_start_date
def _get_spread_end_date(self, period_type, period_number, spread_start_date):
self.ensure_one()
spread_end_date = spread_start_date
number_of_periods = (
period_number if spread_start_date.day != 1 else period_number - 1
)
if period_type == "month":
spread_end_date = spread_start_date + relativedelta(
months=number_of_periods
)
elif period_type == "quarter":
months = number_of_periods * 3
spread_end_date = spread_start_date + relativedelta(months=months)
elif period_type == "year":
spread_end_date = spread_start_date + relativedelta(years=number_of_periods)
# calculate by days and not first day of month should compute residual day only
if self.days_calc and spread_end_date.day != 1:
spread_end_date = spread_end_date - timedelta(days=1)
else:
spread_end_date = self._get_last_day_of_month(spread_end_date)
return spread_end_date
def _get_amount_per_day(self, amount):
self.ensure_one()
spread_start_date = self.spread_date
spread_end_date = self._get_spread_end_date(
self.period_type, self.period_number, spread_start_date
)
number_of_days = (spread_end_date - spread_start_date).days + 1
return amount / number_of_days
def _compute_board_amount(
self, sequence, amount, number_of_periods, spread_end_date
):
"""Calculates the amount for the spread lines."""
self.ensure_one()
amount_to_spread = self.total_amount
period = self.period_number
if sequence != number_of_periods:
amount = amount_to_spread / self.period_number
amount = amount_to_spread / period
if sequence == 1:
date = self.spread_date
month_days = calendar.monthrange(date.year, date.month)[1]
days = month_days - date.day + 1
period = self.period_number
amount = (amount_to_spread / period) / month_days * days
if self.days_calc:
spread_start_date = self._get_spread_start_date(
self.period_type, spread_end_date
)
days = (spread_end_date - spread_start_date).days + 1
amount = self._get_amount_per_day(amount_to_spread) * days
return amount
def compute_spread_board(self):

View File

@ -50,6 +50,11 @@ class AccountSpreadTemplate(models.Model):
help="Period length for the entries",
)
start_date = fields.Date()
days_calc = fields.Boolean(
string="Calculate by days",
default=False,
help="Use number of days to calculate amount",
)
auto_spread = fields.Boolean(
string="Auto assign template on invoice validate",
help="If checked, provide option to auto create spread during "
@ -120,6 +125,7 @@ class AccountSpreadTemplate(models.Model):
"template_id": self.id,
"journal_id": self.spread_journal_id.id,
"use_invoice_line_account": self.use_invoice_line_account,
"days_calc": self.days_calc,
"company_id": company.id,
}

View File

@ -249,6 +249,7 @@
domain="[('company_id', '=', company_id)]"
widget="selection"
/>
<field name="days_calc" />
</group>
</group>
<notebook name="notebook">

View File

@ -26,6 +26,7 @@
<field name="period_number" />
<field name="period_type" />
<field name="start_date" />
<field name="days_calc" />
</group>
<group>
<field name="use_invoice_line_account" />