Move account_credit_control_dunning_fees to root folder

Set account_credit_control_dunning_fees to installable

Extract the module description to README.rst

Port Dunning fees to the new API, activate the tests for 8.0

Add fees in the report

Use the new API instead of mocks for FixedFeesTester

It will be easier to write additional tests

Remove required on the currency and fallback to company's currency...

... on the policy level if it is empty.

Also, it fixes a bug when a credit line had no currency and the level
had the company's currency. As False is different than any currency,
it entered in res_currency.compute() with a False currency. It must
just fallback on the company's currency if the credit line's currency
is empty.
This commit is contained in:
Guewen Baconnier
2014-10-31 17:15:40 +01:00
committed by Akim Juillerat
parent 089b4846b4
commit da48baad91
16 changed files with 769 additions and 123 deletions

View File

@@ -0,0 +1,30 @@
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 fixed fees amount, 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
Credit control Summary report includes a new fees column
--------------------------------------------------------
Support of fees price list

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

@@ -25,44 +25,12 @@
'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 fixed fees amount, 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
Credit control Summary report includes a new fees column.
-------
Support of fees price list
""",
'website': 'http://www.camptocamp.com',
'data': ['view/policy_view.xml',
'view/line_view.xml',
'report/report.xml',
'security/ir.model.access.csv'],
'report/report_credit_control_summary.xml',
'security/ir.model.access.csv',
],
'demo': [],
'test': [],
'installable': True,

View File

@@ -0,0 +1,81 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account_credit_control_dunning_fees
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-05-07 11:44+0000\n"
"PO-Revision-Date: 2014-05-07 11:44+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_line
#, python-format
msgid "A credit control line"
msgstr ""
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_policy_level
#, python-format
msgid "A credit control policy level"
msgstr ""
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_run
#, python-format
msgid "Credit control line generator"
msgstr ""
#. module: account_credit_control_dunning_fees
#: field:credit.control.line,dunning_fees_amount:0
#: view:credit.control.policy:0
msgid "Fees"
msgstr ""
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_fixed_amount:0
msgid "Fees Fixed Amount"
msgstr ""
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_product_id:0
msgid "Fees Product"
msgstr ""
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_currency_id:0
msgid "Fees currency"
msgstr ""
#. module: account_credit_control_dunning_fees
#: selection:credit.control.policy.level,dunning_fees_type:0
msgid "Fixed"
msgstr ""
#. module: account_credit_control_dunning_fees
#: view:credit.control.policy:0
msgid "Mail and reporting"
msgstr ""
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_dunning_fees_computer
#, python-format
msgid "credit.control.dunning.fees.computer"
msgstr ""
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_fees_type:0
msgid "unknown"
msgstr ""

View File

@@ -0,0 +1,80 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account_credit_control_dunning_fees
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-04-16 07:11+0000\n"
"PO-Revision-Date: 2014-04-16 07:11+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_line
#, python-format
msgid "A credit control line"
msgstr "Ligne de relance"
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_policy_level
#, python-format
msgid "A credit control policy level"
msgstr "Une politique de relance"
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_run
#, python-format
msgid "Credit control line generator"
msgstr "Générateur de relance"
#. module: account_credit_control_dunning_fees
#: field:credit.control.line,dunning_fees_amount:0
#: view:credit.control.policy:0
msgid "Fees"
msgstr "Frais de relance"
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_fixed_amount:0
msgid "Fees Fixed Amount"
msgstr "Montant des frais"
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_product_id:0
msgid "Fees Product"
msgstr "Article lié"
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_currency_id:0
msgid "Fees currency"
msgstr "Devises"
#. module: account_credit_control_dunning_fees
#: selection:credit.control.policy.level,dunning_fees_type:0
msgid "Fixed"
msgstr "Fixe"
#. module: account_credit_control_dunning_fees
#: view:credit.control.policy:0
msgid "Mail and reporting"
msgstr "Lettres et e-mails"
#. module: account_credit_control_dunning_fees
#: code:_description:0
#: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_dunning_fees_computer
#, python-format
msgid "credit.control.dunning.fees.computer"
msgstr "credit.control.dunning.fees.computer"
#. module: account_credit_control_dunning_fees
#: field:credit.control.policy.level,dunning_fees_type:0
msgid "unknown"
msgstr "inconnu"

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

@@ -18,16 +18,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm
from openerp import models, api
class FeesComputer(orm.BaseModel):
class FeesComputer(models.BaseModel):
"""Model that compute dunnig fees.
This class does not need any database storage as
it contains pure logic.
It inherits form ``orm.BaseModel`` to benefit of orm facility
It inherits form ``models.BaseModel`` to benefit of orm facility
Similar to AbstractModel but log access and actions
"""
@@ -38,16 +38,18 @@ class FeesComputer(orm.BaseModel):
_register = True
_transient = False
@api.model
def _get_compute_fun(self, level_fees_type):
"""Retrieve function of class that should compute the fees based on type
"""Retrieve function of class that should compute the fees based
on type
:param level_fee_type: type exisiting in model
:param level_fee_type: type existing in model
`credit.control.policy.level`
for field dunning_fees_type
:returns: a function of class :class:`FeesComputer`
with following signature
self, cr, uid, credit_line (record), context
self, credit_line (record)
"""
if level_fees_type == 'fixed':
@@ -56,33 +58,30 @@ class FeesComputer(orm.BaseModel):
raise NotImplementedError('fees type %s is not supported' %
level_fees_type)
def _compute_fees(self, cr, uid, credit_line_ids, context=None):
"""Compute fees for `credit_line_ids` parameter
@api.model
def _compute_fees(self, credit_lines):
"""Compute fees for `credit_lines` parameter
Fees amount is written on credit line in field dunning_fees_amount
Fees amount is written on credit lines in the field dunning_fees_amount
:param credit_line_ids: list of `credit.control.line` ids
:param credit_lines: recordset of `credit.control.line`
:returns: `credit_line_ids` list of `credit.control.line` ids
:returns: recordset of `credit.control.line`
"""
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)
if not credit_lines:
return credit_lines
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
self._compute(credit)
return credit_lines
def _compute(self, cr, uid, credit_line, context=None):
@api.model
def _compute(self, credit_line):
"""Compute fees for a given credit line
Fees amount is written on credit line in field dunning_fees_amount
Fees amount is written on credit line in then field dunning_fees_amount
:param credit_line: credit line record
@@ -90,13 +89,13 @@ class FeesComputer(orm.BaseModel):
"""
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)
fees = compute(credit_line)
if fees:
credit_line.write({'dunning_fees_amount': fees},
context=context)
credit_line.write({'dunning_fees_amount': fees})
return credit_line
def compute_fixed_fees(self, cr, uid, credit_line, context=None):
@api.model
def compute_fixed_fees(self, credit_line):
"""Compute fees amount for fixed fees.
Correspond to the fixed dunning fees type
@@ -109,16 +108,15 @@ class FeesComputer(orm.BaseModel):
:return: fees amount float (in credit line currency)
"""
currency_model = self.pool['res.currency']
credit_currency = credit_line.currency_id
credit_currency = (credit_line.currency_id or
credit_line.company_id.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
fees_currency = (level.dunning_currency_id or
level.policy_id.company_id.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)
return fees_currency.compute(fees_amount, credit_currency)

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 import models, fields
class CreditControlLine(models.Model):
"""Add dunning_fees_amount_fees field"""
_inherit = "credit.control.line"
dunning_fees_amount = fields.Float(string='Fees')

View File

@@ -0,0 +1,44 @@
# -*- 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 import models, fields
class CreditControlPolicy(models.Model):
"""ADD dunning fees fields"""
_inherit = "credit.control.policy.level"
dunning_product_id = fields.Many2one('product.product',
string='Fees Product')
dunning_fixed_amount = fields.Float(string='Fees Fixed Amount')
dunning_currency_id = fields.Many2one(
'res.currency',
string='Fees currency',
help="Currency of the dunning fees. If empty, it takes the "
"company's currency."
)
# planned type are fixed, percent, compound
dunning_fees_type = fields.Selection([('fixed', 'Fixed')],
string='Type',
default='fixed')

View File

@@ -18,22 +18,19 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm
from openerp import models, api
class credit_control_run(orm.Model):
class CreditControlRun(models.Model):
"""Add computation of fees"""
_inherit = "credit.control.run"
def _generate_credit_lines(self, cr, uid, run_id, context=None):
@api.multi
@api.returns('credit.control.line')
def _generate_credit_lines(self):
"""Override method to add fees computation"""
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
credit_lines = super(CreditControlRun, self)._generate_credit_lines()
fees_model = self.env['credit.control.dunning.fees.computer']
fees_model._compute_fees(credit_lines)
return credit_lines

View File

@@ -0,0 +1,246 @@
## -*- coding: utf-8 -*-
<html>
<head>
<style type="text/css">
${css}
body {
font-family: helvetica;
font-size: 12px;
}
.custom_text {
font-family: helvetica;
font-size: 12px;
}
table {
font-family: helvetica;
font-size: 12px;
}
.header {
margin-left: 0px;
text-align: left;
width: 300px;
font-size: 12px;
}
.title {
font-size: 16px;
font-weight: bold;
}
.basic_table{
text-align: center;
border: 1px solid lightGrey;
border-collapse: collapse;
font-family: helvetica;
font-size: 12px;
}
.basic_table th {
border: 1px solid lightGrey;
font-size: 11px;
font-weight: bold;
}
.basic_table td {
border: 1px solid lightGrey;
font-size: 12px;
}
.list_table {
border-color: black;
text-align: center;
border-collapse: collapse;
}
.list_table td {
border-color: gray;
border-top: 1px solid gray;
text-align: left;
font-size: 12px;
padding-right: 3px;
padding-left: 3px;
padding-top: 3px;
padding-bottom:3px;
}
.list_table th {
border-bottom: 2px solid black;
text-align: left;
font-size: 11px;
font-weight: bold;
padding-right: 3px
padding-left: 3px
}
.list_table thead {
display: table-header-group;
}
.address table {
font-size: 11px;
border-collapse: collapse;
margin: 0px;
padding: 0px;
}
.address .shipping {
}
.address .invoice {
margin-top: 10px;
}
.address .recipient {
font-size: 13px;
margin-right: 120px;
margin-left: 350px;
float: right;
}
table .address_title {
font-weight: bold;
}
.address td.name {
font-weight: bold;
}
td.amount, th.amount {
text-align: right;
padding-right:2px;
}
h1 {
font-size: 16px;
font-weight: bold;
}
tr.line .note {
border-style: none;
font-size: 9px;
padding-left: 10px;
}
tr.line {
margin-bottom: 10px;
}
</style>
</head>
<body>
%for comm in objects :
<% setLang(comm.get_contact_address().lang) %>
<div class="address">
<table class="recipient">
<%
add = comm.get_contact_address()
%>
%if comm.partner_id.id == add.id:
<tr><td class="name">${comm.partner_id.title and comm.partner_id.title.name or ''} ${comm.partner_id.name }</td></tr>
<% address_lines = comm.partner_id.contact_address.split("\n") %>
%else:
<tr><td class="name">${comm.partner_id.name or ''}</td></tr>
<tr><td>${add.title and add.title.name or ''} ${add.name}</td></tr>
<% address_lines = add.contact_address.split("\n")[1:] %>
%endif
%for part in address_lines:
%if part:
<tr><td>${part}</td></tr>
%endif
%endfor
</table>
<br/>
<br/>
<br/>
<br/>
</div>
<br/>
<br/>
<br/>
<div>
<h3 style="clear: both; padding-top: 20px;">
${_('Reminder')}: ${comm.current_policy_level.name or '' }
</h3>
<p>${_('Dear')},</p>
<p class="custom_text" width="95%">${comm.current_policy_level.custom_text.replace('\n', '<br />')}</p>
<br/>
<br/>
<p><b>${_('Summary')}<br/></b></p>
<table class="basic_table" style="width: 100%;">
<tr>
<th width="200">${_('Invoice number')}</th>
<th>${_('Invoice date')}</th>
<th>${_('Date due')}</th>
<th>${_('Invoiced amount')}</th>
<th>${_('Open amount')}</th>
<th>${_('Fees')}</th>
<th>${_('Currency')}</th>
</tr>
%for line in comm.credit_control_line_ids:
<tr>
%if line.invoice_id:
<td width="200">${line.invoice_id.number}
%if line.invoice_id.name:
<br/>
${line.invoice_id.name}
%endif
</td>
%else:
<td width="200">${line.move_line_id.name}</td>
%endif
<td class="date">${line.date_entry}</td>
<td class="date">${line.date_due}</td>
<td class="amount">${line.amount_due}</td>
<td class="amount">${line.balance_due}</td>
<td class="amount">${line.dunning_fees_amount}</td>
<td class="amount">${line.currency_id.name or comm.company_id.currency_id.name}</td>
</tr>
%endfor
</table>
<br/>
<br/>
<%doc>
<!-- uncomment to have info after summary -->
<p>${_('If you have any question, do not hesitate to contact us.')}</p>
<p>${comm.user_id.name} ${comm.user_id.email and '<%s>'%(comm.user_id.email) or ''}<br/>
${comm.company_id.name}<br/>
% if comm.company_id.street:
${comm.company_id.street or ''}<br/>
% endif
% if comm.company_id.street2:
${comm.company_id.street2}<br/>
% endif
% if comm.company_id.city or comm.company_id.zip:
${comm.company_id.zip or ''} ${comm.company_id.city or ''}<br/>
% endif
% if comm.company_id.country_id:
${comm.company_id.state_id and ('%s, ' % comm.company_id.state_id.name) or ''} ${comm.company_id.country_id.name or ''}<br/>
% endif
% if comm.company_id.phone:
Phone: ${comm.company_id.phone}<br/>
% endif
% if comm.company_id.website:
${comm.company_id.website or ''}<br/>
% endif
</%doc>
<p style="page-break-after:always"></p>
%endfor
</body>
</html>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="report_credit_control_summary_document_fees"
inherit_id="account_credit_control.report_credit_control_summary_document">
<xpath expr="//table[@id='summary_table']/thead/tr/th[last()]" position="after">
<th class="text-right">Fees</th>
</xpath>
<xpath expr="//span[@t-field='l.balance_due']" position="replace">
<span t-field="l.balance_due"/>
</xpath>
<xpath expr="//table[@id='summary_table']/tbody/tr/td[last()]" position="after">
<td class="text-right">
<span t-field="l.dunning_fees_amount"
t-field-options='{"widget": "monetary",
"display_currency": "l.currency_id or l.company_id.currency_id"}'/>
</td>
</xpath>
</template>
</data>
</openerp>

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 test_fees_generation

View File

@@ -18,42 +18,41 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from mock import MagicMock
import openerp.tests.common as test_common
from openerp.tests import common
class FixedFeesTester(test_common.TransactionCase):
@common.at_install(True)
@common.post_install(True)
class FixedFeesTester(common.TransactionCase):
def setUp(self):
"""Initialize credit control 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.currency_model = self.env['res.currency']
self.euro = self.currency_model.search([('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.usd = self.currency_model.search([('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.company = self.browse_ref('base.main_company')
self.company.currency_id = self.euro
self.usd_level = MagicMock(name='USD 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'
)
level_obj = self.env['credit.control.policy.level']
self.euro_level = level_obj.new({
'name': 'Euro Level',
'dunning_fixed_amount': 5.0,
'dunning_currency_id': self.euro,
'dunning_type': 'fixed',
})
self.usd_level = level_obj.new({
'name': 'USD Level',
'dunning_fixed_amount': 5.0,
'dunning_currency_id': self.usd,
'dunning_type': 'fixed',
})
self.dunning_model = self.env['credit.control.dunning.fees.computer']
self.line_model = self.env['credit.control.line']
def test_type_getter(self):
"""Test that correct compute function is returned for "fixed" type"""
@@ -67,31 +66,63 @@ class FixedFeesTester(test_common.TransactionCase):
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,
{})
credit_line = self.line_model.new({
'policy_level_id': self.euro_level,
'currency_id': self.euro,
'company_id': self.company,
})
fees = self.dunning_model.compute_fixed_fees(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,
{})
credit_line = self.line_model.new({
'policy_level_id': self.euro_level,
'currency_id': self.usd.id,
'company_id': self.company,
})
fees = self.dunning_model.compute_fixed_fees(credit_line)
self.assertNotEqual(fees, self.euro_level.dunning_fixed_amount)
def test_computation_credit_currency_empty(self):
"""Test that fees are correctly computed with empty credit currency"""
credit_line = self.line_model.new({
'policy_level_id': self.euro_level,
'currency_id': False,
'company_id': self.company,
})
fees = self.dunning_model.compute_fixed_fees(credit_line)
self.assertEqual(fees, self.euro_level.dunning_fixed_amount)
def test_computation_level_currency_empty(self):
"""Test that fees are correctly computed with empty level currency"""
credit_line = self.line_model.new({
'policy_level_id': self.euro_level,
'currency_id': self.euro,
'company_id': self.company,
})
self.euro_level.currency_id = False
fees = self.dunning_model.compute_fixed_fees(credit_line)
self.assertEqual(fees, self.euro_level.dunning_fixed_amount)
def test_computation_all_currency_empty(self):
"""Test that fees are correctly computed with empty currencies"""
credit_line = self.line_model.new({
'policy_level_id': self.euro_level,
'currency_id': False,
'company_id': self.company,
})
self.euro_level.currency_id = False
fees = self.dunning_model.compute_fixed_fees(credit_line)
self.assertEqual(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
credit_line = self.line_model.new({
'policy_level_id': self.euro_level,
'currency_id': self.usd,
'company_id': self.company,
})
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,
{})
fees = self.dunning_model.compute_fixed_fees(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,24 @@
<?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"/>
<field name="dunning_currency_id"/>
</group>
</group>
</page>
</page>
</field>
</record>
</data>
</openerp>