Skip to content

Commit

Permalink
Merge pull request OCA#141 from jcoux/migrate_account_payment_term_ex…
Browse files Browse the repository at this point in the history
…tension

Migration V9 account_payment_term_extension
  • Loading branch information
gurneyalex committed Apr 27, 2016
2 parents 502b7ba + 89ca6b3 commit ebe1b7e
Show file tree
Hide file tree
Showing 10 changed files with 842 additions and 72 deletions.
51 changes: 44 additions & 7 deletions account_payment_term_extension/README.rst
Original file line number Diff line number Diff line change
@@ -1,33 +1,70 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3

==============================
Account Payment Term Extension
==============================

This module was written to extend the functionality of payment terms to support rounding, months and weeks on payment term lines.
This module extends the functionality of payment terms to :

By default in Odoo, if you have a payment term of *30 days end of months* and you invoice on January 30, you will have a due date on March 31st. With this module, if you configure the payment term line with months = 1, days = 0 and days2 = -1, you will have a due date on February 28th.
* support rounding, months and weeks on payment term lines
* allow to set more than one day of payment in payment terms
* allow to apply a chronological order on lines
* for example, with a payment term which contains 2 lines
* on standard, the due date of all lines is calculated from the invoice date
* with this feature, the due date of the second line is calculated from the due date of the first line

Configuration
=============

To configure the Payment Terms and see the new options on the Payment Term Lines, go to the menu Accounting > Configuration > Miscellaneous > Payment Terms.
To configure the Payment Terms and see the new options on the Payment Term Lines, you need to:

#. Go to the menu Accounting > Configuration > Management > Payment Terms.

To use multiple payment days, define for each payment term line which payment days apply, separated by spaces, commas or dashes.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/account-invoicing/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed `feedback
<https://github.com/OCA/
account-invoicing/issues/new?body=module:%20
account_payment_term_extension%0Aversion:%20
9.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
* https://openclipart.org/detail/198659/mono-template-invoice
* https://openclipart.org/detail/5571/calendar-icon-large

Contributors
------------

* Yannick Vaucher <[email protected]>
* Alexis de Lattre <[email protected]>
* Julien Coux <[email protected]>
* Pedro M. Baeza <[email protected]>

Maintainer
----------

.. image:: http://odoo-community.org/logo.png
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
:target: https://odoo-community.org

This module is maintained by the OCA.

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

To contribute to this module, please visit http://odoo-community.org.
To contribute to this module, please visit https://odoo-community.org.
12 changes: 7 additions & 5 deletions account_payment_term_extension/__openerp__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@

{
'name': 'Payment Term Extension',
'version': '8.0.1.0.0',
'version': '9.0.1.0.0',
'category': 'Accounting & Finance',
'summary': 'Adds rounding, months and weeks properties on '
'payment term lines',
'summary': 'Adds rounding, months, weeks and multiple payment days '
'properties on payment term lines',
'description': "",
'author': 'Camptocamp,Odoo Community Association (OCA)',
'author': 'Camptocamp,'
'Serv. Tecnol. Avanzados - Pedro M. Baeza,'
'Odoo Community Association (OCA)',
'maintainer': 'OCA',
'website': 'http://www.camptocamp.com/',
'license': 'AGPL-3',
'depends': ['account'],
'data': ['account_view.xml'],
'demo': ['account_demo.xml'],
'test': [],
'installable': False,
'installable': True,
}
134 changes: 103 additions & 31 deletions account_payment_term_extension/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@
#
##############################################################################

from datetime import datetime
from dateutil.relativedelta import relativedelta
import time

from openerp import models, fields, api
from openerp.tools.float_utils import float_round
from openerp import models, fields, api, exceptions, _
from openerp.tools.float_utils import float_is_zero, float_round

import openerp.addons.decimal_precision as dp
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT

import calendar


class AccountPaymentTermLine(models.Model):
Expand Down Expand Up @@ -58,54 +57,127 @@ def compute_line_amount(self, total_amount, remaining_amount):
:returns: computed amount for this line
"""
self.ensure_one()
prec = self.env['decimal.precision'].precision_get('Account')
if self.env.context.get('currency_id'):
currency = self.env['res.currency'].browse(
self.env.context['currency_id'])
else:
currency = self.env.user.company_id.currency_id
prec = currency.decimal_places
if self.value == 'fixed':
return float_round(self.value_amount, precision_digits=prec)
elif self.value == 'procent':
amt = total_amount * self.value_amount
elif self.value == 'percent':
amt = total_amount * (self.value_amount / 100.0)
if self.amount_round:
amt = float_round(amt, precision_rounding=self.amount_round)
return float_round(amt, precision_digits=prec)
elif self.value == 'balance':
return float_round(remaining_amount, precision_digits=prec)
return None

def _decode_payment_days(self, days_char):
# Admit space, dash and comma as separators
days_char = days_char.replace(' ', '-').replace(',', '-')
days_char = [x.strip() for x in days_char.split('-') if x]
days = [int(x) for x in days_char]
days.sort()
return days

@api.one
@api.constrains('payment_days')
def _check_payment_days(self):
if not self.payment_days:
return
try:
payment_days = self._decode_payment_days(self.payment_days)
error = any(day <= 0 or day > 31 for day in payment_days)
except:
error = True
if error:
raise exceptions.Warning(
_('Payment days field format is not valid.'))

payment_days = fields.Char(
string='Payment day(s)',
help="Put here the day or days when the partner makes the payment. "
"Separate each possible payment day with dashes (-), commas (,) "
"or spaces ( ).")


class AccountPaymentTerm(models.Model):
_inherit = "account.payment.term"

def compute(self, cr, uid, id, value, date_ref=False, context=None):
sequential_lines = fields.Boolean(
string='Sequential lines',
default=False,
help="Allows to apply a chronological order on lines.")

def apply_payment_days(self, line, date):
"""Calculate the new date with days of payments"""
if line.payment_days:
payment_days = line._decode_payment_days(line.payment_days)
if payment_days:
new_date = None
payment_days.sort()
days_in_month = calendar.monthrange(date.year, date.month)[1]
for day in payment_days:
if date.day <= day:
if day > days_in_month:
day = days_in_month
new_date = date + relativedelta(day=day)
break
if not new_date:
day = payment_days[0]
if day > days_in_month:
day = days_in_month
new_date = date + relativedelta(day=day, months=1)
return new_date
return date

@api.one
def compute(self, value, date_ref=False):
"""Complete overwrite of compute method to add rounding on line
computing and also to handle weeks and months
"""
obj_precision = self.pool['decimal.precision']
prec = obj_precision.precision_get(cr, uid, 'Account')
if not date_ref:
date_ref = datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT)
pt = self.browse(cr, uid, id, context=context)
date_ref = date_ref or fields.Date.today()
amount = value
result = []
for line in pt.line_ids:
if self.env.context.get('currency_id'):
currency = self.env['res.currency'].browse(
self.env.context['currency_id'])
else:
currency = self.env.user.company_id.currency_id
prec = currency.decimal_places
next_date = fields.Date.from_string(date_ref)
for line in self.line_ids:
amt = line.compute_line_amount(value, amount)
if not amt:
continue
next_date = (datetime.strptime(date_ref,
DEFAULT_SERVER_DATE_FORMAT) +
relativedelta(days=line.days,
weeks=line.weeks,
months=line.months))
if line.days2 < 0:
if not self.sequential_lines:
# For all lines, the beginning date is `date_ref`
next_date = fields.Date.from_string(date_ref)
if float_is_zero(amt, precision_rounding=prec):
continue
if line.option == 'day_after_invoice_date':
next_date += relativedelta(days=line.days,
weeks=line.weeks,
months=line.months)
elif line.option == 'fix_day_following_month':
# Getting 1st of next month
next_first_date = next_date + relativedelta(day=1, months=1)
next_date = next_first_date + relativedelta(days=line.days2)
if line.days2 > 0:
next_date += relativedelta(day=line.days2, months=1)
result.append(
(next_date.strftime(DEFAULT_SERVER_DATE_FORMAT), amt))
amount -= amt

next_date = next_first_date + relativedelta(days=line.days - 1,
weeks=line.weeks,
months=line.months)
elif line.option == 'last_day_following_month':
# Getting last day of next month
next_date += relativedelta(day=31, months=1)
elif line.option == 'last_day_current_month':
# Getting last day of next month
next_date += relativedelta(day=31, months=0)
next_date = self.apply_payment_days(line, next_date)
if not float_is_zero(amt, precision_rounding=prec):
result.append((fields.Date.to_string(next_date), amt))
amount -= amt
amount = reduce(lambda x, y: x + y[1], result, 0.0)
dist = round(value - amount, prec)
if dist:
result.append((time.strftime(DEFAULT_SERVER_DATE_FORMAT), dist))
last_date = result and result[-1][0] or fields.Date.today()
result.append((last_date, dist))
return result
30 changes: 11 additions & 19 deletions account_payment_term_extension/account_demo.xml
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>

<openerp>
<data noupdate="1">
<data noupdate="1">

<record id="account.account_payment_term_line" model="account.payment.term.line">
<field name="days" eval="0"/>
<field name="months" eval="1"/>
</record>
<record id="sixty_days_end_of_month" model="account.payment.term">
<field name="name">60 Days End of Month</field>
<field name="note">60 Days End of Month</field>
<field name="sequential_lines">True</field>
<field name="line_ids"
eval="[(0,0, {'months': 2, 'option': 'day_after_invoice_date', 'sequence': 20, 'value': 'fixed', 'value_amount': 0}),
(0,0, {'days': 0, 'option': 'last_day_current_month', 'sequence': 30, 'value': 'balance', 'value_amount': 0})
]" />
</record>

<record id="sixty_days_end_of_month" model="account.payment.term">
<field name="name">60 Days End of Month</field>
<field name="note">60 Days End of Month</field>
</record>

<record id="sixty_days_end_of_month_line" model="account.payment.term.line">
<field name="payment_id" ref="sixty_days_end_of_month"/>
<field name="value">balance</field>
<field name="months" eval="2"/>
<field name="days" eval="0"/>
<field name="days2" eval="-1"/>
</record>

</data>
</data>
</openerp>
29 changes: 23 additions & 6 deletions account_payment_term_extension/account_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,35 @@
<openerp>
<data>

<record id="view_payment_term_form" model="ir.ui.view">
<field name="name">account.payment.term.form.extension</field>
<field name="model">account.payment.term</field>
<field name="inherit_id" ref="account.view_payment_term_form"/>
<field name="arch" type="xml">
<field name="active" position="after">
<field name="sequential_lines"/>
</field>
</field>
</record>

<record id="view_payment_term_line_form" model="ir.ui.view">
<field name="name">account.payment.term.line.form.extension</field>
<field name="model">account.payment.term.line</field>
<field name="inherit_id" ref="account.view_payment_term_line_form"/>
<field name="arch" type="xml">
<div attrs="{'invisible':[('value','=','balance')]}" position="after">
<div attrs="{'invisible':[('value','=', 'balance')]}" position="after">
<field name="amount_round"
attrs="{'invisible':[('value','=','balance')]}"/>
attrs="{'invisible':[('value','=','balance')]}"/>
</div>
<field name="days" position="after">
<field name="weeks"/>
<field name="months"/>
</field>
<xpath expr="/form/group/group[2]" position="replace">
<group string="Due Date Computation">
<field name="days" attrs="{'invisible': [('option', 'in', ['last_day_following_month', 'last_day_current_month'])]}"/>
<field name="weeks" attrs="{'invisible': [('option', 'in', ['last_day_following_month', 'last_day_current_month'])]}"/>
<field name="months" attrs="{'invisible': [('option', 'in', ['last_day_following_month', 'last_day_current_month'])]}"/>
<field name="payment_days" attrs="{'invisible': [('option', 'in', ['last_day_following_month', 'last_day_current_month'])]}"/>
<field name="option" widget="radio"/>
</group>
</xpath>
</field>
</record>

Expand All @@ -29,6 +45,7 @@
<field name="days" position="after">
<field name="weeks"/>
<field name="months"/>
<field name="payment_days"/>
</field>
</field>
</record>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ebe1b7e

Please sign in to comment.