Carlos Dauden
8 years ago
committed by
Pedro M. Baeza
18 changed files with 901 additions and 0 deletions
-
74partner_financial_risk/README.rst
-
4partner_financial_risk/__init__.py
-
22partner_financial_risk/__openerp__.py
-
15partner_financial_risk/data/partner_financial_risk_data.xml
-
321partner_financial_risk/i18n/es.po
-
6partner_financial_risk/models/__init__.py
-
38partner_financial_risk/models/account_invoice.py
-
13partner_financial_risk/models/res_company.py
-
12partner_financial_risk/models/res_config.py
-
150partner_financial_risk/models/res_partner.py
-
3partner_financial_risk/tests/__init__.py
-
79partner_financial_risk/tests/test_partner_financial_risk.py
-
15partner_financial_risk/views/account_invoice_view.xml
-
21partner_financial_risk/views/res_config_view.xml
-
58partner_financial_risk/views/res_partner_view.xml
-
3partner_financial_risk/wizard/__init__.py
-
37partner_financial_risk/wizard/parner_risk_exceeded.py
-
30partner_financial_risk/wizard/partner_risk_exceeded_view.xml
@ -0,0 +1,74 @@ |
|||
.. 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 |
|||
|
|||
====================== |
|||
Partner Financial Risk |
|||
====================== |
|||
|
|||
Adds a new page in partner to manage its *Financial Risk*. |
|||
|
|||
If any limit is exceeded, you won't be able to confirm any of its invoices |
|||
unless you are authorized (Account Adviser group). |
|||
|
|||
Configuration |
|||
============= |
|||
|
|||
To configure this module, you need to: |
|||
|
|||
#. Go to *Invoicing/Accounting > Configuration > Settings > Invoicing & Payments* |
|||
#. In the *Financial Risk* section, fill *Unpaid Margin* for setting the number |
|||
of days to last after the due date to consider an invoice as unpaid. |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
To use this module, you need to: |
|||
|
|||
#. Go to *Invoicing/Accounting > Sales > Customers*. |
|||
#. Select an existing customer or create a new one. |
|||
#. Open the *Financial Risk* tab. |
|||
#. Set limits and choose options to compute in credit limit. |
|||
#. Go to *Invoicing/Accounting > Sales > Customer invoices* and create new |
|||
customer invoices. |
|||
#. Test the restriction trying to create an invoice for the partner for an |
|||
amount higher of the limit you have set. |
|||
|
|||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
|||
:alt: Try me on Runbot |
|||
:target: https://runbot.odoo-community.org/runbot/134/9.0 |
|||
|
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues |
|||
<https://github.com/OCA/partner-contact/issues>`_. In case of trouble, please |
|||
check there if your issue has already been reported. If you spotted it first, |
|||
help us smashing it by providing a detailed and welcomed feedback. |
|||
|
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
* Pedro M. Baeza <pedro.baeza@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. |
@ -0,0 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import models |
|||
from . import wizard |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
{ |
|||
'name': 'Partner Financial Risk', |
|||
'summary': 'Manage partner risk', |
|||
'version': '9.0.1.0.0', |
|||
'category': 'Sales Management', |
|||
'license': 'AGPL-3', |
|||
'author': 'Tecnativa, Odoo Community Association (OCA)', |
|||
'website': 'https://www.tecnativa.com', |
|||
'depends': ['account'], |
|||
'data': [ |
|||
'data/partner_financial_risk_data.xml', |
|||
'views/res_config_view.xml', |
|||
'views/res_partner_view.xml', |
|||
'views/account_invoice_view.xml', |
|||
'wizard/partner_risk_exceeded_view.xml', |
|||
], |
|||
'installable': True, |
|||
} |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl-3). --> |
|||
<odoo> |
|||
<record id="ir_cron_due_invoice_every_day" model="ir.cron"> |
|||
<field name="name">Financial risk: Process due invoices</field> |
|||
<field name="interval_number">1</field> |
|||
<field name="interval_type">days</field> |
|||
<field name="numbercall">-1</field> |
|||
<field name="doall" eval="False"/> |
|||
<field name="model" eval="'res.partner'"/> |
|||
<field name="function" eval="'process_unpaid_invoices'"/> |
|||
<field name="args" eval="'()'"/> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,321 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * partner_financial_risk |
|||
# |
|||
# Translators: |
|||
# Carlos Dauden <carlos.dauden@tecnativa.com>, 2016 |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: partner-contact (9.0)\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2016-09-18 22:47+0000\n" |
|||
"PO-Revision-Date: 2016-09-19 01:14+0100\n" |
|||
"Last-Translator: Carlos Incaser <carlos@incaser.es>\n" |
|||
"Language-Team: Spanish (http://www.transifex.com/oca/OCA-partner-contact-9-0/" |
|||
"language/es/)\n" |
|||
"Language: es\n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: 8bit\n" |
|||
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
|||
"X-Generator: Poedit 1.5.4\n" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.partner_risk_exceeded_wizard |
|||
msgid "Cancel" |
|||
msgstr "Cancelar" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model,name:partner_financial_risk.model_res_company |
|||
msgid "Companies" |
|||
msgstr "Compañías" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.partner_risk_exceeded_wizard |
|||
msgid "Continue" |
|||
msgstr "Continuar" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_continue_method |
|||
msgid "Continue method" |
|||
msgstr "Método continuo" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_create_uid |
|||
msgid "Created by" |
|||
msgstr "Creado por" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_create_date |
|||
msgid "Created on" |
|||
msgstr "Creado en" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_credit_policy |
|||
msgid "Credit policy" |
|||
msgstr "Póliza de crédito" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_partner_id |
|||
msgid "Customer" |
|||
msgstr "Cliente" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_account_config_settings_invoice_unpaid_margin |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_company_invoice_unpaid_margin |
|||
msgid "Days after due date to set an invoice as unpaid" |
|||
msgstr "" |
|||
"Días después de la fecha de vencimiento para considerar una factura como " |
|||
"impagada" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_account_amount |
|||
msgid "Difference between accounting credit and rest of totals" |
|||
msgstr "Diferencia entre el saldo contable y el resto de totales" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_display_name |
|||
msgid "Display Name" |
|||
msgstr "Nombre a mostrar" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_exception_msg |
|||
msgid "Exception msg" |
|||
msgstr "Se ha producido una anomalía" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.res_partner_view_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.view_account_config |
|||
msgid "Financial Risk" |
|||
msgstr "Riesgo financiero" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.view_account_config |
|||
msgid "Financial Risk div" |
|||
msgstr "Riesgo financiero div" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: code:addons/partner_financial_risk/models/account_invoice.py:19 |
|||
#, python-format |
|||
msgid "Financial risk exceeded.\n" |
|||
msgstr "Riesgo financiero excedido.\n" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_account_amount_include |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_draft_include |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_open_include |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_unpaid_include |
|||
msgid "Full risk computation" |
|||
msgstr "Cómputo de riesgo total" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.res_partner_view_risk |
|||
msgid "General Limits" |
|||
msgstr "Límites generales" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_id |
|||
msgid "ID" |
|||
msgstr "ID (identificación)" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_draft_include |
|||
msgid "Include Draft Invoices" |
|||
msgstr "Incluir facturas borrador" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_open_include |
|||
msgid "Include Open Invoices" |
|||
msgstr "Incluir facturas abiertas" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_account_amount_include |
|||
msgid "Include Other Account Amount" |
|||
msgstr "Incluir otros saldos contables" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_unpaid_include |
|||
msgid "Include Unpaid Invoices" |
|||
msgstr "Incluir facturas impagadas" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.res_partner_view_risk |
|||
msgid "Info" |
|||
msgstr "Información" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model,name:partner_financial_risk.model_account_invoice |
|||
msgid "Invoice" |
|||
msgstr "Factura" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_exception |
|||
msgid "It Indicate if partner risk exceeded" |
|||
msgstr "Indica si se ha excedido el riesgo" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz___last_update |
|||
msgid "Last Modified on" |
|||
msgstr "Última modificación en" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_write_uid |
|||
msgid "Last Updated by" |
|||
msgstr "Última actualización de" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_write_date |
|||
msgid "Last Updated on" |
|||
msgstr "Última actualización en" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_draft_limit |
|||
msgid "Limit In Draft Invoices" |
|||
msgstr "Límite en facturas borrador" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_open_limit |
|||
msgid "Limit In Open Invoices" |
|||
msgstr "Límite en facturas abiertas" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_unpaid_limit |
|||
msgid "Limit In Unpaid Invoices" |
|||
msgstr "Límite en facturas impagadas" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_account_amount_limit |
|||
msgid "Limit Other Account Amount" |
|||
msgstr "Límite en otros saldos contables" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_account_config_settings_invoice_unpaid_margin |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_company_invoice_unpaid_margin |
|||
msgid "Maturity Margin" |
|||
msgstr "Margen vencimiento" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_partner_risk_exceeded_wiz_origin_reference |
|||
msgid "Object" |
|||
msgstr "Objeto" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_account_amount |
|||
msgid "Other Account Amount" |
|||
msgstr "Otros saldos contables" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model,name:partner_financial_risk.model_res_partner |
|||
msgid "Partner" |
|||
msgstr "Empresa" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: code:addons/partner_financial_risk/wizard/parner_risk_exceeded.py:25 |
|||
#, python-format |
|||
msgid "Partner risk exceeded" |
|||
msgstr "Empresa con riesgo excedido" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_unpaid |
|||
msgid "" |
|||
"Residual amount of invoices in Open state and the date due is exceeded, " |
|||
"considering Unpaid Margin set in account settings" |
|||
msgstr "" |
|||
"Importe pendiente en facturas abiertas cuya fecha de vencimiento se ha " |
|||
"excedido, considerando el margen de días establecido en configuración de " |
|||
"contabilidad" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_open |
|||
msgid "" |
|||
"Residual amount of invoices in Open state and the date due is not exceeded, " |
|||
"considering Due Margin set in account settings" |
|||
msgstr "" |
|||
"Importe pendiente en facturas abiertas cuya fecha de vencimiento no se ha " |
|||
"excedido, considerando el margen de días establecido en configuración de " |
|||
"contabilidad" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_exception |
|||
msgid "Risk Exception" |
|||
msgstr "Excepción por riesgo" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_allow_edit |
|||
msgid "Risk allow edit" |
|||
msgstr "Permitir editar riesgo" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.partner_risk_exceeded_wizard |
|||
msgid "Risk exceeded" |
|||
msgstr "Riesgo excedido" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_account_amount_limit |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_draft_limit |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_open_limit |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_unpaid_limit |
|||
msgid "Set 0 if it is not locked" |
|||
msgstr "Establece 0 si no está bloqueado" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.res_partner_view_risk |
|||
msgid "Specific Limits" |
|||
msgstr "Límites específicos" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_total |
|||
msgid "Sum of total risk included" |
|||
msgstr "Suma de riesgo total incluido" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.ui.view,arch_db:partner_financial_risk.partner_risk_exceeded_wizard |
|||
msgid "The partner has exceeded his risk" |
|||
msgstr "La empresa ha excedido su riesgo" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: code:addons/partner_financial_risk/models/account_invoice.py:28 |
|||
#, python-format |
|||
msgid "This invoice exceeds the financial risk.\n" |
|||
msgstr "Esta factura excede el riesgo financiero.\n" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: code:addons/partner_financial_risk/models/account_invoice.py:23 |
|||
#, python-format |
|||
msgid "This invoice exceeds the open invoices risk.\n" |
|||
msgstr "Esta factura excede el riesgo de facturas abiertas.\n" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_draft |
|||
msgid "Total Draft Invoices" |
|||
msgstr "Total facturas borrador" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_open |
|||
msgid "Total Open Invoices" |
|||
msgstr "Total facturas borrador abiertas" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_total |
|||
msgid "Total Risk" |
|||
msgstr "Riesgo total" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,field_description:partner_financial_risk.field_res_partner_risk_invoice_unpaid |
|||
msgid "Total Unpaid Invoices" |
|||
msgstr "Total facturas impagadas" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model.fields,help:partner_financial_risk.field_res_partner_risk_invoice_draft |
|||
msgid "Total amount of invoices in Draft or Pro-forma state" |
|||
msgstr "Importe total de facturas borrador o pro-forma" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model,name:partner_financial_risk.model_account_config_settings |
|||
msgid "account.config.settings" |
|||
msgstr "" |
|||
|
|||
#. module: partner_financial_risk |
|||
#: model:ir.model,name:partner_financial_risk.model_partner_risk_exceeded_wiz |
|||
msgid "partner.risk.exceeded.wiz" |
|||
msgstr "" |
@ -0,0 +1,6 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import account_invoice |
|||
from . import res_company |
|||
from . import res_config |
|||
from . import res_partner |
@ -0,0 +1,38 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp import api, models, _ |
|||
|
|||
|
|||
class AccountInvoice(models.Model): |
|||
_inherit = 'account.invoice' |
|||
|
|||
@api.multi |
|||
def invoice_open(self): |
|||
if self.env.context.get('bypass_risk', False): |
|||
return self.signal_workflow('invoice_open') |
|||
for invoice in self: |
|||
partner = invoice.partner_id |
|||
exception_msg = "" |
|||
if partner.risk_exception: |
|||
exception_msg = _("Financial risk exceeded.\n") |
|||
elif partner.risk_invoice_open_limit and ( |
|||
(partner.risk_invoice_open + invoice.amount_total) > |
|||
partner.risk_invoice_open_limit): |
|||
exception_msg = _( |
|||
"This invoice exceeds the open invoices risk.\n") |
|||
elif partner.risk_invoice_open_include and ( |
|||
(partner.risk_total + invoice.amount_total) > |
|||
partner.credit_limit): |
|||
exception_msg = _( |
|||
"This invoice exceeds the financial risk.\n") |
|||
if exception_msg: |
|||
return self.env['partner.risk.exceeded.wiz'].create({ |
|||
'exception_msg': exception_msg, |
|||
'partner_id': partner.id, |
|||
'origin_reference': |
|||
'%s,%s' % (self._model, invoice.id), |
|||
'continue_method': 'invoice_open', |
|||
}).action_show() |
|||
return self.signal_workflow('invoice_open') |
@ -0,0 +1,13 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp import fields, models |
|||
|
|||
|
|||
class ResCompany(models.Model): |
|||
_inherit = 'res.company' |
|||
|
|||
invoice_unpaid_margin = fields.Integer( |
|||
string="Maturity Margin", |
|||
help="Days after due date to set an invoice as unpaid") |
@ -0,0 +1,12 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp import fields, models |
|||
|
|||
|
|||
class AccountConfigSettings(models.TransientModel): |
|||
_inherit = 'account.config.settings' |
|||
|
|||
invoice_unpaid_margin = fields.Integer( |
|||
related='company_id.invoice_unpaid_margin') |
@ -0,0 +1,150 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from datetime import datetime |
|||
from dateutil.relativedelta import relativedelta |
|||
from openerp import api, fields, models |
|||
|
|||
|
|||
class ResPartner(models.Model): |
|||
_inherit = 'res.partner' |
|||
|
|||
risk_invoice_draft_include = fields.Boolean( |
|||
string='Include Draft Invoices', help='Full risk computation') |
|||
risk_invoice_draft_limit = fields.Monetary( |
|||
string='Limit In Draft Invoices', help='Set 0 if it is not locked') |
|||
risk_invoice_draft = fields.Monetary( |
|||
compute='_compute_risk_invoice', store=True, |
|||
string='Total Draft Invoices', |
|||
help='Total amount of invoices in Draft or Pro-forma state') |
|||
risk_invoice_open_include = fields.Boolean( |
|||
string='Include Open Invoices', help='Full risk computation') |
|||
risk_invoice_open_limit = fields.Monetary( |
|||
string='Limit In Open Invoices', help='Set 0 if it is not locked') |
|||
risk_invoice_open = fields.Monetary( |
|||
compute='_compute_risk_invoice', store=True, |
|||
string='Total Open Invoices', |
|||
help='Residual amount of invoices in Open state and the date due is ' |
|||
'not exceeded, considering Due Margin set in account ' |
|||
'settings') |
|||
risk_invoice_unpaid_include = fields.Boolean( |
|||
string='Include Unpaid Invoices', help='Full risk computation') |
|||
risk_invoice_unpaid_limit = fields.Monetary( |
|||
string='Limit In Unpaid Invoices', help='Set 0 if it is not locked') |
|||
risk_invoice_unpaid = fields.Monetary( |
|||
compute='_compute_risk_invoice', store=True, |
|||
string='Total Unpaid Invoices', |
|||
help='Residual amount of invoices in Open state and the date due is ' |
|||
'exceeded, considering Unpaid Margin set in account settings') |
|||
|
|||
risk_account_amount_include = fields.Boolean( |
|||
string='Include Other Account Amount', help='Full risk computation') |
|||
risk_account_amount_limit = fields.Monetary( |
|||
string='Limit Other Account Amount', help='Set 0 if it is not locked') |
|||
risk_account_amount = fields.Monetary( |
|||
compute='_compute_risk_account_amount', |
|||
string='Other Account Amount', |
|||
help='Difference between accounting credit and rest of totals') |
|||
|
|||
risk_total = fields.Monetary( |
|||
compute='_compute_risk_exception', |
|||
string='Total Risk', help='Sum of total risk included') |
|||
risk_exception = fields.Boolean( |
|||
compute='_compute_risk_exception', |
|||
string='Risk Exception', |
|||
help='It Indicate if partner risk exceeded') |
|||
credit_policy = fields.Char() |
|||
risk_allow_edit = fields.Boolean(compute='_compute_risk_allow_edit') |
|||
|
|||
@api.multi |
|||
def _compute_risk_allow_edit(self): |
|||
is_editable = self.env.user.has_group( |
|||
'base.group_sale_manager') or self.env.user.has_group( |
|||
'account.group_account_manager') |
|||
for partner in self: |
|||
partner.risk_allow_edit = is_editable |
|||
|
|||
@api.multi |
|||
@api.depends('invoice_ids', 'invoice_ids.state', |
|||
'invoice_ids.amount_total', 'invoice_ids.residual', |
|||
'invoice_ids.company_id.invoice_unpaid_margin') |
|||
def _compute_risk_invoice(self): |
|||
max_date = self._max_risk_date_due() |
|||
for partner in self: |
|||
invoices_out = partner.invoice_ids.filtered( |
|||
lambda x: x.type == 'out_invoice') |
|||
invoices = invoices_out.filtered( |
|||
lambda x: x.state in ['draft', 'proforma', 'proforma2']) |
|||
partner.risk_invoice_draft = sum(invoices.mapped('amount_total')) |
|||
invoices = invoices_out.filtered( |
|||
lambda x: x.state == 'open' and x.date_due >= max_date) |
|||
partner.risk_invoice_open = sum(invoices.mapped('residual')) |
|||
invoices = invoices_out.filtered( |
|||
lambda x: x.state == 'open' and x.date_due < max_date) |
|||
partner.risk_invoice_unpaid = sum(invoices.mapped('residual')) |
|||
|
|||
@api.multi |
|||
@api.depends('credit', 'risk_invoice_open', 'risk_invoice_unpaid') |
|||
def _compute_risk_account_amount(self): |
|||
for partner in self: |
|||
partner.risk_account_amount = ( |
|||
partner.credit - partner.risk_invoice_open - |
|||
partner.risk_invoice_unpaid) |
|||
|
|||
@api.multi |
|||
@api.depends(lambda x: x._get_depends_compute_risk_exception()) |
|||
def _compute_risk_exception(self): |
|||
risk_field_list = self._risk_field_list() |
|||
for partner in self: |
|||
amount = 0.0 |
|||
for risk_field in risk_field_list: |
|||
field_value = getattr(partner, risk_field[0], 0.0) |
|||
max_value = getattr(partner, risk_field[1], 0.0) |
|||
if max_value and field_value > max_value: |
|||
partner.risk_exception = True |
|||
if getattr(partner, risk_field[2], False): |
|||
amount += field_value |
|||
partner.risk_total = amount |
|||
if amount > partner.credit_limit: |
|||
partner.risk_exception = True |
|||
|
|||
@api.model |
|||
def _max_risk_date_due(self): |
|||
return fields.Date.to_string(datetime.today().date() - relativedelta( |
|||
days=self.env.user.company_id.invoice_unpaid_margin)) |
|||
|
|||
@api.model |
|||
def _risk_field_list(self): |
|||
return [ |
|||
('risk_invoice_draft', 'risk_invoice_draft_limit', |
|||
'risk_invoice_draft_include'), |
|||
('risk_invoice_open', 'risk_invoice_open_limit', |
|||
'risk_invoice_open_include'), |
|||
('risk_invoice_unpaid', 'risk_invoice_unpaid_limit', |
|||
'risk_invoice_unpaid_include'), |
|||
('risk_account_amount', 'risk_account_amount_limit', |
|||
'risk_account_amount_include'), |
|||
] |
|||
|
|||
@api.model |
|||
def _get_depends_compute_risk_exception(self): |
|||
# TODO: Improve code without performance loss |
|||
tuple_list = self._risk_field_list() |
|||
res = [x[0] for x in tuple_list] |
|||
res.extend([x[1] for x in tuple_list]) |
|||
res.extend([x[2] for x in tuple_list]) |
|||
res.append('credit_limit') |
|||
return res |
|||
|
|||
@api.model |
|||
def process_unpaid_invoices(self): |
|||
today = fields.Date.today() |
|||
ConfigParameter = self.env['ir.config_parameter'] |
|||
last_check = ConfigParameter.get_param( |
|||
'partner_financial_risk.last_check', default='2016-01-01') |
|||
invoices = self.env['account.invoice'].search([ |
|||
('date_due', '>=', last_check), ('date_due', '<', today)]) |
|||
invoices.mapped('partner_id')._compute_risk_invoice() |
|||
ConfigParameter.set_param('partner_financial_risk.last_check', today) |
|||
return True |
@ -0,0 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import test_partner_financial_risk |
@ -0,0 +1,79 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp.tests.common import TransactionCase |
|||
from openerp import fields |
|||
|
|||
|
|||
class TestPartnerFinancialRisk(TransactionCase): |
|||
def setUp(self): |
|||
super(TestPartnerFinancialRisk, self).setUp() |
|||
self.env.user.groups_id |= self.env.ref('base.group_sale_manager') |
|||
self.partner = self.env['res.partner'].create({ |
|||
'name': 'Partner test', |
|||
'customer': True, |
|||
}) |
|||
self.journal = self.env['account.journal'].create({ |
|||
'type': 'sale', |
|||
'name': 'Test Sales', |
|||
'code': 'TSALE', |
|||
}) |
|||
self.prod_account = self.env.ref('account.demo_coffee_machine_account') |
|||
self.inv_account = self.env.ref('account.demo_sale_of_land_account') |
|||
self.invoice = self.env['account.invoice'].create({ |
|||
'journal_id': self.journal.id, |
|||
'company_id': self.env.user.company_id.id, |
|||
'currency_id': self.env.user.company_id.currency_id.id, |
|||
'partner_id': self.partner.id, |
|||
'invoice_line_ids': [(0, 0, { |
|||
'account_id': self.prod_account.id, |
|||
'name': 'Test line', |
|||
'price_unit': 50, |
|||
'quantity': 10, |
|||
})] |
|||
}) |
|||
|
|||
def test_invoices(self): |
|||
self.partner.risk_invoice_draft_include = True |
|||
self.assertAlmostEqual(self.partner.risk_invoice_draft, 500.0) |
|||
self.assertAlmostEqual(self.partner.risk_total, 500.0) |
|||
self.invoice.signal_workflow('invoice_open') |
|||
self.assertAlmostEqual(self.partner.risk_invoice_draft, 0.0) |
|||
self.assertFalse(self.invoice.date_due) |
|||
self.partner.risk_invoice_unpaid_include = True |
|||
self.assertAlmostEqual(self.partner.risk_total, 500.0) |
|||
self.partner.credit_limit = 100.0 |
|||
self.assertTrue(self.partner.risk_exception) |
|||
self.partner.credit_limit = 1000.0 |
|||
self.assertFalse(self.partner.risk_exception) |
|||
self.partner.risk_invoice_unpaid_limit = 499.0 |
|||
self.assertTrue(self.partner.risk_exception) |
|||
invoice2 = self.invoice.copy() |
|||
wiz_dic = invoice2.invoice_open() |
|||
wiz = self.env[wiz_dic['res_model']].browse(wiz_dic['res_id']) |
|||
self.assertEqual(wiz.exception_msg, "Financial risk exceeded.\n") |
|||
self.partner.risk_invoice_unpaid_limit = 0.0 |
|||
self.assertFalse(self.partner.risk_exception) |
|||
self.partner.risk_invoice_open_limit = 300.0 |
|||
invoice2.date_due = fields.Date.today() |
|||
wiz_dic = invoice2.invoice_open() |
|||
wiz = self.env[wiz_dic['res_model']].browse(wiz_dic['res_id']) |
|||
self.assertEqual(wiz.exception_msg, |
|||
"This invoice exceeds the open invoices risk.\n") |
|||
self.partner.risk_invoice_open_limit = 0.0 |
|||
self.partner.risk_invoice_draft_include = False |
|||
self.partner.risk_invoice_open_include = True |
|||
self.partner.credit_limit = 900.0 |
|||
wiz_dic = invoice2.invoice_open() |
|||
wiz = self.env[wiz_dic['res_model']].browse(wiz_dic['res_id']) |
|||
self.assertEqual(wiz.exception_msg, |
|||
"This invoice exceeds the financial risk.\n") |
|||
self.assertAlmostEqual(self.partner.risk_invoice_open, 0.0) |
|||
wiz.button_continue() |
|||
self.assertAlmostEqual(self.partner.risk_invoice_open, 500.0) |
|||
self.assertTrue(self.partner.risk_allow_edit) |
|||
self.partner.process_unpaid_invoices() |
|||
self.assertEqual(self.env['ir.config_parameter'].get_param( |
|||
'partner_financial_risk.last_check'), |
|||
fields.Date.today()) |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl-3). --> |
|||
<odoo> |
|||
<record id="invoice_partner_risk_form" model="ir.ui.view"> |
|||
<field name="name">account.invoice.partner.risk.form</field> |
|||
<field name="model">account.invoice</field> |
|||
<field name="inherit_id" ref="account.invoice_form"/> |
|||
<field name="arch" type="xml"> |
|||
<button name="invoice_open" position="attributes"> |
|||
<attribute name="type">object</attribute> |
|||
</button> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,21 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl-3). --> |
|||
<odoo> |
|||
|
|||
<record id="view_account_config" model="ir.ui.view"> |
|||
<field name="name">account settings</field> |
|||
<field name="model">account.config.settings</field> |
|||
<field name="inherit_id" ref="account.view_account_config_settings"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//div[@name='payment_acquirer']/.." position="after"> |
|||
<label for="id" string="Financial Risk"/> |
|||
<div name="financial_risk" string="Financial Risk div"> |
|||
<label for="invoice_unpaid_margin"/> |
|||
<field name="invoice_unpaid_margin" class="oe_inline"/> |
|||
</div> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
|
|||
</odoo> |
@ -0,0 +1,58 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl-3). --> |
|||
<odoo> |
|||
<record id="res_partner_view_risk" model="ir.ui.view"> |
|||
<field name="name">res.partner.view.risk</field> |
|||
<field name="model">res.partner</field> |
|||
<field name="inherit_id" ref="base.view_partner_form" /> |
|||
<field name="priority" eval="20"/> |
|||
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman')), (4, ref('account.group_account_manager'))]"/> |
|||
<field name="arch" type="xml"> |
|||
<page name="sales_purchases" position="after"> |
|||
<page name="financial_risk" string="Financial Risk" attrs="{'invisible': [('customer','=',False)]}"> |
|||
<group name="risk_general" col="3"> |
|||
<group string="General Limits" name="risk_include" col="1" colspan="2"> |
|||
<group col="3" class="oe_subtotal_footer"> |
|||
<field name="risk_invoice_draft_include" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_invoice_draft" nolabel="1"/> |
|||
<field name="risk_invoice_open_include" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_invoice_open" nolabel="1"/> |
|||
<field name="risk_invoice_unpaid_include" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_invoice_unpaid" nolabel="1"/> |
|||
<field name="risk_account_amount_include" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_account_amount" nolabel="1"/> |
|||
<field name="risk_total" colspan="3" class="oe_subtotal_footer_separator"/> |
|||
</group> |
|||
</group> |
|||
<group string="Specific Limits" name="risk_limits" col="1"> |
|||
<group class="oe_subtotal_footer"> |
|||
<field name="risk_invoice_draft_limit" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_invoice_open_limit" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_invoice_unpaid_limit" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_account_amount_limit" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_allow_edit" invisible="1"/> |
|||
</group> |
|||
</group> |
|||
</group> |
|||
<group string="Info" col="4"> |
|||
<field name="credit_limit" |
|||
widget="monetary" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="credit_policy" |
|||
attrs="{'readonly': [('risk_allow_edit', '=', False)]}"/> |
|||
<field name="risk_exception"/> |
|||
</group> |
|||
</page> |
|||
</page> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import parner_risk_exceeded |
@ -0,0 +1,37 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp import api, fields, models, _ |
|||
|
|||
|
|||
class PartnerRiskExceededWiz(models.TransientModel): |
|||
_name = 'partner.risk.exceeded.wiz' |
|||
|
|||
partner_id = fields.Many2one( |
|||
comodel_name='res.partner', readonly=True, string='Customer') |
|||
exception_msg = fields.Text(readonly=True) |
|||
origin_reference = fields.Reference( |
|||
lambda self: [ |
|||
(m.model, m.name) for m in self.env['ir.model'].search([])], |
|||
string='Object') |
|||
continue_method = fields.Char() |
|||
|
|||
@api.multi |
|||
def action_show(self): |
|||
self.ensure_one() |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': _('Partner risk exceeded'), |
|||
'res_model': self._name, |
|||
'res_id': self.id, |
|||
'view_type': 'form', |
|||
'view_mode': 'form', |
|||
'target': 'new', |
|||
} |
|||
|
|||
@api.multi |
|||
def button_continue(self): |
|||
self.ensure_one() |
|||
return getattr(self.origin_reference.with_context( |
|||
bypass_risk=True), self.continue_method)() |
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- © 2016 Carlos Dauden <carlos.dauden@tecnativa.com> |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl-3). --> |
|||
<odoo> |
|||
<record id="partner_risk_exceeded_wizard" model="ir.ui.view"> |
|||
<field name="name">Partner risk exceeded</field> |
|||
<field name="model">partner.risk.exceeded.wiz</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Risk exceeded"> |
|||
<p>The partner has exceeded his risk</p> |
|||
<field name="exception_msg" colspan="2" nolabel="1"/> |
|||
<group> |
|||
<field name="partner_id"/> |
|||
</group> |
|||
<footer> |
|||
<button string="Continue" |
|||
class="oe_highlight" |
|||
name="button_continue" |
|||
type="object" |
|||
groups="base.group_sale_manager,account.group_account_manager" |
|||
/> |
|||
<button string="Cancel" |
|||
class="oe_link" |
|||
special="cancel" |
|||
/> |
|||
</footer> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue