openerp-community-reviewer team mailing list archive
-
openerp-community-reviewer team
-
Mailing list archive
-
Message #03248
[Merge] lp:~savoirfairelinux-openerp/partner-contact-management/partner-contact-management-base_contact into lp:partner-contact-management
You have been requested to review the proposed merge of lp:~savoirfairelinux-openerp/partner-contact-management/partner-contact-management-base_contact into lp:partner-contact-management.
For more details, see:
https://code.launchpad.net/~savoirfairelinux-openerp/partner-contact-management/partner-contact-management-base_contact/+merge/203979
- Added base_contact module.This module has been migrated from OP6.1 to OP7.0 and a merge is proposed at 2013-10-22.
Details of MP: https://code.launchpad.net/~openerp-dev/openobject-addons/7.0-base-contact-xal/+merge/192129
--
https://code.launchpad.net/~savoirfairelinux-openerp/partner-contact-management/partner-contact-management-base_contact/+merge/203979
Your team Partner and Contact Core Editors is requested to review the proposed merge of lp:~savoirfairelinux-openerp/partner-contact-management/partner-contact-management-base_contact into lp:partner-contact-management.
=== added directory 'base_contact'
=== added file 'base_contact/__init__.py'
--- base_contact/__init__.py 1970-01-01 00:00:00 +0000
+++ base_contact/__init__.py 2014-01-30 14:39:48 +0000
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-TODAY OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from . import base_contact
=== added file 'base_contact/__openerp__.py'
--- base_contact/__openerp__.py 1970-01-01 00:00:00 +0000
+++ base_contact/__openerp__.py 2014-01-30 14:39:48 +0000
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (C) 2013-TODAY OpenERP S.A. (<http://openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+ 'name': 'Contacts Management',
+ 'version': '1.0',
+ 'author': 'OpenERP SA',
+ 'website': 'http://www.openerp.com',
+ 'category': 'Customer Relationship Management',
+ 'complexity': "expert",
+ 'description': """
+This module allows you to manage your contacts
+==============================================
+
+It lets you define groups of contacts sharing some common information, like:
+ * Birthdate
+ * Nationality
+ * Native Language
+
+Contributors
+------------
+* OpenERP SA
+* El Hadji Dem (elhadji.dem@xxxxxxxxxxxxxxxxxxxx
+""",
+ 'depends': [
+ 'base',
+ 'process',
+ 'contacts'
+ ],
+ 'external_dependencies': {},
+ 'data': [
+ 'base_contact_view.xml',
+ ],
+ 'demo': [
+ 'base_contact_demo.xml',
+ ],
+ 'test': [],
+ 'installable': True,
+ 'auto_install': False,
+ 'images': [],
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== added file 'base_contact/base_contact.py'
--- base_contact/base_contact.py 1970-01-01 00:00:00 +0000
+++ base_contact/base_contact.py 2014-01-30 14:39:48 +0000
@@ -0,0 +1,214 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-TODAY OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, orm, expression
+
+
+class res_partner(orm.Model):
+ _inherit = 'res.partner'
+
+ _contact_type = [
+ ('standalone', 'Standalone Contact'),
+ ('attached', 'Attached to existing Contact'),
+ ]
+
+ def _get_contact_type(self, cr, uid, ids, field_name, args, context=None):
+ if context is None:
+ context = {}
+ result = dict.fromkeys(ids, 'standalone')
+ for partner in self.browse(cr, uid, ids, context=context):
+ if partner.contact_id:
+ result[partner.id] = 'attached'
+ return result
+
+ _columns = {
+ 'contact_type': fields.function(_get_contact_type, type='selection',
+ selection=_contact_type,
+ string='Contact Type',
+ required=True,
+ select=1,
+ store=True,
+ help="Contact type."),
+ 'contact_id': fields.many2one('res.partner', 'Main Contact',
+ domain=[('is_company', '=', False),
+ ('contact_type', '=', 'standalone')],
+ help="Contact."),
+ 'other_contact_ids': fields.one2many('res.partner',
+ 'contact_id',
+ 'Others Positions',
+ help="Others Positions."),
+ # Person specific fields
+ # add a 'birthdate' as date field, i.e different from char 'birthdate' introduced v6.1!
+ 'birthdate_date': fields.date('Birthdate', help="Birthdate."),
+ 'nationality_id': fields.many2one('res.country', 'Nationality', help="Nationality."),
+ }
+
+ _defaults = {
+ 'contact_type': 'standalone',
+ }
+
+ def _basecontact_check_context(self, cr, user, mode, context=None):
+ if context is None:
+ context = {}
+ """
+ Remove 'search_show_all_positions' for non-search mode.
+ Keeping it in context can result in unexpected behaviour (ex: reading
+ one2many might return wrong result - i.e with "attached contact" removed
+ even if it's directly linked to a company).
+ """
+ if mode != 'search':
+ context.pop('search_show_all_positions', None)
+ return context
+
+ def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
+ if context is None:
+ context = {}
+ if context.get('search_show_all_positions') is False:
+ """
+ Display only standalone contact matching ``args`` or having
+ attached contact matching ``args``
+ """
+
+ args = expression.normalize_domain(args)
+ attached_contact_args = expression.AND((args, [('contact_type', '=', 'attached')]))
+ attached_contact_ids = super(res_partner, self).search(cr, user, attached_contact_args,
+ context=context)
+ args = expression.OR((
+ expression.AND(([('contact_type', '=', 'standalone')], args)),
+ [('other_contact_ids', 'in', attached_contact_ids)],
+ ))
+ return super(res_partner, self).search(cr, user, args, offset=offset, limit=limit,
+ order=order, context=context, count=count)
+
+ def create(self, cr, user, vals, context=None):
+ context = self._basecontact_check_context(cr, user, 'create', context)
+ if not vals.get('name') and vals.get('contact_id'):
+ vals['name'] = self.browse(cr, user, vals['contact_id'], context=context).name
+ return super(res_partner, self).create(cr, user, vals, context=context)
+
+ def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
+ context = self._basecontact_check_context(cr, user, 'read', context)
+ return super(res_partner, self).read(cr, user, ids, fields=fields, context=context, load=load)
+
+ def write(self, cr, user, ids, vals, context=None):
+ context = self._basecontact_check_context(cr, user, 'write', context)
+ return super(res_partner, self).write(cr, user, ids, vals, context=context)
+
+ def unlink(self, cr, user, ids, context=None):
+ context = self._basecontact_check_context(cr, user, 'unlink', context)
+ return super(res_partner, self).unlink(cr, user, ids, context=context)
+
+ def _commercial_partner_compute(self, cr, uid, ids, name, args, context=None):
+ """
+ Returns the partner that is considered the commercial
+ entity of this partner. The commercial entity holds the master data
+ for all commercial fields (see :py:meth:`~_commercial_fields`)
+ """
+ result = super(res_partner, self)._commercial_partner_compute(cr, uid, ids, name, args, context=context)
+ for partner in self.browse(cr, uid, ids, context=context):
+ if partner.contact_type == 'attached' and not partner.parent_id:
+ result[partner.id] = partner.contact_id.id
+ return result
+
+ def _contact_fields(self, cr, uid, context=None):
+ """
+ Returns the list of contact fields that are synced from the parent
+ when a partner is attached to him.
+ """
+ return ['name', 'title']
+
+ def _contact_sync_from_parent(self, cr, uid, partner, context=None):
+ """
+ Handle sync of contact fields when a new parent contact entity is set,
+ as if they were related fields
+ """
+ if partner.contact_id:
+ contact_fields = self._contact_fields(cr, uid, context=context)
+ sync_vals = self._update_fields_values(cr, uid, partner.contact_id,
+ contact_fields, context=context)
+ partner.write(sync_vals)
+
+ def update_contact(self, cr, uid, ids, vals, context=None):
+ if context is None:
+ context = {}
+ if context.get('__update_contact_lock'):
+ return
+ contact_fields = self._contact_fields(cr, uid, context=context)
+ contact_vals = dict((field, vals[field]) for field in contact_fields if field in vals)
+ if contact_vals:
+ ctx = dict(context, __update_contact_lock=True)
+ self.write(cr, uid, ids, contact_vals, context=ctx)
+
+ def _fields_sync(self, cr, uid, partner, update_values, context=None):
+ """
+ Sync commercial fields and address fields from company and to children,
+ contact fields from contact and to attached contact after create/update,
+ just as if those were all modeled as fields.related to the parent
+ """
+ if context is None:
+ context = {}
+ super(res_partner, self)._fields_sync(cr, uid, partner, update_values, context=context)
+ contact_fields = self._contact_fields(cr, uid, context=context)
+ # 1. From UPSTREAM: sync from parent contact
+ if update_values.get('contact_id'):
+ self._contact_sync_from_parent(cr, uid, partner, context=context)
+ # 2. To DOWNSTREAM: sync contact fields to parent or related
+ elif any(field in contact_fields for field in update_values):
+ update_ids = [c.id for c in partner.other_contact_ids if not c.is_company]
+ if partner.contact_id:
+ update_ids.append(partner.contact_id.id)
+ self.update_contact(cr, uid, update_ids, update_values, context=context)
+
+ def onchange_contact_id(self, cr, uid, ids, contact_id, context=None):
+ values = {}
+ if contact_id:
+ values['name'] = self.browse(cr, uid, contact_id, context=context).name
+ return {'value': values}
+
+ def onchange_contact_type(self, cr, uid, ids, contact_type, context=None):
+ values = {}
+ if contact_type == 'standalone':
+ values['contact_id'] = False
+ return {'value': values}
+
+
+class ir_actions_window(orm.Model):
+ _inherit = 'ir.actions.act_window'
+
+ def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
+ action_ids = ids
+ if isinstance(ids, (int, long)):
+ action_ids = [ids]
+ actions = super(ir_actions_window, self).read(cr, user, action_ids, fields=fields, context=context, load=load)
+ for action in actions:
+ if action.get('res_model', '') == 'res.partner':
+ # By default, only show standalone contact
+ action_context = action.get('context', '{}') or '{}'
+ if 'search_show_all_positions' not in action_context:
+ action['context'] = action_context.replace('{',
+ "{'search_show_all_positions': False,", 1)
+ if isinstance(ids, (int, long)):
+ if actions:
+ return actions[0]
+ return False
+ return actions
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== added file 'base_contact/base_contact_demo.xml'
--- base_contact/base_contact_demo.xml 1970-01-01 00:00:00 +0000
+++ base_contact/base_contact_demo.xml 2014-01-30 14:39:48 +0000
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+ <data>
+
+ <record id="res_partner_main2_position_consultant" model="res.partner">
+ <field name="name">Roger Scott</field>
+ <field name="function">Consultant</field>
+ <field name="parent_id" ref="base.res_partner_11"/>
+ <field name="contact_id" ref="base.res_partner_main2"/>
+ <field name="use_parent_address" eval="True"/>
+ </record>
+
+ <record id="res_partner_contact1" model="res.partner">
+ <field name="name">Bob Egnops</field>
+ <field name="birthdate_date">1984-01-01</field>
+ <field name="email">bob@xxxxxxxxxxxxxxxxxxxxxxxxxxxxx</field>
+ </record>
+
+ <record id="res_partner_contact1_work_position1" model="res.partner">
+ <field name="name">Bob Egnops</field>
+ <field name="function">Technician</field>
+ <field name="email">bob@xxxxxxxxxxxxxxx</field>
+ <field name="parent_id" ref="base.main_partner"/>
+ <field name="contact_id" ref="res_partner_contact1"/>
+ <field name="use_parent_address" eval="True"/>
+ </record>
+
+ </data>
+</openerp>
\ No newline at end of file
=== added file 'base_contact/base_contact_view.xml'
--- base_contact/base_contact_view.xml 1970-01-01 00:00:00 +0000
+++ base_contact/base_contact_view.xml 2014-01-30 14:39:48 +0000
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+<data>
+
+ <record id="view_res_partner_filter_contact" model="ir.ui.view">
+ <field name="name">res.partner.select.contact</field>
+ <field name="model">res.partner</field>
+ <field name="inherit_id" ref="base.view_res_partner_filter"/>
+ <field name="arch" type="xml">
+ <filter name="type_company" position="after">
+ <separator/>
+ <filter string="All positions" name="type_otherpositions"
+ context="{'search_show_all_positions': True}"
+ help="All partner positions"/>
+ </filter>
+ <xpath expr="/search/group/filter[@string='Company']" position="before">
+ <filter string="Person" name="group_person" context="{'group_by': 'contact_id'}"/>
+ </xpath>
+ </field>
+ </record>
+
+ <record id="view_res_partner_tree_contact" model="ir.ui.view">
+ <field name="name">res.partner.tree.contact</field>
+ <field name="model">res.partner</field>
+ <field name="inherit_id" ref="base.view_partner_tree"/>
+ <field name="arch" type="xml">
+ <field name="parent_id" position="after">
+ <field name="contact_id" invisible="1"/>
+ </field>
+ </field>
+ </record>
+
+ <record model="ir.ui.view" id="view_partner_form_inherit">
+ <field name="name">res.partner.form.contact</field>
+ <field name="model">res.partner</field>
+ <field name="inherit_id" ref="base.view_partner_form"/>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <field name="is_company" position="after">
+ <field name="contact_type" invisible="1"/>
+ </field>
+ <page string="Contacts" position="after">
+ <page string="Other Positions" attrs="{'invisible': ['|',('is_company','=',True),('contact_id','!=',False)]}">
+ <field name="other_contact_ids" context="{'default_contact_id': active_id, 'default_name': name, 'default_street': street, 'default_street2': street2, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_supplier': supplier}}" mode="kanban">
+ <kanban>
+ <field name="color"/>
+ <field name="name"/>
+ <field name="title"/>
+ <field name="email"/>
+ <field name="parent_id"/>
+ <field name="is_company"/>
+ <field name="function"/>
+ <field name="phone"/>
+ <field name="street"/>
+ <field name="street2"/>
+ <field name="zip"/>
+ <field name="city"/>
+ <field name="country_id"/>
+ <field name="mobile"/>
+ <field name="fax"/>
+ <field name="state_id"/>
+ <field name="has_image"/>
+ <templates>
+ <t t-name="kanban-box">
+ <t t-set="color" t-value="kanban_color(record.color.raw_value)"/>
+ <div t-att-class="color + (record.title.raw_value == 1 ? ' oe_kanban_color_alert' : '')" style="position: relative">
+ <a t-if="! read_only_mode" type="delete" style="position: absolute; right: 0; padding: 4px; diplay: inline-block">X</a>
+ <div class="oe_module_vignette">
+ <a type="open">
+ <t t-if="record.has_image.raw_value === true">
+ <img t-att-src="kanban_image('res.partner', 'image', record.id.value, {'preview_image': 'image_small'})" class="oe_avatar oe_kanban_avatar_smallbox"/>
+ </t>
+ <t t-if="record.image and record.image.raw_value !== false">
+ <img t-att-src="'data:image/png;base64,'+record.image.raw_value" class="oe_avatar oe_kanban_avatar_smallbox"/>
+ </t>
+ <t t-if="record.has_image.raw_value === false and (!record.image or record.image.raw_value === false)">
+ <t t-if="record.is_company.raw_value === true">
+ <img t-att-src='_s + "/base/static/src/img/company_image.png"' class="oe_kanban_image oe_kanban_avatar_smallbox"/>
+ </t>
+ <t t-if="record.is_company.raw_value === false">
+ <img t-att-src='_s + "/base/static/src/img/avatar.png"' class="oe_kanban_image oe_kanban_avatar_smallbox"/>
+ </t>
+ </t>
+ </a>
+ <div class="oe_module_desc">
+ <div class="oe_kanban_box_content oe_kanban_color_bglight oe_kanban_color_border">
+ <table class="oe_kanban_table">
+ <tr>
+ <td class="oe_kanban_title1" align="left" valign="middle">
+ <h4><a type="open"><field name="name"/></a></h4>
+ <i>
+ <t t-if="record.parent_id.raw_value and !record.function.raw_value"><field name="parent_id"/></t>
+ <t t-if="!record.parent_id.raw_value and record.function.raw_value"><field name="function"/></t>
+ <t t-if="record.parent_id.raw_value and record.function.raw_value"><field name="function"/> à <field name="parent_id"/></t>
+ </i>
+ <div><a t-if="record.email.raw_value" title="Mail" t-att-href="'mailto:'+record.email.value">
+ <field name="email"/>
+ </a></div>
+ <div t-if="record.phone.raw_value">Phone: <field name="phone"/></div>
+ <div t-if="record.mobile.raw_value">Mobile: <field name="mobile"/></div>
+ <div t-if="record.fax.raw_value">Fax: <field name="fax"/></div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ <form string="Contact" version="7.0">
+ <sheet>
+ <field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_medium"}'/>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only"/>
+ <h1><field name="name" style="width: 70%%"/></h1>
+ </div>
+ <group>
+ <!-- inherited part -->
+ <field name="category_id" widget="many2many_tags" placeholder="Tags..." style="width: 70%%"/>
+ <field name="parent_id" placeholder="Company" domain="[('is_company','=',True)]"/>
+ <!-- inherited part end -->
+ <field name="function" placeholder="e.g. Sales Director"/>
+ <field name="email"/>
+ <field name="phone"/>
+ <field name="mobile"/>
+ </group>
+ <div>
+ <field name="use_parent_address"/><label for="use_parent_address"/>
+ </div>
+ <group>
+ <label for="type"/>
+ <div name="div_type">
+ <field class="oe_inline" name="type"/>
+ </div>
+ <label for="street" string="Address" attrs="{'invisible': [('use_parent_address','=', True)]}"/>
+ <div attrs="{'invisible': [('use_parent_address','=', True)]}" name="div_address">
+ <field name="street" placeholder="Street..."/>
+ <field name="street2"/>
+ <div class="address_format">
+ <field name="city" placeholder="City" style="width: 40%%"/>
+ <field name="state_id" class="oe_no_button" placeholder="State" style="width: 37%%" options='{"no_open": True}' on_change="onchange_state(state_id)"/>
+ <field name="zip" placeholder="ZIP" style="width: 20%%"/>
+ </div>
+ <field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": True}'/>
+ </div>
+ </group>
+ <field name="supplier" invisible="True"/>
+ </sheet>
+ </form>
+ </field>
+ </page>
+ <page name="personal-info" string="Personal Information" attrs="{'invisible': ['|',('is_company','=',True)]}">
+ <p attrs="{'invisible': [('contact_id','=',False)]}">
+ To see personal information about this contact, please go to to the his person form: <field name="contact_id" class="oe_inline" domain="[('contact_type','!=','attached')]" context="{'show_address': 1}"
+ on_change="onchange_contact_id(contact_id)" options="{'always_reload': True}"/>
+ </p>
+ <group attrs="{'invisible': [('contact_id','!=',False)]}">
+ <field name="birthdate_date"/>
+ <field name="nationality_id"/>
+ </group>
+ </page>
+ </page>
+ <xpath expr="//field[@name='child_ids']/form//field[@name='name']/.." position="before">
+ <field name="contact_type" readonly="0" on_change="onchange_contact_type(contact_type)"/>
+ </xpath>
+ <xpath expr="//field[@name='child_ids']/form//field[@name='name']" position="after">
+ <field name="contact_id" on_change="onchange_contact_id(contact_id)" string="Contact"
+ attrs="{'invisible': [('contact_type','!=','attached')], 'required': [('contact_type','=','attached')]}"/>
+ </xpath>
+ <xpath expr="//field[@name='child_ids']/form//field[@name='name']" position="attributes">
+ <attribute name="attrs">{'invisible': [('contact_type','=','attached')]}</attribute>
+ </xpath>
+ </field>
+ </record>
+
+ <record model="ir.ui.view" id="view_res_partner_kanban_contact">
+ <field name="name">res.partner.kanban.contact</field>
+ <field name="model">res.partner</field>
+ <field name="inherit_id" ref="base.res_partner_kanban_view"/>
+ <field name="arch" type="xml">
+ <field name="is_company" position="after">
+ <field name="other_contact_ids">
+ <tree>
+ <field name="parent_id"/>
+ <field name="function"/>
+ </tree>
+ </field>
+ </field>
+ <xpath expr="//t[@t-name='kanban-box']//div[@class='oe_kanban_details']/ul/li[3]" position="after">
+ <t t-if="record.other_contact_ids.raw_value.length > 0">
+ <li>+<t t-esc="record.other_contact_ids.raw_value.length"/>
+ <t t-if="record.other_contact_ids.raw_value.length == 1">other position</t>
+ <t t-if="record.other_contact_ids.raw_value.length > 1">other positions</t></li>
+ </t>
+ </xpath>
+ </field>
+ </record>
+
+</data>
+</openerp>
=== added directory 'base_contact/i18n'
=== added file 'base_contact/i18n/base_contact.pot'
--- base_contact/i18n/base_contact.pot 1970-01-01 00:00:00 +0000
+++ base_contact/i18n/base_contact.pot 2014-01-30 14:39:48 +0000
@@ -0,0 +1,184 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * base_contact
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-12-10 16:08+0000\n"
+"PO-Revision-Date: 2013-12-10 11:08-0500\n"
+"Last-Translator: \n"
+"Language-Team: \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.5.4\n"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "City"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "other position"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Contacts"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid ""
+"To see personal information about this contact, please go to to the his "
+"person form:"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Street..."
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "State"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "at"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Tags..."
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Other Positions"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Phone:"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Company"
+msgstr ""
+
+#. module: base_contact
+#: field:res.partner,contact_id:0
+msgid "Main Contact"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Fax:"
+msgstr ""
+
+#. module: base_contact
+#: selection:res.partner,contact_type:0
+msgid "Standalone Contact"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Address"
+msgstr ""
+
+#. module: base_contact
+#: field:res.partner,nationality_id:0
+msgid "Nationality"
+msgstr ""
+
+#. module: base_contact
+#: selection:res.partner,contact_type:0
+msgid "Attached to existing Contact"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "ZIP"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Country"
+msgstr ""
+
+#. module: base_contact
+#: field:res.partner,birthdate_date:0
+msgid "Birthdate"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Person"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Contact"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Mobile:"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "All partner positions"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "{'invisible': [('contact_type','=','attached')]}"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "All positions"
+msgstr ""
+
+#. module: base_contact
+#: model:ir.model,name:base_contact.model_ir_actions_act_window
+msgid "ir.actions.act_window"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "other positions"
+msgstr ""
+
+#. module: base_contact
+#: field:res.partner,contact_type:0
+msgid "Contact Type"
+msgstr ""
+
+#. module: base_contact
+#: model:ir.model,name:base_contact.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: base_contact
+#: field:res.partner,other_contact_ids:0
+msgid "Others Positions"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Personal Information"
+msgstr ""
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "e.g. Sales Director"
+msgstr ""
=== added file 'base_contact/i18n/fr.po'
--- base_contact/i18n/fr.po 1970-01-01 00:00:00 +0000
+++ base_contact/i18n/fr.po 2014-01-30 14:39:48 +0000
@@ -0,0 +1,186 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * base_contact
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-12-10 16:09+0000\n"
+"PO-Revision-Date: 2013-12-10 11:15-0500\n"
+"Last-Translator: \n"
+"Language-Team: \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.5.4\n"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "City"
+msgstr "Ville"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "other position"
+msgstr "Autre fonction"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Contacts"
+msgstr "Contacts"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid ""
+"To see personal information about this contact, please go to to the his "
+"person form:"
+msgstr ""
+"Pour voir des informations personnelles sur ce contact, s'il vous plaît "
+"aller à la sa forme de personne:"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Street..."
+msgstr "Rue..."
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "State"
+msgstr "État"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "at"
+msgstr "à"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Tags..."
+msgstr "Étiquettes..."
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Other Positions"
+msgstr "Autres Fonctions"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Phone:"
+msgstr "Téléphone:"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Company"
+msgstr "Organisme"
+
+#. module: base_contact
+#: field:res.partner,contact_id:0
+msgid "Main Contact"
+msgstr "Contact principal"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Fax:"
+msgstr "Fax :"
+
+#. module: base_contact
+#: selection:res.partner,contact_type:0
+msgid "Standalone Contact"
+msgstr "Contact simple"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Address"
+msgstr "Adresse"
+
+#. module: base_contact
+#: field:res.partner,nationality_id:0
+msgid "Nationality"
+msgstr "Nationalité"
+
+#. module: base_contact
+#: selection:res.partner,contact_type:0
+msgid "Attached to existing Contact"
+msgstr "Attaché à contacter existante"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "ZIP"
+msgstr "Code postal"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Country"
+msgstr "Pays"
+
+#. module: base_contact
+#: field:res.partner,birthdate_date:0
+msgid "Birthdate"
+msgstr "Date de naissance"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Person"
+msgstr "Personne"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Contact"
+msgstr "Contact"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Mobile:"
+msgstr "Portable :"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "All partner positions"
+msgstr "Toutes les fonctions"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "{'invisible': [('contact_type','=','attached')]}"
+msgstr "{'invisible': [('contact_type','=','attached')]}"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "All positions"
+msgstr "Toutes les positions"
+
+#. module: base_contact
+#: model:ir.model,name:base_contact.model_ir_actions_act_window
+msgid "ir.actions.act_window"
+msgstr "ir.actions.act_window"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "other positions"
+msgstr "Autres fonctions"
+
+#. module: base_contact
+#: field:res.partner,contact_type:0
+msgid "Contact Type"
+msgstr "Type de contact"
+
+#. module: base_contact
+#: model:ir.model,name:base_contact.model_res_partner
+msgid "Partner"
+msgstr "Partenaire"
+
+#. module: base_contact
+#: field:res.partner,other_contact_ids:0
+msgid "Others Positions"
+msgstr "Autres fonctions"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "Personal Information"
+msgstr "Informations personnelles"
+
+#. module: base_contact
+#: view:res.partner:0
+msgid "e.g. Sales Director"
+msgstr "e.g. Directeur"
=== added directory 'base_contact/tests'
=== added file 'base_contact/tests/__init__.py'
--- base_contact/tests/__init__.py 1970-01-01 00:00:00 +0000
+++ base_contact/tests/__init__.py 2014-01-30 14:39:48 +0000
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 ⁻*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (C) 2013-TODAY OpenERP S.A. (<http://openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from . import test_base_contact
+
+checks = [
+ test_base_contact,
+]
=== added file 'base_contact/tests/test_base_contact.py'
--- base_contact/tests/test_base_contact.py 1970-01-01 00:00:00 +0000
+++ base_contact/tests/test_base_contact.py 2014-01-30 14:39:48 +0000
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 ⁻*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (C) 2013-TODAY OpenERP S.A. (<http://openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.tests import common
+
+
+class Test_Base_Contact(common.TransactionCase):
+
+ def setUp(self):
+ """*****setUp*****"""
+ super(Test_Base_Contact, self).setUp()
+ cr, uid = self.cr, self.uid
+ ModelData = self.registry('ir.model.data')
+ self.partner = self.registry('res.partner')
+
+ # Get test records reference
+ for attr, module, name in [
+ ('main_partner_id', 'base', 'main_partner'),
+ ('bob_contact_id', 'base_contact', 'res_partner_contact1'),
+ ('bob_job1_id', 'base_contact', 'res_partner_contact1_work_position1'),
+ ('roger_contact_id', 'base', 'res_partner_main2'),
+ ('roger_job2_id', 'base_contact', 'res_partner_main2_position_consultant')]:
+ r = ModelData.get_object_reference(cr, uid, module, name)
+ setattr(self, attr, r[1] if r else False)
+
+ def test_00_show_only_standalone_contact(self):
+ """Check that only standalone contact are shown if context explicitly state to not display all positions"""
+ cr, uid = self.cr, self.uid
+ ctx = {'search_show_all_positions': False}
+ partner_ids = self.partner.search(cr, uid, [], context=ctx)
+ partner_ids.sort()
+ self.assertTrue(self.bob_job1_id not in partner_ids)
+ self.assertTrue(self.roger_job2_id not in partner_ids)
+
+ def test_01_show_all_positions(self):
+ """Check that all contact are show if context is empty or explicitly state to display all positions"""
+ cr, uid = self.cr, self.uid
+
+ partner_ids = self.partner.search(cr, uid, [], context=None)
+ self.assertTrue(self.bob_job1_id in partner_ids)
+ self.assertTrue(self.roger_job2_id in partner_ids)
+
+ ctx = {'search_show_all_positions': True}
+ partner_ids = self.partner.search(cr, uid, [], context=ctx)
+ self.assertTrue(self.bob_job1_id in partner_ids)
+ self.assertTrue(self.roger_job2_id in partner_ids)
+
+ def test_02_reading_other_contact_one2many_show_all_positions(self):
+ """Check that readonly partner's ``other_contact_ids`` return all values whatever the context"""
+ cr, uid = self.cr, self.uid
+
+ def read_other_contacts(pid, context=None):
+ return self.partner.read(cr, uid, [pid], ['other_contact_ids'], context=context)[0]['other_contact_ids']
+
+ def read_contacts(pid, context=None):
+ return self.partner.read(cr, uid, [pid], ['child_ids'], context=context)[0]['child_ids']
+
+ ctx = None
+ self.assertEqual(read_other_contacts(self.bob_contact_id, context=ctx), [self.bob_job1_id])
+ ctx = {'search_show_all_positions': False}
+ self.assertEqual(read_other_contacts(self.bob_contact_id, context=ctx), [self.bob_job1_id])
+ ctx = {'search_show_all_positions': True}
+ self.assertEqual(read_other_contacts(self.bob_contact_id, context=ctx), [self.bob_job1_id])
+
+ ctx = None
+ self.assertTrue(self.bob_job1_id in read_contacts(self.main_partner_id, context=ctx))
+ ctx = {'search_show_all_positions': False}
+ self.assertTrue(self.bob_job1_id in read_contacts(self.main_partner_id, context=ctx))
+ ctx = {'search_show_all_positions': True}
+ self.assertTrue(self.bob_job1_id in read_contacts(self.main_partner_id, context=ctx))
+
+ def test_03_search_match_attached_contacts(self):
+ """Check that searching partner also return partners having attached contacts matching search criteria"""
+ cr, uid = self.cr, self.uid
+ # Bob's contact has one other position which is related to 'Your Company'
+ # so search for all contacts working for 'Your Company' should contain bob position.
+ partner_ids = self.partner.search(cr, uid, [('parent_id', 'ilike', 'Your Company')], context=None)
+ self.assertTrue(self.bob_job1_id in partner_ids)
+
+ # but when searching without 'all positions', we should get the position standalone contact instead.
+ ctx = {'search_show_all_positions': False}
+ partner_ids = self.partner.search(cr, uid, [('parent_id', 'ilike', 'Your Company')], context=ctx)
+ self.assertTrue(self.bob_contact_id in partner_ids)
+
+ def test_04_contact_creation(self):
+ """Check that we're begin to create a contact"""
+ cr, uid = self.cr, self.uid
+
+ # Create a contact using only name
+ new_contact_id = self.partner.create(cr, uid, {'name': 'Bob Egnops'})
+ self.assertEqual(self.partner.browse(cr, uid, new_contact_id).contact_type, 'standalone')
+
+ # Create a contact with only contact_id
+ new_contact_id = self.partner.create(cr, uid, {'contact_id': self.bob_contact_id})
+ new_contact = self.partner.browse(cr, uid, new_contact_id)
+ self.assertEqual(new_contact.name, 'Bob Egnops')
+ self.assertEqual(new_contact.contact_type, 'attached')
+
+ # Create a contact with both contact_id and name;
+ # contact's name should override provided value in that case
+ new_contact_id = self.partner.create(cr, uid, {'contact_id': self.bob_contact_id, 'name': 'Rob Egnops'})
+ self.assertEqual(self.partner.browse(cr, uid, new_contact_id).name, 'Bob Egnops')
+
+ # Reset contact to standalone
+ self.partner.write(cr, uid, [new_contact_id], {'contact_id': False})
+ self.assertEqual(self.partner.browse(cr, uid, new_contact_id).contact_type, 'standalone')
+
+ def test_05_contact_fields_sync(self):
+ """Check that contact's fields are correctly synced between parent contact or related contacts"""
+ cr, uid = self.cr, self.uid
+
+ # Test DOWNSTREAM sync
+ self.partner.write(cr, uid, [self.bob_contact_id], {'name': 'Rob Egnops'})
+ self.assertEqual(self.partner.browse(cr, uid, self.bob_job1_id).name, 'Rob Egnops')
+
+ # Test UPSTREAM sync
+ self.partner.write(cr, uid, [self.bob_job1_id], {'name': 'Bob Egnops'})
+ self.assertEqual(self.partner.browse(cr, uid, self.bob_contact_id).name, 'Bob Egnops')
References