Browse Source

Merge pull request #103 from savoirfairelinux/partner_relations

Partner relations Port to v8
pull/123/head
Holger Brunn 9 years ago
parent
commit
302da894ae
  1. 89
      partner_relations/README.rst
  2. 21
      partner_relations/__init__.py
  3. 51
      partner_relations/__openerp__.py
  4. 38
      partner_relations/data/demo.xml
  5. 379
      partner_relations/i18n/es.po
  6. 383
      partner_relations/i18n/fr.po
  7. 291
      partner_relations/i18n/nl.po
  8. 376
      partner_relations/i18n/partner_relations.pot
  9. 39
      partner_relations/model/__init__.py
  10. 320
      partner_relations/model/res_partner.py
  11. 366
      partner_relations/model/res_partner_relation.py
  12. 212
      partner_relations/model/res_partner_relation_all.py
  13. 66
      partner_relations/model/res_partner_relation_type.py
  14. 175
      partner_relations/model/res_partner_relation_type_selection.py
  15. 7
      partner_relations/security/ir.model.access.csv
  16. BIN
      partner_relations/static/src/img/icon.png
  17. 25
      partner_relations/view/menu.xml
  18. 53
      partner_relations/view/res_partner.xml
  19. 97
      partner_relations/view/res_partner_relation.xml
  20. 92
      partner_relations/view/res_partner_relation_all.xml
  21. 44
      partner_relations/view/res_partner_relation_type.xml

89
partner_relations/README.rst

@ -0,0 +1,89 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License
Partner Relations
=================
This module aims to provide generic means to model relations between partners.
Examples would be 'is sibling of' or 'is friend of', but also 'has contract X
with' or 'is assistant of'. This way, you can encode your knowledge about your
partners directly in your partner list.
Installation
============
Configuration
=============
Usage
=====
Before being able to use relations, you'll have define some first. Do that in
Sales / Configuration / Address Book / Partner relations. Here, you need to
name both sides of the relation: To have an assistant-relation, you would name
one side 'is assistant of' and the other side 'has assistant'. This relation
only makes sense between people, so you would choose 'Person' for both partner
types. For the relation 'is a competitor of', both sides would be companies,
while the relation 'has worked for' should have persons on the left side and
companies on the right side. If you leave this field empty, the relation is
applicable to all types of partners.
If you use categories to further specify the type of partners, you could for
example enforce that the 'is member of' relation can only have companies with
label 'Organization' on the left side.
Now open a partner and choose relations as appropriate in the 'Relations' tab.
Searching partners with relations
---------------------------------
Searching for relations is integrated transparently into the partner search
form. To find all assistants in your database, fill in 'is assistant of' and
autocomplete will propose to search for partners having this relation. Now if
you want to find Anna's assistant, you fill in 'Anna' and one of the proposals
is to search for partners having a relation with Anna. This results in Anna's
assistant(s), as you searched for assistants before.
By default, only active, not expired relations are shown. If you need to find
partners that had some relation at a certain date, fill in that date in the
search box and one of the proposals is to search for relations valid at that
date.
More info
---------
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap
======================
Credits
=======
Contributors
------------
* Holger Brunn <hbrunn@therp.nl>
* Stefan Rijnhart <stefan@therp.nl>
* Ronald Portier <ronald@therp.nl>
* Sandy Carter <sandy.carter@savoirfairelinux.com>
* Bruno Joliveau <bruno.joliveau@savoirfairelinux.com>
* Adriana Ierfino <adriana.ierfino@savoirfairelinux.com>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://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 http://odoo-community.org.

21
partner_relations/__init__.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import model

51
partner_relations/__openerp__.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# 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": "Partner relations",
"version": "1.1",
"author": "Therp BV,Odoo Community Association (OCA)",
"complexity": "normal",
"category": "Customer Relationship Management",
"depends": [
],
"demo": [
"data/demo.xml",
],
"data": [
"view/res_partner_relation_all.xml",
'view/res_partner_relation.xml',
'view/res_partner.xml',
'view/res_partner_relation_type.xml',
'view/menu.xml',
'security/ir.model.access.csv',
],
"js": [
],
"css": [
],
"qweb": [
],
"auto_install": False,
"installable": True,
"external_dependencies": {
'python': [],
},
}

38
partner_relations/data/demo.xml

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="rel_type_assistant" model="res.partner.relation.type">
<field name="name">Is assistant of</field>
<field name="name_inverse">Has assistant</field>
<field name="contact_type_left">p</field>
<field name="contact_type_right">p</field>
</record>
<record id="rel_type_competitor" model="res.partner.relation.type">
<field name="name">Is competitor of</field>
<field name="name_inverse">Is competitor of</field>
<field name="contact_type_left">c</field>
<field name="contact_type_right">c</field>
</record>
<record id="rel_type_has_worked_for" model="res.partner.relation.type">
<field name="name">Has worked for</field>
<field name="name_inverse">Has former employee</field>
<field name="contact_type_left">p</field>
<field name="contact_type_right">c</field>
</record>
<record id="rel_1" model="res.partner.relation">
<field name="left_partner_id" ref="base.res_partner_12" />
<field name="right_partner_id" ref="base.res_partner_23" />
<field name="type_id" ref="rel_type_competitor" />
</record>
<record id="rel_2" model="res.partner.relation">
<field name="left_partner_id" ref="base.res_partner_13" />
<field name="right_partner_id" ref="base.res_partner_23" />
<field name="type_id" ref="rel_type_competitor" />
</record>
<record id="rel_3" model="res.partner.relation">
<field name="left_partner_id" ref="base.res_partner_12" />
<field name="right_partner_id" ref="base.res_partner_13" />
<field name="type_id" ref="rel_type_competitor" />
</record>
</data>
</openerp>

379
partner_relations/i18n/es.po

@ -0,0 +1,379 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_relations
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-15 16:13+0000\n"
"PO-Revision-Date: 2015-04-15 16:13+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_relations
#: model:ir.actions.act_window,help:partner_relations.action_res_partner_relation
#: model:ir.actions.act_window,help:partner_relations.action_res_partner_relation_all
msgid "<p class=\"oe_view_nocontent_create\">\n"
" Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.\n"
" </p>\n"
" "
msgstr "<p class=\"oe_view_nocontent_create\">\n"
" Registro y seguimiento de las relaciones de sus empresas. Las relaciones pueden estar vinculadas a otras empresas con un tipo de relación directa o inversamente.\n"
" </p>\n"
" "
#. module: partner_relations
#: field:res.partner.relation,active:0
#: field:res.partner.relation.all,active:0
msgid "Active"
msgstr "Activo"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr "Todas (no-inversas + inversas) las relaciones entre empresas"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr "Todos los tipos de relaciones"
#. module: partner_relations
#: field:res.partner,relation_all_ids:0
msgid "All relations with current partner"
msgstr "Todas las relaciones con la empresa actual"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation_type.py:64
#, python-format
msgid "Company"
msgstr "Empresa"
#. module: partner_relations
#: field:res.partner.relation,create_uid:0
#: field:res.partner.relation.type,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: partner_relations
#: field:res.partner.relation,create_date:0
#: field:res.partner.relation.type,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: partner_relations
#: field:res.partner.relation.all,this_partner_id:0
msgid "Current Partner"
msgstr "Empresa actual"
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_this:0
#: field:res.partner.relation.type.selection,search_partner_category_this:0
msgid "Current record's category"
msgstr "Etiqueta del registro actual"
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_this:0
msgid "Current record's partner type"
msgstr "Tipo de empresa del registro actual"
#. module: partner_relations
#: field:res.partner.relation,right_partner_id:0
msgid "Destination Partner"
msgstr "Empresa destino"
#. module: partner_relations
#: field:res.partner.relation,date_end:0
#: field:res.partner.relation.all,date_end:0
msgid "Ending date"
msgstr "Fecha fin"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Group By"
msgstr "Agrupar por"
#. module: partner_relations
#: field:res.partner,search_relation_id:0
msgid "Has relation of type"
msgstr "Tiene una relación de tipo"
#. module: partner_relations
#: field:res.partner,search_relation_partner_id:0
msgid "Has relation with"
msgstr "Tiene una relación con"
#. module: partner_relations
#: field:res.partner,search_relation_partner_category_id:0
msgid "Has relation with a partner in category"
msgstr "Tiene una relación con las empresas con la etiqueta"
#. module: partner_relations
#: field:res.partner.relation,id:0
#: field:res.partner.relation.all,id:0
#: field:res.partner.relation.type,id:0
#: field:res.partner.relation.type.selection,id:0
msgid "ID"
msgstr "ID"
#. module: partner_relations
#: field:res.partner.relation.type,name_inverse:0
msgid "Inverse name"
msgstr "Nombre inverso"
#. module: partner_relations
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
msgid "Inverse type"
msgstr "Tipo inverso"
#. module: partner_relations
#: field:res.partner.relation,write_uid:0
#: field:res.partner.relation.type,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: partner_relations
#: field:res.partner.relation,write_date:0
#: field:res.partner.relation.type,write_date:0
msgid "Last Updated on"
msgstr "Última actualización en"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
msgid "Left Partner"
msgstr "Empresa izquierda"
#. module: partner_relations
#: field:res.partner.relation,left_contact_type:0
msgid "Left Partner Type"
msgstr "Tipo de empresa izquierda"
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_left:0
msgid "Left partner category"
msgstr "Etiqueta empresa izquierda"
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_left:0
msgid "Left partner type"
msgstr "Tipo de empresa izquierda"
#. module: partner_relations
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
msgid "Left side of relation"
msgstr "Lado izquierdo de la relación"
#. module: partner_relations
#: field:res.partner.relation.type,name:0
#: field:res.partner.relation.type.selection,name:0
msgid "Name"
msgstr "Nombre"
#. module: partner_relations
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
#: field:res.partner.relation.all,other_partner_id:0
msgid "Other Partner"
msgstr "Otra empresa"
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_other:0
msgid "Other record's category"
msgstr "Etiqueta del otro registro"
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_other:0
msgid "Other record's partner type"
msgstr "Tipo de empresa del otro registro"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner
#: field:res.partner.relation,partner_id_display:0
msgid "Partner"
msgstr "Empresa"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.form_res_partner_relation
msgid "Partner Relation"
msgstr "Relación entre empresas"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type
msgid "Partner Relation Type"
msgstr "Tipo de relación entre empresas"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.tree_res_partner_relation
#: view:res.partner.relation.all:partner_relations.tree_res_partner_relation_all
msgid "Partner Relations"
msgstr "Relaciones entre empresas"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_type
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_type
msgid "Partner Relations Types"
msgstr "Tipos de relaciones entre empresas"
#. module: partner_relations
#: field:res.partner.relation.all,contact_type:0
msgid "Partner Type"
msgstr "Tipo de empresa"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation
#: view:res.partner.relation.all:partner_relations.form_res_partner_relation_all
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
#: view:res.partner.relation.type:partner_relations.tree_res_partner_relation_type
msgid "Partner relation"
msgstr "Relación de empresa"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:291
#, python-format
msgid "Partners cannot have a relation with themselves."
msgstr "Partners cannot have a relation with themselves."
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation_type.py:65
#, python-format
msgid "Person"
msgstr "Contacto"
#. module: partner_relations
#: field:res.partner.relation.all,record_type:0
msgid "Record Type"
msgstr "Tipo de registro"
#. module: partner_relations
#: field:res.partner.relation.type.selection,record_type:0
msgid "Record type"
msgstr "Tipo de registro"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:360
#, python-format
msgid "Related partners"
msgstr "Empresas relacionadas"
#. module: partner_relations
#: field:res.partner.relation.all,relation_id:0
msgid "Relation"
msgstr "Relación"
#. module: partner_relations
#: field:res.partner.relation.all,type_id:0
#: field:res.partner.relation.all,type_selection_id:0
msgid "Relation Type"
msgstr "Tipo de relación"
#. module: partner_relations
#: field:res.partner,search_relation_date:0
msgid "Relation valid"
msgstr "Relación válida"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_all
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_sales
#: view:res.partner:partner_relations.view_partner_form
#: field:res.partner,relation_ids:0
msgid "Relations"
msgstr "Relaciones"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Relationship Type"
msgstr "Tipo de relación"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
msgid "Right Partner"
msgstr "Empresa derecha"
#. module: partner_relations
#: field:res.partner.relation,right_contact_type:0
msgid "Right Partner Type"
msgstr "Tipo de empresa derecha"
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_right:0
msgid "Right partner category"
msgstr "Etiqueta empresa derecha"
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_right:0
msgid "Right partner type"
msgstr "Tipo empresa derecha"
#. module: partner_relations
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
msgid "Right side of relation"
msgstr "Lado derecho de la relación"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Search Relations"
msgstr "Buscar relaciones"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_show_partner_relations
msgid "Show partner's relations"
msgstr "Mostrar la relaiones de la empresa"
#. module: partner_relations
#: model:ir.actions.server,name:partner_relations.action_show_right_relation_partners
msgid "Show partners"
msgstr "Mostrar empresas"
#. module: partner_relations
#: field:res.partner.relation,left_partner_id:0
msgid "Source Partner"
msgstr "Empresa origen"
#. module: partner_relations
#: field:res.partner.relation,date_start:0
#: field:res.partner.relation.all,date_start:0
msgid "Starting date"
msgstr "Fecha inicio"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:278
#, python-format
msgid "The %s partner is not applicable for this relation type."
msgstr "La empresa %s no aplica para este tipo de relación"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:245
#, python-format
msgid "The starting date cannot be after the ending date."
msgstr "La fecha de inicio no puede ser posterior a la fecha de fin."
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:319
#, python-format
msgid "There is already a similar relation with overlapping dates"
msgstr "Hay una relación similar que se solapa en fechas"
#. module: partner_relations
#: field:res.partner.relation,type_id:0
#: field:res.partner.relation,type_selection_id:0
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
#: field:res.partner.relation.type.selection,type_id:0
msgid "Type"
msgstr "Tipo"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner.py:109
#, python-format
msgid "Unsupported search operand \"%s\""
msgstr "Operando de búsqueda no soportado: \"%s\""

383
partner_relations/i18n/fr.po

@ -0,0 +1,383 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_relations
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-15 16:09+0000\n"
"PO-Revision-Date: 2015-04-16 11:04-0500\n"
"Last-Translator: Sandy Carter <sandy.carter@savoirfairelinux.com>\n"
"Language-Team: \n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"X-Generator: Poedit 1.7.5\n"
#. module: partner_relations
#: model:ir.actions.act_window,help:partner_relations.action_res_partner_relation
#: model:ir.actions.act_window,help:partner_relations.action_res_partner_relation_all
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Record and track your partners' relations. Relations may "
"be linked to other partners with a type either directly or inversely.\n"
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Enregistrer et suivre les relations de vos partenaires. "
"Les relations peuvent être liés avec d'autre partenaires avec un type, soit "
"directement ou inversement.\n"
" </p>\n"
" "
#. module: partner_relations
#: field:res.partner.relation,active:0 field:res.partner.relation.all,active:0
msgid "Active"
msgstr "Actif"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr "Tous les relations (non-inverse et inverse) entre partenaires"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr "Tous types de relations"
#. module: partner_relations
#: field:res.partner,relation_all_ids:0
msgid "All relations with current partner"
msgstr "Tous les relations avec le partenaire courant"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation_type.py:64
#, python-format
msgid "Company"
msgstr "Société"
#. module: partner_relations
#: field:res.partner.relation,create_uid:0
#: field:res.partner.relation.type,create_uid:0
msgid "Created by"
msgstr "Créé par"
#. module: partner_relations
#: field:res.partner.relation,create_date:0
#: field:res.partner.relation.type,create_date:0
msgid "Created on"
msgstr "Créé le"
#. module: partner_relations
#: field:res.partner.relation.all,this_partner_id:0
msgid "Current Partner"
msgstr "Partenaire courant"
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_this:0
#: field:res.partner.relation.type.selection,search_partner_category_this:0
msgid "Current record's category"
msgstr "Catégorie de l'enregistrement courante"
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_this:0
msgid "Current record's partner type"
msgstr "Type de partenaire de l'enregistrement courrant"
#. module: partner_relations
#: field:res.partner.relation,right_partner_id:0
msgid "Destination Partner"
msgstr "Partenaire destinataire"
#. module: partner_relations
#: field:res.partner.relation,date_end:0
#: field:res.partner.relation.all,date_end:0
msgid "Ending date"
msgstr "Date de fin"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Group By"
msgstr "Regrouper par"
#. module: partner_relations
#: field:res.partner,search_relation_id:0
msgid "Has relation of type"
msgstr "A une relation de type"
#. module: partner_relations
#: field:res.partner,search_relation_partner_id:0
msgid "Has relation with"
msgstr "A une relation avec"
#. module: partner_relations
#: field:res.partner,search_relation_partner_category_id:0
msgid "Has relation with a partner in category"
msgstr "A une relation avec un partenaire dans la catégorie"
#. module: partner_relations
#: field:res.partner.relation,id:0 field:res.partner.relation.all,id:0
#: field:res.partner.relation.type,id:0
#: field:res.partner.relation.type.selection,id:0
msgid "ID"
msgstr "Id"
#. module: partner_relations
#: field:res.partner.relation.type,name_inverse:0
msgid "Inverse name"
msgstr "Nom inverse"
#. module: partner_relations
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
msgid "Inverse type"
msgstr "Type inverse"
#. module: partner_relations
#: field:res.partner.relation,write_uid:0
#: field:res.partner.relation.type,write_uid:0
msgid "Last Updated by"
msgstr "Dernière modification par"
#. module: partner_relations
#: field:res.partner.relation,write_date:0
#: field:res.partner.relation.type,write_date:0
msgid "Last Updated on"
msgstr "Dernière mise à jour le"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
msgid "Left Partner"
msgstr "Partenaire de gauche"
#. module: partner_relations
#: field:res.partner.relation,left_contact_type:0
msgid "Left Partner Type"
msgstr "Type de partenaire de gauche"
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_left:0
msgid "Left partner category"
msgstr "Catégorie du partenaire de gauche"
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_left:0
msgid "Left partner type"
msgstr "Type de partenaire de gauche"
#. module: partner_relations
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
msgid "Left side of relation"
msgstr "Côté gauche de la relation"
#. module: partner_relations
#: field:res.partner.relation.type,name:0
#: field:res.partner.relation.type.selection,name:0
msgid "Name"
msgstr "Nom"
#. module: partner_relations
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
#: field:res.partner.relation.all,other_partner_id:0
msgid "Other Partner"
msgstr "L'autre partenaire"
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_other:0
msgid "Other record's category"
msgstr "La catégorie de l'enregistrement de gauche"
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_other:0
msgid "Other record's partner type"
msgstr "Le type de l'enregistrement de gauche"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner
#: field:res.partner.relation,partner_id_display:0
msgid "Partner"
msgstr "Partenaire"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.form_res_partner_relation
msgid "Partner Relation"
msgstr "Relation du partenaire"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type
msgid "Partner Relation Type"
msgstr "Type de relation de partenaire"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.tree_res_partner_relation
#: view:res.partner.relation.all:partner_relations.tree_res_partner_relation_all
msgid "Partner Relations"
msgstr "Relations du partenaire"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_type
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_type
msgid "Partner Relations Types"
msgstr "Types de relation de partenaire"
#. module: partner_relations
#: field:res.partner.relation.all,contact_type:0
msgid "Partner Type"
msgstr "Type de partenaire"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation
#: view:res.partner.relation.all:partner_relations.form_res_partner_relation_all
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
#: view:res.partner.relation.type:partner_relations.tree_res_partner_relation_type
msgid "Partner relation"
msgstr "Relation du partenaire"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:291
#, python-format
msgid "Partners cannot have a relation with themselves."
msgstr "Un partenaire ne peut pas avoir une relation avec soi-même."
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation_type.py:65
#, python-format
msgid "Person"
msgstr "Personne"
#. module: partner_relations
#: field:res.partner.relation.all,record_type:0
msgid "Record Type"
msgstr "Type d'enregistrement"
#. module: partner_relations
#: field:res.partner.relation.type.selection,record_type:0
msgid "Record type"
msgstr "Type d'enregistrement"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:360
#, python-format
msgid "Related partners"
msgstr "Partenaires liés"
#. module: partner_relations
#: field:res.partner.relation.all,relation_id:0
msgid "Relation"
msgstr "Relation"
#. module: partner_relations
#: field:res.partner.relation.all,type_id:0
#: field:res.partner.relation.all,type_selection_id:0
msgid "Relation Type"
msgstr "Type de relation"
#. module: partner_relations
#: field:res.partner,search_relation_date:0
msgid "Relation valid"
msgstr "Relation valide"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_all
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_sales
#: view:res.partner:partner_relations.view_partner_form
#: field:res.partner,relation_ids:0
msgid "Relations"
msgstr "Relations"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Relationship Type"
msgstr "Type de relation"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
msgid "Right Partner"
msgstr "Partenaire de droite"
#. module: partner_relations
#: field:res.partner.relation,right_contact_type:0
msgid "Right Partner Type"
msgstr "Type du partenaire de droite"
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_right:0
msgid "Right partner category"
msgstr "Catégorie du partenaire de droite"
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_right:0
msgid "Right partner type"
msgstr "Type du partenaire de droite"
#. module: partner_relations
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
msgid "Right side of relation"
msgstr "Côté droite de la relation"
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Search Relations"
msgstr "Rechercher les relations"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_show_partner_relations
msgid "Show partner's relations"
msgstr "Montrer les relations du partenaire"
#. module: partner_relations
#: model:ir.actions.server,name:partner_relations.action_show_right_relation_partners
msgid "Show partners"
msgstr "Montrer les partenaires"
#. module: partner_relations
#: field:res.partner.relation,left_partner_id:0
msgid "Source Partner"
msgstr "Partenaire source"
#. module: partner_relations
#: field:res.partner.relation,date_start:0
#: field:res.partner.relation.all,date_start:0
msgid "Starting date"
msgstr "Date de début"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:278
#, python-format
msgid "The %s partner is not applicable for this relation type."
msgstr "Le partenaire %s n'es pas applicable pour cette type de relation."
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:245
#, python-format
msgid "The starting date cannot be after the ending date."
msgstr "La date de début ne peut pas être après la date de fin."
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:319
#, python-format
msgid "There is already a similar relation with overlapping dates"
msgstr "Il existe des dates en conflit des relations similaires."
#. module: partner_relations
#: field:res.partner.relation,type_id:0
#: field:res.partner.relation,type_selection_id:0
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
#: field:res.partner.relation.type.selection,type_id:0
msgid "Type"
msgstr "Type"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner.py:109
#, python-format
msgid "Unsupported search operand \"%s\""
msgstr "Opérateur de recherche non-supporté « %s »"

291
partner_relations/i18n/nl.po

@ -0,0 +1,291 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * partner_relations
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-06-19 13:02+0000\n"
"PO-Revision-Date: 2014-06-19 13:02+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_relations
#: field:res.partner.relation,active:0
#: field:res.partner.relation.all,active:0
msgid "Active"
msgstr "Actief"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr "Alle (non-inverse + inverse) koppelingen tussen relaties"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr "Alle relaties"
#. module: partner_relations
#: field:res.partner,relation_all_ids:0
msgid "All relations with current partner"
msgstr "Alle koppelingen met huidige relatie"
#. module: partner_relations
#: field:res.partner.relation.all,this_partner_id:0
msgid "Current partner"
msgstr "Huidige relatie"
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_this:0
#: field:res.partner.relation.type.selection,search_partner_category_this:0
msgid "Current record's category"
msgstr "Categorie van huidige record"
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_this:0
msgid "Current record's partner type"
msgstr "Relatietype van huidige record"
#. module: partner_relations
#: field:res.partner.relation,date_end:0
#: field:res.partner.relation.all,date_end:0
msgid "Ending date"
msgstr "Einddatum"
#. module: partner_relations
#: field:res.partner,search_relation_id:0
msgid "Has relation of type"
msgstr "Heeft koppeling"
#. module: partner_relations
#: field:res.partner,search_relation_partner_id:0
msgid "Has relation with"
msgstr "Heeft koppeling met"
#. module: partner_relations
#: field:res.partner,search_relation_partner_category_id:0
msgid "Has relation with a partner in category"
msgstr "Heeft koppeling met relatie van de categorie"
#. module: partner_relations
#: field:res.partner.relation.type,name_inverse:0
msgid "Inverse name"
msgstr "Inverse naam"
#. module: partner_relations
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
msgid "Inverse type"
msgstr "Inverse type"
#. module: partner_relations
#: field:res.partner.relation,left_partner_id:0
msgid "Left partner"
msgstr "Linkerrelatie"
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_left:0
msgid "Left partner category"
msgstr "Linker-relatielabel"
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_left:0
msgid "Left partner type"
msgstr "Linker-relatietype"
#. module: partner_relations
#: view:res.partner.relation.type:0
msgid "Left side of relation"
msgstr "Linkerkant van de koppeling"
#. module: partner_relations
#: field:res.partner.relation.type,name:0
#: field:res.partner.relation.type.selection,name:0
msgid "Name"
msgstr "Naam"
#. module: partner_relations
#: field:res.partner.relation.all,other_partner_id:0
msgid "Other partner"
msgstr "Andere relatie"
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_other:0
msgid "Other record's category"
msgstr "Categorie andere record"
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_other:0
msgid "Other record's partner type"
msgstr "Type andere record"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:259
#, python-format
msgid "Overlapping relation"
msgstr "Overlappende koppeling"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type
#: model:ir.model,name:partner_relations.model_res_partner_relation_type_inverse
msgid "Parter relation type"
msgstr "Type relatiekoppeling"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner
#: field:res.partner.relation,partner_id_display:0
msgid "Partner"
msgstr "Relatie"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_category
msgid "Partner Categories"
msgstr "Relatielabels"
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation
#: view:res.partner.relation:0
#: view:res.partner.relation.type:0
msgid "Partner relation"
msgstr "Relatiekoppeling"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_type
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_type
msgid "Partner relations"
msgstr "Relatiekoppelingen"
#. module: partner_relations
#: constraint:res.partner.relation:0
msgid "Partners cannot have a relation with themselves."
msgstr "Relaties kunnen niet aan zichzelf gekoppeld worden."
#. module: partner_relations
#: field:res.partner.relation.all,record_type:0
#: field:res.partner.relation.type.selection,record_type:0
msgid "Record type"
msgstr "Record type"
#. module: partner_relations
#: field:res.partner.relation.all,relation_id:0
msgid "Relation"
msgstr "Koppeling"
#. module: partner_relations
#: field:res.partner.relation,is_relation_expired:0
msgid "Relation is expired"
msgstr "Koppeling is beëindigd"
#. module: partner_relations
#: field:res.partner.relation,is_relation_future:0
msgid "Relation is in the future"
msgstr "Koppeling is in de toekomst"
#. module: partner_relations
#: field:res.partner.relation.all,type_id:0
msgid "Relation type"
msgstr "Koppelingstype"
#. module: partner_relations
#: field:res.partner,search_relation_date:0
msgid "Relation valid"
msgstr "Datum koppeling"
#. module: partner_relations
#: view:res.partner:0
#: field:res.partner,relation_ids:0
msgid "Relations"
msgstr "Koppelingen"
#. module: partner_relations
#: field:res.partner.relation,right_partner_id:0
msgid "Right partner"
msgstr "Rechterrelatie"
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_right:0
msgid "Right partner category"
msgstr "Rechter-relatielabel"
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_right:0
msgid "Right partner type"
msgstr "Rechter-relatietype"
#. module: partner_relations
#: view:res.partner.relation.type:0
msgid "Right side of relation"
msgstr "Rechterkant van de koppeling"
#. module: partner_relations
#: field:res.partner.relation,date_start:0
#: field:res.partner.relation.all,date_start:0
msgid "Starting date"
msgstr "Begindatum"
#. module: partner_relations
#: constraint:res.partner.relation:0
msgid "The left partner is not applicable for this relation type."
msgstr "De linkerrelatie is niet geldig voor dit type koppeling."
#. module: partner_relations
#: constraint:res.partner.relation:0
msgid "The right partner is not applicable for this relation type."
msgstr "De rechterrelatie is niet geldig voor dit type koppeling."
#. module: partner_relations
#: constraint:res.partner.relation:0
msgid "The starting date cannot be after the ending date."
msgstr "De begindatum mag niet na de einddatum liggen."
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:260
#, python-format
msgid "Unsupported search operand \"%s\""
msgstr "Operator \"%s\" is niet ondersteund"
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:260
#, python-format
msgid "There is already a similar relation with overlapping dates"
msgstr "Er is al een soortgelijke, overlappende koppeling."
#. module: partner_relations
#: field:res.partner.relation,type_id:0
#: field:res.partner.relation,type_selection_id:0
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
#: field:res.partner.relation.type.selection,type_id:0
msgid "Type"
msgstr "Type"
#. module: partner_relations
#: field:res.partner.category,only_for_organisation:0
msgid "Valid for organisation only"
msgstr "Alleen geldig voor organisaties"
#. module: partner_relations
#: field:res.partner.category,only_for_person:0
msgid "Valid for person only"
msgstr "Alleen geldig voor personen"
#. module: partner_relations
#: field:res.partner,search_relation_partner_category_id:0
msgid "Has relation with a partner in category"
msgstr "Heeft koppeling met relatie van de categorie"
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_show_partner_relations
msgid "Show partner's relations"
msgstr "Toon relatiekoppelingen"
#. module: partner_relations
#: constraint:res.partner.relation:0
msgid "The same relation can't be created twice."
msgstr "Dezelfde koppeling kan niet dubbel aan worden gemaakt."

376
partner_relations/i18n/partner_relations.pot

@ -0,0 +1,376 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_relations
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-15 16:09+0000\n"
"PO-Revision-Date: 2015-04-15 16:09+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_relations
#: model:ir.actions.act_window,help:partner_relations.action_res_partner_relation
#: model:ir.actions.act_window,help:partner_relations.action_res_partner_relation_all
msgid "<p class=\"oe_view_nocontent_create\">\n"
" Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.\n"
" </p>\n"
" "
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,active:0
#: field:res.partner.relation.all,active:0
msgid "Active"
msgstr ""
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr ""
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr ""
#. module: partner_relations
#: field:res.partner,relation_all_ids:0
msgid "All relations with current partner"
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation_type.py:64
#, python-format
msgid "Company"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,create_uid:0
#: field:res.partner.relation.type,create_uid:0
msgid "Created by"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,create_date:0
#: field:res.partner.relation.type,create_date:0
msgid "Created on"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.all,this_partner_id:0
msgid "Current Partner"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_this:0
#: field:res.partner.relation.type.selection,search_partner_category_this:0
msgid "Current record's category"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_this:0
msgid "Current record's partner type"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,right_partner_id:0
msgid "Destination Partner"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,date_end:0
#: field:res.partner.relation.all,date_end:0
msgid "Ending date"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Group By"
msgstr ""
#. module: partner_relations
#: field:res.partner,search_relation_id:0
msgid "Has relation of type"
msgstr ""
#. module: partner_relations
#: field:res.partner,search_relation_partner_id:0
msgid "Has relation with"
msgstr ""
#. module: partner_relations
#: field:res.partner,search_relation_partner_category_id:0
msgid "Has relation with a partner in category"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,id:0
#: field:res.partner.relation.all,id:0
#: field:res.partner.relation.type,id:0
#: field:res.partner.relation.type.selection,id:0
msgid "ID"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type,name_inverse:0
msgid "Inverse name"
msgstr ""
#. module: partner_relations
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
msgid "Inverse type"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,write_uid:0
#: field:res.partner.relation.type,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,write_date:0
#: field:res.partner.relation.type,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
msgid "Left Partner"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,left_contact_type:0
msgid "Left Partner Type"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_left:0
msgid "Left partner category"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_left:0
msgid "Left partner type"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
msgid "Left side of relation"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type,name:0
#: field:res.partner.relation.type.selection,name:0
msgid "Name"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
#: field:res.partner.relation.all,other_partner_id:0
msgid "Other Partner"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type.selection,partner_category_other:0
msgid "Other record's category"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type.selection,contact_type_other:0
msgid "Other record's partner type"
msgstr ""
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner
#: field:res.partner.relation,partner_id_display:0
msgid "Partner"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.form_res_partner_relation
msgid "Partner Relation"
msgstr ""
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation_type
msgid "Partner Relation Type"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.tree_res_partner_relation
#: view:res.partner.relation.all:partner_relations.tree_res_partner_relation_all
msgid "Partner Relations"
msgstr ""
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_type
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_type
msgid "Partner Relations Types"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.all,contact_type:0
msgid "Partner Type"
msgstr ""
#. module: partner_relations
#: model:ir.model,name:partner_relations.model_res_partner_relation
#: view:res.partner.relation.all:partner_relations.form_res_partner_relation_all
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
#: view:res.partner.relation.type:partner_relations.tree_res_partner_relation_type
msgid "Partner relation"
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:291
#, python-format
msgid "Partners cannot have a relation with themselves."
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation_type.py:65
#, python-format
msgid "Person"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.all,record_type:0
msgid "Record Type"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type.selection,record_type:0
msgid "Record type"
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:360
#, python-format
msgid "Related partners"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.all,relation_id:0
msgid "Relation"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.all,type_id:0
#: field:res.partner.relation.all,type_selection_id:0
msgid "Relation Type"
msgstr ""
#. module: partner_relations
#: field:res.partner,search_relation_date:0
msgid "Relation valid"
msgstr ""
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation
#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_all
#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_sales
#: view:res.partner:partner_relations.view_partner_form
#: field:res.partner,relation_ids:0
msgid "Relations"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Relationship Type"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
msgid "Right Partner"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,right_contact_type:0
msgid "Right Partner Type"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type,partner_category_right:0
msgid "Right partner category"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation.type,contact_type_right:0
msgid "Right partner type"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation.type:partner_relations.form_res_partner_relation_type
msgid "Right side of relation"
msgstr ""
#. module: partner_relations
#: view:res.partner.relation:partner_relations.search_res_partner_relation
#: view:res.partner.relation.all:partner_relations.search_res_partner_relation_all
msgid "Search Relations"
msgstr ""
#. module: partner_relations
#: model:ir.actions.act_window,name:partner_relations.action_show_partner_relations
msgid "Show partner's relations"
msgstr ""
#. module: partner_relations
#: model:ir.actions.server,name:partner_relations.action_show_right_relation_partners
msgid "Show partners"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,left_partner_id:0
msgid "Source Partner"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,date_start:0
#: field:res.partner.relation.all,date_start:0
msgid "Starting date"
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:278
#, python-format
msgid "The %s partner is not applicable for this relation type."
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:245
#, python-format
msgid "The starting date cannot be after the ending date."
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner_relation.py:319
#, python-format
msgid "There is already a similar relation with overlapping dates"
msgstr ""
#. module: partner_relations
#: field:res.partner.relation,type_id:0
#: field:res.partner.relation,type_selection_id:0
#: selection:res.partner.relation.all,record_type:0
#: selection:res.partner.relation.type.selection,record_type:0
#: field:res.partner.relation.type.selection,type_id:0
msgid "Type"
msgstr ""
#. module: partner_relations
#: code:addons/partner_relations/model/res_partner.py:109
#, python-format
msgid "Unsupported search operand \"%s\""
msgstr ""

39
partner_relations/model/__init__.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# 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/>.
#
##############################################################################
PADDING = 10
def get_partner_type(partner):
"""Get partner type for relation.
:param partner: a res.partner either a company or not
:return: 'c' for company or 'p' for person
:rtype: str
"""
return 'c' if partner.is_company else 'p'
from . import res_partner
from . import res_partner_relation
from . import res_partner_relation_type
from . import res_partner_relation_all
from . import res_partner_relation_type_selection

320
partner_relations/model/res_partner.py

@ -0,0 +1,320 @@
# -*- coding: utf-8 -*-
'''Extend res.partner model'''
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# 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 time
from openerp import osv, models, fields, exceptions, api
from openerp.osv.expression import is_leaf, AND, OR, FALSE_LEAF
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
from openerp.tools.translate import _
class ResPartner(models.Model):
_inherit = 'res.partner'
relation_count = fields.Integer(
'Relation Count',
compute="_count_relations"
)
@api.one
@api.depends("relation_ids")
def _count_relations(self):
"""Count the number of relations this partner has for Smart Button
Don't count inactive relations.
"""
self.relation_count = len([r for r in self.relation_ids if r.active])
def _get_relation_ids_select(self, cr, uid, ids, field_name, arg,
context=None):
'''return the partners' relations as tuple
(id, left_partner_id, right_partner_id)'''
cr.execute(
'''select id, left_partner_id, right_partner_id
from res_partner_relation
where (left_partner_id in %s or right_partner_id in %s)''' +
' order by ' + self.pool['res.partner.relation']._order,
(tuple(ids), tuple(ids))
)
return cr.fetchall()
def _get_relation_ids(
self, cr, uid, ids, field_name, arg, context=None):
'''getter for relation_ids'''
if context is None:
context = {}
result = dict([(i, []) for i in ids])
# TODO: do a permission test on returned ids
for row in self._get_relation_ids_select(
cr, uid, ids, field_name, arg, context=context):
if row[1] in result:
result[row[1]].append(row[0])
if row[2] in result:
result[row[2]].append(row[0])
return result
def _set_relation_ids(
self, cr, uid, ids, dummy_name, field_value, dummy_arg,
context=None):
'''setter for relation_ids'''
if context is None:
context = {}
relation_obj = self.pool.get('res.partner.relation')
context2 = self._update_context(context, ids)
for value in field_value:
if value[0] == 0:
relation_obj.create(cr, uid, value[2], context=context2)
if value[0] == 1:
# if we write partner_id_display, we also need to pass
# type_selection_id in order to have this write end up on
# the correct field
if 'partner_id_display' in value[2] and 'type_selection_id'\
not in value[2]:
relation_data = relation_obj.read(
cr, uid, [value[1]], ['type_selection_id'],
context=context)[0]
value[2]['type_selection_id'] =\
relation_data['type_selection_id']
relation_obj.write(
cr, uid, value[1], value[2], context=context2)
if value[0] == 2:
relation_obj.unlink(cr, uid, value[1], context=context2)
def _search_relation_id(
self, cr, uid, dummy_obj, name, args, context=None):
result = []
for arg in args:
if isinstance(arg, tuple) and arg[0] == name:
if arg[1] not in ['=', '!=', 'like', 'not like', 'ilike',
'not ilike', 'in', 'not in']:
raise exceptions.ValidationError(
_('Unsupported search operand "%s"') % arg[1])
relation_type_selection_ids = []
relation_type_selection = self\
.pool['res.partner.relation.type.selection']
if arg[1] == '=' and isinstance(arg[2], (long, int)):
relation_type_selection_ids.append(arg[2])
elif arg[1] == '!=' and isinstance(arg[2], (long, int)):
type_id, is_inverse = (
relation_type_selection.browse(cr, uid, arg[2],
context=context)
.get_type_from_selection_id()
)
result = OR([
result,
[
('relation_all_ids.type_id', '!=', type_id),
]
])
continue
else:
relation_type_selection_ids = relation_type_selection\
.search(
cr, uid,
[
('type_id.name', arg[1], arg[2]),
('record_type', '=', 'a'),
],
context=context)
relation_type_selection_ids.extend(
relation_type_selection.search(
cr, uid,
[
('type_id.name_inverse', arg[1], arg[2]),
('record_type', '=', 'b'),
],
context=context))
if not relation_type_selection_ids:
result = AND([result, [FALSE_LEAF]])
for relation_type_selection_id in relation_type_selection_ids:
type_id, is_inverse = (
relation_type_selection.browse(
cr, uid, relation_type_selection_id,
context=context
).get_type_from_selection_id()
)
result = OR([
result,
[
'&',
('relation_all_ids.type_id', '=', type_id),
('relation_all_ids.record_type', '=',
'b' if is_inverse else 'a')
],
])
return result
def _search_relation_date(self, cr, uid, obj, name, args, context=None):
result = []
for arg in args:
if isinstance(arg, tuple) and arg[0] == name:
# TODO: handle {<,>}{,=}
if arg[1] != '=':
continue
result.extend([
'&',
'|',
('relation_all_ids.date_start', '=', False),
('relation_all_ids.date_start', '<=', arg[2]),
'|',
('relation_all_ids.date_end', '=', False),
('relation_all_ids.date_end', '>=', arg[2]),
])
return result
def _search_related_partner_id(
self, cr, uid, dummy_obj, name, args, context=None):
result = []
for arg in args:
if isinstance(arg, tuple) and arg[0] == name:
result.append(
(
'relation_all_ids.other_partner_id',
arg[1],
arg[2],
))
return result
def _search_related_partner_category_id(
self, cr, uid, dummy_obj, name, args, context=None):
result = []
for arg in args:
if isinstance(arg, tuple) and arg[0] == name:
result.append(
(
'relation_all_ids.other_partner_id.category_id',
arg[1],
arg[2],
))
return result
_columns = {
'relation_ids': osv.fields.function(
lambda self, *args, **kwargs: self._get_relation_ids(
*args, **kwargs),
fnct_inv=_set_relation_ids,
type='one2many', obj='res.partner.relation',
string='Relations',
selectable=False,
),
'relation_all_ids': osv.fields.one2many(
'res.partner.relation.all', 'this_partner_id',
string='All relations with current partner',
auto_join=True,
selectable=False,
),
'search_relation_id': osv.fields.function(
lambda self, cr, uid, ids, *args: dict([
(i, False) for i in ids]),
fnct_search=_search_relation_id,
string='Has relation of type',
type='many2one', obj='res.partner.relation.type.selection'
),
'search_relation_partner_id': osv.fields.function(
lambda self, cr, uid, ids, *args: dict([
(i, False) for i in ids]),
fnct_search=_search_related_partner_id,
string='Has relation with',
type='many2one', obj='res.partner'
),
'search_relation_date': osv.fields.function(
lambda self, cr, uid, ids, *args: dict([
(i, False) for i in ids]),
fnct_search=_search_relation_date,
string='Relation valid', type='date'
),
'search_relation_partner_category_id': osv.fields.function(
lambda self, cr, uid, ids, *args: dict([
(i, False) for i in ids]),
fnct_search=_search_related_partner_category_id,
string='Has relation with a partner in category',
type='many2one', obj='res.partner.category'
),
}
def copy_data(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
default.setdefault('relation_ids', [])
default.setdefault('relation_all_ids', [])
return super(ResPartner, self).copy_data(cr, uid, id, default=default,
context=context)
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
if context is None:
context = {}
# inject searching for current relation date if we search for relation
# properties and no explicit date was given
date_args = []
for arg in args:
if is_leaf(arg) and arg[0].startswith('search_relation'):
if arg[0] == 'search_relation_date':
date_args = []
break
if not date_args:
date_args = [
('search_relation_date', '=', time.strftime(
DEFAULT_SERVER_DATE_FORMAT))]
# because of auto_join, we have to do the active test by hand
active_args = []
if context.get('active_test', True):
for arg in args:
if is_leaf(arg) and\
arg[0].startswith('search_relation'):
active_args = [('relation_all_ids.active', '=', True)]
break
return super(ResPartner, self).search(
cr, uid, args + date_args + active_args, offset=offset,
limit=limit, order=order, context=context, count=count)
def read(
self, cr, uid, ids, fields=None, context=None,
load='_classic_read'):
return super(ResPartner, self).read(
cr, uid, ids, fields=fields,
context=self._update_context(context, ids))
def write(self, cr, uid, ids, vals, context=None):
return super(ResPartner, self).write(
cr, uid, ids, vals, context=self._update_context(context, ids))
def _update_context(self, context, ids):
if context is None:
context = {}
ids = ids if isinstance(ids, list) else [ids] if ids else []
result = context.copy()
result.setdefault('active_id', ids[0] if ids else None)
result.setdefault('active_ids', ids)
result.setdefault('active_model', self._name)
return result

366
partner_relations/model/res_partner_relation.py

@ -0,0 +1,366 @@
# -*- coding: utf-8 -*-
'''Define model res.partner.relation'''
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# 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 osv, models, fields, api, exceptions, _
from . import get_partner_type
class ResPartnerRelation(models.Model):
'''Model res.partner.relation is used to describe all links or relations
between partners in the database.
In many parts of the code we have to know whether the active partner is
the left partner, or the right partner. If the active partner is the
right partner we have to show the inverse name.
Because the active partner is crucial for the working of partner
relationships, we make sure on the res.partner model that the partner id
is set in the context where needed.
'''
_name = 'res.partner.relation'
_description = 'Partner relation'
_order = 'active desc, date_start desc, date_end desc'
def _get_computed_fields(
self, cr, uid, ids, field_names, arg, context=None):
'''Return a dictionary of dictionaries, with for every partner for
ids, the computed values.'''
def get_values(self, dummy_field_names, dummy_arg, context=None):
'''Get computed values for record'''
values = {}
on_right_partner = self._on_right_partner(self.right_partner_id.id)
# type_selection_id
values['type_selection_id'] = (
((self.type_id.id) * 10) + (on_right_partner and 1 or 0))
# partner_id_display
values['partner_id_display'] = (
self.left_partner_id.id
if on_right_partner
else self.right_partner_id.id
)
return values
return dict([
(i.id, get_values(i, field_names, arg, context=context))
for i in self.browse(cr, uid, ids, context=context)
])
_columns = {
'type_selection_id': osv.fields.function(
_get_computed_fields,
multi="computed_fields",
fnct_inv=lambda *args: None,
type='many2one', obj='res.partner.relation.type.selection',
string='Type',
),
'partner_id_display': osv.fields.function(
_get_computed_fields,
multi="computed_fields",
fnct_inv=lambda *args: None,
type='many2one', obj='res.partner',
string='Partner'
),
}
left_contact_type = fields.Selection(
lambda s: s.env['res.partner.relation.type']._get_partner_types(),
'Left Partner Type',
compute='_get_partner_type_any',
store=True,
)
right_contact_type = fields.Selection(
lambda s: s.env['res.partner.relation.type']._get_partner_types(),
'Right Partner Type',
compute='_get_partner_type_any',
store=True,
)
any_partner_id = fields.Many2many(
'res.partner',
string='Partner',
compute='_get_partner_type_any',
)
left_partner_id = fields.Many2one(
'res.partner',
string='Source Partner',
required=True,
auto_join=True,
ondelete='cascade',
)
right_partner_id = fields.Many2one(
'res.partner',
string='Destination Partner',
required=True,
auto_join=True,
ondelete='cascade',
)
type_id = fields.Many2one(
'res.partner.relation.type',
string='Type',
required=True,
auto_join=True,
)
date_start = fields.Date('Starting date')
date_end = fields.Date('Ending date')
active = fields.Boolean('Active', default=True)
@api.one
@api.depends('left_partner_id', 'right_partner_id')
def _get_partner_type_any(self):
self.left_contact_type = get_partner_type(self.left_partner_id)
self.right_contact_type = get_partner_type(self.right_partner_id)
self.any_partner_id = self.left_partner_id + self.right_partner_id
def _on_right_partner(self, cr, uid, right_partner_id, context=None):
'''Determine wether functions are called in a situation where the
active partner is the right partner. Default False!
'''
if (context and 'active_ids' in context and
right_partner_id in context.get('active_ids', [])):
return True
return False
def _correct_vals(self, vals):
"""Fill type and left and right partner id, according to whether
we have a normal relation type or an inverse relation type
"""
vals = vals.copy()
# If type_selection_id ends in 1, it is a reverse relation type
if 'type_selection_id' in vals:
prts_model = self.env['res.partner.relation.type.selection']
type_selection_id = vals['type_selection_id']
(type_id, is_reverse) = (
prts_model.browse(type_selection_id).
get_type_from_selection_id()
)
vals['type_id'] = type_id
if self._context.get('active_id'):
if is_reverse:
vals['right_partner_id'] = self._context['active_id']
else:
vals['left_partner_id'] = self._context['active_id']
if vals.get('partner_id_display'):
if is_reverse:
vals['left_partner_id'] = vals['partner_id_display']
else:
vals['right_partner_id'] = vals['partner_id_display']
if vals.get('other_partner_id'):
if is_reverse:
vals['left_partner_id'] = vals['other_partner_id']
else:
vals['right_partner_id'] = vals['other_partner_id']
del vals['other_partner_id']
if vals.get('contact_type'):
del vals['contact_type']
return vals
@api.multi
def write(self, vals):
"""Override write to correct values, before being stored."""
vals = self._correct_vals(vals)
return super(ResPartnerRelation, self).write(vals)
@api.model
def create(self, vals):
"""Override create to correct values, before being stored."""
vals = self._correct_vals(vals)
return super(ResPartnerRelation, self).create(vals)
def on_change_type_selection_id(
self, cr, uid, dummy_ids, type_selection_id, context=None):
'''Set domain on partner_id_display, when selection a relation type'''
result = {
'domain': {'partner_id_display': []},
'value': {'type_id': False}
}
if not type_selection_id:
return result
prts_model = self.pool['res.partner.relation.type.selection']
type_model = self.pool['res.partner.relation.type']
(type_id, is_reverse) = (
prts_model.get_type_from_selection_id(
cr, uid, type_selection_id)
)
result['value']['type_id'] = type_id
type_obj = type_model.browse(cr, uid, type_id, context=context)
partner_domain = []
check_contact_type = type_obj.contact_type_right
check_partner_category = (
type_obj.partner_category_right and
type_obj.partner_category_right.id
)
if is_reverse:
# partner_id_display is left partner
check_contact_type = type_obj.contact_type_left
check_partner_category = (
type_obj.partner_category_left and
type_obj.partner_category_left.id
)
if check_contact_type == 'c':
partner_domain.append(('is_company', '=', True))
if check_contact_type == 'p':
partner_domain.append(('is_company', '=', False))
if check_partner_category:
partner_domain.append(
('category_id', 'child_of', check_partner_category))
result['domain']['partner_id_display'] = partner_domain
return result
@api.one
@api.constrains('date_start', 'date_end')
def _check_dates(self):
"""End date should not be before start date, if not filled
:raises exceptions.Warning: When constraint is violated
"""
if (self.date_start and self.date_end and
self.date_start > self.date_end):
raise exceptions.Warning(
_('The starting date cannot be after the ending date.')
)
@api.one
@api.constrains('left_partner_id', 'type_id')
def _check_partner_type_left(self):
"""Check left partner for required company or person
:raises exceptions.Warning: When constraint is violated
"""
self._check_partner_type("left")
@api.one
@api.constrains('right_partner_id', 'type_id')
def _check_partner_type_right(self):
"""Check right partner for required company or person
:raises exceptions.Warning: When constraint is violated
"""
self._check_partner_type("right")
@api.one
def _check_partner_type(self, side):
"""Check partner to left or right for required company or person
:param str side: left or right
:raises exceptions.Warning: When constraint is violated
"""
assert side in ['left', 'right']
ptype = getattr(self.type_id, "contact_type_%s" % side)
company = getattr(self, '%s_partner_id' % side).is_company
if (ptype == 'c' and not company) or (ptype == 'p' and company):
raise exceptions.Warning(
_('The %s partner is not applicable for this relation type.') %
side
)
@api.one
@api.constrains('left_partner_id', 'right_partner_id')
def _check_not_with_self(self):
"""Not allowed to link partner to same partner
:raises exceptions.Warning: When constraint is violated
"""
if self.left_partner_id == self.right_partner_id:
raise exceptions.Warning(
_('Partners cannot have a relation with themselves.')
)
@api.one
@api.constrains('left_partner_id', 'right_partner_id', 'active')
def _check_relation_uniqueness(self):
"""Forbid multiple active relations of the same type between the same
partners
:raises exceptions.Warning: When constraint is violated
"""
if not self.active:
return
domain = [
('type_id', '=', self.type_id.id),
('active', '=', True),
('id', '!=', self.id),
('left_partner_id', '=', self.left_partner_id.id),
('right_partner_id', '=', self.right_partner_id.id),
]
if self.date_start:
domain += ['|', ('date_end', '=', False),
('date_end', '>=', self.date_start)]
if self.date_end:
domain += ['|', ('date_start', '=', False),
('date_start', '<=', self.date_end)]
if self.search(domain):
raise exceptions.Warning(
_('There is already a similar relation with overlapping dates')
)
def get_action_related_partners(self, cr, uid, ids, context=None):
'''return a window action showing a list of partners taking part in the
relations names by ids. Context key 'partner_relations_show_side'
determines if we show 'left' side, 'right' side or 'all' (default)
partners.
If active_model is res.partner.relation.all, left=this and
right=other'''
if context is None:
context = {}
field_names = {}
if context.get('active_model', self._name) == self._name:
field_names = {
'left': ['left'],
'right': ['right'],
'all': ['left', 'right']
}
elif context.get('active_model') == 'res.partner.relation.all':
field_names = {
'left': ['this'],
'right': ['other'],
'all': ['this', 'other']
}
else:
assert False, 'Unknown active_model!'
partner_ids = []
field_names = field_names[
context.get('partner_relations_show_side', 'all')]
field_names = ['%s_partner_id' % n for n in field_names]
for relation in self.pool[context.get('active_model')].read(
cr, uid, ids, context=context, load='_classic_write'):
for name in field_names:
partner_ids.append(relation[name])
return {
'name': _('Related partners'),
'type': 'ir.actions.act_window',
'res_model': 'res.partner',
'domain': [('id', 'in', partner_ids)],
'views': [(False, 'tree'), (False, 'form')],
'view_type': 'form'
}

212
partner_relations/model/res_partner_relation_all.py

@ -0,0 +1,212 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
#
# 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.tools import drop_view_if_exists
from .res_partner_relation_type_selection import \
ResPartnerRelationTypeSelection
from . import get_partner_type, PADDING
class ResPartnerRelationAll(models.AbstractModel):
_auto = False
_log_access = False
_name = 'res.partner.relation.all'
_overlays = 'res.partner.relation'
_description = 'All (non-inverse + inverse) relations between partners'
_additional_view_fields = []
'''append to this list if you added fields to res_partner_relation that
you need in this model and related fields are not adequate (ie for sorting)
You must use the same name as in res_partner_relation.
Don't overwrite this list in your declaration but append in _auto_init:
def _auto_init(self, cr, context=None):
self._additional_view_fields.append('my_field')
return super(ResPartnerRelationAll, self)._auto_init(
cr, context=context)
my_field = fields...
'''
this_partner_id = fields.Many2one(
'res.partner',
string='Current Partner',
required=True,
)
other_partner_id = fields.Many2one(
'res.partner',
string='Other Partner',
required=True,
)
type_id = fields.Many2one(
'res.partner.relation.type',
string='Relation Type',
required=True,
)
type_selection_id = fields.Many2one(
'res.partner.relation.type.selection',
string='Relation Type',
required=True,
)
relation_id = fields.Many2one(
'res.partner.relation',
'Relation',
readonly=True,
)
record_type = fields.Selection(
ResPartnerRelationTypeSelection._RECORD_TYPES,
'Record Type',
readonly=True,
)
contact_type = fields.Selection(
lambda s: s.env['res.partner.relation.type']._get_partner_types(),
'Partner Type',
default=lambda self: self._get_default_contact_type()
)
date_start = fields.Date('Starting date')
date_end = fields.Date('Ending date')
active = fields.Boolean('Active', default=True)
def _auto_init(self, cr, context=None):
drop_view_if_exists(cr, self._table)
additional_view_fields = ','.join(self._additional_view_fields)
additional_view_fields = (',' + additional_view_fields)\
if additional_view_fields else ''
cr.execute(
'''create or replace view %(table)s as
select
id * %(padding)d as id,
id as relation_id,
type_id,
cast('a' as char(1)) as record_type,
left_contact_type as contact_type,
left_partner_id as this_partner_id,
right_partner_id as other_partner_id,
date_start,
date_end,
active,
type_id * %(padding)d as type_selection_id
%(additional_view_fields)s
from %(underlying_table)s
union select
id * %(padding)d + 1,
id,
type_id,
cast('b' as char(1)),
right_contact_type,
right_partner_id,
left_partner_id,
date_start,
date_end,
active,
type_id * %(padding)d + 1
%(additional_view_fields)s
from %(underlying_table)s''' % {
'table': self._table,
'padding': PADDING,
'additional_view_fields': additional_view_fields,
'underlying_table': 'res_partner_relation',
}
)
return super(ResPartnerRelationAll, self)._auto_init(
cr, context=context)
@api.one
def get_underlying_object(self):
"""Get the record on which this record is overlaid"""
return self.env[self._overlays].browse(self.id / PADDING)
def _get_default_contact_type(self):
partner_id = self._context.get('default_this_partner_id')
if partner_id:
partner = self.env['res.partner'].browse(partner_id)
return get_partner_type(partner)
return False
@api.multi
def name_get(self):
return {
this.id: '%s %s %s' % (
this.this_partner_id.name,
this.type_selection_id.name_get()[0][1],
this.other_partner_id.name,
)
for this in self
}
@api.onchange('type_selection_id')
def onchange_type_selection_id(self):
"""Add domain on other_partner_id according to category_other"""
if not self.type_selection_id.partner_category_other:
return {'domain': []}
is_company = self.type_selection_id.partner_category_other == 'c'
return {
'domain': {
'other_partner_id': [('is_company', '=', is_company)],
}
}
@api.one
def write(self, vals):
"""divert non-problematic writes to underlying table"""
underlying_objs = self.get_underlying_object()
vals = {
key: val
for key, val in vals.iteritems()
if not self._columns[key].readonly
}
vals['type_selection_id'] = vals.get(
'type_selection_id',
underlying_objs.type_selection_id.id
)
return underlying_objs.write(vals)
@api.model
def create(self, vals):
"""divert non-problematic creates to underlying table
Create a res.partner.relation but return the converted id
"""
vals = {
key: val
for key, val in vals.iteritems()
if not self._columns[key].readonly
}
vals['type_selection_id'] = vals.get(
'type_selection_id',
False,
)
res = self.env[self._overlays].create(vals)
return self.browse(res.id * PADDING)
@api.one
def unlink(self):
"""divert non-problematic creates to underlying table"""
return self.get_underlying_object().unlink()

66
partner_relations/model/res_partner_relation_type.py

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
'''Define model res.partner.relation.type'''
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# 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, _
class ResPartnerRelationType(models.Model):
"""Model that defines relation types that might exist between partners"""
_name = 'res.partner.relation.type'
_description = 'Partner Relation Type'
_order = 'name'
name = fields.Char(
'Name',
size=128,
required=True,
translate=True,
)
name_inverse = fields.Char(
'Inverse name',
size=128,
required=True,
translate=True,
)
contact_type_left = fields.Selection(
'_get_partner_types',
'Left partner type',
)
contact_type_right = fields.Selection(
'_get_partner_types',
'Right partner type',
)
partner_category_left = fields.Many2one(
'res.partner.category',
'Left partner category',
)
partner_category_right = fields.Many2one(
'res.partner.category',
'Right partner category',
)
@api.model
def _get_partner_types(self):
return [
('c', _('Company')),
('p', _('Person')),
]

175
partner_relations/model/res_partner_relation_type_selection.py

@ -0,0 +1,175 @@
# -*- coding: UTF-8 -*-
'''
Created on 23 may 2014
@author: Ronald Portier, Therp
rportier@therp.nl
http://www.therp.nl
For the model defined here _auto is set to False to prevent creating a
database file. All i/o operations are overridden to use a sql SELECT that
takes data from res_partner_connection_type where each type is included in the
result set twice, so it appears that the connection type and the inverse
type are separate records..
The original function _auto_init is still called because this function
normally (if _auto == True) not only creates the db tables, but it also takes
care of registering all fields in ir_model_fields. This is needed to make
the field labels translatable.
example content for last lines of _statement:
select id, record_type,
customer_id, customer_name, customer_city, customer_zip, customer_street,
caller_id, caller_name, caller_phone, caller_fax, caller_email
from FULL_LIST as ResPartnerRelationTypeSelection where record_type = 'c'
ORDER BY ResPartnerRelationTypeSelection.customer_name asc,
ResPartnerRelationTypeSelection.caller_name asc;
'''
from openerp import api
from openerp.osv import fields
from openerp.osv import orm
from openerp.tools import drop_view_if_exists
from .res_partner_relation_type import ResPartnerRelationType
from . import PADDING
class ResPartnerRelationTypeSelection(orm.Model):
'''Virtual relation types'''
_RECORD_TYPES = [
('a', 'Type'),
('b', 'Inverse type'),
]
_auto = False # Do not try to create table in _auto_init(..)
_log_access = False
@api.multi
def get_type_from_selection_id(self):
"""Selection id ic computed from id of underlying type and the
kind of record. This function does the inverse computation to give
back the original type id, and about the record type."""
type_id = self.id / PADDING
is_reverse = (self.id % PADDING) > 0
return type_id, is_reverse
def _auto_init(self, cr, context=None):
drop_view_if_exists(cr, self._table)
# TODO: we lose field value's translations here.
# probably we need to patch ir_translation.get_source for that
# to get res_partner_relation_type's translations
cr.execute(
'''create or replace view %(table)s as
select
id * %(padding)d as id,
id as type_id,
cast('a' as char(1)) as record_type,
name as name,
contact_type_left as contact_type_this,
contact_type_right as contact_type_other,
partner_category_left as partner_category_this,
partner_category_right as partner_category_other
from %(underlying_table)s
union select
id * %(padding)d + 1,
id,
cast('b' as char(1)),
name_inverse,
contact_type_right,
contact_type_left,
partner_category_right,
partner_category_left
from %(underlying_table)s''' % {
'table': self._table,
'padding': PADDING,
'underlying_table': 'res_partner_relation_type',
})
return super(ResPartnerRelationTypeSelection, self)._auto_init(
cr, context=context)
def _search_partner_category_this(self, cr, uid, obj, field_name, args,
context=None):
category_ids = []
for arg in args:
if isinstance(arg, tuple) and arg[0] == field_name\
and (arg[1] == '=' or arg[1] == 'in'):
# TODO don't we have an api function to eval that?
for delta in arg[2]:
if delta[0] == 6:
category_ids.extend(delta[2])
if category_ids:
return [
'|',
('partner_category_this', '=', False),
('partner_category_this', 'in', category_ids),
]
else:
return [('partner_category_this', '=', False)]
_name = 'res.partner.relation.type.selection'
_description = 'All relation types'
_foreign_keys = []
_columns = {
'record_type': fields.selection(_RECORD_TYPES, 'Record type', size=16),
'type_id': fields.many2one(
'res.partner.relation.type', 'Type'),
'name': fields.char('Name', size=64),
'contact_type_this': fields.selection(
ResPartnerRelationType._get_partner_types.im_func,
'Current record\'s partner type'),
'contact_type_other': fields.selection(
ResPartnerRelationType._get_partner_types.im_func,
'Other record\'s partner type'),
'partner_category_this': fields.many2one(
'res.partner.category', 'Current record\'s category'),
'partner_category_other': fields.many2one(
'res.partner.category', 'Other record\'s category'),
# search field to handle many2many deltas from the client
'search_partner_category_this': fields.function(
lambda self, cr, uid, ids, context=None: dict(
[(i, False) for i in ids]),
fnct_search=_search_partner_category_this,
type='many2many', obj='res.partner.category',
string='Current record\'s category'),
}
_order = 'name asc'
def name_get(self, cr, uid, ids, context=None):
'translate name using translations from res.partner.relation.type'
result = super(ResPartnerRelationTypeSelection, self).name_get(
cr, uid, ids, context=context)
ir_translation = self.pool['ir.translation']
return [
(i, ir_translation._get_source(
cr, uid,
'res.partner.relation.type,name_inverse'
if self.get_type_from_selection_id(cr, uid, i)[1]
else 'res.partner.relation.type,name',
'model', context.get('lang'), name))
for i, name in result]
def name_search(self, cr, uid, name='', args=None, operator='ilike',
context=None, limit=100):
'search for translated names in res.partner.relation.type'
res_partner_relation_type = self.pool['res.partner.relation.type']
relation_ids = res_partner_relation_type.search(
cr, uid, [('name', operator, name)],
context=context)
inverse_relation_ids = res_partner_relation_type.search(
cr, uid, [('name_inverse', operator, name)],
context=context)
all_ids = self.search(
cr, uid,
[
('id', 'in',
map(lambda x: x * PADDING, relation_ids) +
map(lambda x: x * PADDING + 1, inverse_relation_ids)),
] + (args or []),
context=context, limit=limit)
return self.name_get(cr, uid, all_ids, context=context)

7
partner_relations/security/ir.model.access.csv

@ -0,0 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
read_res_partner_relation,access_res_partner_relation,model_res_partner_relation,,1,0,0,0
read_res_partner_relation_all,access_res_partner_relation,model_res_partner_relation_all,,1,0,0,0
read_res_partner_relation_type,access_res_partner_relation_type,model_res_partner_relation_type,,1,0,0,0
read_res_partner_relation_type_selection,access_res_partner_relation_type,model_res_partner_relation_type_selection,,1,0,0,0
crud_res_partner_relation,access_res_partner_relation,model_res_partner_relation,base.group_partner_manager,1,1,1,1
crud_res_partner_relation_type,access_res_partner_relation_type,model_res_partner_relation_type,base.group_sale_manager,1,1,1,1

BIN
partner_relations/static/src/img/icon.png

After

Width: 90  |  Height: 90  |  Size: 13 KiB

25
partner_relations/view/menu.xml

@ -0,0 +1,25 @@
<openerp>
<data>
<menuitem
id="menu_res_partner_relation_sales"
sequence="2"
parent="base.menu_sales"
action="action_res_partner_relation"
/>
<act_window
id="action_res_partner_relation_type"
res_model="res.partner.relation.type"
view_mode="tree,form"
name="Partner Relations Types"
/>
<menuitem
id="menu_res_partner_relation_type"
parent="base.menu_config_address_book"
action="action_res_partner_relation_type"
/>
</data>
</openerp>

53
partner_relations/view/res_partner.xml

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_res_partner_filter" model="ir.ui.view">
<field name="name">partner_relations.view_partner_filter</field>
<field name="inherit_id" ref="base.view_res_partner_filter" />
<field name="model">res.partner</field>
<field type="xml" name="arch">
<data>
<field name="parent_id" position="after">
<field name="search_relation_partner_id" />
<field name="search_relation_id" />
<field name="search_relation_date" />
<field name="search_relation_partner_category_id" />
</field>
</data>
</field>
</record>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">partner_relations.view_partner_form</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="model">res.partner</field>
<field type="xml" name="arch">
<xpath expr="//div[@name='buttons']" position="inside">
<button class="oe_inline oe_stat_button"
type="action"
context="{
'search_default_this_partner_id': active_id,
'default_left_partner_id': active_id,
'active_model': 'res.partner',
'active_id': id,
'active_ids': [id],
'active_test': False,
}"
name="%(action_res_partner_relation_all)d"
icon="fa-users">
<field string="Relations" name="relation_count" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
<act_window id="action_show_partner_relations"
name="Show partner's relations"
src_model="res.partner"
res_model="res.partner.relation.all"
domain="[('this_partner_id', 'in', active_ids)]"
key2="client_action_multi" />
</data>
</openerp>

97
partner_relations/view/res_partner_relation.xml

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="form_res_partner_relation" model="ir.ui.view">
<field name="model">res.partner.relation</field>
<field type="xml" name="arch">
<form string="Partner Relation">
<sheet>
<field name="left_partner_id" />
<field name="type_id" />
<field name="right_partner_id" />
</sheet>
</form>
</field>
</record>
<record id="tree_res_partner_relation" model="ir.ui.view">
<field name="model">res.partner.relation</field>
<field name="arch" type="xml">
<tree
string="Partner Relations"
colors="gray:date_end and date_end &lt; current_date or not active;blue:date_start &gt; current_date"
editable="top"
>
<field
name="left_partner_id"
options="{'create': false, 'create_edit': false}"
/>
<field
name="type_selection_id"
required="True"
options="{'create': false, 'create_edit': false}"/>
<field
name="right_partner_id"
options="{'create': false, 'create_edit': false}"
/>
<field name="date_start" />
<field name="date_end" />
<field name="active" />
</tree>
</field>
</record>
<record id="search_res_partner_relation" model="ir.ui.view">
<field name="model">res.partner.relation</field>
<field name="arch" type="xml">
<search string="Search Relations">
<field name="any_partner_id"/>
<field name="left_partner_id"/>
<field name="right_partner_id"/>
<field name="type_id"/>
<field name="active"/>
<group expand="0" string="Group By">
<filter string="Left Partner" context="{'group_by': 'left_partner_id'}"/>
<filter string="Right Partner" context="{'group_by': 'right_partner_id'}"/>
<filter string="Relationship Type" context="{'group_by': 'type_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_res_partner_relation" model="ir.actions.act_window">
<field name="name">Relations</field>
<field name="res_model">res.partner.relation</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="tree_res_partner_relation"/>
<field name="search_view_id" ref="search_res_partner_relation"/>
<field name="domain">[('active', '=', True)]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.
</p>
</field>
</record>
<record id="action_show_right_relation_partners" model="ir.actions.server">
<field name="sequence" eval="5"/>
<field name="state">code</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_res_partner_relation"/>
<field name="code">action = self.get_action_related_partners(cr, uid, context.get('active_ids', []), dict(context or {}, partner_relations_show_side='right'))</field>
<field name="condition">True</field>
<field name="name">Show partners</field>
</record>
<record id="action_show_right_relation_partners_value" model="ir.values">
<field name="name">Show partners</field>
<field name="key">action</field>
<field name="key2">client_action_multi</field>
<field name="model">res.partner.relation.all</field>
<field name="value" eval="'ir.actions.server,%d' % ref('partner_relations.action_show_right_relation_partners')" />
</record>
</data>
</openerp>

92
partner_relations/view/res_partner_relation_all.xml

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="tree_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field name="arch" type="xml">
<tree
string="Partner Relations"
colors="gray:(date_end and date_end &lt; current_date) or not active;blue:date_start &gt; current_date"
editable="top"
>
<field
name="this_partner_id"
readonly="1"
/>
<field
name="type_selection_id"
required="True"
domain="[
'|',
('contact_type_this', '=', False),
('contact_type_this', '=', contact_type),
]"
options="{'create': false, 'create_edit': false}"
/>
<field
name="other_partner_id"
attrs="{
'readonly': [('type_selection_id', '=', False)],
}"
options="{'create': false, 'create_edit': false}"
/>
<field name="date_start" />
<field name="date_end" />
<field name="active" />
<field name="contact_type" invisible="1"/>
</tree>
</field>
</record>
<record id="form_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field name="arch" type="xml">
<form string="Partner relation">
<group>
<field name="this_partner_id" />
<field name="type_selection_id" />
<field name="other_partner_id" />
</group>
<group>
<field name="date_start" />
<field name="date_end" />
<field name="active" />
</group>
</form>
</field>
</record>
<record id="search_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field name="arch" type="xml">
<search string="Search Relations">
<field name="this_partner_id"/>
<field name="other_partner_id"/>
<field name="type_id"/>
<field name="active"/>
<group expand="0" string="Group By">
<filter string="Other Partner" context="{'group_by': 'other_partner_id'}"/>
<filter string="Relationship Type" context="{'group_by': 'type_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_res_partner_relation_all" model="ir.actions.act_window">
<field name="name">Relations</field>
<field name="res_model">res.partner.relation.all</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="tree_res_partner_relation_all"/>
<field name="search_view_id" ref="search_res_partner_relation_all"/>
<field name="domain">[('active', '=', True)]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.
</p>
</field>
</record>
</data>
</openerp>

44
partner_relations/view/res_partner_relation_type.xml

@ -0,0 +1,44 @@
<openerp>
<data>
<record id="tree_res_partner_relation_type" model="ir.ui.view">
<field name="model">res.partner.relation.type</field>
<field name="type">tree</field>
<field type="xml" name="arch">
<tree version="7.0" string="Partner relation">
<field name="name" />
<field name="name_inverse" />
<field name="contact_type_left" />
<field name="contact_type_right" />
</tree>
</field>
</record>
<record id="form_res_partner_relation_type" model="ir.ui.view">
<field name="model">res.partner.relation.type</field>
<field name="type">form</field>
<field type="xml" name="arch">
<form version="7.0" string="Partner relation">
<sheet>
<group>
<group
colspan="2" col="2"
string="Left side of relation"
>
<field name="name" />
<field name="contact_type_left" />
<field name="partner_category_left" />
</group>
<group
colspan="2" col="2"
string="Right side of relation"
>
<field name="name_inverse" />
<field name="contact_type_right" />
<field name="partner_category_right" />
</group>
</group>
</sheet>
</form>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save