mirror of
https://github.com/OCA/account-financial-tools.git
synced 2025-02-02 12:47:26 +02:00
[ADD] credit control dunning fees module
This commit is contained in:
21
account_credit_control_dunning_fees/__init__.py
Normal file
21
account_credit_control_dunning_fees/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import model
|
||||
70
account_credit_control_dunning_fees/__openerp__.py
Normal file
70
account_credit_control_dunning_fees/__openerp__.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
{'name': 'Credit control dunning fees',
|
||||
'version': '0.1.0',
|
||||
'author': 'Camptocamp',
|
||||
'maintainer': 'Camptocamp',
|
||||
'category': 'Accounting',
|
||||
'complexity': 'normal',
|
||||
'depends': ['account_credit_control'],
|
||||
'description': """
|
||||
Dunning Fees for Credit Control
|
||||
===============================
|
||||
|
||||
This extention of credit control adds the notion of dunning fees
|
||||
on credit control lines.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
For release 0.1 only fixed fees are supported.
|
||||
|
||||
You can specifiy a fees fixed a product and a currency
|
||||
on the credit control level form.
|
||||
|
||||
The amount will be used as fees values the currency will determine
|
||||
the currency of the fee. If the credit control line has not the
|
||||
same currency as the fees currency, fees will be converted to
|
||||
the credit control line currency.
|
||||
|
||||
The product is used to compute taxes in reconciliation process.
|
||||
|
||||
Run
|
||||
---
|
||||
Fees are automatically computed on credit run and saved
|
||||
on the generated credit lines.
|
||||
|
||||
Fees can be manually edited as long credit line is draft
|
||||
|
||||
To Come
|
||||
-------
|
||||
Support of fees price list
|
||||
|
||||
""",
|
||||
'website': 'http://www.camptocamp.com',
|
||||
'data': ['view/policy_view.xml',
|
||||
'view/line_view.xml'],
|
||||
'demo': [],
|
||||
'test': [],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'license': 'AGPL-3',
|
||||
'application': False,
|
||||
}
|
||||
24
account_credit_control_dunning_fees/model/__init__.py
Normal file
24
account_credit_control_dunning_fees/model/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import line
|
||||
from . import policy
|
||||
from . import run
|
||||
from . import dunning
|
||||
71
account_credit_control_dunning_fees/model/dunning.py
Normal file
71
account_credit_control_dunning_fees/model/dunning.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class FeesComputer(orm.TransientModel):
|
||||
_name = 'credit.control.dunning.fees.computer'
|
||||
_auto = False
|
||||
_log_access = True
|
||||
|
||||
def _get_compute_fun(self, level_fees_type):
|
||||
if level_fees_type == 'fixed':
|
||||
return self.compute_fixed_fees
|
||||
else:
|
||||
raise NotImplementedError('fees type %s is not supported' % level_fees_type)
|
||||
|
||||
def _compute_fees(self, cr, uid, credit_line_ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if not credit_line_ids:
|
||||
return credit_line_ids
|
||||
c_model = self.pool['credit.control.line']
|
||||
credit_lines = c_model.browse(cr, uid, credit_line_ids, context=context)
|
||||
for credit in credit_lines:
|
||||
# if there is no dependence between generated credit lines
|
||||
# this could be threaded
|
||||
self._compute(cr, uid, credit, context=context),
|
||||
return credit_line_ids
|
||||
|
||||
def _compute(self, cr, uid, credit_line, context=None):
|
||||
"""Compute fees for a given credit line"""
|
||||
fees_type = credit_line.policy_level_id.dunning_fees_type
|
||||
compute = self._get_compute_fun(fees_type)
|
||||
fees = compute(cr, uid, credit_line, context=context)
|
||||
if fees:
|
||||
credit_line.write({'dunning_fees_amount': fees},
|
||||
context=context)
|
||||
|
||||
def compute_fixed_fees(self, cr, uid, credit_line, context=None):
|
||||
currency_model = self.pool['res.currency']
|
||||
credit_currency = credit_line.currency_id
|
||||
level = credit_line.policy_level_id
|
||||
fees_amount = level.dunning_fixed_amount
|
||||
if not fees_amount:
|
||||
return 0.0
|
||||
fees_currency = level.dunning_currency_id
|
||||
if fees_currency == credit_currency:
|
||||
return fees_amount
|
||||
else:
|
||||
return currency_model.compute(cr, uid, fees_currency.id,
|
||||
credit_currency.id, fees_amount,
|
||||
context=context)
|
||||
29
account_credit_control_dunning_fees/model/line.py
Normal file
29
account_credit_control_dunning_fees/model/line.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
|
||||
class credit_control_line(orm.Model):
|
||||
"""Add fees computations"""
|
||||
|
||||
_inherit = "credit.control.line"
|
||||
|
||||
_columns = {'dunning_fees_amount': fields.float('Fees')}
|
||||
36
account_credit_control_dunning_fees/model/policy.py
Normal file
36
account_credit_control_dunning_fees/model/policy.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
|
||||
class credit_control_policy(orm.Model):
|
||||
"""ADD dunning fees fields"""
|
||||
|
||||
_inherit = "credit.control.policy.level"
|
||||
_columns = {'dunning_product_id': fields.many2one('product.product',
|
||||
'Fees Product'),
|
||||
'dunning_fixed_amount': fields.float('Fees Fixed Amount'),
|
||||
'dunning_currency_id': fields.many2one('res.currency',
|
||||
'Fees currency'),
|
||||
# planned type are fixed, percent, compound
|
||||
'dunning_fees_type': fields.selection([('fixed', 'Fixed')])}
|
||||
|
||||
_defaults = {'dunning_fees_type': 'fixed'}
|
||||
39
account_credit_control_dunning_fees/model/run.py
Normal file
39
account_credit_control_dunning_fees/model/run.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
|
||||
class credit_control_run(orm.Model):
|
||||
"""Add computation of fees"""
|
||||
|
||||
_inherit = "credit.control.run"
|
||||
|
||||
def _generate_credit_lines(self, cr, uid, run_id, context=None):
|
||||
|
||||
credit_line_ids = super(credit_control_run, self)._generate_credit_lines(
|
||||
cr,
|
||||
uid,
|
||||
run_id,
|
||||
context=context
|
||||
)
|
||||
fees_model = self.pool['credit.control.dunning.fees.computer']
|
||||
fees_model._compute_fees(cr, uid, credit_line_ids, context=context)
|
||||
return credit_line_ids
|
||||
23
account_credit_control_dunning_fees/tests/__init__.py
Normal file
23
account_credit_control_dunning_fees/tests/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import test_fees_generation
|
||||
|
||||
checks = [test_fees_generation]
|
||||
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Nicolas Bessi
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from mock import MagicMock
|
||||
import openerp.tests.common as test_common
|
||||
|
||||
|
||||
class FixedFeesTester(test_common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Initialaize level mock to test fees computations"""
|
||||
super(FixedFeesTester, self).setUp()
|
||||
self.currency_model = self.registry('res.currency')
|
||||
self.euro = self.currency_model.search(self.cr, self.uid,
|
||||
[('name', '=', 'EUR')])
|
||||
self.assertTrue(self.euro)
|
||||
self.euro = self.registry('res.currency').browse(self.cr,
|
||||
self.uid,
|
||||
self.euro[0])
|
||||
|
||||
self.usd = self.currency_model.search(self.cr, self.uid,
|
||||
[('name', '=', 'USD')])
|
||||
self.assertTrue(self.usd)
|
||||
self.usd = self.registry('res.currency').browse(self.cr,
|
||||
self.uid,
|
||||
self.usd[0])
|
||||
|
||||
self.euro_level = MagicMock(name='Euro policy level')
|
||||
self.euro_level.dunning_fixed_amount = 5.0
|
||||
self.euro_level.dunning_currency_id = self.euro
|
||||
self.euro_level.dunning_type = 'fixed'
|
||||
|
||||
self.usd_level = MagicMock(name='Euro policy level')
|
||||
self.usd_level.dunning_fixed_amount = 5.0
|
||||
self.usd_level.dunning_currency_id = self.usd
|
||||
self.usd_level.dunning_type = 'fixed'
|
||||
self.dunning_model = self.registry('credit.control.dunning.fees.computer')
|
||||
|
||||
def test_type_getter(self):
|
||||
"""Test that correct compute function is returned for "fixed" type"""
|
||||
c_fun = self.dunning_model._get_compute_fun('fixed')
|
||||
self.assertEqual(c_fun, self.dunning_model.compute_fixed_fees)
|
||||
|
||||
def test_unknow_type(self):
|
||||
"""Test that non implemented error is raised if invalide fees type"""
|
||||
with self.assertRaises(NotImplementedError):
|
||||
self.dunning_model._get_compute_fun('bang')
|
||||
|
||||
def test_computation_same_currency(self):
|
||||
"""Test that fees are correctly computed with same currency"""
|
||||
credit_line = MagicMock(name='Euro credit line')
|
||||
credit_line.policy_level_id = self.euro_level
|
||||
credit_line.currency_id = self.euro
|
||||
fees = self.dunning_model.compute_fixed_fees(self.cr, self.uid,
|
||||
credit_line,
|
||||
{})
|
||||
self.assertEqual(fees, self.euro_level.dunning_fixed_amount)
|
||||
|
||||
def test_computation_different_currency(self):
|
||||
"""Test that fees are correctly computed with different currency"""
|
||||
credit_line = MagicMock(name='USD credit line')
|
||||
credit_line.policy_level_id = self.euro_level
|
||||
credit_line.currency_id = self.usd
|
||||
fees = self.dunning_model.compute_fixed_fees(self.cr, self.uid,
|
||||
credit_line,
|
||||
{})
|
||||
self.assertNotEqual(fees, self.euro_level.dunning_fixed_amount)
|
||||
|
||||
def test_no_fees(self):
|
||||
"""Test that fees are not generated if no amount defined on level"""
|
||||
credit_line = MagicMock(name='USD credit line')
|
||||
credit_line.policy_level_id = self.euro_level
|
||||
self.euro_level.dunning_fixed_amount = 0.0
|
||||
credit_line.currency_id = self.usd
|
||||
fees = self.dunning_model.compute_fixed_fees(self.cr, self.uid,
|
||||
credit_line,
|
||||
{})
|
||||
self.assertEqual(fees, 0.0)
|
||||
30
account_credit_control_dunning_fees/view/line_view.xml
Normal file
30
account_credit_control_dunning_fees/view/line_view.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="add_fees_on_credit_control_line" model="ir.ui.view">
|
||||
<field name="name">add fees on credit control line</field>
|
||||
<field name="model">credit.control.line</field>
|
||||
<field name="inherit_id" ref="account_credit_control.credit_control_line_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="balance_due" position="after">
|
||||
<field name="dunning_fees_amount"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="add_fees_on_credit_control_line_from" model="ir.ui.view">
|
||||
<field name="name">add fees on credit control line form</field>
|
||||
<field name="model">credit.control.line</field>
|
||||
<field name="inherit_id" ref="account_credit_control.credit_control_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="balance_due" position="after">
|
||||
<field name="dunning_fees_amount"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
26
account_credit_control_dunning_fees/view/policy_view.xml
Normal file
26
account_credit_control_dunning_fees/view/policy_view.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="add_dunning_fees_on_policy" model="ir.ui.view">
|
||||
<field name="name">add dunning fees on policy</field>
|
||||
<field name="model">credit.control.policy</field>
|
||||
<field name="inherit_id" ref="account_credit_control.credit_control_policy_form" />
|
||||
<field name="arch" type="xml">
|
||||
<page string="Mail and reporting" position="after">
|
||||
<page string="Fees">
|
||||
<group>
|
||||
<group>
|
||||
<field name="dunning_fixed_amount"/>
|
||||
<field name="dunning_product_id"
|
||||
attrs="{'required': [('dunning_fixed_amount', '!=', False)]}"/>
|
||||
<field name="dunning_currency_id"
|
||||
attrs="{'required': [('dunning_fixed_amount', '!=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user