Browse Source

[ADD] partner_financial_risk (#292)

pull/322/head
Carlos Dauden 8 years ago
committed by Pedro M. Baeza
parent
commit
2daa106a48
  1. 74
      partner_financial_risk/README.rst
  2. 4
      partner_financial_risk/__init__.py
  3. 22
      partner_financial_risk/__openerp__.py
  4. 15
      partner_financial_risk/data/partner_financial_risk_data.xml
  5. 321
      partner_financial_risk/i18n/es.po
  6. 6
      partner_financial_risk/models/__init__.py
  7. 38
      partner_financial_risk/models/account_invoice.py
  8. 13
      partner_financial_risk/models/res_company.py
  9. 12
      partner_financial_risk/models/res_config.py
  10. 150
      partner_financial_risk/models/res_partner.py
  11. 3
      partner_financial_risk/tests/__init__.py
  12. 79
      partner_financial_risk/tests/test_partner_financial_risk.py
  13. 15
      partner_financial_risk/views/account_invoice_view.xml
  14. 21
      partner_financial_risk/views/res_config_view.xml
  15. 58
      partner_financial_risk/views/res_partner_view.xml
  16. 3
      partner_financial_risk/wizard/__init__.py
  17. 37
      partner_financial_risk/wizard/parner_risk_exceeded.py
  18. 30
      partner_financial_risk/wizard/partner_risk_exceeded_view.xml

74
partner_financial_risk/README.rst

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

4
partner_financial_risk/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import models
from . import wizard

22
partner_financial_risk/__openerp__.py

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

15
partner_financial_risk/data/partner_financial_risk_data.xml

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

321
partner_financial_risk/i18n/es.po

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

6
partner_financial_risk/models/__init__.py

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from . import account_invoice
from . import res_company
from . import res_config
from . import res_partner

38
partner_financial_risk/models/account_invoice.py

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

13
partner_financial_risk/models/res_company.py

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

12
partner_financial_risk/models/res_config.py

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

150
partner_financial_risk/models/res_partner.py

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

3
partner_financial_risk/tests/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import test_partner_financial_risk

79
partner_financial_risk/tests/test_partner_financial_risk.py

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

15
partner_financial_risk/views/account_invoice_view.xml

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

21
partner_financial_risk/views/res_config_view.xml

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

58
partner_financial_risk/views/res_partner_view.xml

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

3
partner_financial_risk/wizard/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import parner_risk_exceeded

37
partner_financial_risk/wizard/parner_risk_exceeded.py

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

30
partner_financial_risk/wizard/partner_risk_exceeded_view.xml

@ -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>
Loading…
Cancel
Save