Merge lp:~therp-nl/partner-contact-management/7.0_partner_relations into lp:~partner-contact-core-editors/partner-contact-management/7.0

Proposed by Holger Brunn (Therp)
Status: Needs review
Proposed branch: lp:~therp-nl/partner-contact-management/7.0_partner_relations
Merge into: lp:~partner-contact-core-editors/partner-contact-management/7.0
Diff against target: 1628 lines (+1543/-0)
15 files modified
partner_relations/__init__.py (+21/-0)
partner_relations/__openerp__.py (+91/-0)
partner_relations/i18n/nl.po (+254/-0)
partner_relations/i18n/partner_relations.pot (+254/-0)
partner_relations/model/__init__.py (+25/-0)
partner_relations/model/res_partner.py (+217/-0)
partner_relations/model/res_partner_relation.py (+257/-0)
partner_relations/model/res_partner_relation_all.py (+75/-0)
partner_relations/model/res_partner_relation_type.py (+48/-0)
partner_relations/model/res_partner_relation_type_selection.py (+133/-0)
partner_relations/security/ir.model.access.csv (+7/-0)
partner_relations/view/menu.xml (+15/-0)
partner_relations/view/res_partner.xml (+86/-0)
partner_relations/view/res_partner_relation.xml (+16/-0)
partner_relations/view/res_partner_relation_type.xml (+44/-0)
To merge this branch: bzr merge lp:~therp-nl/partner-contact-management/7.0_partner_relations
Reviewer Review Type Date Requested Status
Lorenzo Battistini (community) Needs Resubmitting
Partner and Contact Core Editors Pending
Review via email: mp+223734@code.launchpad.net

Description of the change

Introdution
-----------

This addon 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 enode your knowledge about your
partners directly in your partner list.

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.

To post a comment you must log in.
43. By Holger Brunn (Therp)

[FIX] revert code cleanup that was pretty harmful

Revision history for this message
Lorenzo Battistini (elbati) wrote :

This project is now hosted on https://github.com/OCA/partner-contact. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

review: Needs Resubmitting

Unmerged revisions

43. By Holger Brunn (Therp)

[FIX] revert code cleanup that was pretty harmful

42. By Holger Brunn (Therp)

[FIX] typo
[IMP] add access records for views

41. By Holger Brunn (Therp)

[ADD] partner_relations

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'partner_relations'
2=== added file 'partner_relations/__init__.py'
3--- partner_relations/__init__.py 1970-01-01 00:00:00 +0000
4+++ partner_relations/__init__.py 2014-06-20 07:56:04 +0000
5@@ -0,0 +1,21 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# OpenERP, Open Source Management Solution
10+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
11+#
12+# This program is free software: you can redistribute it and/or modify
13+# it under the terms of the GNU Affero General Public License as
14+# published by the Free Software Foundation, either version 3 of the
15+# License, or (at your option) any later version.
16+#
17+# This program is distributed in the hope that it will be useful,
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+# GNU Affero General Public License for more details.
21+#
22+# You should have received a copy of the GNU Affero General Public License
23+# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+#
25+##############################################################################
26+import model
27
28=== added file 'partner_relations/__openerp__.py'
29--- partner_relations/__openerp__.py 1970-01-01 00:00:00 +0000
30+++ partner_relations/__openerp__.py 2014-06-20 07:56:04 +0000
31@@ -0,0 +1,91 @@
32+# -*- coding: utf-8 -*-
33+##############################################################################
34+#
35+# OpenERP, Open Source Management Solution
36+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
37+#
38+# This program is free software: you can redistribute it and/or modify
39+# it under the terms of the GNU Affero General Public License as
40+# published by the Free Software Foundation, either version 3 of the
41+# License, or (at your option) any later version.
42+#
43+# This program is distributed in the hope that it will be useful,
44+# but WITHOUT ANY WARRANTY; without even the implied warranty of
45+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46+# GNU Affero General Public License for more details.
47+#
48+# You should have received a copy of the GNU Affero General Public License
49+# along with this program. If not, see <http://www.gnu.org/licenses/>.
50+#
51+##############################################################################
52+{
53+ "name": "Partner relations",
54+ "version": "1.1",
55+ "author": "Therp BV",
56+ "complexity": "normal",
57+ "description": """
58+Introduction
59+------------
60+
61+This addon aims to provide generic means to model relations between partners.
62+
63+Examples would be 'is sibling of' or 'is friend of', but also 'has contract X
64+with' or 'is assistant of'. This way, you can enode your knowledge about your
65+partners directly in your partner list.
66+
67+Usage
68+-----
69+
70+Before being able to use relations, you'll have define some first. Do that in
71+Sales / Configuration / Address Book / Partner relations. Here, you need to
72+name both sides of the relation: To have an assistant-relation, you would name
73+one side 'is assistant of' and the other side 'has assistant'. This relation
74+only makes sense between people, so you would choose 'Person' for both partner
75+types. For the relation 'is a competitor of', both sides would be companies,
76+while the relation 'has worked for' should have persons on the left side and
77+companies on the right side. If you leave this field empty, the relation is
78+applicable to all types of partners.
79+
80+If you use categories to further specify the type of partners, you could for
81+example enforce that the 'is member of' relation can only have companies with
82+label 'Organization' on the left side.
83+
84+Now open a partner and choose relations as appropriate in the 'Relations' tab.
85+
86+Searching partners with relations
87+---------------------------------
88+
89+Searching for relations is integrated transparently into the partner search
90+form. To find all assistants in your database, fill in 'is assistant of' and
91+autocomplete will propose to search for partners having this relation. Now if
92+you want to find Anna's assistant, you fill in 'Anna' and one of the proposals
93+is to search for partners having a relation with Anna. This results in Anna's
94+assistant(s), as you searched for assistants before.
95+
96+By default, only active, not expired relations are shown. If you need to find
97+partners that had some relation at a certain date, fill in that date in the
98+search box and one of the proposals is to search for relations valid at that
99+date.""",
100+ "category": "Customer Relationship Management",
101+ "depends": [
102+ 'web_m2x_options',
103+ ],
104+ "data": [
105+ 'view/res_partner.xml',
106+ 'view/res_partner_relation.xml',
107+ 'view/res_partner_relation_type.xml',
108+ 'view/menu.xml',
109+ 'security/ir.model.access.csv',
110+ ],
111+ "js": [
112+ ],
113+ "css": [
114+ ],
115+ "qweb": [
116+ ],
117+ "auto_install": False,
118+ "installable": True,
119+ "external_dependencies": {
120+ 'python': [],
121+ },
122+}
123
124=== added directory 'partner_relations/data'
125=== added directory 'partner_relations/i18n'
126=== added file 'partner_relations/i18n/nl.po'
127--- partner_relations/i18n/nl.po 1970-01-01 00:00:00 +0000
128+++ partner_relations/i18n/nl.po 2014-06-20 07:56:04 +0000
129@@ -0,0 +1,254 @@
130+# Translation of OpenERP Server.
131+# This file contains the translation of the following modules:
132+# * partner_relations
133+#
134+msgid ""
135+msgstr ""
136+"Project-Id-Version: OpenERP Server 7.0\n"
137+"Report-Msgid-Bugs-To: \n"
138+"POT-Creation-Date: 2014-06-19 13:02+0000\n"
139+"PO-Revision-Date: 2014-06-19 13:02+0000\n"
140+"Last-Translator: <>\n"
141+"Language-Team: \n"
142+"MIME-Version: 1.0\n"
143+"Content-Type: text/plain; charset=UTF-8\n"
144+"Content-Transfer-Encoding: \n"
145+"Plural-Forms: \n"
146+
147+#. module: partner_relations
148+#: field:res.partner.relation,active:0
149+#: field:res.partner.relation.all,active:0
150+msgid "Active"
151+msgstr "Actief"
152+
153+#. module: partner_relations
154+#: model:ir.model,name:partner_relations.model_res_partner_relation_all
155+msgid "All (non-inverse + inverse) relations between partners"
156+msgstr "Alle (non-inverse + inverse) koppelingen tussen relaties"
157+
158+#. module: partner_relations
159+#: model:ir.model,name:partner_relations.model_res_partner_relation_type_selection
160+msgid "All relation types"
161+msgstr "Alle relaties"
162+
163+#. module: partner_relations
164+#: field:res.partner,relation_all_ids:0
165+msgid "All relations with current partner"
166+msgstr "Alle koppelingen met huidige relatie"
167+
168+#. module: partner_relations
169+#: field:res.partner.relation.all,this_partner_id:0
170+msgid "Current partner"
171+msgstr "Huidige relatie"
172+
173+#. module: partner_relations
174+#: field:res.partner.relation.type.selection,partner_category_this:0
175+#: field:res.partner.relation.type.selection,search_partner_category_this:0
176+msgid "Current record's category"
177+msgstr "Categorie van huidige record"
178+
179+#. module: partner_relations
180+#: field:res.partner.relation.type.selection,contact_type_this:0
181+msgid "Current record's partner type"
182+msgstr "Relatietype van huidige record"
183+
184+#. module: partner_relations
185+#: field:res.partner.relation,date_end:0
186+#: field:res.partner.relation.all,date_end:0
187+msgid "Ending date"
188+msgstr "Einddatum"
189+
190+#. module: partner_relations
191+#: field:res.partner,search_relation_id:0
192+msgid "Has relation of type"
193+msgstr "Heeft relatie"
194+
195+#. module: partner_relations
196+#: field:res.partner,search_relation_partner_id:0
197+msgid "Has relation with"
198+msgstr "Heeft relatie met"
199+
200+#. module: partner_relations
201+#: field:res.partner.relation.type,name_inverse:0
202+msgid "Inverse name"
203+msgstr "Inverse naam"
204+
205+#. module: partner_relations
206+#: selection:res.partner.relation.all,record_type:0
207+#: selection:res.partner.relation.type.selection,record_type:0
208+msgid "Inverse type"
209+msgstr "Inverse type"
210+
211+#. module: partner_relations
212+#: field:res.partner.relation,left_partner_id:0
213+msgid "Left partner"
214+msgstr "Linker relatie"
215+
216+#. module: partner_relations
217+#: field:res.partner.relation.type,partner_category_left:0
218+msgid "Left partner category"
219+msgstr "Linker relatielabel"
220+
221+#. module: partner_relations
222+#: field:res.partner.relation.type,contact_type_left:0
223+msgid "Left partner type"
224+msgstr "Linker relatietype"
225+
226+#. module: partner_relations
227+#: view:res.partner.relation.type:0
228+msgid "Left side of relation"
229+msgstr "Linkerkant van de koppeling"
230+
231+#. module: partner_relations
232+#: field:res.partner.relation.type,name:0
233+#: field:res.partner.relation.type.selection,name:0
234+msgid "Name"
235+msgstr "Naam"
236+
237+#. module: partner_relations
238+#: field:res.partner.relation.all,other_partner_id:0
239+msgid "Other partner"
240+msgstr "Andere relatie"
241+
242+#. module: partner_relations
243+#: field:res.partner.relation.type.selection,partner_category_other:0
244+msgid "Other record's category"
245+msgstr "Categorie andere record"
246+
247+#. module: partner_relations
248+#: field:res.partner.relation.type.selection,contact_type_other:0
249+msgid "Other record's partner type"
250+msgstr "Type andere record"
251+
252+#. module: partner_relations
253+#: model:ir.model,name:partner_relations.model_res_partner_relation_type
254+#: model:ir.model,name:partner_relations.model_res_partner_relation_type_inverse
255+msgid "Parter relation type"
256+msgstr "Type relatiekoppeling"
257+
258+#. module: partner_relations
259+#: model:ir.model,name:partner_relations.model_res_partner
260+#: field:res.partner.relation,partner_id_display:0
261+msgid "Partner"
262+msgstr "Relatie"
263+
264+#. module: partner_relations
265+#: model:ir.model,name:partner_relations.model_res_partner_category
266+msgid "Partner Categories"
267+msgstr "Relatie Categorieën"
268+
269+#. module: partner_relations
270+#: model:ir.model,name:partner_relations.model_res_partner_relation
271+#: view:res.partner.relation:0
272+#: view:res.partner.relation.type:0
273+msgid "Partner relation"
274+msgstr "Relatiekoppeling"
275+
276+#. module: partner_relations
277+#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_type
278+#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_type
279+msgid "Partner relations"
280+msgstr "Relatiekoppelingen"
281+
282+#. module: partner_relations
283+#: constraint:res.partner.relation:0
284+msgid "Partners cannot have a relation with themselves."
285+msgstr "Relaties kunnen niet aan zichzelf gekoppeld worden."
286+
287+#. module: partner_relations
288+#: field:res.partner.relation.all,record_type:0
289+#: field:res.partner.relation.type.selection,record_type:0
290+msgid "Record type"
291+msgstr "Record type"
292+
293+#. module: partner_relations
294+#: field:res.partner.relation.all,relation_id:0
295+msgid "Relation"
296+msgstr "Koppeling"
297+
298+#. module: partner_relations
299+#: field:res.partner.relation,is_relation_expired:0
300+msgid "Relation is expired"
301+msgstr "Koppeling is afgelopen"
302+
303+#. module: partner_relations
304+#: field:res.partner.relation,is_relation_future:0
305+msgid "Relation is in the future"
306+msgstr "Koppeling is in de toekomst"
307+
308+#. module: partner_relations
309+#: field:res.partner.relation.all,type_id:0
310+msgid "Relation type"
311+msgstr "Koppelingstype"
312+
313+#. module: partner_relations
314+#: field:res.partner,search_relation_date:0
315+msgid "Relation valid"
316+msgstr "Datum koppeling"
317+
318+#. module: partner_relations
319+#: view:res.partner:0
320+#: field:res.partner,relation_ids:0
321+msgid "Relations"
322+msgstr "Koppelingen"
323+
324+#. module: partner_relations
325+#: field:res.partner.relation,right_partner_id:0
326+msgid "Right partner"
327+msgstr "Rechter relatie"
328+
329+#. module: partner_relations
330+#: field:res.partner.relation.type,partner_category_right:0
331+msgid "Right partner category"
332+msgstr "Rechter relatielabel"
333+
334+#. module: partner_relations
335+#: field:res.partner.relation.type,contact_type_right:0
336+msgid "Right partner type"
337+msgstr "Rechter relatietype"
338+
339+#. module: partner_relations
340+#: view:res.partner.relation.type:0
341+msgid "Right side of relation"
342+msgstr "Rechterkant van de koppeling"
343+
344+#. module: partner_relations
345+#: field:res.partner.relation,date_start:0
346+#: field:res.partner.relation.all,date_start:0
347+msgid "Starting date"
348+msgstr "Begindatum"
349+
350+#. module: partner_relations
351+#: constraint:res.partner.relation:0
352+msgid "The left partner is not applicable for this relation type."
353+msgstr "De linker relatie is niet geldig voor dit type koppeling."
354+
355+#. module: partner_relations
356+#: constraint:res.partner.relation:0
357+msgid "The right partner is not applicable for this relation type."
358+msgstr "De rechter relatie is niet geldig voor dit type koppeling."
359+
360+#. module: partner_relations
361+#: constraint:res.partner.relation:0
362+msgid "The starting date cannot be after the ending date."
363+msgstr "De begindatum mag niet na de einddatum liggen."
364+
365+#. module: partner_relations
366+#: field:res.partner.relation,type_id:0
367+#: field:res.partner.relation,type_selection_id:0
368+#: selection:res.partner.relation.all,record_type:0
369+#: selection:res.partner.relation.type.selection,record_type:0
370+#: field:res.partner.relation.type.selection,type_id:0
371+msgid "Type"
372+msgstr "Type"
373+
374+#. module: partner_relations
375+#: field:res.partner.category,only_for_organisation:0
376+msgid "Valid for organisation only"
377+msgstr "Alleen geldig voor organisaties"
378+
379+#. module: partner_relations
380+#: field:res.partner.category,only_for_person:0
381+msgid "Valid for person only"
382+msgstr "Alleen geldig voor personen"
383+
384
385=== added file 'partner_relations/i18n/partner_relations.pot'
386--- partner_relations/i18n/partner_relations.pot 1970-01-01 00:00:00 +0000
387+++ partner_relations/i18n/partner_relations.pot 2014-06-20 07:56:04 +0000
388@@ -0,0 +1,254 @@
389+# Translation of OpenERP Server.
390+# This file contains the translation of the following modules:
391+# * partner_relations
392+#
393+msgid ""
394+msgstr ""
395+"Project-Id-Version: OpenERP Server 7.0\n"
396+"Report-Msgid-Bugs-To: \n"
397+"POT-Creation-Date: 2014-06-19 13:01+0000\n"
398+"PO-Revision-Date: 2014-06-19 13:01+0000\n"
399+"Last-Translator: <>\n"
400+"Language-Team: \n"
401+"MIME-Version: 1.0\n"
402+"Content-Type: text/plain; charset=UTF-8\n"
403+"Content-Transfer-Encoding: \n"
404+"Plural-Forms: \n"
405+
406+#. module: partner_relations
407+#: field:res.partner.relation,active:0
408+#: field:res.partner.relation.all,active:0
409+msgid "Active"
410+msgstr ""
411+
412+#. module: partner_relations
413+#: model:ir.model,name:partner_relations.model_res_partner_relation_all
414+msgid "All (non-inverse + inverse) relations between partners"
415+msgstr ""
416+
417+#. module: partner_relations
418+#: model:ir.model,name:partner_relations.model_res_partner_relation_type_selection
419+msgid "All relation types"
420+msgstr ""
421+
422+#. module: partner_relations
423+#: field:res.partner,relation_all_ids:0
424+msgid "All relations with current partner"
425+msgstr ""
426+
427+#. module: partner_relations
428+#: field:res.partner.relation.all,this_partner_id:0
429+msgid "Current partner"
430+msgstr ""
431+
432+#. module: partner_relations
433+#: field:res.partner.relation.type.selection,partner_category_this:0
434+#: field:res.partner.relation.type.selection,search_partner_category_this:0
435+msgid "Current record's category"
436+msgstr ""
437+
438+#. module: partner_relations
439+#: field:res.partner.relation.type.selection,contact_type_this:0
440+msgid "Current record's partner type"
441+msgstr ""
442+
443+#. module: partner_relations
444+#: field:res.partner.relation,date_end:0
445+#: field:res.partner.relation.all,date_end:0
446+msgid "Ending date"
447+msgstr ""
448+
449+#. module: partner_relations
450+#: field:res.partner,search_relation_id:0
451+msgid "Has relation of type"
452+msgstr ""
453+
454+#. module: partner_relations
455+#: field:res.partner,search_relation_partner_id:0
456+msgid "Has relation with"
457+msgstr ""
458+
459+#. module: partner_relations
460+#: field:res.partner.relation.type,name_inverse:0
461+msgid "Inverse name"
462+msgstr ""
463+
464+#. module: partner_relations
465+#: selection:res.partner.relation.all,record_type:0
466+#: selection:res.partner.relation.type.selection,record_type:0
467+msgid "Inverse type"
468+msgstr ""
469+
470+#. module: partner_relations
471+#: field:res.partner.relation,left_partner_id:0
472+msgid "Left partner"
473+msgstr ""
474+
475+#. module: partner_relations
476+#: field:res.partner.relation.type,partner_category_left:0
477+msgid "Left partner category"
478+msgstr ""
479+
480+#. module: partner_relations
481+#: field:res.partner.relation.type,contact_type_left:0
482+msgid "Left partner type"
483+msgstr ""
484+
485+#. module: partner_relations
486+#: view:res.partner.relation.type:0
487+msgid "Left side of relation"
488+msgstr ""
489+
490+#. module: partner_relations
491+#: field:res.partner.relation.type,name:0
492+#: field:res.partner.relation.type.selection,name:0
493+msgid "Name"
494+msgstr ""
495+
496+#. module: partner_relations
497+#: field:res.partner.relation.all,other_partner_id:0
498+msgid "Other partner"
499+msgstr ""
500+
501+#. module: partner_relations
502+#: field:res.partner.relation.type.selection,partner_category_other:0
503+msgid "Other record's category"
504+msgstr ""
505+
506+#. module: partner_relations
507+#: field:res.partner.relation.type.selection,contact_type_other:0
508+msgid "Other record's partner type"
509+msgstr ""
510+
511+#. module: partner_relations
512+#: model:ir.model,name:partner_relations.model_res_partner_relation_type
513+#: model:ir.model,name:partner_relations.model_res_partner_relation_type_inverse
514+msgid "Parter relation type"
515+msgstr ""
516+
517+#. module: partner_relations
518+#: model:ir.model,name:partner_relations.model_res_partner
519+#: field:res.partner.relation,partner_id_display:0
520+msgid "Partner"
521+msgstr ""
522+
523+#. module: partner_relations
524+#: model:ir.model,name:partner_relations.model_res_partner_category
525+msgid "Partner Categories"
526+msgstr ""
527+
528+#. module: partner_relations
529+#: model:ir.model,name:partner_relations.model_res_partner_relation
530+#: view:res.partner.relation:0
531+#: view:res.partner.relation.type:0
532+msgid "Partner relation"
533+msgstr ""
534+
535+#. module: partner_relations
536+#: model:ir.actions.act_window,name:partner_relations.action_res_partner_relation_type
537+#: model:ir.ui.menu,name:partner_relations.menu_res_partner_relation_type
538+msgid "Partner relations"
539+msgstr ""
540+
541+#. module: partner_relations
542+#: constraint:res.partner.relation:0
543+msgid "Partners cannot have a relation with themselves."
544+msgstr ""
545+
546+#. module: partner_relations
547+#: field:res.partner.relation.all,record_type:0
548+#: field:res.partner.relation.type.selection,record_type:0
549+msgid "Record type"
550+msgstr ""
551+
552+#. module: partner_relations
553+#: field:res.partner.relation.all,relation_id:0
554+msgid "Relation"
555+msgstr ""
556+
557+#. module: partner_relations
558+#: field:res.partner.relation,is_relation_expired:0
559+msgid "Relation is expired"
560+msgstr ""
561+
562+#. module: partner_relations
563+#: field:res.partner.relation,is_relation_future:0
564+msgid "Relation is in the future"
565+msgstr ""
566+
567+#. module: partner_relations
568+#: field:res.partner.relation.all,type_id:0
569+msgid "Relation type"
570+msgstr ""
571+
572+#. module: partner_relations
573+#: field:res.partner,search_relation_date:0
574+msgid "Relation valid"
575+msgstr ""
576+
577+#. module: partner_relations
578+#: view:res.partner:0
579+#: field:res.partner,relation_ids:0
580+msgid "Relations"
581+msgstr ""
582+
583+#. module: partner_relations
584+#: field:res.partner.relation,right_partner_id:0
585+msgid "Right partner"
586+msgstr ""
587+
588+#. module: partner_relations
589+#: field:res.partner.relation.type,partner_category_right:0
590+msgid "Right partner category"
591+msgstr ""
592+
593+#. module: partner_relations
594+#: field:res.partner.relation.type,contact_type_right:0
595+msgid "Right partner type"
596+msgstr ""
597+
598+#. module: partner_relations
599+#: view:res.partner.relation.type:0
600+msgid "Right side of relation"
601+msgstr ""
602+
603+#. module: partner_relations
604+#: field:res.partner.relation,date_start:0
605+#: field:res.partner.relation.all,date_start:0
606+msgid "Starting date"
607+msgstr ""
608+
609+#. module: partner_relations
610+#: constraint:res.partner.relation:0
611+msgid "The left partner is not applicable for this relation type."
612+msgstr ""
613+
614+#. module: partner_relations
615+#: constraint:res.partner.relation:0
616+msgid "The right partner is not applicable for this relation type."
617+msgstr ""
618+
619+#. module: partner_relations
620+#: constraint:res.partner.relation:0
621+msgid "The starting date cannot be after the ending date."
622+msgstr ""
623+
624+#. module: partner_relations
625+#: field:res.partner.relation,type_id:0
626+#: field:res.partner.relation,type_selection_id:0
627+#: selection:res.partner.relation.all,record_type:0
628+#: selection:res.partner.relation.type.selection,record_type:0
629+#: field:res.partner.relation.type.selection,type_id:0
630+msgid "Type"
631+msgstr ""
632+
633+#. module: partner_relations
634+#: field:res.partner.category,only_for_organisation:0
635+msgid "Valid for organisation only"
636+msgstr ""
637+
638+#. module: partner_relations
639+#: field:res.partner.category,only_for_person:0
640+msgid "Valid for person only"
641+msgstr ""
642+
643
644=== added directory 'partner_relations/model'
645=== added file 'partner_relations/model/__init__.py'
646--- partner_relations/model/__init__.py 1970-01-01 00:00:00 +0000
647+++ partner_relations/model/__init__.py 2014-06-20 07:56:04 +0000
648@@ -0,0 +1,25 @@
649+# -*- coding: utf-8 -*-
650+##############################################################################
651+#
652+# OpenERP, Open Source Management Solution
653+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
654+#
655+# This program is free software: you can redistribute it and/or modify
656+# it under the terms of the GNU Affero General Public License as
657+# published by the Free Software Foundation, either version 3 of the
658+# License, or (at your option) any later version.
659+#
660+# This program is distributed in the hope that it will be useful,
661+# but WITHOUT ANY WARRANTY; without even the implied warranty of
662+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
663+# GNU Affero General Public License for more details.
664+#
665+# You should have received a copy of the GNU Affero General Public License
666+# along with this program. If not, see <http://www.gnu.org/licenses/>.
667+#
668+##############################################################################
669+import res_partner
670+import res_partner_relation
671+import res_partner_relation_type
672+import res_partner_relation_type_selection
673+from . import res_partner_relation_all
674
675=== added file 'partner_relations/model/res_partner.py'
676--- partner_relations/model/res_partner.py 1970-01-01 00:00:00 +0000
677+++ partner_relations/model/res_partner.py 2014-06-20 07:56:04 +0000
678@@ -0,0 +1,217 @@
679+# -*- coding: utf-8 -*-
680+'''Extend res.partner model'''
681+##############################################################################
682+#
683+# OpenERP, Open Source Management Solution
684+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
685+#
686+# This program is free software: you can redistribute it and/or modify
687+# it under the terms of the GNU Affero General Public License as
688+# published by the Free Software Foundation, either version 3 of the
689+# License, or (at your option) any later version.
690+#
691+# This program is distributed in the hope that it will be useful,
692+# but WITHOUT ANY WARRANTY; without even the implied warranty of
693+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
694+# GNU Affero General Public License for more details.
695+#
696+# You should have received a copy of the GNU Affero General Public License
697+# along with this program. If not, see <http://www.gnu.org/licenses/>.
698+#
699+##############################################################################
700+import time
701+from openerp.osv import orm
702+from openerp.osv import fields
703+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
704+
705+
706+class ResPartner(orm.Model):
707+ _inherit = 'res.partner'
708+
709+ def _get_relation_ids(
710+ self, cr, uid, ids, dummy_name, dummy_arg, context=None):
711+ if context is None:
712+ context = {}
713+
714+ #TODO: do a permission test on returned ids
715+ cr.execute(
716+ '''select id, left_partner_id, right_partner_id
717+ from res_partner_relation
718+ where left_partner_id in %s or right_partner_id in %s''' +
719+ (' and active' if context.get('active_test', True) else ''),
720+ (tuple(ids), tuple(ids))
721+ )
722+ result = dict([(i, []) for i in ids])
723+ for row in cr.fetchall():
724+ if row[1] in result:
725+ result[row[1]].append(row[0])
726+ if row[2] in result:
727+ result[row[2]].append(row[0])
728+ return result
729+
730+ def _set_relation_ids(
731+ self, cr, uid, ids, dummy_name, field_value, dummy_arg,
732+ context=None):
733+ if context is None:
734+ context = {}
735+ relation_obj = self.pool.get('res.partner.relation')
736+ context2 = self._update_context(context, ids)
737+ for value in field_value:
738+ if value[0] == 0:
739+ relation_obj.create(cr, uid, value[2], context=context2)
740+ if value[0] == 1:
741+ relation_obj.write(
742+ cr, uid, value[1], value[2], context=context2)
743+ if value[0] == 2:
744+ relation_obj.unlink(cr, uid, value[1], context=context2)
745+
746+ def _search_relation_id(
747+ self, cr, uid, dummy_obj, name, args, context=None):
748+ result = []
749+ for arg in args:
750+ if isinstance(arg, tuple) and arg[0] == name:
751+ if arg[1] != '=':
752+ continue
753+
754+ type_id, is_inverse = self\
755+ .pool['res.partner.relation.type.selection']\
756+ .get_type_from_selection_id(cr, uid, arg[2])
757+
758+ result.extend([
759+ '&',
760+ ('relation_all_ids.type_id', '=', type_id),
761+ ('relation_all_ids.record_type', '=',
762+ 'b' if is_inverse else 'a')
763+ ])
764+
765+ return result
766+
767+ def _search_relation_date(self, cr, uid, obj, name, args, context=None):
768+ result = []
769+ for arg in args:
770+ if isinstance(arg, tuple) and arg[0] == name:
771+ #TODO: handle {<,>}{,=}
772+ if arg[1] != '=':
773+ continue
774+
775+ result.extend([
776+ '&',
777+ '|',
778+ ('relation_all_ids.date_start', '=', False),
779+ ('relation_all_ids.date_start', '<=', arg[2]),
780+ '|',
781+ ('relation_all_ids.date_end', '=', False),
782+ ('relation_all_ids.date_end', '>=', arg[2]),
783+ ])
784+
785+ return result
786+
787+ def _search_related_partner_id(
788+ self, cr, uid, dummy_obj, name, args, context=None):
789+ result = []
790+ for arg in args:
791+ if isinstance(arg, tuple) and arg[0] == name:
792+ if arg[1] != '=':
793+ continue
794+
795+ result.append(
796+ (
797+ 'relation_all_ids.other_partner_id',
798+ '=',
799+ arg[2],
800+ ))
801+
802+ return result
803+
804+ _columns = {
805+ 'relation_ids': fields.function(
806+ _get_relation_ids,
807+ fnct_inv=_set_relation_ids,
808+ type='one2many', obj='res.partner.relation',
809+ string='Relations'
810+ ),
811+ 'relation_all_ids': fields.one2many(
812+ 'res.partner.relation.all', 'this_partner_id',
813+ string='All relations with current partner',
814+ auto_join=True,
815+ ),
816+ 'search_relation_id': fields.function(
817+ lambda self, cr, uid, ids, *args: dict([
818+ (i, False) for i in ids]),
819+ fnct_search=_search_relation_id,
820+ string='Has relation of type',
821+ type='many2one', obj='res.partner.relation.type.selection'
822+ ),
823+ 'search_relation_partner_id': fields.function(
824+ lambda self, cr, uid, ids, *args: dict([
825+ (i, False) for i in ids]),
826+ fnct_search=_search_related_partner_id,
827+ string='Has relation with',
828+ type='many2one', obj='res.partner'
829+ ),
830+ 'search_relation_date': fields.function(
831+ lambda self, cr, uid, ids, *args: dict([
832+ (i, False) for i in ids]),
833+ fnct_search=_search_relation_date,
834+ string='Relation valid', type='date'
835+ ),
836+ }
837+
838+ def copy_data(self, cr, uid, id, default=None, context=None):
839+ if default is None:
840+ default = {}
841+ default.setdefault('relation_ids', [])
842+ default.setdefault('relation_all_ids', [])
843+ return super(ResPartner, self).copy_data(cr, uid, id, default=default,
844+ context=context)
845+
846+ def search(self, cr, uid, args, offset=0, limit=None, order=None,
847+ context=None, count=False):
848+ if context is None:
849+ context = {}
850+ #inject searching for current relation date if we search for relation
851+ #properties and no explicit date was given
852+ date_args = []
853+ for arg in args:
854+ if isinstance(arg, list) and arg[0].startswith('search_relation'):
855+ if arg[0] == 'search_relation_date':
856+ date_args = []
857+ break
858+ if not date_args:
859+ date_args = [
860+ ('search_relation_date', '=', time.strftime(
861+ DEFAULT_SERVER_DATE_FORMAT))]
862+
863+ #because of auto_join, we have to do the active test by hand
864+ active_args = []
865+ if context.get('active_test', True):
866+ for arg in args:
867+ if isinstance(arg, list) and\
868+ arg[0].startswith('search_relation'):
869+ active_args = [('relation_all_ids.active', '=', True)]
870+ break
871+
872+ return super(ResPartner, self).search(
873+ cr, uid, args + date_args + active_args, offset=offset,
874+ limit=limit, order=order, context=context, count=count)
875+
876+ def read(
877+ self, cr, uid, ids, fields=None, context=None,
878+ load='_classic_read'):
879+ return super(ResPartner, self).read(
880+ cr, uid, ids, fields=fields,
881+ context=self._update_context(context, ids))
882+
883+ def write(self, cr, uid, ids, vals, context=None):
884+ return super(ResPartner, self).write(
885+ cr, uid, ids, vals, context=self._update_context(context, ids))
886+
887+ def _update_context(self, context, ids):
888+ if context is None:
889+ context = {}
890+ ids = ids if isinstance(ids, list) else [ids] if ids else []
891+ result = context.copy()
892+ result.setdefault('active_id', ids[0] if ids else None)
893+ result.setdefault('active_ids', ids)
894+ result.setdefault('active_model', self._name)
895+ return result
896
897=== added file 'partner_relations/model/res_partner_relation.py'
898--- partner_relations/model/res_partner_relation.py 1970-01-01 00:00:00 +0000
899+++ partner_relations/model/res_partner_relation.py 2014-06-20 07:56:04 +0000
900@@ -0,0 +1,257 @@
901+# -*- coding: utf-8 -*-
902+'''Define model res.partner.relation'''
903+##############################################################################
904+#
905+# OpenERP, Open Source Management Solution
906+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
907+#
908+# This program is free software: you can redistribute it and/or modify
909+# it under the terms of the GNU Affero General Public License as
910+# published by the Free Software Foundation, either version 3 of the
911+# License, or (at your option) any later version.
912+#
913+# This program is distributed in the hope that it will be useful,
914+# but WITHOUT ANY WARRANTY; without even the implied warranty of
915+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
916+# GNU Affero General Public License for more details.
917+#
918+# You should have received a copy of the GNU Affero General Public License
919+# along with this program. If not, see <http://www.gnu.org/licenses/>.
920+#
921+##############################################################################
922+from openerp.osv.orm import Model
923+from openerp.osv import fields
924+
925+
926+class ResPartnerRelation(Model):
927+ '''Model res.partner.relation is used to describe all links or relations
928+ between partners in the database.
929+
930+ In many parts of the code we have to know whether the active partner is
931+ the left partner, or the right partner. If the active partner is the
932+ right partner we have to show the inverse name.
933+
934+ Because the active partner is crucial for the working of partner
935+ relationships, we make sure on the res.partner model that the partner id
936+ is set in the context where needed.
937+ '''
938+ _name = 'res.partner.relation'
939+ _description = 'Partner relation'
940+
941+ def _on_right_partner(self, cr, uid, right_partner_id, context=None):
942+ '''Determine wether functions are called in a situation where the
943+ active partner is the right partner. Default False!
944+ '''
945+ if (context and 'active_ids' in context
946+ and right_partner_id in context.get('active_ids', [])):
947+ return True
948+ return False
949+
950+ def _correct_vals(self, cr, uid, vals, context=None):
951+ '''Fill type and left and right partner id, according to wether
952+ we have a normal relation type or an inverse relation type'''
953+ vals = vals.copy()
954+ # If type_selection_id ends in 1, it is a reverse relation type
955+ if 'type_selection_id' in vals:
956+ prts_model = self.pool['res.partner.relation.type.selection']
957+ type_selection_id = vals['type_selection_id']
958+ (type_id, is_reverse) = (
959+ prts_model.get_type_from_selection_id(
960+ cr, uid, type_selection_id))
961+ vals['type_id'] = type_id
962+ if context.get('active_id'):
963+ if is_reverse:
964+ vals['right_partner_id'] = context['active_id']
965+ else:
966+ vals['left_partner_id'] = context['active_id']
967+ if vals.get('partner_id_display'):
968+ if is_reverse:
969+ vals['left_partner_id'] = vals['partner_id_display']
970+ else:
971+ vals['right_partner_id'] = vals['partner_id_display']
972+ return vals
973+
974+ def _get_computed_fields(
975+ self, cr, uid, ids, field_names, arg, context=None):
976+ '''Return a dictionary of dictionaries, with for every partner for
977+ ids, the computed values.'''
978+ def get_values(this, dummy_field_names, dummy_arg, context=None):
979+ '''Get computed values for record'''
980+ values = {}
981+ on_right_partner = self._on_right_partner(
982+ cr, uid, this.right_partner_id.id, context=context)
983+ # type_selection_id
984+ values['type_selection_id'] = (
985+ ((this.type_id.id) * 10) + (on_right_partner and 1 or 0))
986+ # partner_id_display
987+ values['partner_id_display'] = (
988+ on_right_partner and this.left_partner_id.id
989+ or this.right_partner_id.id
990+ )
991+ # is_relation_expired
992+ today = fields.date.context_today(self, cr, uid, context=context)
993+ values['is_relation_expired'] = (
994+ this.date_end and (this.date_end < today))
995+ # is_relation_future
996+ values['is_relation_future'] = this.date_start > today
997+ return values
998+
999+ return dict([
1000+ (this.id, get_values(this, field_names, arg, context=context))
1001+ for this in self.browse(cr, uid, ids, context=context)
1002+ ])
1003+
1004+ def write(self, cr, uid, ids, vals, context=None):
1005+ '''Override write to correct values, before being stored.'''
1006+ vals = self._correct_vals(cr, uid, vals, context=context)
1007+ return super(ResPartnerRelation, self).write(
1008+ cr, uid, ids, vals, context=context)
1009+
1010+ def create(self, cr, uid, vals, context=None):
1011+ '''Override create to correct values, before being stored.'''
1012+ vals = self._correct_vals(cr, uid, vals, context=context)
1013+ return super(ResPartnerRelation, self).create(
1014+ cr, uid, vals, context=context)
1015+
1016+ def on_change_type_selection_id(
1017+ self, cr, uid, dummy_ids, type_selection_id, context=None):
1018+ '''Set domain on partner_id_display, when selection a relation type'''
1019+ result = {
1020+ 'domain': {'partner_id_display': []},
1021+ 'value': {'type_id': False}
1022+ }
1023+ if not type_selection_id:
1024+ return result
1025+ prts_model = self.pool['res.partner.relation.type.selection']
1026+ type_model = self.pool['res.partner.relation.type']
1027+ (type_id, is_reverse) = (
1028+ prts_model.get_type_from_selection_id(
1029+ cr, uid, type_selection_id)
1030+ )
1031+ result['value']['type_id'] = type_id
1032+ type_obj = type_model.browse(cr, uid, type_id, context=context)
1033+ partner_domain = []
1034+ check_contact_type = type_obj.contact_type_right
1035+ check_partner_category = (
1036+ type_obj.partner_category_right and
1037+ type_obj.partner_category_right.id
1038+ )
1039+ if is_reverse:
1040+ # partner_id_display is left partner
1041+ check_contact_type = type_obj.contact_type_left
1042+ check_partner_category = (
1043+ type_obj.partner_category_left and
1044+ type_obj.partner_category_left.id
1045+ )
1046+ if check_contact_type == 'c':
1047+ partner_domain.append(('is_company', '=', True))
1048+ if check_contact_type == 'p':
1049+ partner_domain.append(('is_company', '=', False))
1050+ if check_partner_category:
1051+ partner_domain.append(
1052+ ('category_id', 'child_of', check_partner_category))
1053+ result['domain']['partner_id_display'] = partner_domain
1054+ return result
1055+
1056+ _columns = {
1057+ 'left_partner_id': fields.many2one(
1058+ 'res.partner', string='Left partner', required=True,
1059+ auto_join=True),
1060+ 'right_partner_id': fields.many2one(
1061+ 'res.partner', string='Right partner', required=True,
1062+ auto_join=True),
1063+ 'type_id': fields.many2one(
1064+ 'res.partner.relation.type', string='Type', required=True,
1065+ auto_join=True),
1066+ 'date_start': fields.date('Starting date'),
1067+ 'date_end': fields.date('Ending date'),
1068+ 'type_selection_id': fields.function(
1069+ _get_computed_fields,
1070+ multi="computed_fields",
1071+ fnct_inv=lambda *args: None,
1072+ type='many2one', obj='res.partner.relation.type.selection',
1073+ string='Type',
1074+ ),
1075+ 'partner_id_display': fields.function(
1076+ _get_computed_fields,
1077+ multi="computed_fields",
1078+ fnct_inv=lambda *args: None,
1079+ type='many2one', obj='res.partner',
1080+ string='Partner'
1081+ ),
1082+ 'is_relation_expired': fields.function(
1083+ _get_computed_fields,
1084+ multi="computed_fields",
1085+ type='boolean',
1086+ method=True,
1087+ string='Relation is expired',
1088+ ),
1089+ 'is_relation_future': fields.function(
1090+ _get_computed_fields,
1091+ multi="computed_fields",
1092+ type='boolean',
1093+ method=True,
1094+ string='Relation is in the future',
1095+ ),
1096+ 'active': fields.boolean('Active'),
1097+ }
1098+
1099+ _defaults = {
1100+ 'active': True,
1101+ }
1102+
1103+ def _check_dates(self, cr, uid, ids, context=None):
1104+ '''End date should not be before start date, if noth filled'''
1105+ for line in self.browse(cr, uid, ids, context=context):
1106+ if line.date_start and line.date_end:
1107+ if line.date_start > line.date_end:
1108+ return False
1109+ return True
1110+
1111+ def _check_partner_type_left(self, cr, uid, ids, context=None):
1112+ '''Check left partner for required company or person'''
1113+ for this in self.browse(cr, uid, ids, context=context):
1114+ ptype = this.type_id.contact_type_left
1115+ company = this.left_partner_id.is_company
1116+ if (ptype == 'c' and not company) or (ptype == 'p' and company):
1117+ return False
1118+ return True
1119+
1120+ def _check_partner_type_right(self, cr, uid, ids, context=None):
1121+ '''Check right partner for required company or person'''
1122+ for this in self.browse(cr, uid, ids, context=context):
1123+ ptype = this.type_id.contact_type_right
1124+ company = this.right_partner_id.is_company
1125+ if (ptype == 'c' and not company) or (ptype == 'p' and company):
1126+ return False
1127+ return True
1128+
1129+ def _check_not_with_self(self, cr, uid, ids, context=None):
1130+ '''Not allowed to link partner to same partner'''
1131+ for this in self.browse(cr, uid, ids, context=context):
1132+ if this.left_partner_id == this.right_partner_id:
1133+ return False
1134+ return True
1135+
1136+ _constraints = [
1137+ (
1138+ _check_dates,
1139+ 'The starting date cannot be after the ending date.',
1140+ ['date_start', 'date_end']
1141+ ),
1142+ (
1143+ _check_partner_type_left,
1144+ 'The left partner is not applicable for this relation type.',
1145+ ['left_partner_id', 'type_id']
1146+ ),
1147+ (
1148+ _check_partner_type_right,
1149+ 'The right partner is not applicable for this relation type.',
1150+ ['right_partner_id', 'type_id']
1151+ ),
1152+ (
1153+ _check_not_with_self,
1154+ 'Partners cannot have a relation with themselves.',
1155+ ['left_partner_id', 'right_partner_id']
1156+ ),
1157+ ]
1158
1159=== added file 'partner_relations/model/res_partner_relation_all.py'
1160--- partner_relations/model/res_partner_relation_all.py 1970-01-01 00:00:00 +0000
1161+++ partner_relations/model/res_partner_relation_all.py 2014-06-20 07:56:04 +0000
1162@@ -0,0 +1,75 @@
1163+# -*- coding: utf-8 -*-
1164+##############################################################################
1165+#
1166+# OpenERP, Open Source Management Solution
1167+# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
1168+#
1169+# This program is free software: you can redistribute it and/or modify
1170+# it under the terms of the GNU Affero General Public License as
1171+# published by the Free Software Foundation, either version 3 of the
1172+# License, or (at your option) any later version.
1173+#
1174+# This program is distributed in the hope that it will be useful,
1175+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1176+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1177+# GNU Affero General Public License for more details.
1178+#
1179+# You should have received a copy of the GNU Affero General Public License
1180+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1181+#
1182+##############################################################################
1183+from openerp.osv.orm import Model
1184+from openerp.osv import fields
1185+from openerp.tools import drop_view_if_exists
1186+from res_partner_relation_type_selection import ResPartnerRelationTypeSelection
1187+
1188+
1189+class ResPartnerRelationAll(Model):
1190+ _auto = False
1191+ _log_access = False
1192+ _name = 'res.partner.relation.all'
1193+ _description = 'All (non-inverse + inverse) relations between partners'
1194+
1195+ def _auto_init(self, cr, context=None):
1196+ drop_view_if_exists(cr, self._table)
1197+ cr.execute(
1198+ '''create or replace view %s as
1199+ select
1200+ id * 10 as id,
1201+ id as relation_id,
1202+ type_id,
1203+ cast('a' as char(1)) as record_type,
1204+ left_partner_id as this_partner_id,
1205+ right_partner_id as other_partner_id,
1206+ date_start,
1207+ date_end,
1208+ active
1209+ from res_partner_relation
1210+ union select
1211+ id * 10 + 1,
1212+ id,
1213+ type_id,
1214+ cast('b' as char(1)),
1215+ right_partner_id,
1216+ left_partner_id,
1217+ date_start,
1218+ date_end,
1219+ active
1220+ from res_partner_relation''' % self._table)
1221+
1222+ return super(ResPartnerRelationAll, self)._auto_init(
1223+ cr, context=context)
1224+
1225+ _columns = {
1226+ 'record_type': fields.selection(
1227+ ResPartnerRelationTypeSelection._RECORD_TYPES, 'Record type'),
1228+ 'relation_id': fields.many2one(
1229+ 'res.partner.relation', 'Relation'),
1230+ 'type_id': fields.many2one(
1231+ 'res.partner.relation.type', 'Relation type'),
1232+ 'this_partner_id': fields.many2one('res.partner', 'Current partner'),
1233+ 'other_partner_id': fields.many2one('res.partner', 'Other partner'),
1234+ 'date_start': fields.date('Starting date'),
1235+ 'date_end': fields.date('Ending date'),
1236+ 'active': fields.boolean('Active'),
1237+ }
1238
1239=== added file 'partner_relations/model/res_partner_relation_type.py'
1240--- partner_relations/model/res_partner_relation_type.py 1970-01-01 00:00:00 +0000
1241+++ partner_relations/model/res_partner_relation_type.py 2014-06-20 07:56:04 +0000
1242@@ -0,0 +1,48 @@
1243+# -*- coding: utf-8 -*-
1244+'''Define model res.partner.relation.type'''
1245+##############################################################################
1246+#
1247+# OpenERP, Open Source Management Solution
1248+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
1249+#
1250+# This program is free software: you can redistribute it and/or modify
1251+# it under the terms of the GNU Affero General Public License as
1252+# published by the Free Software Foundation, either version 3 of the
1253+# License, or (at your option) any later version.
1254+#
1255+# This program is distributed in the hope that it will be useful,
1256+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1257+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1258+# GNU Affero General Public License for more details.
1259+#
1260+# You should have received a copy of the GNU Affero General Public License
1261+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1262+#
1263+##############################################################################
1264+from openerp.osv.orm import Model
1265+from openerp.osv import fields
1266+
1267+
1268+class ResPartnerRelationType(Model):
1269+ '''Model that defines relation types that might exist between partners'''
1270+ _name = 'res.partner.relation.type'
1271+ _description = 'Parter relation type'
1272+ _order = 'name'
1273+
1274+ def _get_partner_types(self, cr, uid, context=None):
1275+ return (('c', 'Company'), ('p', 'Person'),)
1276+
1277+ _columns = {
1278+ 'name': fields.char(
1279+ 'Name', size=128, required=True, translate=True),
1280+ 'name_inverse': fields.char(
1281+ 'Inverse name', size=128, required=True, translate=True),
1282+ 'contact_type_left': fields.selection(
1283+ _get_partner_types, 'Left partner type'),
1284+ 'contact_type_right': fields.selection(
1285+ _get_partner_types, 'Right partner type'),
1286+ 'partner_category_left': fields.many2one(
1287+ 'res.partner.category', 'Left partner category'),
1288+ 'partner_category_right': fields.many2one(
1289+ 'res.partner.category', 'Right partner category'),
1290+ }
1291
1292=== added file 'partner_relations/model/res_partner_relation_type_selection.py'
1293--- partner_relations/model/res_partner_relation_type_selection.py 1970-01-01 00:00:00 +0000
1294+++ partner_relations/model/res_partner_relation_type_selection.py 2014-06-20 07:56:04 +0000
1295@@ -0,0 +1,133 @@
1296+# -*- coding: UTF-8 -*-
1297+'''
1298+Created on 23 may 2014
1299+
1300+@author: Ronald Portier, Therp
1301+
1302+rportier@therp.nl
1303+http://www.therp.nl
1304+
1305+For the model defined here _auto is set to False to prevent creating a
1306+database file. All i/o operations are overridden to use a sql SELECT that
1307+takes data from res_partner_connection_type where each type is included in the
1308+result set twice, so it appears that the connection type and the inverse
1309+type are separate records..
1310+
1311+The original function _auto_init is still called because this function
1312+normally (if _auto == True) not only creates the db tables, but it also takes
1313+care of registering all fields in ir_model_fields. This is needed to make
1314+the field labels translatable.
1315+
1316+example content for last lines of _statement:
1317+select id, record_type,
1318+ customer_id, customer_name, customer_city, customer_zip, customer_street,
1319+ caller_id, caller_name, caller_phone, caller_fax, caller_email
1320+from FULL_LIST as ResPartnerRelationTypeSelection where record_type = 'c'
1321+ORDER BY ResPartnerRelationTypeSelection.customer_name asc,
1322+ResPartnerRelationTypeSelection.caller_name asc;
1323+
1324+'''
1325+from openerp.osv import fields
1326+from openerp.osv import orm
1327+from openerp.tools import drop_view_if_exists
1328+from openerp.addons.partner_relations.model.res_partner_relation_type\
1329+ import ResPartnerRelationType
1330+
1331+
1332+class ResPartnerRelationTypeSelection(orm.Model):
1333+ '''Virtual relation types'''
1334+
1335+ _RECORD_TYPES = [
1336+ ('a', 'Type'),
1337+ ('b', 'Inverse type'),
1338+ ]
1339+
1340+ _auto = False # Do not try to create table in _auto_init(..)
1341+ _log_access = False
1342+
1343+ def get_type_from_selection_id(self, cr, uid, selection_id):
1344+ '''Selection id ic computed from id of underlying type and the
1345+ kind of record. This function does the inverse computation to give
1346+ back the original type id, and about the record type.'''
1347+ type_id = selection_id / 10
1348+ is_reverse = (selection_id % 10) > 0
1349+ return (type_id, is_reverse)
1350+
1351+ def _auto_init(self, cr, context=None):
1352+ drop_view_if_exists(cr, self._table)
1353+ #TODO: we lose field value's translations here.
1354+ #probably we need to patch ir_translation.get_source for that
1355+ #to get res_partner_relation_type's translations
1356+ cr.execute(
1357+ '''create or replace view %s as
1358+ select
1359+ id * 10 as id,
1360+ id as type_id,
1361+ cast('a' as char(1)) as record_type,
1362+ name as name,
1363+ contact_type_left as contact_type_this,
1364+ contact_type_right as contact_type_other,
1365+ partner_category_left as partner_category_this,
1366+ partner_category_right as partner_category_other
1367+ from res_partner_relation_type
1368+ union select
1369+ id * 10 + 1,
1370+ id,
1371+ cast('b' as char(1)),
1372+ name_inverse,
1373+ contact_type_right,
1374+ contact_type_left,
1375+ partner_category_right,
1376+ partner_category_left
1377+ from res_partner_relation_type''' % self._table)
1378+
1379+ return super(ResPartnerRelationTypeSelection, self)._auto_init(
1380+ cr, context=context)
1381+
1382+ def _search_partner_category_this(self, cr, uid, obj, field_name, args,
1383+ context=None):
1384+ category_ids = []
1385+
1386+ for arg in args:
1387+ if isinstance(arg, tuple) and arg[0] == field_name\
1388+ and (arg[1] == '=' or arg[1] == 'in'):
1389+ #TODO don't we have an api function to eval that?
1390+ for delta in arg[2]:
1391+ if delta[0] == 6:
1392+ category_ids.extend(delta[2])
1393+
1394+ if category_ids:
1395+ return [
1396+ '|',
1397+ ('partner_category_this', '=', False),
1398+ ('partner_category_this', 'in', category_ids),
1399+ ]
1400+ else:
1401+ return [('partner_category_this', '=', False)]
1402+
1403+ _name = 'res.partner.relation.type.selection'
1404+ _description = 'All relation types'
1405+ _foreign_keys = []
1406+ _columns = {
1407+ 'record_type': fields.selection(_RECORD_TYPES, 'Record type', size=16),
1408+ 'type_id': fields.integer('Type'),
1409+ 'name': fields.char('Name', size=64),
1410+ 'contact_type_this': fields.selection(
1411+ ResPartnerRelationType._get_partner_types.im_func,
1412+ 'Current record\'s partner type'),
1413+ 'contact_type_other': fields.selection(
1414+ ResPartnerRelationType._get_partner_types.im_func,
1415+ 'Other record\'s partner type'),
1416+ 'partner_category_this': fields.many2one(
1417+ 'res.partner.category', 'Current record\'s category'),
1418+ 'partner_category_other': fields.many2one(
1419+ 'res.partner.category', 'Other record\'s category'),
1420+ #search field to handle many2many deltas from the client
1421+ 'search_partner_category_this': fields.function(
1422+ lambda self, cr, uid, ids, context=None: dict(
1423+ [(i, False) for i in ids]),
1424+ fnct_search=_search_partner_category_this,
1425+ type='many2many', obj='res.partner.category',
1426+ string='Current record\'s category'),
1427+ }
1428+ _order = 'name asc'
1429
1430=== added directory 'partner_relations/security'
1431=== added file 'partner_relations/security/ir.model.access.csv'
1432--- partner_relations/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
1433+++ partner_relations/security/ir.model.access.csv 2014-06-20 07:56:04 +0000
1434@@ -0,0 +1,7 @@
1435+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1436+read_res_partner_relation,access_res_partner_relation,model_res_partner_relation,,1,0,0,0
1437+read_res_partner_relation_all,access_res_partner_relation,model_res_partner_relation_all,,1,0,0,0
1438+read_res_partner_relation_type,access_res_partner_relation_type,model_res_partner_relation_type,,1,0,0,0
1439+read_res_partner_relation_type_selection,access_res_partner_relation_type,model_res_partner_relation_type_selection,,1,0,0,0
1440+crud_res_partner_relation,access_res_partner_relation,model_res_partner_relation,base.group_partner_manager,1,1,1,1
1441+crud_res_partner_relation_type,access_res_partner_relation_type,model_res_partner_relation_type,base.group_sale_manager,1,1,1,1
1442
1443=== added directory 'partner_relations/static'
1444=== added directory 'partner_relations/static/src'
1445=== added directory 'partner_relations/static/src/img'
1446=== added file 'partner_relations/static/src/img/icon.png'
1447Binary files partner_relations/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and partner_relations/static/src/img/icon.png 2014-06-20 07:56:04 +0000 differ
1448=== added directory 'partner_relations/view'
1449=== added file 'partner_relations/view/menu.xml'
1450--- partner_relations/view/menu.xml 1970-01-01 00:00:00 +0000
1451+++ partner_relations/view/menu.xml 2014-06-20 07:56:04 +0000
1452@@ -0,0 +1,15 @@
1453+<openerp>
1454+ <data>
1455+ <act_window
1456+ id="action_res_partner_relation_type"
1457+ res_model="res.partner.relation.type"
1458+ view_mode="tree,form"
1459+ name="Partner relations"
1460+ />
1461+ <menuitem
1462+ id="menu_res_partner_relation_type"
1463+ parent="base.menu_config_address_book"
1464+ action="action_res_partner_relation_type"
1465+ />
1466+ </data>
1467+</openerp>
1468
1469=== added file 'partner_relations/view/res_partner.xml'
1470--- partner_relations/view/res_partner.xml 1970-01-01 00:00:00 +0000
1471+++ partner_relations/view/res_partner.xml 2014-06-20 07:56:04 +0000
1472@@ -0,0 +1,86 @@
1473+<openerp>
1474+ <data>
1475+ <record id="view_res_partner_filter" model="ir.ui.view">
1476+ <field name="inherit_id" ref="base.view_res_partner_filter" />
1477+ <field name="model">res.partner</field>
1478+ <field type="xml" name="arch">
1479+ <data>
1480+ <field name="parent_id" position="after">
1481+ <field name="search_relation_partner_id" />
1482+ <field name="search_relation_id" />
1483+ <field name="search_relation_date" />
1484+ </field>
1485+ </data>
1486+ </field>
1487+ </record>
1488+ <record id="view_partner_form" model="ir.ui.view">
1489+ <field name="inherit_id" ref="base.view_partner_form" />
1490+ <field name="model">res.partner</field>
1491+ <field type="xml" name="arch">
1492+ <data>
1493+ <xpath expr="//sheet/notebook" position="inside">
1494+ <page string="Relations">
1495+ <field
1496+ name="relation_ids"
1497+ context="{
1498+ 'active_model': 'res.partner',
1499+ 'active_id': id, 'active_ids': [id],
1500+ }"
1501+ >
1502+ <tree
1503+ editable="top"
1504+ colors="gray:is_relation_expired==True;blue:is_relation_future==True"
1505+ >
1506+ <field
1507+ name="type_selection_id"
1508+ required="True"
1509+ context="{
1510+ 'parent_model': 'res.partner',
1511+ 'parent_id': parent.id,
1512+ }"
1513+ domain="[
1514+ '|',
1515+ ('contact_type_this', '=', parent.is_company and 'c' or 'p'),
1516+ ('contact_type_this', '=', False),
1517+ ('search_partner_category_this', '=', parent.category_id),
1518+
1519+ ]
1520+ "
1521+ options="{'create': false, 'create_edit': false}"
1522+ on_change="on_change_type_selection_id(type_selection_id)"
1523+ />
1524+ <field name="type_id" invisible="True" />
1525+ <field
1526+ name="partner_id_display"
1527+ required="True"
1528+ attrs="{
1529+ 'readonly': [('type_selection_id','=',False)],
1530+ }"
1531+ options="{'create': false, 'create_edit': false}"
1532+ />
1533+ <field
1534+ name="date_start"
1535+ />
1536+ <field
1537+ name="date_end"
1538+ />
1539+ <field
1540+ name="active"
1541+ />
1542+ <field
1543+ name="is_relation_expired"
1544+ invisible="True"
1545+ />
1546+ <field
1547+ name="is_relation_future"
1548+ invisible="True"
1549+ />
1550+ </tree>
1551+ </field>
1552+ </page>
1553+ </xpath>
1554+ </data>
1555+ </field>
1556+ </record>
1557+ </data>
1558+</openerp>
1559
1560=== added file 'partner_relations/view/res_partner_relation.xml'
1561--- partner_relations/view/res_partner_relation.xml 1970-01-01 00:00:00 +0000
1562+++ partner_relations/view/res_partner_relation.xml 2014-06-20 07:56:04 +0000
1563@@ -0,0 +1,16 @@
1564+<openerp>
1565+ <data>
1566+ <record id="form_res_partner_relation" model="ir.ui.view">
1567+ <field name="model">res.partner.relation</field>
1568+ <field type="xml" name="arch">
1569+ <form version="7.0" string="Partner relation">
1570+ <sheet>
1571+ <field name="left_partner_id" />
1572+ <field name="type_id" />
1573+ <field name="right_partner_id" />
1574+ </sheet>
1575+ </form>
1576+ </field>
1577+ </record>
1578+ </data>
1579+</openerp>
1580
1581=== added file 'partner_relations/view/res_partner_relation_type.xml'
1582--- partner_relations/view/res_partner_relation_type.xml 1970-01-01 00:00:00 +0000
1583+++ partner_relations/view/res_partner_relation_type.xml 2014-06-20 07:56:04 +0000
1584@@ -0,0 +1,44 @@
1585+<openerp>
1586+ <data>
1587+ <record id="tree_res_partner_relation_type" model="ir.ui.view">
1588+ <field name="model">res.partner.relation.type</field>
1589+ <field name="type">tree</field>
1590+ <field type="xml" name="arch">
1591+ <tree version="7.0" string="Partner relation">
1592+ <field name="name" />
1593+ <field name="name_inverse" />
1594+ <field name="contact_type_left" />
1595+ <field name="contact_type_right" />
1596+ </tree>
1597+ </field>
1598+ </record>
1599+ <record id="form_res_partner_relation_type" model="ir.ui.view">
1600+ <field name="model">res.partner.relation.type</field>
1601+ <field name="type">form</field>
1602+ <field type="xml" name="arch">
1603+ <form version="7.0" string="Partner relation">
1604+ <sheet>
1605+ <group>
1606+ <group
1607+ colspan="2" col="2"
1608+ string="Left side of relation"
1609+ >
1610+ <field name="name" />
1611+ <field name="contact_type_left" />
1612+ <field name="partner_category_left" />
1613+ </group>
1614+ <group
1615+ colspan="2" col="2"
1616+ string="Right side of relation"
1617+ >
1618+ <field name="name_inverse" />
1619+ <field name="contact_type_right" />
1620+ <field name="partner_category_right" />
1621+ </group>
1622+ </group>
1623+ </sheet>
1624+ </form>
1625+ </field>
1626+ </record>
1627+ </data>
1628+</openerp>

Subscribers

People subscribed via source and target branches

to status/vote changes: