[ADD] credit control dunning fees module

This commit is contained in:
Nicolas Bessi
2014-04-14 13:57:02 +02:00
parent 9a94904a63
commit 350ae708ff
11 changed files with 464 additions and 0 deletions

View 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

View 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,
}

View 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

View 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)

View 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')}

View 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'}

View 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

View 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]

View File

@@ -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)

View 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>

View 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>