Partner relations

partner_relations
REPOSITORY
REPOSITORYOCA/partner-contact
GIT
GIThttps://github.com/OCA/partner-contact.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/partner-contact/tree/8.0/partner_relations
VERSION
VERSION 1.1.2
CATEGORY
CATEGORYCustomer Relationship Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Camptocamp, Therp BV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Camptocamp, Therp BV
COMMITTERS
COMMITTERSStéphane Bidoul, Yannick Vaucher, eLBati, Sandy Carter, Holger Brunn, Pedro M. Baeza, Fekete Mihai, Stéphane Bidoul (ACSONE), luc-demeyer, OCA Transbot, Charbel Jacquin, oca-travis, Weblate, Antonio Espinosa, Jonathan Nemry (ACSONE)
WEBSITE
WEBSITE
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:11:21
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (6)
XML IDNameModelTypeStatus
form_res_partner_relation_type res.partner.relation.type form New
search_res_partner_relation_all res.partner.relation.all search New
tree_res_partner_relation_all res.partner.relation.all tree New
tree_res_partner_relation_type res.partner.relation.type tree New
view_partner_form partner_relations.view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter partner_relations.view_partner_filter res.partner data Inherits base.view_res_partner_filter
Models touched (5)

New fields (6)
  • relation_all_ids One2many → res.partner.relation.all
    auto_join=True comodel_name='res.partner.relation.all' copy=False inverse_name='this_partner_id' selectable=False string='All relations with current partner'
  • relation_count Integer
    compute='_compute_relation_count' string='Relation Count'
  • search_relation_date Date
    compute=<expr> search='_search_relation_date' string='Relation valid'
  • search_relation_partner_category_id Many2one → res.partner.category
    comodel_name='res.partner.category' compute=<expr> search='_search_related_partner_category_id' string='Has relation with a partner in category'
  • search_relation_partner_id Many2one → res.partner
    comodel_name='res.partner' compute=<expr> search='_search_related_partner_id' string='Has relation with'
  • search_relation_type_id Many2one → res.partner.relation.type.selection
    comodel_name='res.partner.relation.type.selection' compute=<expr> search='_search_relation_type_id' string='Has relation of type'
Public methods (2)
  • get_partner_type(self)
    @api.multi
    Get partner type for relation. :return: 'c' for company or 'p' for person :rtype: str
  • search(self, args, offset=0, limit=None, order=None, count=False)
    @api.model
    Inject searching for current relation date if we search for relation properties and no explicit date was given.

New fields (5)
  • date_end Date
    args: 'Ending date'
  • date_start Date
    args: 'Starting date'
  • left_partner_id Many2one → res.partner
    auto_join=True comodel_name='res.partner' ondelete='cascade' required=True string='Source Partner'
  • right_partner_id Many2one → res.partner
    auto_join=True comodel_name='res.partner' ondelete='cascade' required=True string='Destination Partner'
  • type_id Many2one → res.partner.relation.type
    auto_join=True comodel_name='res.partner.relation.type' required=True string='Type'
Public methods (1)
  • create(self, vals)
    @api.model
    Override create to correct values, before being stored.

New fields (9)
  • active Boolean
    help='Records with date_end in the past are inactive' string='Active'
  • any_partner_id Many2many → res.partner
    comodel_name='res.partner' compute=<expr> search='_search_any_partner_id' string='Partner'
  • date_end Date
    args: 'Ending date'
  • date_start Date
    args: 'Starting date'
  • other_partner_id Many2one → res.partner
    comodel_name='res.partner' required=True string='Other Partner'
  • record_type Selection
    readonly=True selection=_RECORD_TYPES string='Record Type'
  • relation_id Many2one → res.partner.relation
    comodel_name='res.partner.relation' readonly=True string='Relation'
  • this_partner_id Many2one → res.partner
    comodel_name='res.partner' required=True string='One Partner'
  • type_selection_id Many2one → res.partner.relation.type.selection
    comodel_name='res.partner.relation.type.selection' required=True string='Relation Type'
Public methods (6)
  • create(self, vals)
    @api.model
    Divert non-problematic creates to underlying table. Create a res.partner.relation but return the converted id.
  • name_get(self)
    @api.multi
  • onchange_partner_id(self)
    @api.onchange('this_partner_id', 'other_partner_id')
    Set domain on type_selection_id based on partner(s) selected.
  • onchange_type_selection_id(self)
    @api.onchange('type_selection_id')
    Add domain on partners according to category and contact_type.
  • unlink(self)
    @api.multi
    divert non-problematic creates to underlying table
  • write(self, vals)
    @api.multi
    divert non-problematic writes to underlying table

New fields (9)
  • allow_self Boolean
    default=False help='This relation can be set up with the same partner left and right' string='Reflexive'
  • contact_type_left Selection
    selection='get_partner_types' string='Left partner type'
  • contact_type_right Selection
    selection='get_partner_types' string='Right partner type'
  • handle_invalid_onchange Selection
    default='restrict' help='When adding relations criteria like partner type and category are checked.\nHowever when you change the criteria, there might be relations that do not fit the new criteria.\nSpecify how this situation should be handled.' required=True selection=HANDLE_INVALID_ONCHANGE string='Invalid relation handling'
  • is_symmetric Boolean
    default=False help='This relation is the same from right to left as from left to right' old_name='symmetric' string='Symmetric'
  • name Char
    required=True string='Name' translate=True
  • name_inverse Char
    required=True string='Inverse name' translate=True
  • partner_category_left Many2one → res.partner.category
    comodel_name='res.partner.category' string='Left partner category'
  • partner_category_right Many2one → res.partner.category
    comodel_name='res.partner.category' string='Right partner category'
Public methods (4)
  • check_existing(self, vals)
    @api.multi
    Check wether records exist that do not fit new criteria.
  • get_partner_types(self)
    @api.model
    A partner can be an organisation or an individual.
  • onchange_is_symmetric(self)
    @api.onchange('is_symmetric')
    Set right side to left side if symmetric.
  • write(self, vals)
    @api.multi
    Handle existing relations if conditions change.

New fields (9)
  • allow_self Boolean
    string='Reflexive'
  • contact_type_other Selection
    selection=ResPartnerRelationType.get_partner_types.im_func string="Other record's partner type"
  • contact_type_this Selection
    selection=ResPartnerRelationType.get_partner_types.im_func string="Current record's partner type"
  • is_inverse Boolean
    help='Inverse relations are from right to left partner.' string='Is reverse type?'
  • is_symmetric Boolean
    string='Symmetric'
  • name Char
    args: 'Name'
  • partner_category_other Many2one → res.partner.category
    comodel_name='res.partner.category' string="Other record's category"
  • partner_category_this Many2one → res.partner.category
    comodel_name='res.partner.category' string="Current record's category"
  • type_id Many2one → res.partner.relation.type
    comodel_name='res.partner.relation.type' string='Type'
Public methods (2)
  • name_get(self)
    @api.multi
    Get name or name_inverse from underlying model.
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model
    Search for name or inverse name in underlying model.
REPOSITORY
REPOSITORYOCA/partner-contact
GIT
GIThttps://github.com/OCA/partner-contact.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/partner-contact/tree/7.0/partner_relations
VERSION
VERSION 1.2.0
CATEGORY
CATEGORYCustomer Relationship Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Therp BV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Therp BV
COMMITTERS
COMMITTERSYannick Vaucher, Alexandre Fayolle, Ronald Portier, Sandy Carter, Holger Brunn, Pedro M. Baeza, Stéphane Bidoul (ACSONE), OCA Transbot
WEBSITE
WEBSITE
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:07:13
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/web:
    - web_m2x_options
    - web_tree_many2one_clickable
odoo/odoo:
    - base
    - web
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
Introduction
------------

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.

Code Analysis

Views touched (7)
XML IDNameModelTypeStatus
form_res_partner_relation res.partner.relation form New
form_res_partner_relation_all res.partner.relation.all form New
form_res_partner_relation_type res.partner.relation.type form New
tree_res_partner_relation_all res.partner.relation.all tree New
tree_res_partner_relation_type res.partner.relation.type tree New
view_partner_form partner_relations.view_partner_form res.partner data Inherits base.view_partner_form
view_res_partner_filter partner_relations.view_partner_filter res.partner data Inherits base.view_res_partner_filter
Models touched (5)

New fields (0)

No new fields.

Public methods (4)
  • copy_data(self, cr, uid, id, default=None, context=None)
  • read(self, cr, uid, ids, fields=None, context=None, load='_classic_read')
  • search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False)
  • write(self, cr, uid, ids, vals, context=None)

New fields (0)

No new fields.

Public methods (4)
  • create(self, cr, uid, vals, context=None)
    Override create to correct values, before being stored.
  • 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
  • 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
  • write(self, cr, uid, ids, vals, context=None)
    Override write to correct values, before being stored.

New fields (0)

No new fields.

Public methods (2)
  • name_get(self, cr, uid, ids, context=None)
    Name of relation is names of partners involved + type.
  • write(self, cr, uid, ids, vals, context=None)
    Divert non-problematic writes to underlying table.

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (3)
  • get_type_from_selection_id(self, cr, uid, selection_id)
    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.
  • name_get(self, cr, uid, ids, context=None)
    translate name using translations from res.partner.relation.type
  • name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=100)
    search for translated names in res.partner.relation.type