diff --git a/account_credit_control_dunning_fees/__init__.py b/account_credit_control_dunning_fees/__init__.py
new file mode 100644
index 000000000..6ac610f01
--- /dev/null
+++ b/account_credit_control_dunning_fees/__init__.py
@@ -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 .
+#
+##############################################################################
+from . import model
diff --git a/account_credit_control_dunning_fees/__openerp__.py b/account_credit_control_dunning_fees/__openerp__.py
new file mode 100644
index 000000000..36ceb3944
--- /dev/null
+++ b/account_credit_control_dunning_fees/__openerp__.py
@@ -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 .
+#
+##############################################################################
+{'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,
+}
diff --git a/account_credit_control_dunning_fees/model/__init__.py b/account_credit_control_dunning_fees/model/__init__.py
new file mode 100644
index 000000000..c9a69427a
--- /dev/null
+++ b/account_credit_control_dunning_fees/model/__init__.py
@@ -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 .
+#
+##############################################################################
+from . import line
+from . import policy
+from . import run
+from . import dunning
diff --git a/account_credit_control_dunning_fees/model/dunning.py b/account_credit_control_dunning_fees/model/dunning.py
new file mode 100644
index 000000000..dc383c6dd
--- /dev/null
+++ b/account_credit_control_dunning_fees/model/dunning.py
@@ -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 .
+#
+##############################################################################
+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)
diff --git a/account_credit_control_dunning_fees/model/line.py b/account_credit_control_dunning_fees/model/line.py
new file mode 100644
index 000000000..9cc853326
--- /dev/null
+++ b/account_credit_control_dunning_fees/model/line.py
@@ -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 .
+#
+##############################################################################
+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')}
diff --git a/account_credit_control_dunning_fees/model/policy.py b/account_credit_control_dunning_fees/model/policy.py
new file mode 100644
index 000000000..1cf3c699b
--- /dev/null
+++ b/account_credit_control_dunning_fees/model/policy.py
@@ -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 .
+#
+##############################################################################
+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'}
diff --git a/account_credit_control_dunning_fees/model/run.py b/account_credit_control_dunning_fees/model/run.py
new file mode 100644
index 000000000..a01b43f61
--- /dev/null
+++ b/account_credit_control_dunning_fees/model/run.py
@@ -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 .
+#
+##############################################################################
+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
diff --git a/account_credit_control_dunning_fees/tests/__init__.py b/account_credit_control_dunning_fees/tests/__init__.py
new file mode 100644
index 000000000..db75f16d2
--- /dev/null
+++ b/account_credit_control_dunning_fees/tests/__init__.py
@@ -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 .
+#
+##############################################################################
+from . import test_fees_generation
+
+checks = [test_fees_generation]
diff --git a/account_credit_control_dunning_fees/tests/test_fees_generation.py b/account_credit_control_dunning_fees/tests/test_fees_generation.py
new file mode 100644
index 000000000..bb5ff3609
--- /dev/null
+++ b/account_credit_control_dunning_fees/tests/test_fees_generation.py
@@ -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 .
+#
+##############################################################################
+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)
diff --git a/account_credit_control_dunning_fees/view/line_view.xml b/account_credit_control_dunning_fees/view/line_view.xml
new file mode 100644
index 000000000..9d4688bd5
--- /dev/null
+++ b/account_credit_control_dunning_fees/view/line_view.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+ add fees on credit control line
+ credit.control.line
+
+
+
+
+
+
+
+
+
+ add fees on credit control line form
+ credit.control.line
+
+
+
+
+
+
+
+
+
+
diff --git a/account_credit_control_dunning_fees/view/policy_view.xml b/account_credit_control_dunning_fees/view/policy_view.xml
new file mode 100644
index 000000000..02e9ac618
--- /dev/null
+++ b/account_credit_control_dunning_fees/view/policy_view.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ add dunning fees on policy
+ credit.control.policy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+