Skip to content

Commit

Permalink
[ADD] account_interests: late payment interest feature
Browse files Browse the repository at this point in the history
New feature on late payment interest, now can setup a "daily" interest that calculate thought many days is late payment
  • Loading branch information
ica-adhoc committed Dec 16, 2024
1 parent 69f6c55 commit 5bb0fcb
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 13 deletions.
2 changes: 1 addition & 1 deletion account_interests/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
##############################################################################
{
'name': 'Interests Management',
'version': "17.0.1.1.0",
'version': "17.0.1.2.0",
'category': 'Accounting',
'sequence': 14,
'summary': 'Calculate interests for selected partners',
Expand Down
79 changes: 67 additions & 12 deletions account_interests/models/res_company_interest.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class ResCompanyInterest(models.Model):
)
has_domain = fields.Boolean(compute="_compute_has_domain")

late_payment_interest = fields.Boolean('Late payment interest', default=False, help="The interest calculation takes into account all late payments from the previous period. To obtain the daily rate, the interest is divided by the period. These days are considered depending on the type of period: 360 for annual, 30 for monthly and 7 for weekly.")

@api.model
def _cron_recurring_interests_invoices(self):
_logger.info('Running Interest Invoices Cron Job')
Expand All @@ -93,7 +95,7 @@ def _cron_recurring_interests_invoices(self):
_logger.error('Error creating interest invoices for company: %s', rec.company_id.name)
companies_with_errors.append(rec.company_id.name)
rec.env.cr.rollback()

if companies_with_errors:
company_names = ', '.join(companies_with_errors)
error_message = _("We couldn't run interest invoices cron job in the following companies: %s.") % company_names
Expand Down Expand Up @@ -140,12 +142,10 @@ def create_interest_invoices(self):
# seteamos proxima corrida en hoy mas un periodo
rec.next_date = interests_date + next_delta

def _get_move_line_domains(self, to_date):
def _get_move_line_domains(self):
self.ensure_one()
move_line_domain = [
('account_id', 'in', self.receivable_account_ids.ids),
('full_reconcile_id', '=', False),
('date_maturity', '<', to_date),
('partner_id.active', '=', True),
('parent_state', '=', 'posted'),
]
Expand All @@ -157,20 +157,20 @@ def create_invoices(self, to_date, groupby=['partner_id']):
journal = self.env['account.journal'].search([
('type', '=', 'sale'),
('company_id', '=', self.company_id.id)], limit=1)

if self.receivable_account_ids != journal.default_account_id:
journal = self.env['account.journal'].search([('default_account_id','in',self.receivable_account_ids.ids)], limit=1) or journal

move_line_domain = self._get_move_line_domains(to_date)
move_line_domain_previous_periods = self._get_move_line_domains() + [('full_reconcile_id', '=', False), ('date_maturity', '<', to_date)]
# Check if a filter is set
if self.domain:
move_line_domain += safe_eval(self.domain)
move_line_domain_previous_periods += safe_eval(self.domain)

fields = ['id:recordset', 'amount_residual:sum', 'partner_id:recordset', 'account_id:recordset']

move_line = self.env['account.move.line']
grouped_lines = move_line._read_group(
domain=move_line_domain,
domain=move_line_domain_previous_periods,
groupby=groupby,
aggregates=fields,
)
Expand Down Expand Up @@ -200,6 +200,61 @@ def create_invoices(self, to_date, groupby=['partner_id']):
"Something went wrong creating "
"interests invoice: {}".format(e))

# Feature de intereses por pago tardio (periodo actual)
# ToDo comentar esta funcionalidad
if self.late_payment_interest:
#last_period_lines_domain = self._get_move_line_domains() + [('date_maturity', '>=', to_date)]
interest_rate = {
'daily': 1,
'weekly': 7,
'monthly': 30,
'yearly': 360,
}
last_period_lines_domain = ["&", "&", "&", "&",
('account_id', 'in', self.receivable_account_ids.ids),
('partner_id.active', '=', True),
('parent_state', '=', 'posted'),
('date_maturity', '>=', to_date),
"|",
("amount_residual", ">", 0), ("matched_credit_ids", "!=", False),
]
grouped_lines_last_period = move_line._read_group(
domain=last_period_lines_domain,
groupby=groupby,
aggregates=fields,
)
for idx, line in enumerate(grouped_lines_last_period):
interest = 0
move_lines = line[1].grouped('move_id')
for move, lines in move_lines.items():
if not lines.matched_credit_ids:
interest += sum(lines.mapped('amount_currency')) * self.rate
last_partial = False
# que pasa si en una factura de 1000 del 1/11 vto 10/11 pague 400 el 15/11 y 600 el 5/12, estaría contemplado por la ejecución del cron ya?
for partial in lines.matched_credit_ids.filtered(lambda x: x.debit_move_id.date_maturity < x.credit_move_id.date):
if not last_partial or last_partial.credit_move_id.date <= partial.credit_move_id.date:
last_partial = partial
if last_partial:
days = (last_partial.credit_move_id.date - last_partial.debit_move_id.date_maturity).days
interest += lines.amount_currency * days * (self.rate / interest_rate[self.rule_type])
move_vals = self._prepare_interest_invoice(
line, to_date, journal, interest)
if not move_vals:
continue

_logger.info('Creating Late Payment Interest Invoice with values:\n%s', line)

move = self.env['account.move'].create(move_vals)

if self.automatic_validation:
try:
move.action_post()
except Exception as e:
_logger.error(
"Something went wrong creating "
"interests invoice: {}".format(e))


def prepare_info(self, to_date, debt):
self.ensure_one()

Expand All @@ -216,17 +271,17 @@ def prepare_info(self, to_date, debt):

return res

def _prepare_interest_invoice(self, line, to_date, journal):
def _prepare_interest_invoice(self, line, to_date, journal, forced_interest_amount=False):
self.ensure_one()
debt = line[2]

if not debt or debt <= 0.0:
if (not debt or debt <= 0.0) and not forced_interest_amount:
_logger.info("Debt is negative, skipping...")
return

partner_id = line[0].id
partner = self.env['res.partner'].browse(partner_id)
comment = self.prepare_info(to_date, debt)
comment = self.prepare_info(to_date, debt) if not forced_interest_amount else 'Deuda Vencida por Pago Atrasado'
fpos = partner.property_account_position_id
taxes = self.interest_product_id.taxes_id.filtered(
lambda r: r.company_id == self.company_id)
Expand All @@ -244,7 +299,7 @@ def _prepare_interest_invoice(self, line, to_date, journal):
'invoice_line_ids': [(0, 0, {
"product_id": self.interest_product_id.id,
"quantity": 1.0,
"price_unit": self.rate * debt,
"price_unit": self.rate * debt if not forced_interest_amount else forced_interest_amount,
"partner_id": partner.id,
"name": self.interest_product_id.name + '.\n' + comment,
"analytic_distribution": {self.analytic_account_id.id: 100.0} if self.analytic_account_id.id else False,
Expand Down
1 change: 1 addition & 0 deletions account_interests/views/res_company_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<field name="rule_type"/>
<field name="next_date"/>
<field name="tolerance_interval"/>
<field name="late_payment_interest"/>
</group>
<field name="domain" widget="domain" options="{ 'model': 'account.move.line', 'in_dialog': True }" />
</group>
Expand Down

0 comments on commit 5bb0fcb

Please sign in to comment.