Merge pull request #514 from Tecnativa/9.0-mig-account_credit_control

[ADD] account_credit_control: backport from 10.0
This commit is contained in:
Pedro M. Baeza
2017-08-07 17:33:34 +02:00
committed by GitHub
73 changed files with 2663 additions and 3706 deletions

View File

@@ -1,29 +1,87 @@
.. 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
==============
Credit Control
==============
Installation
============
Just install it
Configuration
-------------
=============
Configure the policies and policy levels in ``Accounting > Configuration >
Credit Control > Credit Policies``.
You can define as many policy levels as you need.
* Configure the policies and policy levels in **Accounting > Configuration >
Credit Control > Credit Control Policies**. You can define as many policy
levels as you need.
Configure a tolerance for the Credit control and a default policy
applied on all partners in each company, under the Accounting tab.
* You must add in every policy, to which account or accounts this policy is
applied. To do, you must go to "Accounts" tab in policy form.
* Configure a tolerance for the Credit control and a default policy
applied on all partners in each company, under the Accounting tab.
* You are able to specify a particular policy for one partner or one invoice.
You are able to specify a particular policy for one partner or one invoice.
Usage
-----
=====
Menu entries are located in ``Accounting > Periodical Processing > Credit
Control``.
Menu entries are located in ``Accounting > Adviser > Credit Control``.
Create a new "run" in the ``Credit Control Run`` menu with the controlling date.
Then, use the ``Compute credit lines`` button. All the credit control lines will
Then, use the ``Compute Credit Lines`` button. All the credit control lines will
be generated. You can find them in the ``Credit Control Lines`` menu.
On each generated line, you have many choices:
* Send a email
* Print a letter
* Change the state (so you can ignore or reopen lines)
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/92/9.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/account-financial-tools/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.
Credits
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Contributors
------------
* Nicolas Bessi (Camptocamp)
* Guewen Baconnier (Camptocamp)
* Sylvain Van Hoof (Okia SPRL) <sylvain@okia.be>
* Akim Juillerat (Camptocamp <akim.juillerat@camptocamp.com>
* Vicent Cubells <vicent.cubells@tecnativa.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
: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.
To contribute to this module, please visit https://odoo-community.org.

View File

@@ -1,29 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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 mail
from . import run
from . import line
from . import account
from . import partner
from . import policy
from . import company
from . import wizard
from . import invoice
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
from . import wizards

View File

@@ -1,51 +1,38 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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': 'Account Credit Control',
'version': '8.0.0.3.0',
'author': "Camptocamp,Odoo Community Association (OCA)",
'maintainer': 'Camptocamp',
'category': 'Finance',
'complexity': "normal",
'depends': ['base',
'account',
'email_template',
],
'website': 'http://www.camptocamp.com',
'data': ["report/report.xml",
"report/report_credit_control_summary.xml",
"data.xml",
"line_view.xml",
"account_view.xml",
"partner_view.xml",
"policy_view.xml",
"run_view.xml",
"company_view.xml",
"wizard/credit_control_emailer_view.xml",
"wizard/credit_control_marker_view.xml",
"wizard/credit_control_printer_view.xml",
"wizard/credit_control_policy_changer_view.xml",
"security/ir.model.access.csv"],
'demo': ["credit_control_demo.xml"],
'tests': [],
'installable': False,
'license': 'AGPL-3',
'application': True
}
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Credit Control',
'version': '9.0.0.1.0',
'author': "Camptocamp, "
"Tecnativa, "
"Odoo Community Association (OCA)",
'license': 'AGPL-3',
'category': 'Finance',
'depends': [
'base',
'account',
'mail',
],
'website': 'http://www.camptocamp.com',
'data': [
"security/res_groups.xml",
"report/report.xml",
"report/report_credit_control_summary.xml",
"data/data.xml",
"views/account_invoice.xml",
"views/credit_control_line.xml",
"views/credit_control_policy.xml",
"views/credit_control_run.xml",
"views/res_company.xml",
"views/res_partner.xml",
"wizards/credit_control_emailer_view.xml",
"wizards/credit_control_marker_view.xml",
"wizards/credit_control_printer_view.xml",
"wizards/credit_control_policy_changer_view.xml",
"security/ir.model.access.csv",
],
'installable': True,
}

View File

@@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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 AccountAccount(models.Model):
""" Add a link to a credit control policy on account.account """
_inherit = "account.account"
credit_control_line_ids = fields.One2many('credit.control.line',
'account_id',
string='Credit Lines',
readonly=True)

View File

@@ -1,45 +0,0 @@
<openerp>
<data>
<act_window
id="act_account_credit_relation_relation"
name="Credit Lines"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"
domain="[('account_id', '=', active_id)]"
res_model="credit.control.line"
src_model="account.account"/>
<record id="invoice_followup_form_view" model="ir.ui.view">
<field name="name">invoice.followup.form.view</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form" />
<field name="arch" type="xml">
<notebook position="inside">
<page string="Credit Control"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info">
<group>
<field name="credit_policy_id" widget="selection"
string="Manual Credit Control Policy"
attrs="{'invisible': [('credit_policy_id', '=', False)]}"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info"/>
</group>
<separator string="Issued Lines" colspan="4"/>
<field name="credit_control_line_ids" colspan="4" nolabel="1"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info" >
<tree string="Credit Control Lines">
<field name="date"/>
<field name="level"/>
<field name="state"/>
<field name="channel"/>
<field name="balance_due"/>
<field name="policy_level_id"/>
<field name="policy_id"/>
</tree>
</field>
</page>
</notebook>
</field>
</record>
</data>
</openerp>

View File

@@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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 ResCompany(models.Model):
""" Add credit control parameters """
_inherit = 'res.company'
credit_control_tolerance = fields.Float(string='Credit Control Tolerance',
default=0.1)
# This is not a property on the partner because we cannot search
# on fields.property (subclass fields.function).
credit_policy_id = fields.Many2one('credit.control.policy',
string='Credit Control Policy',
help="The Credit Control Policy used "
"on partners by default. "
"This setting can be overridden"
" on partners or invoices.")

View File

@@ -1,15 +0,0 @@
<openerp>
<data>
<record id="credit_control_company_form" model="ir.ui.view">
<field name="name">credit.control.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="credit_policy_id" widget="selection"/>
<field name="credit_control_tolerance"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -1,30 +0,0 @@
<openerp>
<data>
<record id="a_recv_1" model="account.account">
<field name="code">X11002-a</field>
<field name="name">B2B Debtors - (test)</field>
<field ref="account.cas" name="parent_id"/>
<field name="type">receivable</field>
<field eval="True" name="reconcile"/>
<field name="user_type" ref="account.data_account_type_receivable"/>
</record>
<record id="a_recv_2" model="account.account">
<field name="code">X11002-b</field>
<field name="name">B2C Debtors - (test)</field>
<field ref="account.cas" name="parent_id"/>
<field name="type">receivable</field>
<field eval="True" name="reconcile"/>
<field name="user_type" ref="account.data_account_type_receivable"/>
</record>
<record id="a_recv_3" model="account.account">
<field name="code">X11002-c</field>
<field name="name">New Debtors - (test)</field>
<field ref="account.cas" name="parent_id"/>
<field name="type">receivable</field>
<field eval="True" name="reconcile"/>
<field name="user_type" ref="account.data_account_type_receivable"/>
</record>
</data>
</openerp>

View File

@@ -1,230 +0,0 @@
<openerp>
<data noupdate="1">
<!--Email template -->
<record id="email_template_credit_control_base" model="email.template">
<field name="name">Credit Control Email</field>
<field name="email_from">noreply@localhost</field>
<field name="subject">Credit Control: (${object.current_policy_level.name or 'n/a'})</field>
<field name="email_to">${object.get_email() or ''}</field>
<field name="model_id" ref="model_credit_control_communication"/>
<field name="auto_delete" eval="True"/>
<field name="lang">${object.get_contact_address().lang or 'en_US'}</field>
<field name="report_template" ref="credit_control_summary"/>
<field name="body_html"><![CDATA[
Dear ${object.contact_address.name or ''}
<br/>
<br/>
${object.current_policy_level.custom_mail_text | safe}
]]></field>
</record>
<!-- policy no follow -->
<record model="credit.control.policy"
id="credit_control_no_follow">
<field name="name">No follow</field>
<field name="do_nothing" eval="1"/>
</record>
<!-- no follow policy -->
<record model="credit.control.policy.level"
id="no_follow_1">
<field name="name">No follow</field>
<field name="level" eval="1"/>
<field name="computation_mode">net_days</field>
<field name="delay_days" eval="0"/>
<field name="email_template_id" ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_no_follow"/>
<field name="channel">email</field>
<field name="custom_text">Manual no follow</field>
<field name="custom_mail_text">Manual no follow</field>
</record>
<!-- policy 1 -->
<record model="credit.control.policy"
id="credit_control_3_time">
<field name="name">3 time policy</field>
</record>
<record model="credit.control.policy.level"
id="3_time_1">
<field name="name">10 days net</field>
<field name="level" eval="1"/>
<field name="computation_mode">net_days</field>
<field name="delay_days" eval="10"/>
<field name="email_template_id" ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_3_time"/>
<field name="channel">email</field>
<field name="custom_text">Our records indicate that we have not received the payment of the above mentioned invoice.
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we have not received the payment of the invoices mentioned in the attached document.<br/>
<br/>
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record model="credit.control.policy.level"
id="3_time_2">
<field name="name">30 days end of month</field>
<field name="level" eval="2"/>
<field name="computation_mode">end_of_month</field>
<field name="delay_days" eval="30"/>
<field name="email_template_id" ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_3_time"/>
<field name="channel">email</field>
<field name="custom_text">Our records indicate that we have not yet received the payment of the above mentioned invoice despite our first reminder.
If it has already been sent, please disregard this notice. If not, please proceed with payment within 5 days.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we have not yet received the payment of the invoices mentioned in the attached document despite our first reminder.<br/>
If it has already been sent, please disregard this notice. If not, please proceed with payment within 5 days.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record model="credit.control.policy.level"
id="3_time_3">
<field name="name">10 days last reminder</field>
<field name="level" eval="3"/>
<field name="computation_mode">previous_date</field>
<field name="delay_days" eval="10"/>
<field name="email_template_id" ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_3_time"/>
<field name="channel">letter</field>
<field name="custom_text">
Our records indicate that we still have not received the payment of the above mentioned invoice despite our two reminders.
If payment have already been sent, please disregard this notice. If not, please proceed with payment.
If your payment has not been received in the next 5 days, your file will be transfered to our debt collection agency.
Should you need us to arrange a payment plan for you, please advise.
A customer account statement is enclosed for you convenience.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we still have not received the payment of the invoices mentioned in the attached document despite our two reminders.<br/>
If payment have already been sent, please disregard this notice. If not, please proceed with payment.<br/>
If your payment has not been received in the next 5 days, your file will be transfered to our debt collection agency.<br/>
<br/>
Should you need us to arrange a payment plan for you, please advise.<br/>
A customer account statement is enclosed for you convenience.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<!-- policy 2 -->
<record model="credit.control.policy"
id="credit_control_2_time">
<field name="name">2 time policy</field>
</record>
<record model="credit.control.policy.level"
id="2_time_1">
<field name="name">30 days end of month</field>
<field name="level" eval="1"/>
<field name="computation_mode">end_of_month</field>
<field name="delay_days" eval="30"/>
<field name="email_template_id" ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_2_time"/>
<field name="channel">email</field>
<field name="custom_text">Our records indicate that we have not received the payment of the above mentioned invoice.
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we have not received the payment of the invoices mentioned in the attached document.<br/>
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record model="credit.control.policy.level"
id="2_time_2">
<field name="name">60 days last reminder</field>
<field name="level" eval="2"/>
<field name="computation_mode">previous_date</field>
<field name="delay_days" eval="60"/>
<field name="email_template_id" ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_2_time"/>
<field name="channel">letter</field>
<field name="custom_text">Our records indicate that we still have not received the payment of the above mentioned invoice despite our reminder.
If payment have already been sent, please disregard this notice. If not, please proceed with payment.
If your payment has not been received in the next 5 days, your file will be transfered to our debt
collection agency.
Should you need us to arrange a payment plan for you, please advise.
A customer account statement is enclosed for you convenience.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we still have not received the payment of the invoices mentioned in the attached document despite our reminder.
<br/>
<br/>
If payment have already been sent, please disregard this notice. If not, please proceed with payment.<br/>
If your payment has not been received in the next 5 days, your file will be transfered to our debt<br/>
collection agency.<br/>
<br/>
Should you need us to arrange a payment plan for you, please advise.<br/>
A customer account statement is enclosed for you convenience.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record id="group_account_credit_control_manager" model="res.groups">
<field name="name">Credit Control Manager</field>
<field name="category_id" ref="base.module_category_accounting_and_finance"/>
</record>
<record id="group_account_credit_control_user" model="res.groups" context="{'noadmin':True}">
<field name="name">Credit Control User</field>
<field name="category_id" ref="base.module_category_accounting_and_finance"/>
</record>
<record id="group_account_credit_control_info" model="res.groups" context="{'noadmin':True}">
<field name="name">Credit Control Info</field>
<field name="category_id" ref="base.module_category_accounting_and_finance"/>
</record>
<record id="base.main_company" model="res.company">
<field name="credit_policy_id" ref="credit_control_3_time"/>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<!--Email template -->
<record id="email_template_credit_control_base" model="mail.template">
<field name="name">Credit Control Email</field>
<field name="email_from">${object.partner_id.company_id.email or ''}</field>
<field name="subject">Credit Control:
(${object.current_policy_level.name or 'n/a'})
</field>
<field name="email_to">${object.get_email() or ''}</field>
<field name="model_id" ref="model_credit_control_communication"/>
<field name="auto_delete" eval="True"/>
<field name="lang">
${object.get_contact_address().lang or 'en_US'}
</field>
<field name="report_template" ref="credit_control_summary"/>
<field name="body_html"><![CDATA[
Dear ${object.contact_address.name or ''}
<br/>
<br/>
${object.current_policy_level.custom_mail_text | safe}
]]></field>
</record>
<!-- policy no follow -->
<record model="credit.control.policy"
id="credit_control_no_follow">
<field name="name">No follow</field>
<field name="do_nothing" eval="1"/>
</record>
<!-- no follow policy -->
<record model="credit.control.policy.level"
id="no_follow_1">
<field name="name">No follow</field>
<field name="level" eval="1"/>
<field name="computation_mode">net_days</field>
<field name="delay_days" eval="0"/>
<field name="email_template_id"
ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_no_follow"/>
<field name="channel">email</field>
<field name="custom_text">Manual no follow</field>
<field name="custom_mail_text">Manual no follow</field>
</record>
<!-- policy 1 -->
<record model="credit.control.policy"
id="credit_control_3_time">
<field name="name">3 time policy</field>
</record>
<record model="credit.control.policy.level"
id="3_time_1">
<field name="name">10 days net</field>
<field name="level" eval="1"/>
<field name="computation_mode">net_days</field>
<field name="delay_days" eval="10"/>
<field name="email_template_id"
ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_3_time"/>
<field name="channel">email</field>
<field name="custom_text">Our records indicate that we have not received the payment of the invoice mentioned below.
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we have not received the payment of the invoices mentioned in the attached document.<br/>
<br/>
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record model="credit.control.policy.level"
id="3_time_2">
<field name="name">30 days end of month</field>
<field name="level" eval="2"/>
<field name="computation_mode">end_of_month</field>
<field name="delay_days" eval="30"/>
<field name="email_template_id"
ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_3_time"/>
<field name="channel">email</field>
<field name="custom_text">Our records indicate that we have not yet received the payment of the invoice mentioned below despite our first reminder.
If it has already been sent, please disregard this notice. If not, please proceed with payment within 5 days.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we have not yet received the payment of the invoices mentioned in the attached document despite our first reminder.<br/>
If it has already been sent, please disregard this notice. If not, please proceed with payment within 5 days.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record model="credit.control.policy.level"
id="3_time_3">
<field name="name">10 days last reminder</field>
<field name="level" eval="3"/>
<field name="computation_mode">previous_date</field>
<field name="delay_days" eval="10"/>
<field name="email_template_id"
ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_3_time"/>
<field name="channel">letter</field>
<field name="custom_text">
Our records indicate that we still have not received the payment of the invoice mentioned below despite our two reminders.
If payment have already been sent, please disregard this notice. If not, please proceed with payment.
If your payment has not been received in the next 5 days, your file will be transfered to our debt collection agency.
Should you need us to arrange a payment plan for you, please advise.
A customer account statement is enclosed for you convenience.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we still have not received the payment of the invoices mentioned in the attached document despite our two reminders.<br/>
If payment have already been sent, please disregard this notice. If not, please proceed with payment.<br/>
If your payment has not been received in the next 5 days, your file will be transfered to our debt collection agency.<br/>
<br/>
Should you need us to arrange a payment plan for you, please advise.<br/>
A customer account statement is enclosed for you convenience.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<!-- policy 2 -->
<record model="credit.control.policy"
id="credit_control_2_time">
<field name="name">2 time policy</field>
</record>
<record model="credit.control.policy.level"
id="2_time_1">
<field name="name">30 days end of month</field>
<field name="level" eval="1"/>
<field name="computation_mode">end_of_month</field>
<field name="delay_days" eval="30"/>
<field name="email_template_id"
ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_2_time"/>
<field name="channel">email</field>
<field name="custom_text">Our records indicate that we have not received the payment of the invoice mentioned below.
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we have not received the payment of the invoices mentioned in the attached document.<br/>
If it has already been sent, please disregard this notice. If not, please proceed with payment within 10 days.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record model="credit.control.policy.level"
id="2_time_2">
<field name="name">60 days last reminder</field>
<field name="level" eval="2"/>
<field name="computation_mode">previous_date</field>
<field name="delay_days" eval="60"/>
<field name="email_template_id"
ref="email_template_credit_control_base"/>
<field name="policy_id" ref="credit_control_2_time"/>
<field name="channel">letter</field>
<field name="custom_text">Our records indicate that we still have not received the payment of the mentioned below invoice despite our reminder.
If payment have already been sent, please disregard this notice. If not, please proceed with payment.
If your payment has not been received in the next 5 days, your file will be transfered to our debt collection agency.
Should you need us to arrange a payment plan for you, please advise.
A customer account statement is enclosed for you convenience.
Thank you in advance for your anticipated cooperation in this matter.
Best regards
</field>
<field name="custom_mail_text"><![CDATA[
Our records indicate that we still have not received the payment of the invoices mentioned in the attached document despite our reminder.
<br/>
<br/>
If payment have already been sent, please disregard this notice. If not, please proceed with payment.<br/>
If your payment has not been received in the next 5 days, your file will be transfered to our debt<br/>
collection agency.<br/>
<br/>
Should you need us to arrange a payment plan for you, please advise.<br/>
A customer account statement is enclosed for you convenience.<br/>
<br/>
Thank you in advance for your anticipated cooperation in this matter.<br/>
<br/>
Best regards
]]></field>
</record>
<record id="base.main_company" model="res.company">
<field name="credit_policy_id" ref="credit_control_3_time"/>
</record>
</odoo>

File diff suppressed because it is too large Load Diff

View File

@@ -1,230 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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/>.
#
##############################################################################
import logging
from openerp import models, fields, api, _
logger = logging.getLogger('credit.line.control')
class CreditControlLine(models.Model):
""" A credit control line describes an amount due by a customer for a due date.
A line is created once the due date of the payment is exceeded.
It is created in "draft" and some actions are available (send by email,
print, ...)
"""
_name = "credit.control.line"
_description = "A credit control line"
_rec_name = "id"
_order = "date DESC"
date = fields.Date(string='Controlling date',
required=True,
select=True)
# maturity date of related move line we do not use
# a related field in order to
# allow manual changes
date_due = fields.Date(string='Due date',
required=True,
readonly=True,
states={'draft': [('readonly', False)]})
date_entry = fields.Date(string='Entry date',
related='move_line_id.date',
store=True,
readonly=True)
date_sent = fields.Date(string='Sent date',
readonly=True,
states={'draft': [('readonly', False)]})
state = fields.Selection([('draft', 'Draft'),
('ignored', 'Ignored'),
('to_be_sent', 'Ready To Send'),
('sent', 'Done'),
('error', 'Error'),
('email_error', 'Emailing Error')],
'State',
required=True,
readonly=True,
default='draft',
help="Draft lines need to be triaged.\n"
"Ignored lines are lines for which we do "
"not want to send something.\n"
"Draft and ignored lines will be "
"generated again on the next run.")
channel = fields.Selection([('letter', 'Letter'),
('email', 'Email')],
string='Channel',
required=True,
readonly=True,
states={'draft': [('readonly', False)]})
invoice_id = fields.Many2one('account.invoice',
string='Invoice',
readonly=True)
partner_id = fields.Many2one('res.partner',
string='Partner',
required=True)
amount_due = fields.Float(string='Due Amount Tax incl.',
required=True, readonly=True)
balance_due = fields.Float(string='Due balance', required=True,
readonly=True)
mail_message_id = fields.Many2one('mail.mail', string='Sent Email',
readonly=True)
move_line_id = fields.Many2one('account.move.line',
string='Move line',
required=True,
readonly=True)
account_id = fields.Many2one('account.account',
related='move_line_id.account_id',
store=True,
readonly=True)
currency_id = fields.Many2one('res.currency',
related='move_line_id.currency_id',
store=True,
readonly=True)
company_id = fields.Many2one('res.company',
related='move_line_id.company_id',
store=True,
readonly=True)
# we can allow a manual change of policy in draft state
policy_level_id = fields.Many2one('credit.control.policy.level',
string='Overdue Level',
required=True,
readonly=True,
states={'draft': [('readonly', False)]})
policy_id = fields.Many2one('credit.control.policy',
related='policy_level_id.policy_id',
store=True,
readonly=True)
level = fields.Integer('credit.control.policy.level',
related='policy_level_id.level',
store=True,
readonly=True)
manually_overridden = fields.Boolean(string='Manually overridden')
run_id = fields.Many2one(comodel_name='credit.control.run',
string='Source')
@api.model
def _prepare_from_move_line(self, move_line, level, controlling_date,
open_amount):
""" Create credit control line """
data = {}
data['date'] = controlling_date
data['date_due'] = move_line.date_maturity
data['state'] = 'draft'
data['channel'] = level.channel
data['invoice_id'] = (move_line.invoice.id if
move_line.invoice else False)
data['partner_id'] = move_line.partner_id.id
data['amount_due'] = (move_line.amount_currency or move_line.debit or
move_line.credit)
data['balance_due'] = open_amount
data['policy_level_id'] = level.id
data['move_line_id'] = move_line.id
return data
@api.model
def create_or_update_from_mv_lines(self, lines, level, controlling_date,
check_tolerance=True):
""" Create or update line based on levels
if check_tolerance is true credit line will not be
created if open amount is too small.
eg. we do not want to send a letter for 10 cents
of open amount.
:param lines: move.line id recordset
:param level: credit.control.policy.level record
:param controlling_date: date string of the credit controlling date.
Generally it should be the same
as create date
:param check_tolerance: boolean if True credit line
will not be generated if open amount
is smaller than company defined
tolerance
:returns: recordset of created credit lines
"""
currency_obj = self.env['res.currency']
user = self.env.user
currencies = currency_obj.search([])
tolerance = {}
tolerance_base = user.company_id.credit_control_tolerance
user_currency = user.company_id.currency_id
for currency in currencies:
tolerance[currency.id] = currency.compute(tolerance_base,
user_currency)
new_lines = self.browse()
for move_line in lines:
open_amount = move_line.amount_residual_currency
cur_tolerance = tolerance.get(move_line.currency_id.id,
tolerance_base)
if check_tolerance and open_amount < cur_tolerance:
continue
vals = self._prepare_from_move_line(move_line,
level,
controlling_date,
open_amount)
line = self.create(vals)
new_lines += line
# when we have lines generated earlier in draft,
# on the same level, it means that we have left
# them, so they are to be considered as ignored
previous_drafts = self.search([('move_line_id', '=', move_line.id),
('policy_level_id', '=', level.id),
('state', '=', 'draft'),
('id', '!=', line.id)])
if previous_drafts:
previous_drafts.write({'state': 'ignored'})
return new_lines
@api.multi
def unlink(self):
for line in self:
if line.state != 'draft':
raise api.Warning(
_('You are not allowed to delete a credit control '
'line that is not in draft state.')
)
return super(CreditControlLine, self).unlink()

View File

@@ -1,171 +0,0 @@
<openerp>
<data>
<record id="credit_control_line_form" model="ir.ui.view">
<field name="name">credit.control.line.form</field>
<field name="model">credit.control.line</field>
<field name="arch" type="xml">
<form string="Control Credit Lines">
<header>
<field name="state" widget="statusbar"
statusbar_visible="draft,to_be_sent,sent"
statusbar_colors='{"error":"red","email_error":"red"}'/>
</header>
<sheet>
<group>
<group>
<field name="partner_id"/>
<field name="policy_level_id"/>
<field name="policy_id"/>
<field name="level"/>
<field name="manually_overridden"/>
</group>
<group>
<field name="date"/>
<field name="date_due"/>
<field name="channel"/>
<field name="date_sent"/>
<field name="mail_message_id"/>
</group>
</group>
<group>
<group>
<field name="invoice_id"/>
<field name="move_line_id"/>
<field name="account_id"/>
</group>
<group>
<field name="amount_due"/>
<field name="balance_due"/>
<field name="currency_id"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="credit_control_line_search" model="ir.ui.view">
<field name="name">Credit Control Lines</field>
<field name="model">credit.control.line</field>
<field name="arch" type="xml">
<search string="Control Credit Lines">
<group string="Filters">
<filter name="filter_draft" icon="terp-mail-message-new"
string="Draft" domain="[('state', '=', 'draft')]"
help="Draft lines have to be triaged."/>
<filter name="filter_to_be_sent" icon="terp-mail-forward"
string="Ready To Send" domain="[('state', '=', 'to_be_sent')]"
help="These lines are ready to send by email or by letter using the Actions."/>
<filter name="filter_ignored" icon="terp-mail_delete"
string="Ignored" domain="[('state', '=', 'ignored')]"
help="Lines which have been ignored from previous runs."/>
<filter name="filter_sent" icon="terp-mail-replied"
string="Sent" domain="[('state', '=', 'sent')]"
help="Lines already sent."/>
<filter name="filter_error" icon="terp-gtk-stop" string="Error"
domain="[('state', 'in', ('error', 'email_error'))]"
help="An error has occured during the sending of the email."/>
<filter name="filter_manual" icon="terp-gtk-stop" string="Manual change"
domain="[('manually_overridden', '=', True)]"
help="The line was deprecated by a manual change of policy on invoice."/>
<separator orientation="vertical"/>
<field name="date"/>
<field name="channel" />
<field name="policy_id"/>
</group>
<newline/>
<group expand="0" string="More...">
<field name="partner_id"/>
<field name="account_id"/>
<field name="invoice_id"/>
<field name="level"/>
<field name="policy_level_id"/>
</group>
<newline/>
<group expand="0" string="Group By...">
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'date'}"
icon="terp-go-month" string="Run date"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'level'}"
icon="terp-gtk-jump-to-rtl" string="Level"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'partner_id'}"
icon="terp-partner" string="Partner"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'account_id'}"
icon="terp-folder-green" string="Account"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'invoice_id'}"
icon="terp-document-new" string="Invoice"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'policy_id'}"
icon="terp-document-new" string="Credit policy"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'policy_level_id'}"
icon="terp-document-new" string="Credit policy level"/>
<separator orientation="vertical"/>
<filter domain='[]' context="{'group_by': 'channel'}"
icon="terp-document-new" string="Channel"/>
<filter domain='[]' context="{'group_by': 'manually_overridden'}"
icon="terp-document-new" string="Manual change"/>
</group>
</search>
</field>
</record>
<record id="credit_control_line_tree" model="ir.ui.view">
<field name="name">credit.control.line.tree</field>
<field name="model">credit.control.line</field>
<field name="arch" type="xml">
<tree editable="bottom" string="Control Credit Lines" colors="green:state == 'sent';red:state in ('error', 'email_error');">
<field name="date"/>
<field name="date_due"/>
<field name="level"/>
<field name="manually_overridden"/>
<field name="state"/>
<field name="channel"/>
<field name="invoice_id"/>
<field name="partner_id"/>
<field name="amount_due"/>
<field name="balance_due"/>
<field name="currency_id"/>
<field name="move_line_id"/>
<field name="account_id"/>
<field name="policy_level_id"/>
<field name="policy_id"/>
<field name="mail_message_id"/>
</tree>
</field>
</record>
<menuitem
name="Credit Control"
parent="account.menu_finance_periodical_processing"
id="base_credit_control_menu"/>
<record model="ir.actions.act_window" id="credit_control_line_action">
<field name="name">Credit Control Lines</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">credit.control.line</field>
<field name="domain"></field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="credit_control_line_tree"/>
<field name="context">{'search_default_filter_draft': 1, 'search_default_filter_to_be_sent': 1}</field>
<field name="search_view_id" ref="credit_control_line_search"/>
</record>
<menuitem
name="Credit Control Lines"
parent="base_credit_control_menu"
action="credit_control_line_action"
sequence="20"
id="credit_control_line_action_menu"/>
</data>
</openerp>

View File

@@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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 Mail(models.Model):
_inherit = 'mail.mail'
# use HTML fields instead of text
body_html = fields.Html('Rich-text Contents',
help="Rich-text/HTML message")

View File

@@ -1,26 +0,0 @@
# -*- encoding: utf-8 -*-
import logging
from openerp import SUPERUSER_ID
from openerp.modules.registry import RegistryManager
uid = SUPERUSER_ID
__name__ = 'Change custom_mail_text text field to hmtl field'
_logger = logging.getLogger(__name__)
def migrate_replace_text_with_html(cr, registry):
cr.execute("""update credit_control_policy_level set
custom_mail_text=regexp_replace(custom_mail_text, E'[\\n]',
'<br/>','g')""")
cr.execute("""update ir_translation set
value=regexp_replace(value, E'[\\n]','<br/>','g')
where name='credit.control.policy.level,custom_mail_text'""")
def migrate(cr, version):
if not version:
# it is the installation of the module
return
registry = RegistryManager.get(cr.dbname)
migrate_replace_text_with_html(cr, registry)

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import account_account
from . import account_invoice
from . import credit_control_line
from . import credit_control_policy
from . import credit_control_run
from . import mail_mail
from . import res_company
from . import res_partner

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import fields, models
class AccountAccount(models.Model):
""" Add a link to a credit control policy on account.account """
_inherit = "account.account"
credit_control_line_ids = fields.One2many(
comodel_name='credit.control.line',
inverse_name='account_id',
string='Credit Lines',
readonly=True,
)

View File

@@ -1,24 +1,11 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Vincent Renaville
# Copyright 2013 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, api, _
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import _, api, fields, models
from openerp.exceptions import UserError
class AccountInvoice(models.Model):
@@ -26,7 +13,7 @@ class AccountInvoice(models.Model):
_inherit = 'account.invoice'
credit_policy_id = fields.Many2one(
'credit.control.policy',
comodel_name='credit.control.policy',
string='Credit Control Policy',
help="The Credit Control Policy used for this "
"invoice. If nothing is defined, it will "
@@ -40,7 +27,8 @@ class AccountInvoice(models.Model):
)
credit_control_line_ids = fields.One2many(
'credit.control.line', 'invoice_id',
comodel_name='credit.control.line',
inverse_name='invoice_id',
string='Credit Lines',
readonly=True,
copy=False,
@@ -56,7 +44,7 @@ class AccountInvoice(models.Model):
('state', '!=', 'draft')]
cc_nondraft_lines = cc_line_obj.search(nondraft_domain)
if cc_nondraft_lines:
raise api.Warning(
raise UserError(
_('You cannot cancel this invoice.\n'
'A payment reminder has already been '
'sent to the customer.\n'

View File

@@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openerp import _, api, fields, models
from openerp.exceptions import UserError
logger = logging.getLogger(__name__)
class CreditControlLine(models.Model):
""" A credit control line describes an amount due by a customer for a due date.
A line is created once the due date of the payment is exceeded.
It is created in "draft" and some actions are available (send by email,
print, ...)
"""
_name = "credit.control.line"
_description = "A credit control line"
_rec_name = "id"
_order = "date DESC"
date = fields.Date(
string='Controlling date',
required=True,
index=True,
)
# maturity date of related move line we do not use
# a related field in order to
# allow manual changes
date_due = fields.Date(
string='Due date',
required=True,
readonly=True,
states={'draft': [('readonly', False)]},
)
date_entry = fields.Date(
string='Entry date',
related='move_line_id.date',
store=True,
readonly=True,
)
date_sent = fields.Date(
string='Sent date',
readonly=True,
states={'draft': [('readonly', False)]},
)
state = fields.Selection(
selection=[
('draft', 'Draft'),
('ignored', 'Ignored'),
('to_be_sent', 'Ready To Send'),
('sent', 'Done'),
('error', 'Error'),
('email_error', 'Emailing Error'),
],
string='State',
required=True,
readonly=True,
default='draft',
help="Draft lines need to be triaged.\n"
"Ignored lines are lines for which we do "
"not want to send something.\n"
"Draft and ignored lines will be "
"generated again on the next run.",
)
channel = fields.Selection(
selection=[
('letter', 'Letter'),
('email', 'Email'),
],
string='Channel',
required=True,
readonly=True,
states={'draft': [('readonly', False)]},
)
invoice_id = fields.Many2one(
comodel_name='account.invoice',
string='Invoice',
readonly=True,
)
partner_id = fields.Many2one(
comodel_name='res.partner',
string='Partner',
required=True,
)
amount_due = fields.Float(
string='Due Amount Tax incl.',
required=True,
readonly=True,
)
balance_due = fields.Float(
string='Due balance',
required=True,
readonly=True,
)
mail_message_id = fields.Many2one(
comodel_name='mail.mail',
string='Sent Email',
readonly=True,
)
move_line_id = fields.Many2one(
comodel_name='account.move.line',
string='Move line',
required=True,
readonly=True,
)
account_id = fields.Many2one(
comodel_name='account.account',
related='move_line_id.account_id',
store=True,
readonly=True,
)
currency_id = fields.Many2one(
comodel_name='res.currency',
related='move_line_id.currency_id',
store=True,
readonly=True,
)
company_id = fields.Many2one(
comodel_name='res.company',
related='move_line_id.company_id',
store=True,
readonly=True,
)
# we can allow a manual change of policy in draft state
policy_level_id = fields.Many2one(
comodel_name='credit.control.policy.level',
string='Overdue Level',
required=True,
readonly=True,
states={'draft': [('readonly', False)]},
)
policy_id = fields.Many2one(
comodel_name='credit.control.policy',
related='policy_level_id.policy_id',
store=True,
readonly=True,
)
level = fields.Integer(
string='Level',
related='policy_level_id.level',
store=True,
readonly=True,
)
manually_overridden = fields.Boolean(
string='Manually overridden',
)
run_id = fields.Many2one(
comodel_name='credit.control.run',
string='Source',
)
@api.model
def _prepare_from_move_line(self, move_line, level, controlling_date,
open_amount):
""" Create credit control line """
data = {}
data['date'] = controlling_date
data['date_due'] = move_line.date_maturity
data['state'] = 'draft'
data['channel'] = level.channel
data['invoice_id'] = (move_line.invoice_id.id if
move_line.invoice_id else False)
data['partner_id'] = move_line.partner_id.id
data['amount_due'] = (move_line.amount_currency or move_line.debit or
move_line.credit)
data['balance_due'] = open_amount
data['policy_level_id'] = level.id
data['move_line_id'] = move_line.id
return data
@api.model
def create_or_update_from_mv_lines(self, lines, level, controlling_date,
check_tolerance=True):
""" Create or update line based on levels
if check_tolerance is true credit line will not be
created if open amount is too small.
eg. we do not want to send a letter for 10 cents
of open amount.
:param lines: move.line id recordset
:param level: credit.control.policy.level record
:param controlling_date: date string of the credit controlling date.
Generally it should be the same
as create date
:param check_tolerance: boolean if True credit line
will not be generated if open amount
is smaller than company defined
tolerance
:returns: recordset of created credit lines
"""
currency_obj = self.env['res.currency']
user = self.env.user
currencies = currency_obj.search([])
tolerance = {}
tolerance_base = user.company_id.credit_control_tolerance
user_currency = user.company_id.currency_id
for currency in currencies:
tolerance[currency.id] = currency.compute(tolerance_base,
user_currency)
new_lines = self.browse()
for move_line in lines:
if move_line.currency_id:
open_amount = move_line.amount_residual_currency
else:
open_amount = move_line.amount_residual
cur_tolerance = tolerance.get(move_line.currency_id.id,
tolerance_base)
if check_tolerance and open_amount < cur_tolerance:
continue
vals = self._prepare_from_move_line(move_line,
level,
controlling_date,
open_amount)
line = self.create(vals)
new_lines |= line
# when we have lines generated earlier in draft,
# on the same level, it means that we have left
# them, so they are to be considered as ignored
previous_drafts = self.search([('move_line_id', '=', move_line.id),
('policy_level_id', '=', level.id),
('state', '=', 'draft'),
('id', '!=', line.id)])
if previous_drafts:
previous_drafts.write({'state': 'ignored'})
return new_lines
@api.multi
def unlink(self):
for line in self:
if line.state != 'draft':
raise UserError(
_('You are not allowed to delete a credit control '
'line that is not in draft state.')
)
return super(CreditControlLine, self).unlink()

View File

@@ -1,24 +1,11 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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, api, _
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import _, api, fields, models
from openerp.exceptions import UserError, ValidationError
class CreditControlPolicy(models.Model):
@@ -27,23 +14,32 @@ class CreditControlPolicy(models.Model):
_name = "credit.control.policy"
_description = """Define a reminder policy"""
name = fields.Char('Name', required=True)
level_ids = fields.One2many('credit.control.policy.level',
'policy_id',
string='Policy Levels')
do_nothing = fields.Boolean('Do nothing',
help='For policies which should not '
'generate lines or are obsolete')
company_id = fields.Many2one('res.company', string='Company')
name = fields.Char(
required=True,
)
level_ids = fields.One2many(
comodel_name='credit.control.policy.level',
inverse_name='policy_id',
string='Policy Levels',
)
do_nothing = fields.Boolean(
help='For policies which should not generate lines or are obsolete',
)
company_id = fields.Many2one(
comodel_name='res.company',
string='Company',
)
account_ids = fields.Many2many(
'account.account',
comodel_name='account.account',
string='Accounts',
required=True,
domain="[('type', '=', 'receivable')]",
domain="[('internal_type', '=', 'receivable')]",
help="This policy will be active only"
" for the selected accounts",
)
active = fields.Boolean('Active', default=True)
active = fields.Boolean(
default=True,
)
@api.multi
def _move_lines_domain(self, controlling_date):
@@ -51,7 +47,7 @@ class CreditControlPolicy(models.Model):
self.ensure_one()
return [('account_id', 'in', self.account_ids.ids),
('date_maturity', '<=', controlling_date),
('reconcile_id', '=', False),
('reconciled', '=', False),
('partner_id', '!=', False)]
@api.multi
@@ -71,7 +67,7 @@ class CreditControlPolicy(models.Model):
move_l_obj = self.env['account.move.line']
user = self.env.user
if user.company_id.credit_policy_id.id != self.id:
return move_l_obj.browse()
return move_l_obj
domain_line = self._move_lines_domain(controlling_date)
return move_l_obj.search(domain_line)
@@ -97,11 +93,10 @@ class CreditControlPolicy(models.Model):
self.ensure_one()
# MARK possible place for a good optimisation
my_obj = self.env[model]
move_l_obj = self.env['account.move.line']
default_domain = self._move_lines_domain(controlling_date)
to_add = move_l_obj.browse()
to_remove = move_l_obj.browse()
to_add = self.env['account.move.line']
to_remove = self.env['account.move.line']
# The lines which are linked to this policy have to be included in the
# run for this policy.
@@ -110,7 +105,7 @@ class CreditControlPolicy(models.Model):
if add_objs:
domain = list(default_domain)
domain.append((move_relation_field, 'in', add_objs.ids))
to_add = move_l_obj.search(domain)
to_add = to_add.search(domain)
# The lines which are linked to another policy do not have to be
# included in the run for this policy.
@@ -119,7 +114,7 @@ class CreditControlPolicy(models.Model):
if neg_objs:
domain = list(default_domain)
domain.append((move_relation_field, 'in', neg_objs.ids))
to_remove = move_l_obj.search(domain)
to_remove = to_remove.search(domain)
return to_add, to_remove
@api.multi
@@ -150,7 +145,7 @@ class CreditControlPolicy(models.Model):
the process
"""
return self._move_lines_subset(controlling_date, 'account.invoice',
'invoice')
'invoice_id')
@api.multi
@api.returns('account.move.line')
@@ -177,8 +172,7 @@ class CreditControlPolicy(models.Model):
existing credit line but with a different policy.
"""
self.ensure_one()
move_line_obj = self.env['account.move.line']
different_lines = move_line_obj.browse()
different_lines = self.env['account.move.line']
if not lines:
return different_lines
cr = self.env.cr
@@ -188,7 +182,7 @@ class CreditControlPolicy(models.Model):
(self.id, tuple(lines.ids)))
res = cr.fetchall()
if res:
return move_line_obj.browse([row[0] for row in res])
return different_lines.browse([row[0] for row in res])
return different_lines
@api.multi
@@ -199,7 +193,7 @@ class CreditControlPolicy(models.Model):
if account in x.account_ids or x.do_nothing]
if self not in allowed:
allowed_names = u"\n".join(x.name for x in allowed)
raise api.Warning(
raise UserError(
_('You can only use a policy set on '
'account %s.\n'
'Please choose one of the following '
@@ -216,47 +210,73 @@ class CreditControlPolicyLevel(models.Model):
_order = 'level'
_description = """A credit control policy level"""
name = fields.Char(string='Name', required=True, translate=True)
policy_id = fields.Many2one('credit.control.policy',
string='Related Policy',
required=True)
level = fields.Integer(string='Level', required=True)
computation_mode = fields.Selection(
[('net_days', 'Due Date'),
('end_of_month', 'Due Date, End Of Month'),
('previous_date', 'Previous Reminder')],
string='Compute Mode',
required=True
name = fields.Char(
required=True,
translate=True,
)
policy_id = fields.Many2one(
comodel_name='credit.control.policy',
string='Related Policy',
required=True,
)
level = fields.Integer(
required=True,
)
computation_mode = fields.Selection(
selection=[
('net_days', 'Due Date'),
('end_of_month', 'Due Date, End Of Month'),
('previous_date', 'Previous Reminder'),
],
string='Compute Mode',
required=True,
)
delay_days = fields.Integer(
string='Delay (in days)',
required=True,
)
email_template_id = fields.Many2one(
comodel_name='mail.template',
string='Email Template',
required=True,
)
channel = fields.Selection(
selection=[
('letter', 'Letter'),
('email', 'Email'),
],
string='Channel',
required=True,
)
custom_text = fields.Text(
string='Custom Message',
required=True,
translate=True,
)
custom_mail_text = fields.Html(
string='Custom Mail Message',
required=True,
translate=True,
)
delay_days = fields.Integer(string='Delay (in days)', required=True)
email_template_id = fields.Many2one('email.template',
string='Email Template',
required=True)
channel = fields.Selection([('letter', 'Letter'),
('email', 'Email')],
string='Channel',
required=True)
custom_text = fields.Text(string='Custom Message',
required=True,
translate=True)
custom_mail_text = fields.Html(string='Custom Mail Message',
required=True, translate=True)
_sql_constraint = [('unique level',
'UNIQUE (policy_id, level)',
'Level must be unique per policy')]
@api.one
@api.multi
@api.constrains('level', 'computation_mode')
def _check_level_mode(self):
""" The smallest level of a policy cannot be computed on the
"previous_date".
"""
smallest_level = self.search([('policy_id', '=', self.policy_id.id)],
order='level asc', limit=1)
if smallest_level.computation_mode == 'previous_date':
return api.ValidationError(_('The smallest level can not be of '
'type Previous Reminder'))
for policy_level in self:
smallest_level = \
self.search([('policy_id', '=', policy_level.policy_id.id)],
order='level asc', limit=1)
if smallest_level.computation_mode == 'previous_date':
raise ValidationError(_('The smallest level can not be '
'of type Previous Reminder'))
@api.multi
def _previous_level(self):
@@ -294,7 +314,7 @@ class CreditControlPolicyLevel(models.Model):
return "(cr_line.date + %(delay)s)::date <= date(%(controlling_date)s)"
@api.multi
def _get_sql_date_boundary_for_computation_mode(self, controlling_date):
def _get_sql_date_boundary_for_computation_mode(self):
""" Return a where clauses statement for the given controlling
date and computation mode of the level
"""
@@ -321,7 +341,7 @@ class CreditControlPolicyLevel(models.Model):
self.ensure_one()
move_line_obj = self.env['account.move.line']
if not lines:
return move_line_obj.browse()
return move_line_obj
cr = self.env.cr
sql = ("SELECT DISTINCT mv_line.id\n"
" FROM account_move_line mv_line\n"
@@ -337,7 +357,7 @@ class CreditControlPolicyLevel(models.Model):
" AND (mv_line.debit IS NOT NULL AND mv_line.debit != 0.0)\n")
sql += " AND"
_get_sql_date_part = self._get_sql_date_boundary_for_computation_mode
sql += _get_sql_date_part(controlling_date)
sql += _get_sql_date_part()
data_dict = {'controlling_date': controlling_date,
'line_ids': tuple(lines.ids),
'delay': self.delay_days}
@@ -345,7 +365,7 @@ class CreditControlPolicyLevel(models.Model):
res = cr.fetchall()
if res:
return move_line_obj.browse([row[0] for row in res])
return move_line_obj.browse()
return move_line_obj
@api.multi
@api.returns('account.move.line')
@@ -355,7 +375,7 @@ class CreditControlPolicyLevel(models.Model):
self.ensure_one()
move_line_obj = self.env['account.move.line']
if not lines:
return move_line_obj.browse()
return move_line_obj
cr = self.env.cr
sql = ("SELECT mv_line.id\n"
" FROM account_move_line mv_line\n"
@@ -377,7 +397,7 @@ class CreditControlPolicyLevel(models.Model):
" AND mv_line.id in %(line_ids)s\n")
sql += " AND "
_get_sql_date_part = self._get_sql_date_boundary_for_computation_mode
sql += _get_sql_date_part(controlling_date)
sql += _get_sql_date_part()
previous_level = self._previous_level()
data_dict = {'controlling_date': controlling_date,
'line_ids': tuple(lines.ids),
@@ -389,15 +409,14 @@ class CreditControlPolicyLevel(models.Model):
res = cr.fetchall()
if res:
return move_line_obj.browse([row[0] for row in res])
return move_line_obj.browse()
return move_line_obj
@api.multi
@api.returns('account.move.line')
def get_level_lines(self, controlling_date, lines):
""" get all move lines in entry lines that match the current level """
self.ensure_one()
move_line_obj = self.env['account.move.line']
matching_lines = move_line_obj.browse()
matching_lines = self.env['account.move.line']
if self._previous_level() is None:
method = self._get_first_level_move_lines
else:

View File

@@ -1,28 +1,15 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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/>.
#
##############################################################################
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openerp import models, fields, api, _
from openerp import _, api, fields, models
from openerp.exceptions import UserError
logger = logging.getLogger('credit.control.run')
logger = logging.getLogger(__name__)
class CreditControlRun(models.Model):
@@ -32,16 +19,18 @@ class CreditControlRun(models.Model):
_rec_name = 'date'
_description = "Credit control line generator"
date = fields.Date(string='Controlling Date', required=True,
readonly=True,
states={'draft': [('readonly', False)]})
@api.model
def _get_policies(self):
return self.env['credit.control.policy'].search([])
date = fields.Date(
string='Controlling Date',
required=True,
readonly=True,
states={'draft': [('readonly', False)]},
)
policy_ids = fields.Many2many(
'credit.control.policy',
comodel_name='credit.control.policy',
rel="credit_run_policy_rel",
id1='run_id', id2='policy_id',
string='Policies',
@@ -49,21 +38,29 @@ class CreditControlRun(models.Model):
states={'draft': [('readonly', False)]},
default=_get_policies,
)
report = fields.Html(string='Report', readonly=True, copy=False)
state = fields.Selection([('draft', 'Draft'),
('done', 'Done')],
string='State',
required=True,
readonly=True,
default='draft')
report = fields.Html(
string='Report',
readonly=True,
copy=False,
)
state = fields.Selection(
selection=[
('draft', 'Draft'),
('done', 'Done'),
],
string='State',
required=True,
readonly=True,
default='draft',
)
line_ids = fields.One2many(
comodel_name='credit.control.line',
inverse_name='run_id',
string='Generated lines')
string='Generated lines',
)
manual_ids = fields.Many2many(
'account.move.line',
comodel_name='account.move.line',
rel="credit_runreject_rel",
string='Lines to handle manually',
help='If a credit control line has been generated'
@@ -74,7 +71,7 @@ class CreditControlRun(models.Model):
copy=False,
)
@api.multi
@api.model
def _check_run_date(self, controlling_date):
""" Ensure that there is no credit line in the future
using controlling_date
@@ -83,33 +80,31 @@ class CreditControlRun(models.Model):
runs = self.search([('date', '>', controlling_date)],
order='date DESC', limit=1)
if runs:
raise api.Warning(_('A run has already been executed more '
'recently than %s') % (runs.date))
raise UserError(_('A run has already been executed more '
'recently than %s') % (runs.date))
line_obj = self.env['credit.control.line']
lines = line_obj.search([('date', '>', controlling_date)],
order='date DESC', limit=1)
if lines:
raise api.Warning(_('A credit control line more '
'recent than %s exists at %s') %
(controlling_date, lines.date))
raise UserError(_('A credit control line more '
'recent than %s exists at %s') %
(controlling_date, lines.date))
@api.multi
@api.returns('credit.control.line')
def _generate_credit_lines(self):
""" Generate credit control lines. """
self.ensure_one()
cr_line_obj = self.env['credit.control.line']
move_line_obj = self.env['account.move.line']
manually_managed_lines = move_line_obj.browse()
manually_managed_lines = self.env['account.move.line']
self._check_run_date(self.date)
policies = self.policy_ids
if not policies:
raise api.Warning(_('Please select a policy'))
raise UserError(_('Please select a policy'))
report = ''
generated = cr_line_obj.browse()
generated = self.env['credit.control.line']
for policy in policies:
if policy.do_nothing:
continue
@@ -117,11 +112,11 @@ class CreditControlRun(models.Model):
manual_lines = policy._lines_different_policy(lines)
lines -= manual_lines
manually_managed_lines |= manual_lines
policy_lines_generated = cr_line_obj.browse()
policy_lines_generated = self.env['credit.control.line']
if lines:
# policy levels are sorted by level
# so iteration is in the correct order
create = cr_line_obj.create_or_update_from_mv_lines
create = policy_lines_generated.create_or_update_from_mv_lines
for level in reversed(policy.level_ids):
level_lines = level.get_level_lines(self.date, lines)
policy_lines_generated += create(level_lines,
@@ -158,8 +153,8 @@ class CreditControlRun(models.Model):
except Exception:
# In case of exception openerp will do a rollback
# for us and free the lock
raise api.Warning(_('A credit control run is already running'
' in background, please try later.'))
raise UserError(_('A credit control run is already running '
'in background, please try later.'))
self._generate_credit_lines()
return True

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import fields, models
class Mail(models.Model):
_inherit = 'mail.mail'
# use HTML fields instead of text
body_html = fields.Html(
string='Rich-text Contents',
help="Rich-text/HTML message",
)

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import fields, models
class ResCompany(models.Model):
""" Add credit control parameters """
_inherit = 'res.company'
credit_control_tolerance = fields.Float(
string='Credit Control Tolerance',
default=0.1,
)
# This is not a property on the partner because we cannot search
# on fields.property (subclass fields.function).
credit_policy_id = fields.Many2one(
comodel_name='credit.control.policy',
string='Credit Control Policy',
help="The Credit Control Policy used on partners by default. "
"This setting can be overridden on partners or invoices.",
)

View File

@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# Copyright 2017 Tecnativa - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models
from openerp.exceptions import UserError, ValidationError
class ResPartner(models.Model):
""" Add a settings on the credit control policy to use on the partners,
and links to the credit control lines.
"""
_inherit = "res.partner"
credit_policy_id = fields.Many2one(
comodel_name='credit.control.policy',
string='Credit Control Policy',
domain="[('account_ids', 'in', property_account_receivable_id)]",
help="The Credit Control Policy used for this "
"partner. This setting can be forced on the "
"invoice. If nothing is defined, it will use "
"the company setting.",
)
credit_control_line_ids = fields.One2many(
comodel_name='credit.control.line',
inverse_name='invoice_id',
string='Credit Control Lines',
readonly=True,
)
@api.constrains('credit_policy_id', 'property_account_receivable_id')
def _check_credit_policy(self):
""" Ensure that policy on partner are limited to the account policy """
for partner in self:
if (not partner.property_account_receivable_id or
not partner.credit_policy_id):
continue
account = partner.property_account_receivable_id
policy = partner.credit_policy_id
try:
policy.check_policy_against_account(account)
except UserError as err:
# constrains should raise ValidationError exceptions
raise ValidationError(err)

View File

@@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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, api
from openerp.exceptions import Warning, ValidationError
class ResPartner(models.Model):
""" Add a settings on the credit control policy to use on the partners,
and links to the credit control lines.
"""
_inherit = "res.partner"
credit_policy_id = fields.Many2one(
'credit.control.policy',
string='Credit Control Policy',
domain="[('account_ids', 'in', property_account_receivable)]",
help="The Credit Control Policy used for this "
"partner. This setting can be forced on the "
"invoice. If nothing is defined, it will use "
"the company setting.",
)
credit_control_line_ids = fields.One2many('credit.control.line',
'invoice_id',
string='Credit Control Lines',
readonly=True)
@api.constrains('credit_policy_id', 'property_account_receivable')
def _check_credit_policy(self):
""" Ensure that policy on partner are limited to the account policy """
for partner in self:
if (not partner.property_account_receivable or
not partner.credit_policy_id):
continue
account = partner.property_account_receivable
policy = partner.credit_policy_id
try:
policy.check_policy_against_account(account)
except Warning as err:
# constrains should raise ValidationError exceptions
raise ValidationError(err)

View File

@@ -1,24 +0,0 @@
<openerp>
<data>
<record id="partner_followup_form_view" model="ir.ui.view">
<field name="name">partner.credit_control.form.view</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form" />
<field name="arch" type="xml">
<field name="credit_limit" position="after">
<field name="credit_policy_id" widget="selection"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_use"/>
</field>
</field>
</record>
<act_window
id="act_partner_credit_relation_relation"
name="Credit Lines"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"
domain="[('partner_id', '=', active_id)]"
res_model="credit.control.line"
src_model="res.partner"/>
</data>
</openerp>

View File

@@ -1,131 +0,0 @@
<openerp>
<data>
<record id="credit_control_policy_form" model="ir.ui.view">
<field name="name">credit.control.policy.form</field>
<field name="model">credit.control.policy</field>
<field name="arch" type="xml">
<form string="Credit control policy">
<group>
<field name="name"/>
<field name="do_nothing"/>
<field name="company_id"/>
<field name="active"/>
</group>
<notebook colspan="4">
<page string="Policy levels">
<field name="level_ids" nolabel="1" colspan="4" >
<tree string="Credit control policy Level">
<field name="name"/>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
<field name="email_template_id"/>
</tree>
<form string="Policy level">
<field name="name"/>
<notebook colspan="4">
<page string="Delay Setting">
<group>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
</group>
</page>
<page string="Mail and reporting">
<group>
<field name="email_template_id"/>
<newline/>
<field name="custom_text" colspan="4"/>
<newline/>
<field name="custom_mail_text" colspan="4"/>
</group>
</page>
</notebook>
</form>
</field>
</page>
<page string="Accounts">
<field name="account_ids" nolabel="1"/>
</page>
</notebook>
</form>
</field>
</record>
<record id="credit_control_policy_tree" model="ir.ui.view">
<field name="name">credit.control.policy.tree</field>
<field name="model">credit.control.policy</field>
<field name="arch" type="xml">
<tree string="Credit control policy">
<field name="name"/>
<field name="do_nothing"/>
</tree>
</field>
</record>
<menuitem
name="Credit Control"
parent="account.menu_finance_configuration"
id="base_credit_control_configuration_menu"/>
<record model="ir.actions.act_window" id="credit_policy_configuration_action">
<field name="name">Credit Control Policies</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">credit.control.policy</field>
<field name="domain"></field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="credit_control_policy_tree"/>
</record>
<menuitem
name="Credit Control Policies"
parent="base_credit_control_configuration_menu"
action="credit_policy_configuration_action"
id="credit_policy_configuration_action_menu"/>
<record id="credit_mangement_policy_level_form" model="ir.ui.view">
<field name="name">credit.mangement.policy.level.form</field>
<field name="model">credit.control.policy.level</field>
<field name="arch" type="xml">
<form string="Policy level">
<field name="name"/>
<notebook colspan="4">
<page string="Delay Setting">
<group>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
</group>
</page>
<page string="Mail and reporting">
<group>
<field name="email_template_id"/>
<field name="custom_text"/>
</group>
</page>
</notebook>
</form>
</field>
</record>
<record id="credit_control_policy_level_tree" model="ir.ui.view">
<field name="name">credit.control.policy.level.tree</field>
<field name="model">credit.control.policy.level</field>
<field name="arch" type="xml">
<tree string="Credit control policy level">
<field name="name"/>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
<field name="email_template_id"/>
</tree>
</field>
</record>
</data>
</openerp>

View File

@@ -1,15 +1,12 @@
<openerp>
<data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<report
id="credit_control_summary"
model="credit.control.communication"
string="Credit Control Summary"
report_type="qweb-pdf"
name="account_credit_control.report_credit_control_summary"
file="account_credit_control.report_credit_control_summary"
auto="False"
/>
</data>
</openerp>
id="credit_control_summary"
model="credit.control.communication"
string="Credit Control Summary"
report_type="qweb-pdf"
name="account_credit_control.report_credit_control_summary"
file="account_credit_control.report_credit_control_summary"
auto="False"
/>
</odoo>

View File

@@ -1,99 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<odoo>
<template id="report_credit_control_summary_document">
<t t-call="report.external_layout">
<div class="page">
<div class="row" id="address">
<div class="col-xs-5 col-xs-offset-7">
<address t-field="o.contact_address"
t-field-options='{"widget": "contact",
<t t-call="report.external_layout">
<div class="page">
<div class="row" id="address">
<div class="col-xs-5 col-xs-offset-7">
<address t-field="doc.contact_address"
t-field-options='{"widget": "contact",
"fields": ["address", "name"],
"no_marker": true}' />
"no_marker": true}'/>
</div>
<div class="col-xs-5 col-xs-offset-7">
<span t-field="doc.report_date"/>
</div>
</div>
<h2 id="policy_level">
<span t-field="doc.current_policy_level.name"/>
</h2>
<div class="col-xs-12">
<span t-field="doc.current_policy_level.custom_text" />
</div>
<h3>Summary</h3>
<table class="table table-condensed" id="summary_table">
<thead>
<tr>
<th>Invoice number</th>
<th>Invoice date</th>
<th>Date due</th>
<th class="text-right">Invoiced amount</th>
<th class="text-right">Open amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="doc.credit_control_line_ids" t-as="l">
<t t-if="l.invoice_id">
<td>
<span t-field="l.invoice_id.number"/>
<t t-if="l.invoice_id.name">
<span t-field="l.invoice_id.name"/>
</t>
</td>
</t>
<t t-if="not l.invoice_id">
<td>
<span t-field="l.move_line_id.name"/>
</td>
</t>
<td>
<span t-field="l.date_entry"/>
</td>
<td>
<span t-field="l.date_due"/>
</td>
<td class="text-right">
<span t-field="l.amount_due"/>
</td>
<td class="text-right">
<span t-field="l.balance_due"/>
</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-xs-4 pull-right">
<table class="table table-condensed">
<tr>
<td>
<strong>Total Invoiced</strong>
</td>
<td class="text-right">
<span t-field="doc.total_invoiced" />
</td>
</tr>
<tr>
<td>
<strong>Total Due</strong>
</td>
<td class="text-right">
<span t-field="doc.total_due"/>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="col-xs-5 col-xs-offset-7">
<span t-field="o.report_date"/>
</div>
</div>
<h2 id="policy_level">
<span t-field="o.current_policy_level.name"/>
</h2>
<p class="mt32 mb32" t-field="o.current_policy_level.custom_text"/>
<h3>Summary</h3>
<table class="table table-condensed" id="summary_table">
<thead>
<tr>
<th>Invoice number</th>
<th>Invoice date</th>
<th>Date due</th>
<th class="text-right">Invoiced amount</th>
<th class="text-right">Open amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.credit_control_line_ids" t-as="l">
<t t-if="l.invoice_id">
<td><span t-field="l.invoice_id.number"/>
<t t-if="l.invoice_id.name">
<span t-field="l.invoice_id.name"/>
</t>
</td>
</t>
<t t-if="not l.invoice_id">
<td><span t-field="l.move_line_id.name"/></td>
</t>
<td>
<span t-field="l.date_entry"/>
</td>
<td>
<span t-field="l.date_due"/>
</td>
<td class="text-right">
<span t-field="l.amount_due"/>
</td>
<td class="text-right">
<span t-field="l.balance_due"
t-field-options='{"widget": "monetary",
"display_currency": "l.currency_id or l.company_id.currency_id"}'/>
</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-xs-4 pull-right">
<table class="table table-condensed">
<tr>
<td><strong>Total Invoiced</strong></td>
<td class="text-right">
<span t-field="o.total_invoiced" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/>
</td>
</tr>
<tr>
<td><strong>Total Due</strong></td>
<td class="text-right">
<span t-field="o.total_due" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/>
</td>
</tr>
</table>
</div>
</div>
</div>
</t>
</t>
</template>
<template id="report_credit_control_summary">
<t t-call="report.html_container">
<t t-foreach="doc_ids" t-as="doc_id">
<t t-raw="translate_doc(doc_id, doc_model, 'partner_id.lang', 'account_credit_control.report_credit_control_summary_document')"/>
<t t-call="report.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="account_credit_control.report_credit_control_summary_document" t-lang="doc.partner_id.lang" />
</t>
</t>
</t>
</template>
</data>
</openerp>
</odoo>

View File

@@ -1,75 +0,0 @@
<openerp>
<data>
<record id="credit_control_run_tree" model="ir.ui.view">
<field name="name">credit.control.run.tree</field>
<field name="model">credit.control.run</field>
<field name="arch" type="xml">
<tree string="Credit control run">
<field name="date"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="credit_control_run_form" model="ir.ui.view">
<field name="name">credit.control.run.form</field>
<field name="model">credit.control.run</field>
<field name="arch" type="xml">
<form string="Credit control run">
<header>
<button name="generate_credit_lines"
string="Compute Credit Control Lines"
class="oe_highlight"
type="object" icon="gtk-execute"
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
<button name="open_credit_lines"
string="Open Credit Control Lines"
type="object"
attrs="{'invisible': [('state', '=', 'draft')]}"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,done"
statusbar_colors='{}'/>
</header>
<sheet>
<group>
<field name="date"/>
</group>
<notebook>
<page string="Policies">
<field name="policy_ids" colspan="4" nolabel="1"/>
<separator string="Report"
attrs="{'invisible': [('report', '=', False)]}"/>
<field name="report" colspan="4" nolabel="1"
attrs="{'invisible': [('report', '=', False)]}"/>
</page>
<page string="Manual Lines" groups="base.group_no_one">
<field name="manual_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="credit_control_run">
<field name="name">Credit Control Run</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">credit.control.run</field>
<field name="domain"></field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="credit_control_run_tree"/>
</record>
<menuitem
name="Credit Control Run"
parent="base_credit_control_menu"
action="credit_control_run"
sequence="10"
id="credit_control_run_menu"/>
</data>
</openerp>

View File

@@ -1,61 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2009 Camptocamp SA
#
#
# The base scenario for the finance data must be executed before this
# one. The finance scenario is included in the oerpscenario base and
# the tag to run it is: @base_finance
#
#
##############################################################################
##############################################################################
# Branch # Module # Processes # System
@account_credit_control @account_credit_control_setup
Feature: General parameters in order to test the credit control module
@account_credit_control_setup_install_modules
Scenario: MODULES INSTALLATION
Given I do not want all demo data to be loaded on install
Given I install the required modules with dependencies:
| name |
| account_credit_control |
Then my modules should have been installed and models reloaded
@deactivate_journal_control
Scenario: Journal setup to avoid unfixed voucher bug
Given I execute the SQL commands
"""
UPDATE account_journal SET allow_date = false;
"""
@email_params_mailtrap
Scenario: E-MAIL PARAMS WITH EMAIL EATER (http://mailtrap.io)
Given I need a "ir.mail_server" with name: mailstrap_testings
And having:
| name | value |
| smtp_host | mailtrap.io |
| sequence | 1 |
| smtp_port | 2525 |
| smtp_user | camptocamp1 |
| smtp_pass | 20468fa2f2879cb9 |
@account_credit_control_policy_2_times
Scenario: Configure the credit control policy in 2 times
Given I configure the following accounts on the credit control policy with oid: "account_credit_control.credit_control_2_time":
| account code |
| 4111 |
| 4112 |
@account_credit_control_policy_3_times
Scenario: Configure the credit control policy in 3 times
Given I configure the following accounts on the credit control policy with oid: "account_credit_control.credit_control_3_time":
| account code |
| 4111 |
| 4112 |

View File

@@ -1,105 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2009 Camptocamp SA
#
##############################################################################
##############################################################################
# Branch # Module # Processes # System
@account_credit_control @account_credit_control_add_policy @account_credit_control_setup
Feature: I add policy to partners already created
@account_credit_control_partner_1
Scenario: Partner_1
Given I need a "res.partner" with oid: scen.partner_1
And having:
| name | value |
| name | partner_1 |
| credit_policy_id | by name: No follow |
@account_credit_control_customer_1
Scenario: Customer_1
Given I need a "res.partner" with oid: scen.customer_1
And having:
| name | value |
| name | customer_1 |
| credit_policy_id | by name: 2 time policy |
@account_credit_control_customer_2
Scenario: Customer_2
Given I need a "res.partner" with oid: scen.customer_2
And having:
| name | value |
| name | customer_2 |
| credit_policy_id | by name: 2 time policy |
@account_credit_control_customer_3
Scenario: Customer_3
Given I need a "res.partner" with oid: scen.customer_3
And having:
| name | value |
| name | customer_3 |
| credit_policy_id | by name: 2 time policy |
@account_credit_control_customer_4
Scenario: Customer_4
Given I need a "res.partner" with oid: scen.customer_4
And having:
| name | value |
| name | customer_4 |
# the credit policy must be 3 time policy (inherited from company)
@account_credit_control_customer_5
Scenario: Customer_5
Given I need a "res.partner" with oid: scen.customer_5
And having:
| name | value |
| name | customer_5_usd |
| credit_policy_id | by name: 3 time policy |
@account_credit_control_customer_6
Scenario: Customer_6
Given I need a "res.partner" with oid: scen.customer_6
And having:
| name | value |
| name | customer_6 |
| credit_policy_id | by name: 3 time policy |
@account_credit_control_customer_partial_pay
Scenario: A customer who like to do partial payments
Given I need a "res.partner" with oid: scen.customer_partial_pay
And having:
| name | value |
| name | Scrooge McDuck |
| zip | 1000 |
| city | Duckburg |
| email | openerp@locahost.dummy |
| phone | |
| street | Duckstreet |
@account_credit_control_customer_multiple_payterm
Scenario: A customer who use payment terms in 2 times
Given I need a "res.partner" with oid: scen.customer_multiple_payterm
And having:
| name | value |
| name | Donald Duck |
| zip | 1100 |
| city | Duckburg |
| email | openerp@locahost.dummy |
| phone | |
| street | Duckstreet |
@account_credit_control_customer_multiple_payterm2
Scenario: A customer who use payment terms in 2 times
Given I need a "res.partner" with oid: scen.customer_multiple_payterm2
And having:
| name | value |
| name | Gus Goose |
| type | default |
| name | Gus Goose |
| zip | 1100 |
| city | Duckburg |
| email | openerp@locahost.dummy |
| phone | |
| street | Duckstreet |

View File

@@ -1,588 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
@account_credit_control @account_credit_control_setup @account_credit_control_base_data @account_credit_control_invoices
Feature: Invoices creation
##################### Partner 1 ##########################################################
@inv_1
Scenario: Create invoice 1
Given I need a "account.invoice" with oid: scen._inv_1
And having:
| name | value |
| name | SI_1 |
| date_invoice | 2013-01-15 |
| partner_id | by oid: scen.partner_1 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Days End of Month |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv1_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1000 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_1 |
Given I find a "account.invoice" with oid: scen._inv_1
Given I need a "account.invoice.line" with oid: scen._inv1_line2
And having:
| name | value |
| name | invoice line 2 |
| quantity | 1 |
| price_unit | 1000 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_1 |
Given I find a "account.invoice" with oid: scen._inv_1
And I open the credit invoice
@inv_2
Scenario: Create invoice 2
Given I need a "account.invoice" with oid: scen._inv_2
And having:
| name | value |
| name | SI_2 |
| date_invoice | 2013-02-15 |
| partner_id | by oid: scen.partner_1 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Days End of Month |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv2_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1200 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_2 |
Given I find a "account.invoice" with oid: scen._inv_2
And I open the credit invoice
@inv_3
Scenario: Create invoice 3
Given I need a "account.invoice" with oid: scen._inv_3
And having:
| name | value |
| name | SI_3 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.partner_1 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Days End of Month |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv3_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_3 |
Given I find a "account.invoice" with oid: scen._inv_3
And I open the credit invoice
##################### Customer 2 ##########################################################
@inv_4
Scenario: Create invoice 4
Given I need a "account.invoice" with oid: scen._inv_4
And having:
| name | value |
| name | SI_4 |
| date_invoice | 2013-01-18 |
| partner_id | by oid: scen.customer_2 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Days End of Month |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv4_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1000 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_4 |
Given I find a "account.invoice" with oid: scen._inv_4
And I open the credit invoice
@inv_5
Scenario: Create invoice 5
Given I need a "account.invoice" with oid: scen._inv_5
And having:
| name | value |
| name | SI_5 |
| date_invoice | 2013-02-15 |
| partner_id | by oid: scen.customer_2 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Days End of Month |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv5_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1200 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_5 |
Given I find a "account.invoice" with oid: scen._inv_5
And I open the credit invoice
@inv_6
Scenario: Create invoice 6
Given I need a "account.invoice" with oid: scen._inv_6
And having:
| name | value |
| name | SI_6 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_2 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Days End of Month |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv6_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_6 |
Given I find a "account.invoice" with oid: scen._inv_6
And I open the credit invoice
##################### Customer 3 ##########################################################
@inv_7
Scenario: Create invoice 7
Given I need a "account.invoice" with oid: scen._inv_7
And having:
| name | value |
| name | SI_7 |
| date_invoice | 2013-01-18 |
| partner_id | by oid: scen.customer_3 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv7_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1000 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_7 |
Given I find a "account.invoice" with oid: scen._inv_7
And I open the credit invoice
@inv_8
Scenario: Create invoice 8
Given I need a "account.invoice" with oid: scen._inv_8
And having:
| name | value |
| name | SI_8 |
| date_invoice | 2013-02-15 |
| partner_id | by oid: scen.customer_3 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv8_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1200 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_8 |
Given I find a "account.invoice" with oid: scen._inv_8
And I open the credit invoice
@inv_9
Scenario: Create invoice 9
Given I need a "account.invoice" with oid: scen._inv_9
And having:
| name | value |
| name | SI_9 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_3 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv9_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_9 |
Given I find a "account.invoice" with oid: scen._inv_9
And I open the credit invoice
##################### Customer 4 ##########################################################
@inv_10
Scenario: Create invoice 10
Given I need a "account.invoice" with oid: scen._inv_10
And having:
| name | value |
| name | SI_10 |
| date_invoice | 2013-01-18 |
| partner_id | by oid: scen.customer_4 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30% Advance End 30 Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv10_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1000 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_10 |
Given I find a "account.invoice" with oid: scen._inv_10
And I open the credit invoice
@inv_11
Scenario: Create invoice 11
Given I need a "account.invoice" with oid: scen._inv_11
And having:
| name | value |
| name | SI_11 |
| date_invoice | 2013-02-15 |
| partner_id | by oid: scen.customer_4 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30% Advance End 30 Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv11_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1200 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_11 |
Given I find a "account.invoice" with oid: scen._inv_11
And I open the credit invoice
@inv_12
Scenario: Create invoice 12
Given I need a "account.invoice" with oid: scen._inv_12
And having:
| name | value |
| name | SI_12 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_4 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30% Advance End 30 Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv12_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_12 |
Given I find a "account.invoice" with oid: scen._inv_12
And I open the credit invoice
##################### Customer 5 ##########################################################
@inv_13
Scenario: Create invoice 13
Given I need a "account.invoice" with oid: scen._inv_13
And having:
| name | value |
| name | SI_13 |
| date_invoice | 2013-01-18 |
| partner_id | by oid: scen.customer_5 |
| account_id | by name: Debtors USD |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv13_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1000 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_13 |
Given I find a "account.invoice" with oid: scen._inv_13
And I open the credit invoice
@inv_14
Scenario: Create invoice 14
Given I need a "account.invoice" with oid: scen._inv_14
And having:
| name | value |
| name | SI_14 |
| date_invoice | 2013-02-15 |
| partner_id | by oid: scen.customer_5 |
| account_id | by name: Debtors USD |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv14_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1200 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_14 |
Given I find a "account.invoice" with oid: scen._inv_14
And I open the credit invoice
@inv_15
Scenario: Create invoice 15
Given I need a "account.invoice" with oid: scen._inv_15
And having:
| name | value |
| name | SI_15 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_5 |
| account_id | by name: Debtors USD |
| journal_id | by name: Sales |
| currency_id | by name: USD |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
Given I need a "account.invoice.line" with oid: scen._inv15_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_15 |
Given I find a "account.invoice" with oid: scen._inv_15
And I open the credit invoice
@inv_16
Scenario: Create invoice 16
Given I need a "account.invoice" with oid: scen._inv_16
And having:
| name | value |
| name | SI_16 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_4 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
And I need a "account.invoice.line" with oid: scen._inv16_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_16 |
Then I find a "account.invoice" with oid: scen._inv_16
And I open the credit invoice
@inv_17
Scenario: Create invoice 17
Given I need a "account.invoice" with oid: scen._inv_17
And having:
| name | value |
| name | SI_17 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_partial_pay |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
And I need a "account.invoice.line" with oid: scen._inv17_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_17 |
Then I find a "account.invoice" with oid: scen._inv_17
And I open the credit invoice
@inv_18
Scenario: Create invoice 18
Given I need a "account.invoice" with oid: scen._inv_18
And having:
| name | value |
| name | SI_18 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_multiple_payterm |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30% Advance End 30 Days |
| type | out_invoice |
And I need a "account.invoice.line" with oid: scen._inv18_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_18 |
Then I find a "account.invoice" with oid: scen._inv_18
And I open the credit invoice
@inv_19
Scenario: Create invoice 19
Given I need a "account.invoice" with oid: scen._inv_19
And having:
| name | value |
| name | SI_19 |
| date_invoice | 2013-03-15 |
| partner_id | by oid: scen.customer_multiple_payterm2 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30% Advance End 30 Days |
| type | out_invoice |
And I need a "account.invoice.line" with oid: scen._inv19_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 1500 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_19 |
Then I find a "account.invoice" with oid: scen._inv_19
And I open the credit invoice
@inv_20
Scenario: Create invoice 20
Given I need a "account.invoice" with oid: scen._inv_20
And having:
| name | value |
| name | SI_20_test_tolerance |
| date_invoice | 2013-03-23 |
| partner_id | by oid: scen.customer_6 |
| account_id | by name: Debtors |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
And I need a "account.invoice.line" with oid: scen._inv20_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 0.09 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_20 |
Then I find a "account.invoice" with oid: scen._inv_20
And I open the credit invoice
@inv_20
Scenario: Create invoice 21 (this receivable account must not be chased-> no credit line creation)
Given I need a "account.invoice" with oid: scen._inv_21
And having:
| name | value |
| name | SI_21_test_receivable_account_excluded |
| date_invoice | 2013-03-25 |
| partner_id | by oid: scen.customer_6 |
| account_id | by name: Debtors GBP |
| journal_id | by name: Sales |
| currency_id | by name: EUR |
| payment_term | by name: 30 Net Days |
| type | out_invoice |
And I need a "account.invoice.line" with oid: scen._inv21_line1
And having:
| name | value |
| name | invoice line 1 |
| quantity | 1 |
| price_unit | 6666 |
| account_id | by name: Sales |
| invoice_id | by oid: scen._inv_21 |
Then I find a "account.invoice" with oid: scen._inv_21
And I open the credit invoice

View File

@@ -1,29 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_jan
Feature: Ensure that mail credit line generation first pass is correct
Scenario: clean data
Given I clean all the credit lines
#Given I unreconcile and clean all move line
@account_credit_control_run_month
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run1
And having:
| name | value |
| date | 2013-01-31 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 300 | 2013-01-18 | Debtors | 3 time policy | 2013-01-31 | customer_4 | email | 1 | SI_10 | 10 days net | draft | 300 | |

View File

@@ -1,33 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_feb
Feature: Ensure that mail credit line generation first pass is correct
@account_credit_control_mark
Scenario: mark lines
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
@account_credit_control_run_month
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run2
And having:
| name | value |
| date | 2013-02-28 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 360 | 2013-02-15 | Debtors | 3 time policy | 2013-02-28 | customer_4 | email | 1 | SI_11 | 10 days net | draft | 360 | USD |
| 1000 | 2013-02-17 | Debtors USD | 3 time policy | 2013-02-28 | customer_5_usd | email | 1 | SI_13 | 10 days net | draft | 1000 | USD |
| 300 | 2013-01-18 | Debtors | 3 time policy | 2013-02-28 | customer_4 | email | 2 | SI_10 | 30 days end of month | draft | 300 | |

View File

@@ -1,45 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_mar
Feature: Ensure that email credit line generation first pass is correct
@account_credit_control_mark
Scenario: mark lines
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
@pay_invoice_si_19_part1
Scenario: I pay a part of the first part of the invoice SI 19,
Given I pay 300.0 on the invoice "SI_19"
Then My invoice "SI_19" is in state "open" reconciled with a residual amount of "1200.0"
@account_credit_control_run_month_mar
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run3
And having:
| name | value |
| date | 2013-03-31 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 1000 | 2013-02-28 | Debtors | 2 time policy | 2013-03-31 | customer_2 | email | 1 | SI_4 | 30 days end of month | draft | 1000 | |
| 1000 | 2013-02-17 | Debtors | 2 time policy | 2013-03-31 | customer_3 | email | 1 | SI_7 | 30 days end of month | draft | 1000 | |
| 700 | 2013-02-28 | Debtors | 3 time policy | 2013-03-31 | customer_4 | email | 1 | SI_10 | 10 days net | draft | 700 | |
| 449.99 | 2013-03-15 | Debtors | 3 time policy | 2013-03-31 | customer_4 | email | 1 | SI_12 | 10 days net | draft | 449.99 | USD |
| 1200 | 2013-03-17 | Debtors USD | 3 time policy | 2013-03-31 | customer_5_usd | email | 1 | SI_14 | 10 days net | draft | 1200 | USD |
| 360 | 2013-02-15 | Debtors | 3 time policy | 2013-03-31 | customer_4 | email | 2 | SI_11 | 30 days end of month | draft | 360 | USD |
| 1000 | 2013-02-17 | Debtors USD | 3 time policy | 2013-03-31 | customer_5_usd | email | 2 | SI_13 | 30 days end of month | draft | 1000 | USD |
| 300 | 2013-01-18 | Debtors | 3 time policy | 2013-03-31 | customer_4 | letter | 3 | SI_10 | 10 days last reminder | draft | 300 | |
| 450 | 2013-03-15 | Debtors | 3 time policy | 2013-03-31 | Donald Duck | email | 1 | SI_18 | 10 days net | draft | 450 | |
| 150 | 2013-03-15 | Debtors | 3 time policy | 2013-03-31 | Gus Goose | email | 1 | SI_19 | 10 days net | draft | 450 | |

View File

@@ -1,44 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_apr
Feature: Ensure that email credit line generation first pass is correct
@account_credit_control_mark
Scenario: mark lines
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
@account_credit_control_run_month
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run4
And having:
| name | value |
| date | 2013-04-30 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 360 | 2013-02-15 | Debtors | 3 time policy | 2013-04-30 | customer_4 | letter | 3 | SI_11 | 10 days last reminder | draft | 360 | USD |
| 1200 | 2013-03-31 | Debtors | 2 time policy | 2013-04-30 | customer_2 | email | 1 | SI_5 | 30 days end of month | draft | 1200 | USD |
| 1200 | 2013-03-17 | Debtors | 2 time policy | 2013-04-30 | customer_3 | email | 1 | SI_8 | 30 days end of month | draft | 1200 | USD |
| 700 | 2013-02-28 | Debtors | 3 time policy | 2013-04-30 | customer_4 | email | 2 | SI_10 | 30 days end of month | draft | 700 | |
| 840 | 2013-03-31 | Debtors | 3 time policy | 2013-04-30 | customer_4 | email | 1 | SI_11 | 10 days net | draft | 840 | USD |
| 449.99 | 2013-03-15 | Debtors | 3 time policy | 2013-04-30 | customer_4 | email | 2 | SI_12 | 30 days end of month | draft | 449.99 | USD |
| 1500 | 2013-04-14 | Debtors USD | 3 time policy | 2013-04-30 | customer_5_usd | email | 1 | SI_15 | 10 days net | draft | 1500 | USD |
| 1200 | 2013-03-17 | Debtors USD | 3 time policy | 2013-04-30 | customer_5_usd | email | 2 | SI_14 | 30 days end of month | draft | 1200 | USD |
| 1500 | 2013-04-14 | Debtors USD | 3 time policy | 2013-04-30 | customer_5_usd | email | 1 | SI_15 | 10 days net | draft | 1500 | USD |
| 1500 | 2013-04-14 | Debtors | 3 time policy | 2013-04-30 | customer_4 | email | 1 | SI_16 | 10 days net | draft | 1500 | |
| 1500 | 2013-04-14 | Debtors | 3 time policy | 2013-04-30 | Scrooge McDuck | email | 1 | SI_17 | 10 days net | draft | 1500 | |
| 450 | 2013-03-15 | Debtors | 3 time policy | 2013-04-30 | Donald Duck | email | 2 | SI_18 | 30 days end of month | draft | 450 | |
| 150 | 2013-03-15 | Debtors | 3 time policy | 2013-04-30 | Gus Goose | email | 2 | SI_19 | 30 days end of month | draft | 450 | |

View File

@@ -1,59 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_may
Feature: Ensure that email credit line generation first pass is correct
@account_credit_control_mark
Scenario: mark lines
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
@pay_invoice_si_16
Scenario: I pay entirely the invoice SI 16, so it should no longer appear in the credit control lines
Given I pay the full amount on the invoice "SI_16"
Then My invoice "SI_16" is in state "paid" reconciled with a residual amount of "0.0"
@pay_invoice_si_17
Scenario: I pay entirely the invoice SI 17, so it should no longer appear in the credit control lines
Given I pay 1000.0 on the invoice "SI_17"
Then My invoice "SI_17" is in state "open" reconciled with a residual amount of "500.0"
@pay_invoice_si_18_part1
Scenario: I pay the first part of the invoice SI 18, so it should no longer appear in the credit control lines however, the second move lines should still appears
Given I pay 450.0 on the invoice "SI_18"
Then My invoice "SI_18" is in state "open" reconciled with a residual amount of "1050.0"
@account_credit_control_run_month
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run5
And having:
| name | value |
| date | 2013-05-31 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 1500 | 2013-04-30 | Debtors | 2 time policy | 2013-05-31 | customer_2 | email | 1 | SI_6 | 30 days end of month | draft | 1500 | USD |
| 1000 | 2013-02-28 | Debtors | 2 time policy | 2013-05-31 | customer_2 | letter | 2 | SI_4 | 60 days last reminder | draft | 1000 | |
| 1000 | 2013-02-17 | Debtors | 2 time policy | 2013-05-31 | customer_3 | letter | 2 | SI_7 | 60 days last reminder | draft | 1000 | |
| 1500 | 2013-04-14 | Debtors | 2 time policy | 2013-05-31 | customer_3 | email | 1 | SI_9 | 30 days end of month | draft | 1500 | |
| 840 | 2013-03-31 | Debtors | 3 time policy | 2013-05-31 | customer_4 | email | 2 | SI_11 | 30 days end of month | draft | 840 | USD |
| 1500 | 2013-04-14 | Debtors USD | 3 time policy | 2013-05-31 | customer_5_usd | email | 2 | SI_15 | 30 days end of month | draft | 1500 | USD |
| 700 | 2013-02-28 | Debtors | 3 time policy | 2013-05-31 | customer_4 | letter | 3 | SI_10 | 10 days last reminder | draft | 700 | |
| 449.99 | 2013-03-15 | Debtors | 3 time policy | 2013-05-31 | customer_4 | letter | 3 | SI_12 | 10 days last reminder | draft | 449.99 | USD |
| 1050.01 | 2013-04-30 | Debtors | 3 time policy | 2013-05-31 | customer_4 | email | 1 | SI_12 | 10 days net | draft | 1050.01 | USD |
| 1200 | 2013-03-17 | Debtors USD | 3 time policy | 2013-05-31 | customer_5_usd | letter | 3 | SI_14 | 10 days last reminder | draft | 1200 | USD |
| 500 | 2013-04-14 | Debtors | 3 time policy | 2013-05-31 | Scrooge McDuck | email | 2 | SI_17 | 30 days end of month | draft | 1500 | |
| 1050 | 2013-04-30 | Debtors | 3 time policy | 2013-05-31 | Donald Duck | email | 1 | SI_18 | 10 days net | draft | 1050 | |
| 150 | 2013-03-15 | Debtors | 3 time policy | 2013-05-31 | Gus Goose | letter | 3 | SI_19 | 10 days last reminder | draft | 450 | |
| 1050 | 2013-04-30 | Debtors | 3 time policy | 2013-05-31 | Gus Goose | email | 1 | SI_19 | 10 days net | draft | 1050 | |

View File

@@ -1,38 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_jun
Feature: Ensure that email credit line generation first pass is correct
@account_credit_control_mark
Scenario: mark lines
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
@account_credit_control_run_month
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run6
And having:
| name | value |
| date | 2013-06-30 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 1200 | 2013-03-31 | Debtors | 2 time policy | 2013-06-30 | customer_2 | letter | 2 | SI_5 | 60 days last reminder | draft | 1200 | USD |
| 1200 | 2013-03-17 | Debtors | 2 time policy | 2013-06-30 | customer_3 | letter | 2 | SI_8 | 60 days last reminder | draft | 1200 | USD |
| 1050.01 | 2013-04-30 | Debtors | 3 time policy | 2013-06-30 | customer_4 | email | 2 | SI_12 | 30 days end of month | draft | 1050.01 | USD |
| 840 | 2013-03-31 | Debtors | 3 time policy | 2013-06-30 | customer_4 | letter | 3 | SI_11 | 10 days last reminder | draft | 840 | USD |
| 1500 | 2013-04-14 | Debtors USD | 3 time policy | 2013-06-30 | customer_5_usd | letter | 3 | SI_15 | 10 days last reminder | draft | 1500 | USD |
| 500 | 2013-04-14 | Debtors | 3 time policy | 2013-06-30 | Scrooge McDuck | letter | 3 | SI_17 | 10 days last reminder | draft | 1500 | |
| 1050 | 2013-04-30 | Debtors | 3 time policy | 2013-06-30 | Donald Duck | email | 2 | SI_18 | 30 days end of month | draft | 1050 | |
| 1050 | 2013-04-30 | Debtors | 3 time policy | 2013-06-30 | Gus Goose | email | 2 | SI_19 | 30 days end of month | draft | 1050 | |

View File

@@ -1,35 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_jul
Feature: Ensure that email credit line generation first pass is correct
@account_credit_control_mark
Scenario: mark lines
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
@account_credit_control_run_month
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.run7
And having:
| name | value |
| date | 2013-07-31 |
When I launch the credit run
Then my credit run should be in state "done"
And the generated credit lines should have the following values:
| balance | date due | account | policy | date | partner | channel | level | move line | policy level | state | amount due | currency |
| 1500 | 2013-04-30 | Debtors | 2 time policy | 2013-07-31 | customer_2 | letter | 2 | SI_6 | 60 days last reminder | draft | 1500 | USD |
| 1500 | 2013-04-14 | Debtors | 2 time policy | 2013-07-31 | customer_3 | letter | 2 | SI_9 | 60 days last reminder | draft | 1500 | USD |
| 1050.01 | 2013-04-30 | Debtors | 3 time policy | 2013-07-31 | customer_4 | letter | 3 | SI_12 | 10 days last reminder | draft | 1050.01 | USD |
| 1050 | 2013-04-30 | Debtors | 3 time policy | 2013-07-31 | Donald Duck | letter | 3 | SI_18 | 10 days last reminder | draft | 1050 | |
| 1050 | 2013-04-30 | Debtors | 3 time policy | 2013-07-31 | Gus Goose | letter | 3 | SI_19 | 10 days last reminder | draft | 1050 | |

View File

@@ -1,30 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_aug
Feature: Ensure that ignore feature works as expected
@account_credit_control_mark_as_ignore
Scenario: mark last line as ignore
Given I ignore the "Gus Goose" credit line at level "3" for move line "SI_19" with amount "1050.0"
@account_credit_control_run_month_aug
Scenario: Create run
Given I need a "credit.control.run" with oid: credit_control.runignored
And having:
| name | value |
| date | 2013-08-30 |
When I launch the credit run
Then my credit run should be in state "done"
@check_ignored_line
Scenario: Check ignored lines
Given I have for "Gus Goose" "2" credit lines at level "3" for move line "SI_19" with amount "1050.0" respectively in state "draft" and "ignored"

View File

@@ -1,42 +0,0 @@
###############################################################################
#
# OERPScenario, OpenERP Functional Tests
# Copyright 2012-2014 Camptocamp SA
# Author Nicolas Bessi
##############################################################################
# Features Generic tags (none for all)
##############################################################################
@account_credit_control @account_credit_control_run @account_credit_control_run_change_level
Feature: Ensure that manually changing an invoice level feature works as expected
@account_credit_control_change_level
Scenario: Change level
Given I change level for invoice "SAJ/2014/0004" to "10 days net" of policy "3 time policy"
Then wizard selected move lines should be:
| name |
| SI_4 |
When I confirm the level change
And I should have "3" credit control lines overridden
And one new credit control line of level "10 days net" related to invoice "SAJ/2014/0004"
Then I force date of generated credit line to "2013-09-15"
@account_credit_control_run_month_sept
Scenario: Create run
Given there is "draft" credit lines
And I mark all draft email to state "to_be_sent"
Then the draft line should be in state "to_be_sent"
Given I need a "credit.control.run" with oid: credit_control.manual_change
And having:
| name | value |
| date | 2013-09-30 |
When I launch the credit run
Then my credit run should be in state "done"
@account_credit_control_manual_next_step
Scenario: Check manually managed line on run
Given the invoice "SAJ/2014/0004" with manual changes
And the invoice has "1" line of level "1" for policy "3 time policy"
And the invoice has "1" line of level "2" for policy "3 time policy"

View File

@@ -1,147 +0,0 @@
# -*- coding: utf-8 -*-
# flake8: noqa
import time
from behave import given, when
from support import model, assert_equal
@given(u'I configure the following accounts on the credit control policy with oid: "{policy_oid}"')
def impl(ctx, policy_oid):
policy = model('credit.control.policy').get(policy_oid)
assert policy, 'No policy % found' % policy_oid
acc_obj = model('account.account')
accounts = []
for row in ctx.table:
acc = acc_obj.get(['code = %s' % row['account code']])
assert acc, "Account with code %s not found" % row['account code']
accounts.append(acc)
policy.write({'account_ids': [x.id for x in accounts]})
@when(u'I launch the credit run')
def impl(ctx):
assert ctx.found_item
# Must be a cleaner way to do it
assert 'credit.control.run' == ctx.found_item._model._name
ctx.found_item.generate_credit_lines()
@given(u'I clean all the credit lines')
def impl(ctx):
model('credit.control.line').browse([]).unlink()
@then(u'my credit run should be in state "done"')
def impl(ctx):
assert ctx.found_item
# Must be a cleaner way to do it
assert model("credit.control.run").get(ctx.found_item.id).state == 'done'
@then(u'the generated credit lines should have the following values')
def impl(ctx):
def _row_to_dict(row):
return dict((name, row[name]) for name in row.headings if row[name])
rows = map(_row_to_dict, ctx.table)
def _parse_date(value):
return time.strftime(value) if '%' in value else value
for row in rows:
account = model('account.account').get(['name = %s' % row['account']])
assert account, "no account named %s found" % row['account']
policy = model('credit.control.policy').get(['name = %s' % row['policy']])
assert policy, "No policy %s found" % row['policy']
partner = model('res.partner').get(['name = %s' % row['partner']])
assert partner, "No partner %s found" % row['partner']
maturity_date = _parse_date(row['date due'])
move_line = model('account.move.line').get(['name = %s' % row['move line'],
'date_maturity = %s' % maturity_date])
assert move_line, "No move line %s found" % row['move line']
level = model('credit.control.policy.level').get(['name = %s' % row['policy level'],
'policy_id = %s' % policy.id])
assert level, "No level % found" % row['policy level']
domain = [['account_id', '=', account.id],
['policy_id', '=', policy.id],
['partner_id', '=', partner.id],
['policy_level_id', '=', level.id],
['amount_due', '=', row.get('amount due', 0.0)],
['state', '=', row['state']],
['level', '=', row.get('level', 0.0)],
['channel', '=', row['channel']],
['balance_due', '=', row.get('balance', 0.0)],
['date_due', '=', _parse_date(row['date due'])],
['date', '=', _parse_date(row['date'])],
['move_line_id', '=', move_line.id],
]
if row.get('currency'):
curreny = model('res.currency').get(['name = %s' % row['currency']])
assert curreny, "No currency %s found" % row['currency']
domain.append(('currency_id', '=', curreny.id))
lines = model('credit.control.line').search(domain)
assert lines, "no line found for %s" % repr(row)
assert len(lines) == 1, "Too many lines found for %s" % repr(row)
date_lines = model('credit.control.line').search([('date', '=', ctx.found_item.date)])
assert len(date_lines) == len(ctx.table.rows), "Too many lines generated"
def open_invoice(ctx):
assert ctx.found_item
ctx.found_item._send('invoice_open')
# _send refresh object
assert ctx.found_item.state == 'open'
@then(u'I open the credit invoice')
def impl(ctx):
open_invoice(ctx)
@given(u'I open the credit invoice')
def impl(ctx):
open_invoice(ctx)
@given(u'there is "{state}" credit lines')
def impl(ctx, state):
assert model('credit.control.line').search(['state = %s' % state])
@given(u'I mark all draft email to state "{state}"')
def impl(ctx, state):
wiz = model('credit.control.marker').create({'name': state})
lines = model('credit.control.line').search([('state', '=', 'draft')])
assert lines
ctx.lines = lines
wiz.write({'line_ids': lines})
wiz.mark_lines()
@then(u'the draft line should be in state "{state}"')
def impl(ctx, state):
assert ctx.lines
lines = model('credit.control.line').search([('state', '!=', state),
('id', 'in', ctx.lines)])
assert not lines
@given(u'I ignore the "{partner}" credit line at level "{level:d}" for move line "{move_line_name}" with amount "{amount:f}"')
def impl(ctx, partner, level, move_line_name, amount):
print ctx, partner, level, move_line_name, amount
to_ignore = model('credit.control.line').search([('partner_id.name', '=', partner),
('level', '=', level),
('amount_due', '=', amount),
('move_line_id.name', '=', move_line_name)])
assert to_ignore
wiz = model('credit.control.marker').create({'name': 'ignored'})
ctx.lines = to_ignore
wiz.write({'line_ids': to_ignore})
wiz.mark_lines()
assert model('credit.control.line').get(to_ignore[0]).state == 'ignored'
@given(u'I have for "{partner}" "{number:d}" credit lines at level "{level:d}" for move line "{move_line_name}" with amount "{amount:f}" respectively in state "draft" and "ignored"')
def impl(ctx, partner, number, level, move_line_name, amount):
to_check = model('credit.control.line').search([('partner_id.name', '=', partner),
('level', '=', level),
('amount_due', '=', amount),
('move_line_id.name', '=', move_line_name),
('state', 'in', ('draft', 'ignored'))])
assert_equal(len(to_check), int(number), msg="More than %s found" % number)
lines = model('credit.control.line').browse(to_check)
assert set(['ignored', 'draft']) == set(lines.state)

View File

@@ -1,79 +0,0 @@
# -*- coding: utf-8 -*-
from support import model, assert_equal, assert_in, assert_true
# flake8: noqa
@given(u'I change level for invoice "{invoice_name}" to "{level_name}" of policy "{policy_name}"')
def impl(ctx, invoice_name, level_name, policy_name):
invoice = model('account.invoice').get([('number', '=', invoice_name)])
assert_true(invoice, msg='No invoices found')
level = model('credit.control.policy.level').get([('name', '=', level_name)])
assert_true(level, 'level not found')
policy = model('credit.control.policy').get([('name', '=', policy_name)])
assert_true(policy, 'Policy not found')
assert_equal(policy.id, level.policy_id.id)
context = {'active_ids': [invoice.id]}
data = {'new_policy_id': policy.id,
'new_policy_level_id': level.id}
wizard = model('credit.control.policy.changer').create(data, context=context)
ctx.wizard = wizard
@then(u'wizard selected move lines should be')
def impl(ctx):
assert_true(ctx.wizard)
names = [x.name for x in ctx.wizard.move_line_ids]
for line in ctx.table:
assert_in(line['name'], names)
@when(u'I confirm the level change')
def impl(ctx):
assert_true(ctx.wizard)
ctx.wizard.set_new_policy()
@when(u'I should have "{line_number:d}" credit control lines overridden')
def impl(ctx, line_number):
assert_true(ctx.wizard)
move_ids = [x.id for x in ctx.wizard.move_line_ids]
overridden = model('credit.control.line').search([('move_line_id', 'in', move_ids),
('manually_overridden', '=', True)])
# assert len(overridden) == line_number
@when(u'one new credit control line of level "{level_name}" related to invoice "{invoice_name}"')
def impl(ctx, level_name, invoice_name):
invoice = model('account.invoice').get([('number', '=', invoice_name)])
assert_true(invoice, msg='No invoices found')
level = model('credit.control.policy.level').get([('name', '=', level_name)])
assert_true(level, 'level not found')
assert_true(ctx.wizard)
move_ids = [x.id for x in ctx.wizard.move_line_ids]
created_id = model('credit.control.line').search([('move_line_id', 'in', move_ids),
('manually_overridden', '=', False)])
assert len(created_id) == 1
created = model('credit.control.line').get(created_id[0])
ctx.created = created
assert_equal(created.policy_level_id.id, level.id)
assert_equal(created.invoice_id.id, invoice.id)
assert_equal(created.invoice_id.credit_policy_id.id, level.policy_id.id)
@then(u'I force date of generated credit line to "{date}"')
def impl(ctx, date):
assert_true(ctx.created)
ctx.created.write({'date': date})
@given(u'the invoice "{invoice_name}" with manual changes')
def impl(ctx, invoice_name):
invoice = model('account.invoice').get([('number', '=', invoice_name)])
assert_true(invoice, msg='No invoices found')
man_lines = (x for x in invoice.credit_control_line_ids if x.manually_overridden)
assert_true(next(man_lines, None), 'No manual change on the invoice')
ctx.invoice = invoice
@given(u'the invoice has "{line_number:d}" line of level "{level:d}" for policy "{policy_name}"')
def impl(ctx, line_number, level, policy_name):
assert_true(ctx.invoice)
policy = model('credit.control.policy').get([('name', '=', policy_name)])
assert_true(policy)
lines = model('credit.control.line').search([('invoice_id', '=', ctx.invoice.id),
('level', '=', level),
('policy_id', '=', policy.id)])
assert_equal(len(lines), line_number)

View File

@@ -1,96 +0,0 @@
# -*- coding: utf-8 -*-
# flake8: noqa
from support import model, assert_equal, assert_almost_equal
import datetime
@step('I pay the full amount on the invoice "{inv_name}"')
def impl(ctx, inv_name):
Invoice = model('account.invoice')
invoice = Invoice.get([('name', '=', inv_name)])
assert invoice
ctx.execute_steps("""
When I pay %f on the invoice "%s"
""" % (invoice.residual, inv_name))
@step('I pay {amount:f} on the invoice "{inv_name}"')
def impl(ctx, amount, inv_name):
Partner = model('res.partner')
Invoice = model('account.invoice')
Voucher = model('account.voucher')
VoucherLine = model('account.voucher.line')
Journal = model('account.journal')
invoice = Invoice.get([('name', '=', inv_name)])
assert invoice
journal = Journal.get('scen.eur_journal')
values = {
'partner_id': invoice.partner_id.commercial_partner_id.id,
'reference': invoice.name,
'amount': amount,
'date': invoice.date_invoice,
'currency_id': invoice.currency_id.id,
'company_id': invoice.company_id.id,
'journal_id': journal.id,
}
if invoice.type in ('out_invoice','out_refund'):
values['type'] = 'receipt'
else:
values['type'] = 'payment'
onchange = Voucher.onchange_partner_id([], values['partner_id'],
values['journal_id'],
values['amount'],
values['currency_id'],
values['type'],
values['date'])
values.update(onchange['value'])
onchange = Voucher.onchange_date([], values['date'],
values['currency_id'],
False,
values['amount'],
values['company_id'])
values.update(onchange['value'])
onchange = Voucher.onchange_amount([], values['amount'],
False,
values['partner_id'],
values['journal_id'],
values['currency_id'],
values['type'],
values['date'],
False,
values['company_id'])
values.update(onchange['value'])
values['line_cr_ids'] = False
voucher = Voucher.create(values)
vals = voucher.recompute_voucher_lines(voucher.partner_id.id,
voucher.journal_id.id,
voucher.amount,
voucher.currency_id.id,
voucher.type,
voucher.date)
for line in vals['value']['line_cr_ids']:
line['voucher_id'] = voucher.id
VoucherLine.create(line)
for line in vals['value']['line_dr_ids']:
line['voucher_id'] = voucher.id
VoucherLine.create(line)
voucher.button_proforma_voucher()
# Workaround to force recomputation of the residual.
# Must be removed once this bug is fixed:
# https://github.com/odoo/odoo/issues/3395
invoice.write({'currency_id': invoice.currency_id.id})
@step('My invoice "{inv_name}" is in state "{state}" reconciled with a residual amount of "{amount:f}"')
def impl(ctx, inv_name, state, amount):
invoice = model('account.invoice').get([('name', '=', inv_name)])
assert_almost_equal(invoice.residual, amount)
assert_equal(invoice.state, state)

View File

@@ -1,20 +1,20 @@
"id","perm_create","perm_unlink","group_id/id","name","model_id/id","perm_read","perm_write"
"account_credit_control.ir_model_access_270",1,1,"group_account_credit_control_manager","credit_control_manager_line","account_credit_control.model_credit_control_line",1,1
"account_credit_control.ir_model_access_271",1,1,"group_account_credit_control_user","credit_control_user_line","account_credit_control.model_credit_control_line",1,1
"account_credit_control.ir_model_access_272",0,0,"group_account_credit_control_info","credit_control_info_line","account_credit_control.model_credit_control_line",1,0
"account_credit_control.ir_model_access_273",1,1,"group_account_credit_control_manager","credit_control_manager_mail_template","email_template.model_email_template",1,1
"account_credit_control.ir_model_access_275",1,1,"group_account_credit_control_manager","credit_control_manager_mail_message","mail.model_mail_message",1,1
"account_credit_control.ir_model_access_276",1,0,"group_account_credit_control_user","credit_control_user_mail_message","mail.model_mail_message",1,1
"account_credit_control.ir_model_access_277",0,0,"group_account_credit_control_info","credit_control_info_mail_message","mail.model_mail_message",1,0
"account_credit_control.ir_model_access_281",1,1,"group_account_credit_control_manager","credit_control_mananger_run","account_credit_control.model_credit_control_run",1,1
"account_credit_control.ir_model_access_282",1,1,"group_account_credit_control_user","credit_control_user_run","account_credit_control.model_credit_control_run",1,1
"account_credit_control.ir_model_access_283",0,0,"group_account_credit_control_info","credit_control_info_run","account_credit_control.model_credit_control_run",1,0
"account_credit_control.ir_model_access_284",1,1,"group_account_credit_control_manager","credit_control_manager_policy","account_credit_control.model_credit_control_policy",1,1
"account_credit_control.ir_model_access_285",0,0,"group_account_credit_control_user","credit_control_user_policy","account_credit_control.model_credit_control_policy",1,0
"account_credit_control.ir_model_access_286",0,0,"group_account_credit_control_info","credit_control_info_policy","account_credit_control.model_credit_control_policy",1,0
"account_credit_control.ir_model_access_287",1,1,"group_account_credit_control_manager","credit_control_manager_level","account_credit_control.model_credit_control_policy_level",1,1
"account_credit_control.ir_model_access_288",0,0,"group_account_credit_control_user","credit_control_user_level","account_credit_control.model_credit_control_policy_level",1,0
"account_credit_control.ir_model_access_289",0,0,"group_account_credit_control_info","credit_control_info_level","account_credit_control.model_credit_control_policy_level",1,0
"account_credit_control.ir_model_access_290",0,0,"account.group_account_user","credit_control_fin_user_line","account_credit_control.model_credit_control_line",1,0
"account_credit_control.ir_model_access_291",0,0,"account.group_account_invoice","credit_control_fin_invoice_line","account_credit_control.model_credit_control_line",1,0
"account_credit_control.ir_model_access_292",1,1,"account.group_account_manager","credit_control_fin_manager_line","account_credit_control.model_credit_control_line",1,1
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
account_credit_control.ir_model_access_270,credit_control_manager_line,account_credit_control.model_credit_control_line,group_account_credit_control_manager,1,1,1,1
account_credit_control.ir_model_access_271,credit_control_user_line,account_credit_control.model_credit_control_line,group_account_credit_control_user,1,1,1,1
account_credit_control.ir_model_access_272,credit_control_info_line,account_credit_control.model_credit_control_line,group_account_credit_control_info,1,0,0,0
account_credit_control.ir_model_access_273,credit_control_manager_mail_template,mail.model_mail_template,group_account_credit_control_manager,1,1,1,1
account_credit_control.ir_model_access_275,credit_control_manager_mail_message,mail.model_mail_message,group_account_credit_control_manager,1,1,1,1
account_credit_control.ir_model_access_276,credit_control_user_mail_message,mail.model_mail_message,group_account_credit_control_user,1,1,1,0
account_credit_control.ir_model_access_277,credit_control_info_mail_message,mail.model_mail_message,group_account_credit_control_info,1,0,0,0
account_credit_control.ir_model_access_281,credit_control_mananger_run,account_credit_control.model_credit_control_run,group_account_credit_control_manager,1,1,1,1
account_credit_control.ir_model_access_282,credit_control_user_run,account_credit_control.model_credit_control_run,group_account_credit_control_user,1,1,1,1
account_credit_control.ir_model_access_283,credit_control_info_run,account_credit_control.model_credit_control_run,group_account_credit_control_info,1,0,0,0
account_credit_control.ir_model_access_284,credit_control_manager_policy,account_credit_control.model_credit_control_policy,group_account_credit_control_manager,1,1,1,1
account_credit_control.ir_model_access_285,credit_control_user_policy,account_credit_control.model_credit_control_policy,group_account_credit_control_user,1,0,0,0
account_credit_control.ir_model_access_286,credit_control_info_policy,account_credit_control.model_credit_control_policy,group_account_credit_control_info,1,0,0,0
account_credit_control.ir_model_access_287,credit_control_manager_level,account_credit_control.model_credit_control_policy_level,group_account_credit_control_manager,1,1,1,1
account_credit_control.ir_model_access_288,credit_control_user_level,account_credit_control.model_credit_control_policy_level,group_account_credit_control_user,1,0,0,0
account_credit_control.ir_model_access_289,credit_control_info_level,account_credit_control.model_credit_control_policy_level,group_account_credit_control_info,1,0,0,0
account_credit_control.ir_model_access_290,credit_control_fin_user_line,account_credit_control.model_credit_control_line,account.group_account_user,1,0,0,0
account_credit_control.ir_model_access_291,credit_control_fin_invoice_line,account_credit_control.model_credit_control_line,account.group_account_invoice,1,0,0,0
account_credit_control.ir_model_access_292,credit_control_fin_manager_line,account_credit_control.model_credit_control_line,account.group_account_manager,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 account_credit_control.ir_model_access_270 credit_control_manager_line account_credit_control.model_credit_control_line group_account_credit_control_manager 1 1 1 1
3 account_credit_control.ir_model_access_271 credit_control_user_line account_credit_control.model_credit_control_line group_account_credit_control_user 1 1 1 1
4 account_credit_control.ir_model_access_272 credit_control_info_line account_credit_control.model_credit_control_line group_account_credit_control_info 1 0 0 0
5 account_credit_control.ir_model_access_273 credit_control_manager_mail_template email_template.model_email_template mail.model_mail_template group_account_credit_control_manager 1 1 1 1
6 account_credit_control.ir_model_access_275 credit_control_manager_mail_message mail.model_mail_message group_account_credit_control_manager 1 1 1 1
7 account_credit_control.ir_model_access_276 credit_control_user_mail_message mail.model_mail_message group_account_credit_control_user 1 1 1 0
8 account_credit_control.ir_model_access_277 credit_control_info_mail_message mail.model_mail_message group_account_credit_control_info 1 0 0 0
9 account_credit_control.ir_model_access_281 credit_control_mananger_run account_credit_control.model_credit_control_run group_account_credit_control_manager 1 1 1 1
10 account_credit_control.ir_model_access_282 credit_control_user_run account_credit_control.model_credit_control_run group_account_credit_control_user 1 1 1 1
11 account_credit_control.ir_model_access_283 credit_control_info_run account_credit_control.model_credit_control_run group_account_credit_control_info 1 0 0 0
12 account_credit_control.ir_model_access_284 credit_control_manager_policy account_credit_control.model_credit_control_policy group_account_credit_control_manager 1 1 1 1
13 account_credit_control.ir_model_access_285 credit_control_user_policy account_credit_control.model_credit_control_policy group_account_credit_control_user 1 0 0 0
14 account_credit_control.ir_model_access_286 credit_control_info_policy account_credit_control.model_credit_control_policy group_account_credit_control_info 1 0 0 0
15 account_credit_control.ir_model_access_287 credit_control_manager_level account_credit_control.model_credit_control_policy_level group_account_credit_control_manager 1 1 1 1
16 account_credit_control.ir_model_access_288 credit_control_user_level account_credit_control.model_credit_control_policy_level group_account_credit_control_user 1 0 0 0
17 account_credit_control.ir_model_access_289 credit_control_info_level account_credit_control.model_credit_control_policy_level group_account_credit_control_info 1 0 0 0
18 account_credit_control.ir_model_access_290 credit_control_fin_user_line account_credit_control.model_credit_control_line account.group_account_user 1 0 0 0
19 account_credit_control.ir_model_access_291 credit_control_fin_invoice_line account_credit_control.model_credit_control_line account.group_account_invoice 1 0 0 0
20 account_credit_control.ir_model_access_292 credit_control_fin_manager_line account_credit_control.model_credit_control_line account.group_account_manager 1 1 1 1

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="category_credit_control" model="ir.module.category">
<field name="name">Credit Control</field>
<field name="sequence" eval="99" />
</record>
<record id="group_account_credit_control_info" model="res.groups" context="{'noadmin':True}">
<field name="name">Info</field>
<field name="category_id" ref="category_credit_control"/>
</record>
<record id="group_account_credit_control_user" model="res.groups" context="{'noadmin':True}">
<field name="name">User</field>
<field name="category_id" ref="category_credit_control"/>
<field name="implied_ids" eval="[(4, ref('group_account_credit_control_info'))]"/>
</record>
<record id="group_account_credit_control_manager" model="res.groups">
<field name="name">Manager</field>
<field name="category_id" ref="category_credit_control"/>
<field name="implied_ids" eval="[(4, ref('group_account_credit_control_user'))]"/>
</record>
</odoo>

View File

@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_credit_control_policy
from . import test_res_partner
from . import test_account_invoice
from . import test_credit_control_run

View File

@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime
from dateutil import relativedelta
from openerp import fields
from openerp.tests.common import TransactionCase
from openerp.exceptions import UserError
class TestAccountInvoice(TransactionCase):
post_install = True
at_install = False
def test_action_cancel(self):
"""
Test the method action_cancel on invoice
We will create an old invoice, generate a control run
and check if I can unlink this invoice
:return:
"""
journal = self.env['account.invoice']._default_journal()
account_type_rec = self.env.ref('account.data_account_type_receivable')
account = self.env['account.account'].create({
'code': '400001',
'name': 'Clients (test)',
'user_type_id': account_type_rec.id,
'reconcile': True,
})
tag_operation = self.env.ref('account.account_tag_operating')
account_type_inc = self.env.ref('account.data_account_type_revenue')
analytic_account = self.env['account.account'].create({
'code': '701001',
'name': 'Ventes en Belgique (test)',
'user_type_id': account_type_inc.id,
'reconcile': True,
'tag_ids': [(6, 0, [tag_operation.id])]
})
payment_term = self.env.ref('account.account_payment_term_immediate')
product = self.env['product.product'].create({
'name': 'Product test'
})
policy = self.env.ref('account_credit_control.credit_control_3_time')
policy.write({
'account_ids': [(6, 0, [account.id])]
})
# There is a bug with Odoo ...
# The field "credit_policy_id" is considered as an "old field" and
# the field property_account_receivable_id like a "new field"
# The ORM will create the record with old field
# and update the record with new fields.
# However constrains are applied after the first creation.
partner = self.env['res.partner'].create({
'name': 'Partner',
'property_account_receivable_id': account.id,
})
partner.credit_policy_id = policy.id
date_invoice = datetime.today() - relativedelta.relativedelta(years=1)
invoice = self.env['account.invoice'].create({
'partner_id': partner.id,
'journal_id': journal.id,
'type': 'out_invoice',
'payment_term_id': payment_term.id,
'date_invoice': fields.Datetime.to_string(date_invoice),
'date_due': fields.Datetime.to_string(date_invoice),
})
invoice.invoice_line_ids.create({
'invoice_id': invoice.id,
'product_id': product.id,
'name': product.name,
'account_id': analytic_account.id,
'quantity': 5,
'price_unit': 100,
})
# Validate the invoice
invoice.signal_workflow('invoice_open')
control_run = self.env['credit.control.run'].create({
'date': fields.Date.today(),
'policy_ids': [(6, 0, [policy.id])]
})
control_run.generate_credit_lines()
self.assertTrue(len(invoice.credit_control_line_ids), 1)
control_line = invoice.credit_control_line_ids
control_marker = self.env['credit.control.marker']
marker_line = control_marker\
.with_context(active_model='credit.control.line',
active_ids=[control_line.id])\
._get_line_ids()
self.assertIn(control_line, marker_line)
marker = self.env['credit.control.marker'].create({
'name': 'to_be_sent',
'line_ids': [(6, 0, [control_line.id])]
})
marker.mark_lines()
with self.assertRaises(UserError):
invoice.unlink()

View File

@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp.exceptions import ValidationError, UserError
from openerp.tests.common import TransactionCase
class TestCreditControlPolicy(TransactionCase):
post_install = True
at_install = False
def test_check_policy_against_account(self):
"""
Test the model check_policy_against_account with several case
:return:
"""
policy = self.env.ref('account_credit_control.credit_control_3_time')
account_type = self.env.ref('account.data_account_type_receivable')
account = self.env['account.account'].create({
'code': '400001',
'name': 'Test',
'user_type_id': account_type.id,
'reconcile': True,
})
# The account is not included in the policy
with self.assertRaises(UserError):
policy.check_policy_against_account(account)
# We set the flag "do_nothing" to True
policy.write({
'account_ids': [(5, 0)],
'do_nothing': True,
})
result = policy.check_policy_against_account(account)
self.assertTrue(result)
# We add the account in the policy
policy.write({
'account_ids': [(6, 0, [account.id])]
})
result = policy.check_policy_against_account(account)
self.assertTrue(result)
def test_check_level_mode(self):
"""
Check the method _check_level_mode on policy level
:return:
"""
level_1 = self.env.ref('account_credit_control.3_time_1')
with self.assertRaises(ValidationError):
level_1.computation_mode = 'previous_date'
def test_previous_level(self):
"""
Check the method _previous_level on policy level
:return:
"""
level_1 = self.env.ref('account_credit_control.3_time_1')
level_2 = self.env.ref('account_credit_control.3_time_2')
previous_level = level_2._previous_level()
self.assertEqual(previous_level, level_1)
def test_get_sql_date_boundary_for_computation_mode(self):
"""
Check the where clauses statement return by the method
_get_sql_date_boundary_for_computation_mode
according the computation mode
:return:
"""
level_2 = self.env.ref('account_credit_control.3_time_2')
level_2.computation_mode = 'net_days'
where_clause = level_2._net_days_get_boundary()
result = level_2._get_sql_date_boundary_for_computation_mode()
self.assertEqual(result, where_clause)
level_2.computation_mode = 'end_of_month'
where_clause = level_2._end_of_month_get_boundary()
result = level_2._get_sql_date_boundary_for_computation_mode()
self.assertEqual(result, where_clause)
level_2.computation_mode = 'previous_date'
where_clause = level_2._previous_date_get_boundary()
result = level_2._get_sql_date_boundary_for_computation_mode()
self.assertEqual(result, where_clause)

View File

@@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import re
from datetime import datetime
from dateutil import relativedelta
from openerp import fields
from openerp.tests.common import TransactionCase
from openerp.exceptions import UserError
class TestCreditControlRun(TransactionCase):
post_install = True
at_install = False
def setUp(self):
super(TestCreditControlRun, self).setUp()
journal = self.env['account.invoice']._default_journal()
account_type_rec = self.env.ref('account.data_account_type_receivable')
account = self.env['account.account'].create({
'code': '400001',
'name': 'Clients (test)',
'user_type_id': account_type_rec.id,
'reconcile': True,
})
tag_operation = self.env.ref('account.account_tag_operating')
account_type_inc = self.env.ref('account.data_account_type_revenue')
analytic_account = self.env['account.account'].create({
'code': '701001',
'name': 'Ventes en Belgique (test)',
'user_type_id': account_type_inc.id,
'reconcile': True,
'tag_ids': [(6, 0, [tag_operation.id])]
})
payment_term = self.env.ref('account.account_payment_term_immediate')
product = self.env['product.product'].create({
'name': 'Product test'
})
self.policy = \
self.env.ref('account_credit_control.credit_control_3_time')
self.policy.write({
'account_ids': [(6, 0, [account.id])]
})
# There is a bug with Odoo ...
# The field "credit_policy_id" is considered as an "old field" and
# the field property_account_receivable_id like a "new field"
# The ORM will create the record with old field
# and update the record with new fields.
# However constrains are applied after the first creation.
partner = self.env['res.partner'].create({
'name': 'Partner',
'property_account_receivable_id': account.id,
})
partner.credit_policy_id = self.policy.id
date_invoice = datetime.today() - relativedelta.relativedelta(years=1)
self.invoice = self.env['account.invoice'].create({
'partner_id': partner.id,
'journal_id': journal.id,
'type': 'out_invoice',
'payment_term_id': payment_term.id,
'date_invoice': fields.Datetime.to_string(date_invoice),
'date_due': fields.Datetime.to_string(date_invoice),
})
self.invoice.invoice_line_ids.create({
'invoice_id': self.invoice.id,
'product_id': product.id,
'name': product.name,
'account_id': analytic_account.id,
'quantity': 5,
'price_unit': 100,
})
# Validate the invoice
self.invoice.signal_workflow('invoice_open')
def test_check_run_date(self):
"""
Create a control run older than the last control run
:return:
"""
control_run = self.env['credit.control.run'].create({
'date': fields.Date.today(),
'policy_ids': [(6, 0, [self.policy.id])]
})
with self.assertRaises(UserError):
today = datetime.today()
previous_date = today - relativedelta.relativedelta(days=15)
previous_date_str = fields.Date.to_string(previous_date)
control_run._check_run_date(previous_date_str)
def test_generate_credit_lines(self):
"""
Test the method generate_credit_lines
:return:
"""
control_run = self.env['credit.control.run'].create({
'date': fields.Date.today(),
'policy_ids': [(6, 0, [self.policy.id])]
})
control_run.with_context(lang='en_US').generate_credit_lines()
self.assertTrue(len(self.invoice.credit_control_line_ids), 1)
self.assertEqual(control_run.state, 'done')
report_regex = \
r'<p>Policy "<b>%s</b>" has generated <b>' \
r'\d+ Credit Control Lines.</b><br></p>' % self.policy.name
regex_result = re.match(report_regex, control_run.report)
self.assertIsNotNone(regex_result)
def test_multi_credit_control_run(self):
"""
Generate several control run
:return:
"""
six_months = datetime.today() - relativedelta.relativedelta(months=6)
six_months_str = fields.Date.to_string(six_months)
three_months = datetime.today() - relativedelta.relativedelta(months=2)
three_months_str = fields.Date.to_string(three_months)
# First run
first_control_run = self.env['credit.control.run'].create({
'date': six_months_str,
'policy_ids': [(6, 0, [self.policy.id])]
})
first_control_run.with_context(lang='en_US').generate_credit_lines()
self.assertTrue(len(self.invoice.credit_control_line_ids), 1)
# Second run
second_control_run = self.env['credit.control.run'].create({
'date': three_months_str,
'policy_ids': [(6, 0, [self.policy.id])]
})
second_control_run.with_context(lang='en_US').generate_credit_lines()
self.assertTrue(len(self.invoice.credit_control_line_ids), 2)
# Last run
last_control_run = self.env['credit.control.run'].create({
'date': fields.Date.today(),
'policy_ids': [(6, 0, [self.policy.id])]
})
last_control_run.with_context(lang='en_US').generate_credit_lines()
self.assertTrue(len(self.invoice.credit_control_line_ids), 2)

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp.tests.common import TransactionCase
from openerp.exceptions import ValidationError
class TestCreditControlPolicyLevel(TransactionCase):
post_install = True
at_install = False
def test_check_credit_policy(self):
"""
Test the constrains on res.partner
First we try to assign an account and a policy with a wrong policy
(this policy doesn't contains the account of the partner).
After that we add the previous account in the policy and
retry to assign this policy and this account on the partner
:return:
"""
policy = self.env.ref('account_credit_control.credit_control_3_time')
partner = self.env['res.partner'].create({
'name': 'Partner 1',
})
account = partner.property_account_receivable_id
with self.assertRaises(ValidationError):
partner.write({
'credit_policy_id': policy.id,
})
policy.write({
'account_ids': [(6, 0, [account.id])]
})
partner.property_account_receivable_id = account.id
partner.credit_policy_id = policy.id

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<act_window
id="act_account_credit_relation_relation"
name="Credit Lines"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"
domain="[('account_id', '=', active_id)]"
res_model="credit.control.line"
src_model="account.account"/>
<record id="invoice_followup_form_view" model="ir.ui.view">
<field name="name">invoice.followup.form.view</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Credit Control"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info">
<group>
<field name="credit_policy_id"
string="Manual Credit Control Policy"
attrs="{'invisible': [('credit_policy_id', '=', False)]}"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info"/>
</group>
<separator string="Issued Lines" colspan="4"/>
<field name="credit_control_line_ids" colspan="4"
nolabel="1"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info">
<tree string="Credit Control Lines">
<field name="date"/>
<field name="level"/>
<field name="state"/>
<field name="channel"/>
<field name="balance_due"/>
<field name="policy_level_id"/>
<field name="policy_id"/>
</tree>
</field>
</page>
</notebook>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_control_line_form" model="ir.ui.view">
<field name="name">credit.control.line.form</field>
<field name="model">credit.control.line</field>
<field name="arch" type="xml">
<form string="Control Credit Lines">
<header>
<field name="state" widget="statusbar"
statusbar_visible="draft,to_be_sent,sent"
statusbar_colors='{"error":"red","email_error":"red"}'/>
</header>
<sheet>
<group>
<group>
<field name="partner_id"/>
<field name="policy_level_id"/>
<field name="policy_id"/>
<field name="level"/>
<field name="manually_overridden"/>
</group>
<group>
<field name="date"/>
<field name="date_due"/>
<field name="channel"/>
<field name="date_sent"/>
<field name="mail_message_id"/>
</group>
</group>
<group>
<group>
<field name="invoice_id"/>
<field name="move_line_id"/>
<field name="account_id"/>
</group>
<group>
<field name="amount_due"/>
<field name="balance_due"/>
<field name="currency_id"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="credit_control_line_search" model="ir.ui.view">
<field name="name">Credit Control Lines</field>
<field name="model">credit.control.line</field>
<field name="arch" type="xml">
<search string="Control Credit Lines">
<group>
<field name="date"/>
<field name="channel"/>
<field name="policy_id"/>
<separator />
<field name="partner_id"/>
<field name="account_id"/>
<field name="invoice_id"/>
<field name="level"/>
<field name="policy_level_id"/>
</group>
<group string="Filters" name="filters">
<filter name="filter_draft" icon="fa-envelope"
string="Draft" domain="[('state', '=', 'draft')]"
help="Draft lines have to be triaged."/>
<filter name="filter_to_be_sent" icon="fa-share"
string="Ready To Send"
domain="[('state', '=', 'to_be_sent')]"
help="These lines are ready to send by email or by letter using the Actions."/>
<filter name="filter_ignored" icon="fa-times"
string="Ignored"
domain="[('state', '=', 'ignored')]"
help="Lines which have been ignored from previous runs."/>
<filter name="filter_sent" icon="fa-paper-plane"
string="Sent" domain="[('state', '=', 'sent')]"
help="Lines already sent."/>
<filter name="filter_error" icon="fa-exclamation-triangle"
string="Error"
domain="[('state', 'in', ('error', 'email_error'))]"
help="An error has occured during the sending of the email."/>
<filter name="filter_manual" icon="fa-hand-paper-o"
string="Manual change"
domain="[('manually_overridden', '=', True)]"
help="The line was deprecated by a manual change of policy on invoice."/>
</group>
<group expand="0" string="Group By" name="group_by">
<filter domain='[]' context="{'group_by': 'date'}"
icon="terp-go-month" string="Run date"/>
<filter domain='[]' context="{'group_by': 'level'}"
icon="terp-gtk-jump-to-rtl" string="Level"/>
<filter domain='[]' context="{'group_by': 'partner_id'}"
icon="terp-partner" string="Partner"/>
<filter domain='[]' context="{'group_by': 'account_id'}"
icon="terp-folder-green" string="Account"/>
<filter domain='[]' context="{'group_by': 'invoice_id'}"
icon="terp-document-new" string="Invoice"/>
<filter domain='[]' context="{'group_by': 'policy_id'}"
icon="terp-document-new" string="Credit policy"/>
<filter domain='[]'
context="{'group_by': 'policy_level_id'}"
icon="terp-document-new"
string="Credit policy level"/>
<filter domain='[]' context="{'group_by': 'channel'}"
icon="terp-document-new" string="Channel"/>
<filter domain='[]'
context="{'group_by': 'manually_overridden'}"
icon="terp-document-new" string="Manual change"/>
</group>
</search>
</field>
</record>
<record id="credit_control_line_tree" model="ir.ui.view">
<field name="name">credit.control.line.tree</field>
<field name="model">credit.control.line</field>
<field name="arch" type="xml">
<tree editable="bottom" string="Control Credit Lines"
colors="green:state == 'sent';red:state in ('error', 'email_error');">
<field name="date"/>
<field name="date_due"/>
<field name="level"/>
<field name="manually_overridden"/>
<field name="state"/>
<field name="channel"/>
<field name="invoice_id"/>
<field name="partner_id"/>
<field name="amount_due"/>
<field name="balance_due"/>
<field name="currency_id"/>
<field name="move_line_id"/>
<field name="account_id"/>
<field name="policy_level_id"/>
<field name="policy_id"/>
<field name="mail_message_id"/>
</tree>
</field>
</record>
<menuitem
name="Credit Control"
parent="account.menu_finance_entries"
id="base_credit_control_menu" sequence="10"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user,account_credit_control.group_account_credit_control_info"/>
<record model="ir.actions.act_window" id="credit_control_line_action">
<field name="name">Credit Control Lines</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">credit.control.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="credit_control_line_tree"/>
<field name="context">{'search_default_filter_draft': 1,
'search_default_filter_to_be_sent': 1}
</field>
<field name="search_view_id" ref="credit_control_line_search"/>
</record>
<menuitem
name="Credit Control Lines"
parent="base_credit_control_menu"
action="credit_control_line_action"
sequence="20"
id="credit_control_line_action_menu"
/>
</odoo>

View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_control_policy_form" model="ir.ui.view">
<field name="name">credit.control.policy.form</field>
<field name="model">credit.control.policy</field>
<field name="arch" type="xml">
<form string="Credit control policy">
<group>
<field name="name"/>
<field name="do_nothing"/>
<field name="company_id"/>
<field name="active"/>
</group>
<notebook colspan="4">
<page string="Policy levels">
<field name="level_ids" nolabel="1" colspan="4">
<tree string="Credit control policy Level">
<field name="name"/>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
<field name="email_template_id"/>
</tree>
<form string="Policy level">
<field name="name"/>
<notebook colspan="4">
<page string="Delay Setting">
<group>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
</group>
</page>
<page string="Mail and reporting">
<group>
<field name="email_template_id"/>
<newline/>
<field name="custom_text"
colspan="4"/>
<newline/>
<field name="custom_mail_text"
colspan="4"/>
</group>
</page>
</notebook>
</form>
</field>
</page>
<page string="Accounts">
<field name="account_ids" nolabel="1"/>
</page>
</notebook>
</form>
</field>
</record>
<record id="credit_control_policy_tree" model="ir.ui.view">
<field name="name">credit.control.policy.tree</field>
<field name="model">credit.control.policy</field>
<field name="arch" type="xml">
<tree string="Credit control policy">
<field name="name"/>
<field name="do_nothing"/>
</tree>
</field>
</record>
<menuitem
name="Credit Control"
parent="account.menu_finance_configuration"
id="base_credit_control_configuration_menu"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"/>
<record model="ir.actions.act_window"
id="credit_policy_configuration_action">
<field name="name">Credit Control Policies</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">credit.control.policy</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="credit_control_policy_tree"/>
</record>
<menuitem
name="Credit Control Policies"
parent="base_credit_control_configuration_menu"
action="credit_policy_configuration_action"
id="credit_policy_configuration_action_menu"/>
<record id="credit_mangement_policy_level_form" model="ir.ui.view">
<field name="name">credit.mangement.policy.level.form</field>
<field name="model">credit.control.policy.level</field>
<field name="arch" type="xml">
<form string="Policy level">
<field name="name"/>
<notebook colspan="4">
<page string="Delay Setting">
<group>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
</group>
</page>
<page string="Mail and reporting">
<group>
<field name="email_template_id"/>
<field name="custom_text"/>
</group>
</page>
</notebook>
</form>
</field>
</record>
<record id="credit_control_policy_level_tree" model="ir.ui.view">
<field name="name">credit.control.policy.level.tree</field>
<field name="model">credit.control.policy.level</field>
<field name="arch" type="xml">
<tree string="Credit control policy level">
<field name="name"/>
<field name="level"/>
<field name="channel"/>
<field name="delay_days"/>
<field name="computation_mode"/>
<field name="email_template_id"/>
</tree>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_control_run_tree" model="ir.ui.view">
<field name="name">credit.control.run.tree</field>
<field name="model">credit.control.run</field>
<field name="arch" type="xml">
<tree string="Credit control run">
<field name="date"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="credit_control_run_form" model="ir.ui.view">
<field name="name">credit.control.run.form</field>
<field name="model">credit.control.run</field>
<field name="arch" type="xml">
<form string="Credit control run">
<header>
<button name="generate_credit_lines"
string="Compute Credit Control Lines"
class="oe_highlight"
type="object" icon="fa-cogs"
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
<button name="open_credit_lines"
string="Open Credit Control Lines"
type="object"
attrs="{'invisible': [('state', '=', 'draft')]}"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,done"
statusbar_colors='{}'/>
</header>
<sheet>
<group>
<field name="date"/>
</group>
<notebook>
<page string="Policies">
<field name="policy_ids" colspan="4" nolabel="1"/>
<separator string="Report"
attrs="{'invisible': [('report', '=', False)]}"/>
<field name="report" colspan="4" nolabel="1"
attrs="{'invisible': [('report', '=', False)]}"/>
</page>
<page string="Manual Lines" groups="base.group_no_one">
<field name="manual_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="credit_control_run">
<field name="name">Credit Control Run</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">credit.control.run</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="credit_control_run_tree"/>
</record>
<menuitem
name="Credit Control Run"
parent="base_credit_control_menu"
action="credit_control_run"
sequence="10"
id="credit_control_run_menu"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"/>
</odoo>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_control_company_form" model="ir.ui.view">
<field name="name">credit.control.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="credit_policy_id" widget="selection"/>
<field name="credit_control_tolerance"/>
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="partner_followup_form_view" model="ir.ui.view">
<field name="name">partner.credit_control.form.view</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="credit" position="after">
<field name="credit_policy_id" widget="selection"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"/>
</field>
</field>
</record>
<act_window
id="act_partner_credit_relation_relation"
name="Credit Lines"
groups="account_credit_control.group_account_credit_control_manager,account_credit_control.group_account_credit_control_user"
domain="[('partner_id', '=', active_id)]"
res_model="credit.control.line"
src_model="res.partner"/>
</odoo>

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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 credit_control_emailer
from . import credit_control_marker
from . import credit_control_printer
from . import credit_control_communication
from . import credit_control_policy_changer

View File

@@ -1,54 +0,0 @@
<openerp>
<data>
<record id="credit_line_emailer_form" model="ir.ui.view">
<field name="name">credit.line.emailer.form</field>
<field name="model">credit.control.emailer</field>
<field name="arch" type="xml">
<form string="Mailer" version="7.0">
<separator string="Send emails for the selected lines" colspan="4"/>
<newline/>
<notebook>
<page string="Lines">
<field name="line_ids" colspan="4" nolabel="1" />
</page>
</notebook>
<newline/>
<footer>
<button class="oe_highlight"
name="email_lines"
string="Send the emails"
type="object"/>
or
<button
class="oe_link"
special="cancel"
string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for menu -->
<act_window name="Send By Email"
res_model="credit.control.emailer"
src_model="credit.control.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="open_credit_line_emailer_wizard_menu_action"/>
<!-- for button -->
<record id="open_credit_line_emailer_wizard" model="ir.actions.act_window">
<field name="name">Send By Email</field>
<field name="res_model">credit.control.emailer</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_line_emailer_form"/>
<field name="target">new</field>
<field name="help">Send an email for the selected lines.</field>
</record>
</data>
</openerp>

View File

@@ -1,60 +0,0 @@
<openerp>
<data>
<record id="credit_line_marker_form" model="ir.ui.view">
<field name="name">credit.line.marker.form</field>
<field name="model">credit.control.marker</field>
<field name="arch" type="xml">
<form string="Lines marker" version="7.0">
<separator string="Change the state of the selected lines" colspan="4"/>
<newline/>
<label string="Warning: you will maybe not be able to revert this operation." colspan="4"></label>
<newline/>
<group>
<group><field name="name"/></group>
<group></group>
</group>
<notebook>
<page string="Lines">
<field name="line_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<newline/>
<footer>
<button
class="oe_highlight"
name="mark_lines"
string="Change Lines' State"
type="object"/>
or
<button
class="oe_link"
special="cancel"
string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for menu -->
<act_window name="Change Lines' State"
res_model="credit.control.marker"
src_model="credit.control.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="open_credit_line_marker_wizard_menu_action"/>
<record id="open_credit_line_marker_wizard" model="ir.actions.act_window">
<field name="name">Change Lines' State</field>
<field name="res_model">credit.control.marker</field>
<field name="src_model">credit.control.line</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_line_marker_form"/>
<field name="target">new</field>
<field name="help">Change the state of the selected lines.</field>
</record>
</data>
</openerp>

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="credit_control_policy_changer_form" model="ir.ui.view">
<field name="name">credit control policy form</field>
<field name="model">credit.control.policy.changer</field>
<field name="arch" type="xml">
<form version="7.0" string="Set current credit level">
<separator string="Change the overdue level of current invoice" colspan="4"/>
<label string="This wizard will let you set the overdue policy and level for selected invoices"/>
<newline/>
<group>
<group>
<field name="new_policy_id"/>
<field name="do_nothing"
invisible="1"/>
<field name="new_policy_level_id"
domain="[('policy_id', '=', new_policy_id)]"/>
</group>
<group></group>
</group>
<notebook colspan="4">
<page string="Move lines to affect">
<field name="move_line_ids"/>
</page>
</notebook>
<footer>
<button class="oe_highlight"
name="set_new_policy"
string="Set new policy"
type="object"/>
or
<button class="oe_link"
special="cancel"
string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for button -->
<record id="action_wizard_credit_policy_changer" model="ir.actions.act_window">
<field name="name">Change current credit policy</field>
<field name="res_model">credit.control.policy.changer</field>
<field name="src_model">account.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_control_policy_changer_form"/>
<field name="target">new</field>
<field name="help">Allows to manually change credit level</field>
</record>
<!-- for menu -->
<act_window name="Change current credit policy"
res_model="credit.control.policy.changer"
src_model="account.invoice"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_wizard_credit_policy_changer_menu_action"/>
</data>
</openerp>

View File

@@ -1,51 +0,0 @@
<openerp>
<data>
<record id="credit_line_printer_form" model="ir.ui.view">
<field name="name">credit.line.printer.form</field>
<field name="model">credit.control.printer</field>
<field name="arch" type="xml">
<form string="Lines report" version="7.0">
<separator string="Print the selected lines" colspan="4"/>
<newline/>
<group>
<field name="mark_as_sent"
colspan="4"/>
</group>
<newline/>
<notebook>
<page string="Lines">
<field name="line_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<footer>
<button class="oe_highlight" name="print_lines" string="Print" type="object"/>
or
<button class="oe_link" special="cancel" string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for menu -->
<act_window name="Print Lines"
res_model="credit.control.printer"
src_model="credit.control.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="open_credit_line_printer_wizard_menu_action"/>
<record id="open_credit_line_printer_wizard" model="ir.actions.act_window">
<field name="name">Print Lines</field>
<field name="res_model">credit.control.printer</field>
<field name="src_model">credit.control.line</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_line_printer_form"/>
<field name="target">new</field>
<field name="help">Print selected lines</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,5 @@
from . import credit_control_emailer
from . import credit_control_marker
from . import credit_control_printer
from . import credit_control_communication
from . import credit_control_policy_changer

View File

@@ -1,27 +1,11 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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/>.
#
##############################################################################
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openerp import models, fields, api
from openerp import api, fields, models
logger = logging.getLogger('credit.control.line.mailing')
logger = logging.getLogger(__name__)
class CreditCommunication(models.TransientModel):
@@ -81,13 +65,14 @@ class CreditCommunication(models.TransientModel):
balance_field = 'credit_control_line_ids.balance_due'
return sum(self.mapped(balance_field))
@api.one
@api.multi
@api.depends('credit_control_line_ids',
'credit_control_line_ids.amount_due',
'credit_control_line_ids.balance_due')
def _compute_total(self):
self.total_invoiced = self._get_total()
self.total_due = self._get_total_due()
for communication in self:
communication.total_invoiced = communication._get_total()
communication.total_due = communication._get_total_due()
@api.model
@api.returns('self', lambda value: value.id)
@@ -176,30 +161,20 @@ class CreditCommunication(models.TransientModel):
@api.returns('mail.mail')
def _generate_emails(self):
""" Generate email message using template related to level """
email_message_obj = self.env['mail.mail']
# Warning: still using the old-api on 'email.template' because
# the method generate_email() does not follow the cr, uid, ids
# convention and the new api wrapper can't translate the call
email_template_obj = self.pool['email.template']
att_obj = self.env['ir.attachment']
emails = email_message_obj.browse()
emails = self.env['mail.mail']
attachments = self.env['ir.attachment']
required_fields = ['subject',
'body_html',
'email_from',
'email_to']
cr, uid, context = self.env.cr, self.env.uid, self.env.context
for comm in self:
template = comm.current_policy_level.email_template_id
email_values = email_template_obj.generate_email(cr, uid,
template.id,
comm.id,
context=context)
email_values['type'] = 'email'
email_values = template.generate_email(comm.id)
# model is Transient record (self) removed periodically so no point
# of storing res_id
email_values.pop('model', None)
email_values.pop('res_id', None)
email = email_message_obj.create(email_values)
email = emails.create(email_values)
state = 'sent'
# The mail will not be send, however it will be in the pool, in an
@@ -213,7 +188,6 @@ class CreditCommunication(models.TransientModel):
comm.credit_control_line_ids.write({'mail_message_id': email.id,
'state': state})
attachments = att_obj.browse()
for att in email_values.get('attachments', []):
attach_fname = att[0]
attach_datas = att[1]
@@ -225,7 +199,7 @@ class CreditCommunication(models.TransientModel):
'res_id': email.id,
'type': 'binary',
}
attachments += att_obj.create(data_attach)
attachments |= attachments.create(data_attach)
email.write({'attachment_ids': [(6, 0, attachments.ids)]})
emails += email
return emails
@@ -242,8 +216,7 @@ class CreditCommunication(models.TransientModel):
@api.multi
@api.returns('credit.control.line')
def _mark_credit_line_as_sent(self):
line_obj = self.env['credit.control.line']
lines = line_obj.browse()
lines = self.env['credit.control.line']
for comm in self:
lines |= comm.credit_control_line_ids

View File

@@ -1,25 +1,10 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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/>.
#
##############################################################################
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp import _, api, fields, models
from openerp.exceptions import UserError
class CreditControlEmailer(models.TransientModel):
@@ -59,7 +44,7 @@ class CreditControlEmailer(models.TransientModel):
def email_lines(self):
self.ensure_one()
if not self.line_ids:
raise api.Warning(_('No credit control lines selected.'))
raise UserError(_('No credit control lines selected.'))
comm_obj = self.env['credit.control.communication']

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_line_emailer_form" model="ir.ui.view">
<field name="name">credit.line.emailer.form</field>
<field name="model">credit.control.emailer</field>
<field name="arch" type="xml">
<form string="Mailer" version="7.0">
<separator string="Send emails for the selected lines"
colspan="4"/>
<newline/>
<notebook>
<page string="Lines">
<field name="line_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<newline/>
<footer>
<button class="oe_highlight"
name="email_lines"
string="Send the emails"
type="object"/>
<button
class="oe_link"
special="cancel"
string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for menu -->
<act_window name="Send By Email"
res_model="credit.control.emailer"
src_model="credit.control.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="open_credit_line_emailer_wizard_menu_action"/>
<!-- for button -->
<record id="open_credit_line_emailer_wizard" model="ir.actions.act_window">
<field name="name">Send By Email</field>
<field name="res_model">credit.control.emailer</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_line_emailer_form"/>
<field name="target">new</field>
<field name="help">Send an email for the selected lines.</field>
</record>
</odoo>

View File

@@ -1,24 +1,9 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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, api, _
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import _, api, fields, models
from openerp.exceptions import UserError
class CreditControlMarker(models.TransientModel):
@@ -71,12 +56,12 @@ class CreditControlMarker(models.TransientModel):
self.ensure_one()
if not self.line_ids:
raise api.Warning(_('No credit control lines selected.'))
raise UserError(_('No credit control lines selected.'))
filtered_lines = self._filter_lines(self.line_ids)
if not filtered_lines:
raise api.Warning(_('No lines will be changed. '
'All the selected lines are already done.'))
raise UserError(_('No lines will be changed. '
'All the selected lines are already done.'))
self._mark_lines(filtered_lines, self.name)

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_line_marker_form" model="ir.ui.view">
<field name="name">credit.line.marker.form</field>
<field name="model">credit.control.marker</field>
<field name="arch" type="xml">
<form string="Lines marker" version="7.0">
<separator string="Change the state of the selected lines"
colspan="4"/>
<newline/>
<label string="Warning: you will maybe not be able to revert this operation." colspan="4"/>
<newline/>
<group>
<group>
<field name="name"/>
</group>
<group/>
</group>
<notebook>
<page string="Lines">
<field name="line_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<newline/>
<footer>
<button
class="oe_highlight"
name="mark_lines"
string="Change Lines' State"
type="object"/>
<button
class="oe_link"
special="cancel"
string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for menu -->
<act_window name="Change Lines' State"
res_model="credit.control.marker"
src_model="credit.control.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="open_credit_line_marker_wizard_menu_action"/>
<record id="open_credit_line_marker_wizard" model="ir.actions.act_window">
<field name="name">Change Lines' State</field>
<field name="res_model">credit.control.marker</field>
<field name="src_model">credit.control.line</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_line_marker_form"/>
<field name="target">new</field>
<field name="help">Change the state of the selected lines.</field>
</record>
</odoo>

View File

@@ -1,29 +1,16 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# 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/>.
#
##############################################################################
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openerp import models, fields, api, _
from openerp import _, api, fields, models
from openerp.exceptions import UserError
logger = logging.getLogger(__name__)
class credit_control_policy_changer(models.TransientModel):
class CreditControlPolicyChanger(models.TransientModel):
""" Wizard that is run from invoices and allows to set manually a policy
Policy are actually apply to related move lines availabe
in selection widget
@@ -52,18 +39,17 @@ class credit_control_policy_changer(models.TransientModel):
context = self.env.context
active_ids = context.get('active_ids')
invoice_obj = self.env['account.invoice']
move_line_obj = self.env['account.move.line']
if not active_ids:
return False
selected_lines = move_line_obj.browse()
selected_lines = self.env['account.move.line']
for invoice in invoice_obj.browse(active_ids):
if invoice.type in ('in_invoice', 'in_refund', 'out_refund'):
raise api.Warning(_('Please use wizard on customer invoices'))
raise UserError(_('Please use wizard on customer invoices'))
domain = [('account_id', '=', invoice.account_id.id),
('move_id', '=', invoice.move_id.id),
('reconcile_id', '=', False)]
move_lines = move_line_obj.search(domain)
('reconciled', '=', False)]
move_lines = selected_lines.search(domain)
selected_lines |= move_lines
return selected_lines
@@ -96,10 +82,7 @@ class credit_control_policy_changer(models.TransientModel):
@api.model
def _set_invoice_policy(self, move_lines, policy):
""" Force policy on invoice """
invoice_obj = self.env['account.invoice']
invoice_ids = set(line.invoice.id for line in move_lines
if line.invoice)
invoices = invoice_obj.browse(invoice_ids)
invoices = move_lines.mapped('invoice_id')
invoices.write({'credit_policy_id': policy.id})
@api.model

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_control_policy_changer_form" model="ir.ui.view">
<field name="name">credit control policy form</field>
<field name="model">credit.control.policy.changer</field>
<field name="arch" type="xml">
<form version="7.0" string="Set current credit level">
<separator string="Change the overdue level of current invoice"
colspan="4"/>
<label string="This wizard will let you set the overdue policy and level for selected invoices"/>
<newline/>
<group>
<group>
<field name="new_policy_id"/>
<field name="do_nothing"
invisible="1"/>
<field name="new_policy_level_id"
domain="[('policy_id', '=', new_policy_id)]"/>
</group>
<group/>
</group>
<notebook colspan="4">
<page string="Move lines to affect">
<field name="move_line_ids"/>
</page>
</notebook>
<footer>
<button class="oe_highlight"
name="set_new_policy"
string="Set new policy"
type="object"/>
<button class="oe_link"
special="cancel"
string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for button -->
<record id="action_wizard_credit_policy_changer"
model="ir.actions.act_window">
<field name="name">Change current credit policy</field>
<field name="res_model">credit.control.policy.changer</field>
<field name="src_model">account.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_control_policy_changer_form"/>
<field name="target">new</field>
<field name="help">Allows to manually change credit level</field>
</record>
<!-- for menu -->
<act_window name="Change current credit policy"
res_model="credit.control.policy.changer"
src_model="account.invoice"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_wizard_credit_policy_changer_menu_action"/>
</odoo>

View File

@@ -1,25 +1,10 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi, Guewen Baconnier
# Copyright 2012-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/>.
#
##############################################################################
# Copyright 2012-2017 Camptocamp SA
# Copyright 2017 Okia SPRL (https://okia.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp import _, api, fields, models
from openerp.exceptions import UserError
class CreditControlPrinter(models.TransientModel):
@@ -57,7 +42,7 @@ class CreditControlPrinter(models.TransientModel):
self.ensure_one()
comm_obj = self.env['credit.control.communication']
if not self.line_ids:
raise api.Warning(_('No credit control lines selected.'))
raise UserError(_('No credit control lines selected.'))
lines = self._get_lines(self.line_ids, self._credit_line_predicate)

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="credit_line_printer_form" model="ir.ui.view">
<field name="name">credit.line.printer.form</field>
<field name="model">credit.control.printer</field>
<field name="arch" type="xml">
<form string="Lines report" version="7.0">
<separator string="Print the selected lines" colspan="4"/>
<newline/>
<group>
<field name="mark_as_sent" colspan="4"/>
</group>
<newline/>
<notebook>
<page string="Lines">
<field name="line_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<footer>
<button class="oe_highlight" name="print_lines"
string="Print" type="object"/>
<button class="oe_link" special="cancel" string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- for menu -->
<act_window name="Print Lines"
res_model="credit.control.printer"
src_model="credit.control.line"
view_mode="form"
target="new"
key2="client_action_multi"
id="open_credit_line_printer_wizard_menu_action"/>
<record id="open_credit_line_printer_wizard" model="ir.actions.act_window">
<field name="name">Print Lines</field>
<field name="res_model">credit.control.printer</field>
<field name="src_model">credit.control.line</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="credit_line_printer_form"/>
<field name="target">new</field>
<field name="help">Print selected lines</field>
</record>
</odoo>