diff --git a/partner_relations/README.rst b/partner_relations/README.rst new file mode 100644 index 000000000..5b891c692 --- /dev/null +++ b/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 +* Stefan Rijnhart +* Ronald Portier +* Sandy Carter +* Bruno Joliveau +* Adriana Ierfino + +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. diff --git a/partner_relations/__init__.py b/partner_relations/__init__.py new file mode 100644 index 000000000..9da2ac3b6 --- /dev/null +++ b/partner_relations/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV (). +# +# 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 . +# +############################################################################## +from . import model diff --git a/partner_relations/__openerp__.py b/partner_relations/__openerp__.py new file mode 100644 index 000000000..c7e3775b9 --- /dev/null +++ b/partner_relations/__openerp__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV (). +# +# 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 . +# +############################################################################## +{ + "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': [], + }, +} diff --git a/partner_relations/data/demo.xml b/partner_relations/data/demo.xml new file mode 100644 index 000000000..d177cecd2 --- /dev/null +++ b/partner_relations/data/demo.xml @@ -0,0 +1,38 @@ + + + + + Is assistant of + Has assistant + p + p + + + Is competitor of + Is competitor of + c + c + + + Has worked for + Has former employee + p + c + + + + + + + + + + + + + + + + + + diff --git a/partner_relations/i18n/es.po b/partner_relations/i18n/es.po new file mode 100644 index 000000000..857bec922 --- /dev/null +++ b/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 "

\n" +" Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.\n" +"

\n" +" " +msgstr "

\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" +"

\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\"" + diff --git a/partner_relations/i18n/fr.po b/partner_relations/i18n/fr.po new file mode 100644 index 000000000..8203682bd --- /dev/null +++ b/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 \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 "" +"

\n" +" Record and track your partners' relations. Relations may " +"be linked to other partners with a type either directly or inversely.\n" +"

\n" +" " +msgstr "" +"

\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" +"

\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 »" diff --git a/partner_relations/i18n/nl.po b/partner_relations/i18n/nl.po new file mode 100644 index 000000000..3fe24eac0 --- /dev/null +++ b/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." diff --git a/partner_relations/i18n/partner_relations.pot b/partner_relations/i18n/partner_relations.pot new file mode 100644 index 000000000..9b700725f --- /dev/null +++ b/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 "

\n" +" Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.\n" +"

\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 "" + diff --git a/partner_relations/model/__init__.py b/partner_relations/model/__init__.py new file mode 100644 index 000000000..9e65bc55b --- /dev/null +++ b/partner_relations/model/__init__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV (). +# +# 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 . +# +############################################################################## + +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 diff --git a/partner_relations/model/res_partner.py b/partner_relations/model/res_partner.py new file mode 100644 index 000000000..cf252246b --- /dev/null +++ b/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 (). +# +# 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 . +# +############################################################################## +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 diff --git a/partner_relations/model/res_partner_relation.py b/partner_relations/model/res_partner_relation.py new file mode 100644 index 000000000..99dbcfbb7 --- /dev/null +++ b/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 (). +# +# 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 . +# +############################################################################## + +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' + } diff --git a/partner_relations/model/res_partner_relation_all.py b/partner_relations/model/res_partner_relation_all.py new file mode 100644 index 000000000..f6f61b369 --- /dev/null +++ b/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 (). +# +# 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 . +# +############################################################################## + +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() diff --git a/partner_relations/model/res_partner_relation_type.py b/partner_relations/model/res_partner_relation_type.py new file mode 100644 index 000000000..d7e68fbe2 --- /dev/null +++ b/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 (). +# +# 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 . +# +############################################################################## + +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')), + ] diff --git a/partner_relations/model/res_partner_relation_type_selection.py b/partner_relations/model/res_partner_relation_type_selection.py new file mode 100644 index 000000000..e8f8f0a48 --- /dev/null +++ b/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) diff --git a/partner_relations/security/ir.model.access.csv b/partner_relations/security/ir.model.access.csv new file mode 100644 index 000000000..840b35875 --- /dev/null +++ b/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 diff --git a/partner_relations/static/src/img/icon.png b/partner_relations/static/src/img/icon.png new file mode 100644 index 000000000..c6863a3e4 Binary files /dev/null and b/partner_relations/static/src/img/icon.png differ diff --git a/partner_relations/view/menu.xml b/partner_relations/view/menu.xml new file mode 100644 index 000000000..40230348a --- /dev/null +++ b/partner_relations/view/menu.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + diff --git a/partner_relations/view/res_partner.xml b/partner_relations/view/res_partner.xml new file mode 100644 index 000000000..e960c58a2 --- /dev/null +++ b/partner_relations/view/res_partner.xml @@ -0,0 +1,53 @@ + + + + + + partner_relations.view_partner_filter + + res.partner + + + + + + + + + + + + + + partner_relations.view_partner_form + + res.partner + + + + + + + + + + + diff --git a/partner_relations/view/res_partner_relation.xml b/partner_relations/view/res_partner_relation.xml new file mode 100644 index 000000000..635107bb7 --- /dev/null +++ b/partner_relations/view/res_partner_relation.xml @@ -0,0 +1,97 @@ + + + + + + res.partner.relation + +
+ + + + + +
+
+
+ + + res.partner.relation + + + + + + + + + + + + + + res.partner.relation + + + + + + + + + + + + + + + + + + Relations + res.partner.relation + form + tree + + + [('active', '=', True)] + +

+ Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely. +

+
+
+ + + + code + ir.actions.server + + action = self.get_action_related_partners(cr, uid, context.get('active_ids', []), dict(context or {}, partner_relations_show_side='right')) + True + Show partners + + + + Show partners + action + client_action_multi + res.partner.relation.all + + + +
+
diff --git a/partner_relations/view/res_partner_relation_all.xml b/partner_relations/view/res_partner_relation_all.xml new file mode 100644 index 000000000..49a820710 --- /dev/null +++ b/partner_relations/view/res_partner_relation_all.xml @@ -0,0 +1,92 @@ + + + + + + res.partner.relation.all + + + + + + + + + + + + + + + res.partner.relation.all + +
+ + + + + + + + + + +
+
+
+ + + res.partner.relation.all + + + + + + + + + + + + + + + + Relations + res.partner.relation.all + form + tree + + + [('active', '=', True)] + +

+ Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely. +

+
+
+ +
+
diff --git a/partner_relations/view/res_partner_relation_type.xml b/partner_relations/view/res_partner_relation_type.xml new file mode 100644 index 000000000..d0a3c0746 --- /dev/null +++ b/partner_relations/view/res_partner_relation_type.xml @@ -0,0 +1,44 @@ + + + + res.partner.relation.type + tree + + + + + + + + + + + res.partner.relation.type + form + +
+ + + + + + + + + + + + + + +
+
+
+
+