[MERGE] Merged with addons/trunk, with lots of conflicts to solve...

bzr revid: tde@openerp.com-20120920074850-7p7or1ze8555fya5
This commit is contained in:
Thibault Delavallée 2012-09-20 09:48:50 +02:00
commit bcbae5e277
53 changed files with 672 additions and 654 deletions

View File

@ -13,7 +13,7 @@
<field name="groups_id" eval="[(5,)]"/>
</record>
<record id="config_default_template_user" model="ir.config_parameter">
<record id="default_template_user_config" model="ir.config_parameter">
<field name="key">auth_signup.template_user_id</field>
<field name="value" ref="default_template_user"/>
</record>

View File

@ -20,7 +20,7 @@
##############################################################################
{
'name': 'Calendar Layer',
'name': 'Calendar',
'version': '1.0',
'depends': ['base', 'base_status', 'mail', 'base_action_rule'],
'description': """
@ -51,6 +51,7 @@ If you need to manage your meetings, you should install the CRM module.
],
'test' : ['test/base_calendar_test.yml'],
'installable': True,
'application': True,
'auto_install': False,
'certificate': '00694071962960352821',
'images': ['images/base_calendar1.jpeg','images/base_calendar2.jpeg','images/base_calendar3.jpeg','images/base_calendar4.jpeg',],

View File

@ -1431,7 +1431,10 @@ rule or repeating pattern of time to exclude from the recurring rule."),
if r['class']=='private':
for f in r.keys():
if f not in ('id','date','date_deadline','duration','user_id','state'):
r[f] = False
if isinstance(r[f], list):
r[f] = []
else:
r[f] = False
if f=='name':
r[f] = _('Busy')

View File

@ -428,5 +428,6 @@
name="Events" parent="base.menu_calendar_configuration"
sequence="15" action="action_view_event"/>
<menuitem name="Agenda" id="mail_menu_agenda" parent="mail.mail_my_stuff" sequence="10" action="action_view_event"/>
</data>
</openerp>

View File

@ -53,7 +53,7 @@ class crm_meeting(base_state, osv.Model):
'partner_ids': fields.many2many('res.partner', 'crm_meeting_partner_rel', 'meeting_id','partner_id',
string='Attendees', states={'done': [('readonly', True)]}),
'state': fields.selection(
[('draft', 'Unconfirmed'), ('open', 'Confirmed'), ('cancel', 'Cancelled'), ('done', 'Done')],
[('draft', 'Unconfirmed'), ('open', 'Confirmed')],
string='Status', size=16, readonly=True),
# Meeting fields
'name': fields.char('Meeting Subject', size=128, required=True, states={'done': [('readonly', True)]}),

View File

@ -69,9 +69,7 @@
<field name="model">crm.meeting</field>
<field name="arch" type="xml">
<form string="Meetings" version="7.0">
<header>
<field name="state" invisible="True"/>
</header>
<field name="state" invisible="True"/>
<sheet>
<div class="oe_title">
<div class="oe_edit_only">

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -69,7 +69,7 @@ class base_stage(object):
return False
return uid
def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
def onchange_partner_address_id(self, cr, uid, ids, add, email=False, context=None):
""" This function returns value of partner email based on Partner Address
:param add: Id of Partner's address
:param email: Partner's email ID
@ -77,10 +77,20 @@ class base_stage(object):
data = {'value': {'email_from': False, 'phone':False}}
if add:
address = self.pool.get('res.partner').browse(cr, uid, add)
data['value'] = {'email_from': address and address.email or False ,
'phone': address and address.phone or False}
if 'phone' not in self._columns:
del data['value']['phone']
data['value'] = {'partner_name': address and address.name or False,
'email_from': address and address.email or False,
'phone': address and address.phone or False,
'street': address and address.street or False,
'street2': address and address.street2 or False,
'city': address and address.city or False,
'state_id': address.state_id and address.state_id.id or False,
'zip': address and address.zip or False,
'country_id': address.country_id and address.country_id.id or False,
}
fields = self.fields_get(cr, uid, context=context or {})
for key in data['value'].keys():
if key not in fields:
del data['value'][key]
return data
def onchange_partner_id(self, cr, uid, ids, part, email=False):

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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/>.
#
##############################################################################

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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': 'Address Book',
'version': '1.0',
'category': 'Tools',
'description': """
This module gives you a quick view of your address book, accessible from your home page.
You can track your suppliers, customers and other contacts.
""",
'author': 'OpenERP SA',
'website': 'http://openerp.com',
'summary': 'Contacts, People and Companies',
'depends': [
'mail',
],
'data': [
'contacts_view.xml',
],
'installable': True,
'application': True,
'auto_install': False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,53 @@
<?xml version="1.0" ?>
<openerp>
<data>
<record id="action_contacts" model="ir.actions.act_window">
<field name="name">Contacts</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="search_view_id" ref="base.view_res_partner_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a contact in your address book.
</p><p>
OpenERP helps you easily track all activities related to
a customer; discussions, history of business opportunities,
documents, etc.
</p>
</field>
</record>
<record id="action_contacts_view_kanban" model="ir.actions.act_window.view">
<field eval="0" name="sequence"/>
<field name="view_mode">kanban</field>
<field name="view_id" ref="base.res_partner_kanban_view"/>
<field name="act_window_id" ref="action_contacts"/>
</record>
<record id="action_contacts_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="base.view_partner_tree"/>
<field name="act_window_id" ref="action_contacts"/>
</record>
<record id="action_contacts_view_form" model="ir.actions.act_window.view">
<field eval="2" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="base.view_partner_form"/>
<field name="act_window_id" ref="action_contacts"/>
</record>
<menuitem name="Contacts"
id="menu_contacts"
parent="mail.mail_my_stuff"
sequence="11"
action="action_contacts"
groups="base.group_user,base.group_partner_manager"/>
</data>
</openerp>

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -25,7 +25,7 @@
'version': '1.0',
'category': 'Customer Relationship Management',
'sequence': 2,
'summary': 'Leads, Opportunities, Agenda',
'summary': 'Leads, Opportunities, Phone Calls',
'description': """
The generic OpenERP Customer Relationship Management
=====================================================

View File

@ -92,9 +92,10 @@ class crm_case_stage(osv.osv):
_defaults = {
'sequence': lambda *args: 1,
'probability': lambda *args: 0.0,
'state': 'draft',
'state': 'open',
'fold': False,
'type': 'both',
'case_default': True,
}
class crm_case_section(osv.osv):

View File

@ -104,57 +104,55 @@
<field name="arch" type="xml">
<form string="Phone Call" version="7.0">
<header>
<button name="case_close" string="Held" type="object" class="oe_highlight"
<button name="case_close" string="Call Done" type="object" class="oe_highlight"
states="open,pending"/>
<button name="case_reset" string="Reset to Todo" type="object"
states="cancel"/>
<button string="Convert to Opportunity"
name="%(phonecall2opportunity_act)d"
type="action"
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state','!=', 'open')]}"/>
<button string="Convert to Opportunity" class="oe_highlight"
name="%(phonecall2opportunity_act)d"
type="action"
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state','!=', 'done')]}"/>
<button string="Schedule Other Call"
name="%(phonecall_to_phonecall_act)d"
type="action"/>
<button string="Schedule a Meeting" name="action_make_meeting" type="object"/>
<button name="case_cancel" string="Cancel" type="object"
states="draft,open,pending"/>
<field name="state" widget="statusbar" nolabel="1" statusbar_visible="open,done"/>
</header>
<sheet string="Phone Call">
<div class="oe_title">
<div class="oe_edit_only">
<label for="name" string="Title"/>
</div>
<h1><field name="name" required="1"/></h1>
<div class="oe_edit_only">
<label for="partner_phone" string="Phone"/>
</div>
<h2><field name="partner_phone"/></h2>
</div>
<group col="4">
<field name="date"/>
<field name="user_id"/>
<field name="duration" widget="float_time"/>
<field name="section_id" colspan="1" widget="selection"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="categ_id" widget="selection"
domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<field name="partner_mobile"/>
<field name="priority"/>
<field name="opportunity_id"/>
</group>
<field name="description" placeholder="Description..."/>
</sheet>
<div class="oe_chatter">
<field name="message_is_follower" invisible="1"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_follower_ids" widget="mail_followers"/>
</div>
<sheet string="Phone Call">
<div class="oe_right">
<button string="Convert to Opportunity"
name="%(phonecall2opportunity_act)d"
type="action"
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state', 'not in', ('open', 'done'))]}"/>
<button string="Schedule Other Call"
name="%(phonecall_to_phonecall_act)d"
type="action"/>
<button string="Schedule a Meeting" name="action_make_meeting" type="object"/>
</div>
<div class="oe_title">
<div class="oe_edit_only">
<label for="name" string="Title"/>
</div>
<h1><field name="name" required="1"/></h1>
<div class="oe_edit_only">
<label for="partner_phone" string="Phone"/>
</div>
<h2><field name="partner_phone"/></h2>
</div>
<group col="4">
<field name="date"/>
<field name="user_id"/>
<field name="duration" widget="float_time"/>
<field name="section_id" colspan="1" widget="selection"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="categ_id" widget="selection"
domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<field name="partner_mobile"/>
<field name="priority"/>
<field name="opportunity_id"/>
</group>
<field name="description" placeholder="Description..."/>
</sheet>
<div class="oe_chatter">
<field name="message_is_follower" invisible="1"/>
<field name="message_ids" widget="mail_thread"/>
<field name="message_follower_ids" widget="mail_followers"/>
</div>
</form>
</field>
</record>

View File

@ -130,10 +130,10 @@
<field name="arch" type="xml">
<xpath expr="//div[@name='buttons']" position="inside">
<button type="action"
string="Schedule a Meeting"
string="Meetings"
name="%(base_calendar.action_crm_meeting)d"
context="{'search_default_partner_ids': active_id, 'default_partner_ids' : [active_id]}"/>
<button type="action" string="Schedule a Call"
<button type="action" string="Calls"
name="%(crm.crm_case_categ_phone_create_partner)d"
context="{'search_default_partner_id': active_id, 'default_duration': 1.0}" />
<button type="action" string="Opportunities" attrs="{'invisible': [('customer', '=', False)]}"

View File

@ -0,0 +1,33 @@
# Icelandic translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-09-19 10:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Icelandic <is@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-09-20 04:43+0000\n"
"X-Generator: Launchpad (build 15985)\n"
#. module: google_map
#: view:res.partner:0
msgid "Map"
msgstr "Landakort"
#. module: google_map
#: model:ir.model,name:google_map.model_res_partner_address
msgid "Partner Addresses"
msgstr "Heimilisfang viðskiptaaðila"
#. module: google_map
#: view:res.partner:0
msgid "Street2 : "
msgstr "Gata2 : "

View File

@ -444,11 +444,9 @@ class sugar_import(import_framework):
import Tasks
"""
task_state = {
'Completed' : 'done',
'Completed' : 'open',
'Not Started':'draft',
'In Progress': 'open',
'Pending Input': 'draft',
'deferred': 'cancel'
}
def import_task(self, val):

View File

@ -9,7 +9,8 @@
sequence="10"/>
<!-- Left-side menu: Feeds -->
<menuitem id="mail_feeds" name="Feeds" parent="mail_feeds_main" groups="base.group_user" sequence="10"/>
<menuitem id="mail_feeds" name="Feeds" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/>
<menuitem id="mail_my_stuff" name="Organizer" parent="mail.mail_feeds_main"/>
<record id="mail_wallfeeds" model="ir.ui.menu">
<field name="name">My Feeds</field>

View File

@ -20,7 +20,7 @@
##############################################################################
{
'name': 'Memos',
'name': 'Notes',
'version': '1.0',
'category': 'Tools',
'description': """
@ -28,12 +28,12 @@ This module allows users to create their own notes inside OpenERP
=================================================================
Use notes to write meeting minutes, organize ideas, organize personnal todo
lists, etc. Each user manages his own personnal memos. Notes are available to
lists, etc. Each user manages his own personnal Notes. Notes are available to
their authors only, but they can share notes to others users so that several
people can work on the same note in real time. It's very efficient to share
meeting minutes.
Memos can be found in the 'Home' menu.
Notes can be found in the 'Home' menu.
""",
'author': 'OpenERP SA',
'website': 'http://openerp.com',

View File

@ -63,11 +63,8 @@ class note_note(osv.osv):
def _get_note_first_line(self, cr, uid, ids, name="", args={}, context=None):
res = {}
for note in self.browse(cr, uid, ids, context=context):
text_note = (note.memo or '').strip().split('\n')[0]
text_note = re.sub(r'(\S?)(<br[ /]*>|<[/]?p>|<[/]?div>|<table>)[\s\S]*',r'\1',text_note)
text_note = re.sub(r'<[^>]+>','',text_note)
text_note = html2plaintext(text_note)
res[note.id] = text_note
res[note.id] = (note.memo and html2plaintext(note.memo) or "").strip().replace('*','').split("\n")[0]
return res
#unactivate a sticky note and record the date
@ -98,7 +95,8 @@ class note_note(osv.osv):
def _set_stage_per_user(self, cr, uid, id, name, value, args=None, context=None):
note = self.browse(cr, uid, id, context=context)
if not value: return False
return self.write(cr, uid, [id], {'stage_ids': [(4, value)]}, context=context)
stage_ids = [value] + [stage.id for stage in note.stage_ids if stage.user_id.id != uid ]
return self.write(cr, uid, [id], {'stage_ids': [(6, 0, stage_ids)]}, context=context)
def _get_stage_per_user(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)

View File

@ -28,7 +28,7 @@
<record id="note_1" model="note.note">
<field name="name">Customer report #349872</field>
<field name="memo"><![CDATA[Customer report #349872
<field name="memo"><![CDATA[<b>Customer report #349872</b>
<br/><br/>* Calendar app in Home
<br/>* The base_calendar module should create a menu in Home, like described above.
<br/>* This module should become a main application (in the first screen at installation)
@ -40,7 +40,7 @@
</record>
<record id="note_2" model="note.note">
<field name="memo"><![CDATA[Call Fabien
<field name="memo"><![CDATA[<b>Call Fabien</b>
<br/><br/>* Followed by the telephone conversation and mail about D.544.3
]]>
</field>
@ -48,21 +48,21 @@
</record>
<record id="note_3" model="note.note">
<field name="memo"><![CDATA[Call Marc
<field name="memo"><![CDATA[<b>Call Marc</b>
<br/><br/>]]>
</field>
<field name="stage_id" ref="note_stage_01"/>
</record>
<record id="note_4" model="note.note">
<field name="memo"><![CDATA[Project N.947.5
<field name="memo"><![CDATA[<b>Project N.947.5</b>
<br/><br/>]]>
</field>
<field name="stage_id" ref="note_stage_02"/>
</record>
<record id="note_5" model="note.note">
<field name="memo"><![CDATA[Shop for family dinner
<field name="memo"><![CDATA[<b>Shop for family dinner</b>
<br/>* stuffed turkey
<br/>* wine
]]>
@ -71,7 +71,7 @@
</record>
<record id="note_6" model="note.note">
<field name="memo"><![CDATA[Idea to develop
<field name="memo"><![CDATA[<b>Idea to develop</b>
<br/><br/>* Create a module note_pad
it transforms the html editable memo text field into widget='pad', similar to project_pad depends on 'memo' and 'pad' modules
]]>
@ -80,7 +80,7 @@
</record>
<record id="note_7" model="note.note">
<field name="memo"><![CDATA[Read some documentation about OpenERP before diving into the code
<field name="memo"><![CDATA[<b>Read some documentation about OpenERP before diving into the code</b>
<br/><br/>* Open ERP: a modern approach to integrated business management
<br/>* Open ERP for Retail and Industrial Management
]]>
@ -89,7 +89,7 @@
</record>
<record id="note_8" model="note.note">
<field name="memo"><![CDATA[New computer specs
<field name="memo"><![CDATA[<b>New computer specs</b>
<br/><br/>* Motherboard
according to processor
<br/>* Processor
@ -111,7 +111,7 @@
</record>
<record id="note_9" model="note.note">
<field name="memo"><![CDATA[Read those books
<field name="memo"><![CDATA[<b>Read those books</b>
<br/><br/>* Open ERP: a modern approach to integrated business management
<br/>* Open ERP for Retail and Industrial Management
]]>
@ -120,7 +120,7 @@
</record>
<record id="note_10" model="note.note">
<field name="memo"><![CDATA[Read some documentation about OpenERP before diving into the code
<field name="memo"><![CDATA[<b>Read some documentation about OpenERP before diving into the code</b>
<br/><br/>* Open ERP: a modern approach to integrated business management
<br/>* Open ERP for Retail and Industrial Management
]]>
@ -129,7 +129,7 @@
</record>
<record id="note_12" model="note.note">
<field name="memo"><![CDATA[Read some documentation about OpenERP before diving into the code
<field name="memo"><![CDATA[<b>Read some documentation about OpenERP before diving into the code</b>
<br/><br/>* Open ERP: a modern approach to integrated business management
<br/>* Open ERP for Retail and Industrial Management
]]>

View File

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data>
<menuitem name="Organizer" id="note_my_stuff" parent="mail.mail_feeds_main"/>
<!-- note Stage Form View -->
<record model="ir.ui.view" id="view_note_stage_form">
<field name="name">note.stage.form</field>
@ -38,8 +36,6 @@
<field name="domain">[('user_id','=',uid)]</field>
</record>
<menuitem name="Categories" id="menu_notes_stage" parent="note_my_stuff" action="action_note_stage" sequence="40" groups="base.group_no_one"/>
<!-- New note Kanban View -->
<record model="ir.ui.view" id="view_note_note_kanban">
<field name="name">note.note.kanban</field>
@ -117,12 +113,10 @@
<field name="arch" type="xml">
<form string="Note" version="7.0">
<header>
<field name="tag_ids" widget="many2many_tags" class="oe_inline" placeholder="Tags"/>
<field name="stage_id" domain="[('user_id','=',uid)]" widget="statusbar" clickable="1"/>
</header>
<field name="memo" widget="html"/><!-- editor_width="100%%" editor_height="60%%" -->
<group groups="note.group_note_tags" col="2">
<field name="tag_ids" widget="many2many_tags"/>
</group>
<div class="oe_chatter">
<field name="message_is_follower" invisible="1"/>
<field name="message_ids" widget="mail_thread"/>
@ -188,7 +182,8 @@
<field name="context">{'search_default_open_true':True}</field>
</record>
<menuitem name="Notes" id="note_notes" parent="note_my_stuff" sequence="20" action="action_note_note"/>
<menuitem name="Notes" id="menu_note_notes" parent="mail.mail_my_stuff" sequence="20" action="note.action_note_note"/>
<menuitem name="Categories" id="menu_notes_stage" parent="mail.mail_my_stuff" action="note.action_note_stage" sequence="21" groups="base.group_no_one"/>
</data>
</openerp>

View File

@ -31,11 +31,5 @@ class note_pad_note(osv.osv):
_pad_fields = ['note_pad']
_columns = {
'note_pad_url': fields.char('Pad Url',
pad_content_field='memo',
size=250 ),
}
#_defaults = {
# 'note_pad_url': lambda self, cr, uid, context: self.pad_generate_url(cr, uid, context),
#}
'note_pad_url': fields.char('Pad Url', pad_content_field='memo'),
}

View File

@ -21,7 +21,7 @@ class pad_common(osv.osv_memory):
s = string.ascii_uppercase + string.digits
salt = ''.join([s[random.randint(0, len(s) - 1)] for i in range(10)])
# contruct the url
url = '%s/p/%s-%s-%s' % (pad_server, cr.dbname, self._name, salt)
url = '%s/p/%s-%s-%s' % (pad_server, cr.dbname.replace('_','-'), self._name, salt)
return url
def pad_get_content(self, cr, uid, url, context=None):
@ -35,22 +35,21 @@ class pad_common(osv.osv_memory):
# TODO
# reverse engineer protocol to be setHtml without using the api key
# override read and copy to generate url and store the content if empty
def default_get(self, cr, uid, fields, context=None):
data = super(pad_common, self).default_get(cr, uid, fields, context)
for k in fields:
field = self._all_columns[k].column
if hasattr(field,'pad_content_field'):
data[k] = self.pad_generate_url(cr, uid, context=context)
return data
def write(self, cr, uid, ids, vals, context=None):
self._set_pad_value(cr, uid, vals, context)
return super(pad_common, self).write(cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context=None):
self._set_pad_value(cr, uid, vals, context)
return super(pad_common, self).create(cr, uid, vals, context=context)
# Set the pad content in vals
def _set_pad_value(self, cr, uid, vals, context=None):
for k,v in vals.items():
field = self._all_columns[k].column
if hasattr(field,'pad_content_field'):
vals[field.pad_content_field] = self.pad_get_content(cr, uid, v, context=context)
return super(pad_common, self).write(cr, uid, ids, vals, context=context)
vals[field.pad_content_field] = self.pad_get_content(cr, uid, v, context=context)
def copy(self, cr, uid, id, default=None, context=None):
if not default:

View File

@ -16,8 +16,15 @@ instance.web.form.FieldPad = instance.web.form.AbstractField.extend({
var self = this;
var _super = self._super;
_super.apply(self,[val]);
if (val === false || val === "") {
self.field_manager.dataset.call('pad_generate_url').then(function(r) {
_super.apply(self,[r]);
self.render_value();
});
} else {
self.render_value();
}
this._dirty_flag = true;
self.render_value();
},
render_value: function() {
console.log("display");

View File

@ -0,0 +1,109 @@
# Icelandic translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-09 00:36+0000\n"
"PO-Revision-Date: 2012-09-19 10:08+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Icelandic <is@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-09-20 04:43+0000\n"
"X-Generator: Launchpad (build 15985)\n"
#. module: plugin_thunderbird
#: field:plugin_thunderbird.installer,pdf_file:0
msgid "Installation Manual"
msgstr "Uppsetningarhandbók"
#. module: plugin_thunderbird
#: field:plugin_thunderbird.installer,description:0
msgid "Description"
msgstr "Lýsing"
#. module: plugin_thunderbird
#: view:plugin_thunderbird.installer:0
msgid "title"
msgstr "titill"
#. module: plugin_thunderbird
#: model:ir.model,name:plugin_thunderbird.model_plugin_thunderbird_installer
msgid "plugin_thunderbird.installer"
msgstr "plugin_thunderbird.installer"
#. module: plugin_thunderbird
#: field:plugin_thunderbird.installer,config_logo:0
msgid "Image"
msgstr "Mynd"
#. module: plugin_thunderbird
#: field:plugin_thunderbird.installer,plugin_file:0
#: field:plugin_thunderbird.installer,thunderbird:0
msgid "Thunderbird Plug-in"
msgstr "Thunderbird viðbót"
#. module: plugin_thunderbird
#: view:plugin_thunderbird.installer:0
msgid ""
"This plug-in allows you to link your email to OpenERP's documents. You can "
"attach it to any existing one in OpenERP or create a new one."
msgstr ""
#. module: plugin_thunderbird
#: help:plugin_thunderbird.installer,thunderbird:0
msgid ""
"Allows you to select an object that you would like to add to your email and "
"its attachments."
msgstr ""
"Gerir þér kleift að velja hlut sem þú vilt bæta við póstinn og viðhengi hans."
#. module: plugin_thunderbird
#: help:plugin_thunderbird.installer,pdf_file:0
msgid "The documentation file :- how to install Thunderbird Plug-in."
msgstr "Handbókin :- hvernig á að setja inn Thunderbird viðbót."
#. module: plugin_thunderbird
#: view:plugin_thunderbird.installer:0
msgid "_Close"
msgstr "_Loka"
#. module: plugin_thunderbird
#: view:plugin_thunderbird.installer:0
msgid "Installation and Configuration Steps"
msgstr ""
#. module: plugin_thunderbird
#: field:plugin_thunderbird.installer,name:0
#: field:plugin_thunderbird.installer,pdf_name:0
msgid "File name"
msgstr "Skrárheiti"
#. module: plugin_thunderbird
#: help:plugin_thunderbird.installer,plugin_file:0
msgid ""
"Thunderbird plug-in file. Save as this file and install this plug-in in "
"thunderbird."
msgstr ""
"Skrá með Thunderbird viðbót. Vistaðu skrána og settu viðbótina inn í "
"Thunderbird."
#. module: plugin_thunderbird
#: model:ir.actions.act_window,name:plugin_thunderbird.action_thunderbird_installer
#: model:ir.ui.menu,name:plugin_thunderbird.menu_base_config_plugins_thunderbird
#: view:plugin_thunderbird.installer:0
msgid "Install Thunderbird Plug-In"
msgstr "Setja inn Thunderbird viðbót"
#~ msgid ""
#~ "This plug-in allows you to link your e-mail to OpenERP's documents. You can "
#~ "attach it to any existing one in OpenERP or create a new one."
#~ msgstr ""
#~ "Þessi viðbót gerir þér kleift að tengja tölvupóst við OpenERP skjöl. Þú "
#~ "getur viðhengt póstinn við skjöl sem þegar eru til í OpenERP eða búið til "
#~ "nýtt."

View File

@ -43,7 +43,7 @@ class mail_mail_portal(osv.Model):
:param partner: browse_record of the specific recipient partner
"""
if partner:
portal_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal', 'portal')
portal_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')
portal_id = portal_ref and portal_ref[1] or False
url = self._generate_signin_url(cr, uid, partner.id, portal_id, 1234, context=context)
body = tools.append_content_to_html(mail.body_html, url)

View File

@ -20,196 +20,14 @@
##############################################################################
from osv import osv, fields
from tools.translate import _
class portal(osv.osv):
""" A portal is simply a group of users with the flag 'is_portal' set to True.
The flag 'is_portal' makes a user group usable as a portal.
"""
A portal is a group of users with specific menu, widgets, and typically
restricted access rights.
"""
_name = 'res.portal'
_description = 'Portal'
_inherits = {'res.groups': 'group_id'}
_inherit = 'res.groups'
_columns = {
'group_id': fields.many2one('res.groups', required=True, ondelete='cascade',
string='Group',
help='The group corresponding to this portal'),
'url': fields.char('URL',
help="The url where portal users can connect to the server"),
'home_action_id': fields.many2one('ir.actions.actions',
string='Home Action',
help="if set, replaces the standard home action (first screen after loggin) for the portal's users"),
'menu_action_id': fields.many2one('ir.actions.act_window', readonly=True,
# ISSUE: 'ondelete' constraints do not seem effective on this field...
string='Menu Action',
help="If set, replaces the standard menu for the portal's users"),
'parent_menu_id': fields.many2one('ir.ui.menu', ondelete='restrict',
string='Parent Menu',
help='The menu action opens the submenus of this menu item'),
'widget_ids': fields.one2many('res.portal.widget', 'portal_id',
string='Widgets',
help='Widgets assigned to portal users'),
'is_portal': fields.boolean('Portal', help="If checked, this group is usable as a portal."),
}
def copy(self, cr, uid, id, values, context=None):
""" override copy(): menu_action_id must be different """
values['menu_action_id'] = None
return super(portal, self).copy(cr, uid, id, values, context)
def create(self, cr, uid, values, context=None):
""" extend create() to assign the portal menu to users """
if context is None:
context = {}
# create portal (admin should not be included)
context['noadmin'] = True
portal_id = super(portal, self).create(cr, uid, values, context)
# assign menu action and widgets to users
if values.get('users') or values.get('menu_action_id'):
self._assign_menu(cr, uid, [portal_id], context)
if values.get('users') or values.get('widget_ids'):
self._assign_widgets(cr, uid, [portal_id], context)
return portal_id
def write(self, cr, uid, ids, values, context=None):
""" extend write() to reflect changes on users """
# first apply portal changes
super(portal, self).write(cr, uid, ids, values, context)
# assign menu action and widgets to users
if values.get('users') or values.get('menu_action_id'):
self._assign_menu(cr, uid, ids, context)
if values.get('users') or values.get('widget_ids'):
self._assign_widgets(cr, uid, ids, context)
# if parent_menu_id has changed, apply the change on menu_action_id
if 'parent_menu_id' in values:
act_window_obj = self.pool.get('ir.actions.act_window')
portals = self.browse(cr, uid, ids, context)
action_ids = [p.menu_action_id.id for p in portals if p.menu_action_id]
if action_ids:
action_values = {'domain': [('parent_id', '=', values['parent_menu_id'])]}
act_window_obj.write(cr, uid, action_ids, action_values, context)
return True
def _assign_menu(self, cr, uid, ids, context=None):
""" assign portal_menu_settings to users of portals (ids) """
user_obj = self.pool.get('res.users')
for p in self.browse(cr, uid, ids, context):
# user menu action = portal menu action if set in portal
if p.menu_action_id:
user_ids = [u.id for u in p.users if u.id != 1]
user_values = {'menu_id': p.menu_action_id.id}
user_obj.write(cr, uid, user_ids, user_values, context)
def _assign_widgets(self, cr, uid, ids, context=None):
""" assign portal widgets to users of portals (ids) """
widget_user_obj = self.pool.get('res.widget.user')
for p in self.browse(cr, uid, ids, context):
for w in p.widget_ids:
values = {'sequence': w.sequence, 'widget_id': w.widget_id.id}
for u in p.users:
if u.id == 1: continue
values['user_id'] = u.id
widget_user_obj.create(cr, uid, values, context)
def _res_xml_id(self, cr, uid, module, xml_id):
""" return the resource id associated to the given xml_id """
data_obj = self.pool.get('ir.model.data')
data_id = data_obj._get_id(cr, uid, module, xml_id)
return data_obj.browse(cr, uid, data_id).res_id
portal()
class portal_override_menu(osv.osv):
"""
Extend res.portal with a boolean field 'Override Users Menu', that
triggers the creation or removal of menu_action_id
"""
_name = 'res.portal'
_inherit = 'res.portal'
def _get_override_menu(self, cr, uid, ids, field_name, arg, context=None):
assert field_name == 'override_menu'
result = {}
for p in self.browse(cr, uid, ids, context):
result[p.id] = bool(p.menu_action_id)
return result
def _set_override_menu(self, cr, uid, id, field_name, field_value, arg, context=None):
assert field_name == 'override_menu'
if field_value:
self.create_menu_action(cr, uid, id, context)
else:
self.write(cr, uid, [id], {'menu_action_id': False}, context)
def create_menu_action(self, cr, uid, id, context=None):
""" create, if necessary, a menu action that opens the menu items below
parent_menu_id """
p = self.browse(cr, uid, id, context)
if not p.menu_action_id:
actions_obj = self.pool.get('ir.actions.act_window')
parent_id = p.parent_menu_id.id if p.parent_menu_id else False
action_values = {
'name': _('%s Menu') % p.name,
'type': 'ir.actions.act_window',
'usage': 'menu',
'res_model': 'ir.ui.menu',
'view_type': 'tree',
'view_id': self._res_xml_id(cr, uid, 'base', 'view_menu'),
'domain': [('parent_id', '=', parent_id)],
}
action_id = actions_obj.create(cr, uid, action_values, context)
self.write(cr, uid, [id], {'menu_action_id': action_id}, context)
_columns = {
'override_menu': fields.function(
_get_override_menu, fnct_inv=_set_override_menu,
type='boolean', string='Override Menu Action of Users',
help='Enable this option to override the Menu Action of portal users'),
}
portal_override_menu()
class portal_widget(osv.osv):
"""
Similar to res.widget.user (res_widget.py), but with a portal instead.
New users in a portal are assigned the portal's widgets.
"""
_name='res.portal.widget'
_description = 'Portal Widgets'
_order = 'sequence'
_columns = {
'sequence': fields.integer('Sequence'),
'portal_id': fields.many2one('res.portal', select=1, ondelete='cascade',
string='Portal'),
'widget_id': fields.many2one('res.widget', required=True, ondelete='cascade',
string='Widget'),
}
def create(self, cr, uid, values, context=None):
domain = [('portal_id', '=', values.get('portal_id')),
('widget_id', '=', values.get('widget_id'))]
existing = self.search(cr, uid, domain, context=context)
if existing:
res = existing[0]
else:
res = super(portal_widget, self).create(cr, uid, values, context=context)
return res
portal_widget()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -2,14 +2,6 @@
<openerp>
<data noupdate="1">
<record id="portal" model="res.portal">
<field name="name">Portal</field>
<field name="group_id" ref="group_portal_member"/>
<field name="override_menu" eval="False"/>
<!-- Insert the template user from auth_signup in the portal members group -->
<field name="users" eval="[(4,ref('auth_signup.default_template_user'))]"/>
</record>
<!-- Mail group for the company's news -->
<record id="company_news_feed" model="mail.group">
<field name="name">Company's news</field>

View File

@ -15,7 +15,7 @@
</record>
<!-- Add the demo user to the portal (and therefore to the portal member group) -->
<record id="portal" model="res.portal">
<record id="group_portal" model="res.groups">
<field name="users" eval="[(4,ref('demo_user0'))]"/>
</record>

View File

@ -5,7 +5,7 @@
<!-- Top menu item -->
<menuitem name="Portal"
id="portal_menu"
groups="base.group_no_one,portal.group_portal_member,auth_anonymous.group_anonymous"
groups="base.group_no_one,portal.group_portal,auth_anonymous.group_anonymous"
sequence="20"/>
<menuitem name="Our company" id="portal_company" parent="portal_menu" sequence="10"/>
@ -21,71 +21,31 @@
<menuitem name="Projects" id="portal_projects" parent="portal_menu" sequence="40"/>
<menuitem name="After Sale Services" id="portal_after_sales" parent="portal_menu" sequence="50"/>
<!-- portal tree view -->
<record id="portal_list_view" model="ir.ui.view">
<field name="name">Portal List</field>
<field name="model">res.portal</field>
<!-- extend res.groups search view -->
<record id="group_search_view" model="ir.ui.view">
<field name="name">Group Search</field>
<field name="model">res.groups</field>
<field name="inherit_id" ref="base.view_groups_search"/>
<field name="arch" type="xml">
<tree string="Portals">
<field name="name" string="Portal Name"/>
</tree>
<field name="name" position="after">
<filter name="portal" string="Portal Groups" domain="[('is_portal','=',True)]"/>
<filter name="no_portal" string="Non-Portal Groups" domain="[('is_portal','=',False)]"/>
<separator orientation="vertical"/>
</field>
</field>
</record>
<!-- portal form view -->
<record id="portal_form_view" model="ir.ui.view">
<!-- extend res.groups form view -->
<record id="group_form_view" model="ir.ui.view">
<field name="name">Portal Form</field>
<field name="model">res.portal</field>
<field name="model">res.groups</field>
<field name="inherit_id" ref="base.view_groups_form"/>
<field name="arch" type="xml">
<page string="Users" position="before">
<page string="Portal">
<group>
<group>
<field name="url" widget="url" string="Portal URL"/>
<field name="home_action_id"/>
</group>
<group>
<field name="override_menu"/>
<field name="parent_menu_id"
context="{'ir.ui.menu.full_list': True}"/>
<label for="partent_menu_id" colspan="1"/>
</group>
<separator string="Widgets Assigned to Users" colspan="2"/>
<field name="widget_ids" nolabel="1" colspan="2">
<tree string="Widgets" editable="bottom">
<field name="sequence"/>
<field name="widget_id"/>
</tree>
</field>
</group>
</page>
</page>
<field name="name" position="after">
<field name="is_portal"/>
</field>
</field>
</record>
<!-- action Administration/Portals/Portals -->
<record id="portal_list_action" model="ir.actions.act_window">
<field name="name">Portals</field>
<field name="res_model">res.portal</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<!-- a context is necessary to get the right portal form view -->
<field name="context">{'form_view_ref': 'portal.portal_form_view'}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new portal.
</p><p>
A portal helps defining specific views and rules for a group of
users (the portal group). A portal menu, widgets and specific
groups may be assigned to the portal's users.
</p>
</field>
</record>
<!-- menu Administration/Portals/Portals -->
<menuitem name="Portals Settings" id="portal_menu_settings" parent="base.menu_administration" groups="group_portal_manager"/>
<menuitem name="Portals" id="portal_list_menu" parent="portal_menu_settings" action="portal_list_action"/>
</data>
</openerp>

View File

@ -1,6 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_all,access.portal.all,model_res_portal,,1,0,0,0
access_widget_all,access.portal.widget.all,model_res_portal_widget,,1,0,0,0
access_manager,access.portal.manager,model_res_portal,group_portal_manager,1,1,1,1
access_widget_manager,access.portal.widget.manager,model_res_portal_widget,group_portal_manager,1,1,1,1
access_mail_message_portal,mail.message.portal,mail.model_mail_message,group_portal_member,1,1,1,1
access_mail_message_portal,mail.message.portal,mail.model_mail_message,group_portal,1,0,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_all access_mail_message_portal access.portal.all mail.message.portal model_res_portal mail.model_mail_message group_portal 1 0 0 1 0 1
access_widget_all access.portal.widget.all model_res_portal_widget 1 0 0 0
access_manager access.portal.manager model_res_portal group_portal_manager 1 1 1 1
access_widget_manager access.portal.widget.manager model_res_portal_widget group_portal_manager 1 1 1 1
access_mail_message_portal mail.message.portal mail.model_mail_message group_portal_member 1 1 1 1

View File

@ -2,31 +2,14 @@
<openerp>
<data noupdate="1">
<!-- Don't use any implied_ids here; this group's behavior is particular -->
<record id="group_portal_member" model="res.groups">
<field name="name">Portal Member</field>
<field name="comment">Portal members can access information through the portal menu. Also, they are chrooted in this specific menu.</field>
</record>
<record id="module_category_portal" model="ir.module.category">
<!-- The portal group -->
<record id="group_portal" model="res.groups">
<field name="name">Portal</field>
<field name="parent_id" ref="base.module_category_tools"/>
<field name="sequence">25</field>
</record>
<!-- No implied ids with 'member' since this group is highly restrictive (chrooted menu) -->
<record id="group_portal_officer" model="res.groups">
<field name="name">Officer</field>
<field name="comment">Portal officers can create new portal users with the portal wizard.</field>
<field name="category_id" ref="module_category_portal"/>
</record>
<record id="group_portal_manager" model="res.groups">
<field name="name">Manager</field>
<field name="comment">Portal managers have access to the portal definitions, and can easily configure the users, access rights and menus of portal users.</field>
<field name="category_id" ref="module_category_portal"/>
<field name="implied_ids" eval="[(4, ref('group_portal_officer'))]"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="comment">Portal members have specific access rights (such as record rules and restricted menus).
They usually do not belong to the usual OpenERP groups.</field>
<field name="is_portal" eval="True"/>
<!-- Insert the template user from auth_signup in the portal members group -->
<field name="users" eval="[(4,ref('auth_signup.default_template_user'))]"/>
</record>
</data>

View File

@ -80,7 +80,7 @@ class test_portal(test_mail.TestMailMockups):
user_admin = self.res_users.browse(cr, uid, uid)
self.mail_invite = self.registry('mail.wizard.invite')
base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='')
portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'portal')
portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')
portal_id = portal_ref and portal_ref[1] or False
# 0 - Admin

View File

@ -23,33 +23,43 @@ import logging
import random
from osv import osv, fields
from tools.misc import email_re
from tools.translate import _
from tools.misc import email_re
from openerp import SUPERUSER_ID
from base.res.res_partner import _lang_get
_logger = logging.getLogger(__name__)
# welcome email sent to new portal users (note that calling tools.translate._
# has no effect except exporting those strings for translation)
# welcome/goodbye email sent to portal users
# (note that calling '_' has no effect except exporting those strings for translation)
WELCOME_EMAIL_SUBJECT = _("Your OpenERP account at %(company)s")
WELCOME_EMAIL_BODY = _("""Dear %(name)s,
You have been created an OpenERP account at %(url)s.
You have been given access to %(portal)s at %(url)s.
Your login account data is:
Database: %(db)s
User: %(login)s
Password: %(password)s
%(message)s
%(welcome_message)s
--
OpenERP - Open Source Business Applications
http://www.openerp.com
""")
ROOT_UID = 1
GOODBYE_EMAIL_SUBJECT = _("Your OpenERP account at %(company)s")
GOODBYE_EMAIL_BODY = _("""Dear %(name)s,
Your access to %(portal)s has been withdrawn.
%(goodbye_message)s
--
OpenERP - Open Source Business Applications
http://www.openerp.com
""")
# character sets for passwords, excluding 0, O, o, 1, I, l
_PASSU = 'ABCDEFGHIJKLMNPQRSTUVWXYZ'
@ -71,169 +81,173 @@ def extract_email(email):
class wizard(osv.osv_memory):
"""
A wizard to create portal users from instances of 'res.partner'. The purpose
is to provide an OpenERP database access to customers or suppliers.
A wizard to manage the creation/removal of portal users.
"""
_name = 'res.portal.wizard'
_description = 'Portal Wizard'
_name = 'portal.wizard'
_description = 'Portal Access Management'
_columns = {
'portal_id': fields.many2one('res.portal', required=True,
string='Portal',
help="The portal in which new users must be added"),
'user_ids': fields.one2many('res.portal.wizard.user', 'wizard_id',
string='Users'),
'message': fields.text(string='Invitation message',
help="This text is included in the welcome email sent to the users"),
'portal_id': fields.many2one('res.groups', domain=[('is_portal', '=', True)], required=True,
string='Portal', help="The portal that users can be added in or removed from."),
'user_ids': fields.one2many('portal.wizard.user', 'wizard_id', string='Users'),
'welcome_message': fields.text(string='Invitation Message',
help="This text is included in the email sent to new users of the portal."),
'goodbye_message': fields.text(string='Withdrawal Message',
help="This text is included in the email sent to users withdrawn from the portal."),
}
def _default_user_ids(self, cr, uid, context):
""" determine default user_ids from the active records """
def create_user_from_address(address):
if isinstance(address, int):
res_partner_obj = self.pool.get('res.partner')
address = res_partner_obj.browse(cr, uid, address, context=context)
lang = address.id and address.lang or 'en_US'
partner_id = address.id
else:
lang = address.parent_id and address.parent_id.lang or 'en_US'
partner_id = address.parent_id and address.parent_id.id
return{
'name': address.name,
'email': extract_email(address.email),
'lang': lang,
'partner_id': partner_id,
}
user_ids = []
if context.get('active_model') == 'res.partner':
partner_obj = self.pool.get('res.partner')
partner_ids = context.get('active_ids', [])
partners = partner_obj.browse(cr, uid, partner_ids, context)
for p in partners:
# add one user per contact, or one user if no contact
if p.child_ids:
user_ids.extend(map(create_user_from_address, p.child_ids))
elif p.is_company == False and p.customer == True:
user_ids.extend(map(create_user_from_address, [p.id]))
else:
user_ids.append({'lang': p.lang or 'en_US', 'parent_id': p.id})
return user_ids
def _default_portal(self, cr, uid, context):
portal_ids = self.pool.get('res.groups').search(cr, uid, [('is_portal', '=', True)])
return portal_ids and portal_ids[0] or False
_defaults = {
'user_ids': _default_user_ids
'portal_id': _default_portal,
}
def action_create(self, cr, uid, ids, context=None):
""" create new users in portal(s), and notify them by email """
# we copy the context to change the language for translating emails
context0 = context or {}
context0['noshortcut'] = True # prevent shortcut creation
context = context0.copy()
user_obj = self.pool.get('res.users')
user = user_obj.browse(cr, ROOT_UID, uid, context0)
if not user.email:
raise osv.except_osv(_('Email required'),
_('You must have an email address in your User Preferences'
' to send emails.'))
portal_obj = self.pool.get('res.portal')
for wiz in self.browse(cr, uid, ids, context):
# determine existing users
login_cond = [('login', 'in', [u.email for u in wiz.user_ids])]
existing_uids = user_obj.search(cr, ROOT_UID, login_cond)
existing_users = user_obj.browse(cr, ROOT_UID, existing_uids)
existing_logins = [u.login for u in existing_users]
# create new users in portal (skip existing logins)
new_users_data = [ {
'name': u.name,
'login': u.email,
'password': random_password(),
'email': u.email,
'lang': u.lang,
'share': True,
'action_id': wiz.portal_id.home_action_id and wiz.portal_id.home_action_id.id or False,
'partner_id': u.partner_id and u.partner_id.id,
'groups_id': [(6, 0, [])],
} for u in wiz.user_ids if u.email not in existing_logins ]
portal_obj.write(cr, ROOT_UID, [wiz.portal_id.id],
{'users': [(0, 0, data) for data in new_users_data]}, context0)
# send email to all users (translated in their language)
data = {
'company': user.company_id.name,
'message': wiz.message or "",
'url': wiz.portal_id.url or _("(missing url)"),
'db': cr.dbname,
}
mail_mail_obj = self.pool.get('mail.mail')
dest_uids = user_obj.search(cr, ROOT_UID, login_cond)
dest_users = user_obj.browse(cr, ROOT_UID, dest_uids)
for dest_user in dest_users:
context['lang'] = dest_user.lang
data['login'] = dest_user.login
data['password'] = dest_user.password
data['name'] = dest_user.name
email_from = user.email
email_to = dest_user.email
subject = _(WELCOME_EMAIL_SUBJECT) % data
body = _(WELCOME_EMAIL_BODY) % data
mail_id = mail_mail_obj.create(cr, uid, {
'email_from': email_from ,
'email_to': email_to,
'subject': subject,
'state': 'outgoing',
'body_html': '<pre>%s</pre>' % body}, context=context)
def onchange_portal_id(self, cr, uid, ids, portal_id, context=None):
# for each partner, determine corresponding portal.wizard.user records
res_partner = self.pool.get('res.partner')
partner_ids = context and context.get('active_ids') or []
contact_ids = set()
user_changes = []
for partner in res_partner.browse(cr, SUPERUSER_ID, partner_ids, context):
for contact in (partner.child_ids or [partner]):
# make sure that each contact appears at most once in the list
if contact.id not in contact_ids:
contact_ids.add(contact.id)
in_portal = False
if contact.user_ids:
in_portal = portal_id in [g.id for g in contact.user_ids[0].groups_id]
user_changes.append((0, 0, {
'partner_id': contact.id,
'email': contact.email,
'in_portal': in_portal,
}))
return {'value': {'user_ids': user_changes}}
def action_apply(self, cr, uid, ids, context=None):
wizard = self.browse(cr, uid, ids[0], context)
portal_user_ids = [user.id for user in wizard.user_ids]
self.pool.get('portal.wizard.user').action_apply(cr, uid, portal_user_ids, context)
return {'type': 'ir.actions.act_window_close'}
wizard()
class wizard_user(osv.osv_memory):
"""
A model to configure users in the portal wizard.
"""
_name = 'res.portal.wizard.user'
_name = 'portal.wizard.user'
_description = 'Portal User Config'
_columns = {
'wizard_id': fields.many2one('res.portal.wizard', required=True,
string='Wizard'),
'name': fields.char(size=64, required=True,
string='User Name',
help="The user's real name"),
'email': fields.char(size=64, required=True,
string='Email',
help="Will be used as user login. "
"Also necessary to send the account information to new users"),
'lang': fields.selection(_lang_get, required=True,
string='Language',
help="The language for the user's user interface"),
'partner_id': fields.many2one('res.partner',
string='Partner'),
'wizard_id': fields.many2one('portal.wizard', string='Wizard', required=True),
'partner_id': fields.many2one('res.partner', string='Contact', required=True, readonly=True),
'email': fields.char(size=240, string='Email'),
'in_portal': fields.boolean('In Portal'),
}
def _check_email(self, cr, uid, ids):
""" check syntax of email address """
for wuser in self.browse(cr, uid, ids):
if not email_re.match(wuser.email): return False
return True
def create(self, cr, uid, values, context=None):
""" overridden to update the partner's email (if necessary) """
id = super(wizard_user, self).create(cr, uid, values, context)
wuser = self.browse(cr, uid, id, context)
if wuser.partner_id.email != wuser.email:
wuser.partner_id.write({'email': wuser.email})
return id
_constraints = [
(_check_email, 'Invalid email address', ['email']),
]
def action_apply(self, cr, uid, ids, context=None):
res_users = self.pool.get('res.users')
for wizard_user in self.browse(cr, SUPERUSER_ID, ids, context):
portal = wizard_user.wizard_id.portal_id
user = self._retrieve_user(cr, SUPERUSER_ID, wizard_user, context)
if wizard_user.in_portal:
# create a user if necessary, and make sure it is in the portal group
if not user:
user = self._create_user(cr, SUPERUSER_ID, wizard_user, context)
if (not user.active) or (portal not in user.groups_id):
user.write({'active': True, 'groups_id': [(4, portal.id)]})
wizard_user = self.browse(cr, SUPERUSER_ID, wizard_user.id, context)
self._send_email(cr, uid, wizard_user, context)
else:
# remove the user (if it exists) from the portal group
if user and (portal in user.groups_id):
# if user belongs to portal only, deactivate it
if len(user.groups_id) <= 1:
user.write({'groups_id': [(3, portal.id)], 'active': False})
else:
user.write({'groups_id': [(3, portal.id)]})
wizard_user = self.browse(cr, SUPERUSER_ID, wizard_user.id, context)
self._send_email(cr, uid, wizard_user, context)
wizard_user()
def _retrieve_user(self, cr, uid, wizard_user, context=None):
""" retrieve the (possibly inactive) user corresponding to wizard_user.partner_id
@param wizard_user: browse record of model portal.wizard.user
@return: browse record of model res.users
"""
if wizard_user.partner_id.user_ids:
return wizard_user.partner_id.user_ids[0]
# the user may be inactive, search for it
res_users = self.pool.get('res.users')
domain = [('partner_id', '=', wizard_user.partner_id.id), ('active', '=', False)]
user_ids = res_users.search(cr, uid, domain)
return user_ids and res_users.browse(cr, uid, user_ids[0], context) or False
def _create_user(self, cr, uid, wizard_user, context=None):
""" create a new user for wizard_user.partner_id
@param wizard_user: browse record of model portal.wizard.user
@return: browse record of model res.users
"""
res_users = self.pool.get('res.users')
create_context = dict(context or {}, noshortcut=True) # to prevent shortcut creation
values = {
'login': extract_email(wizard_user.email),
'password': random_password(),
'partner_id': wizard_user.partner_id.id,
'groups_id': [(6, 0, [])],
'share': True,
}
user_id = res_users.create(cr, uid, values, context=create_context)
return res_users.browse(cr, uid, user_id, context)
def _send_email(self, cr, uid, wizard_user, context=None):
""" send notification email to a new/former portal user
@param wizard_user: browse record of model portal.wizard.user
@return: the id of the created mail.mail record
"""
this_context = context
this_user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context)
if not this_user.email:
raise osv.except_osv(_('Email required'),
_('You must have an email address in your User Preferences to send emails.'))
# determine subject and body in the portal user's language
url = self.pool.get('ir.config_parameter').get_param(cr, SUPERUSER_ID, 'web.base.url', context=this_context)
user = self._retrieve_user(cr, SUPERUSER_ID, wizard_user, context)
context = dict(this_context or {}, lang=user.lang)
data = {
'company': this_user.company_id.name,
'portal': wizard_user.wizard_id.portal_id.name,
'welcome_message': wizard_user.wizard_id.welcome_message or "",
'goodbye_message': wizard_user.wizard_id.goodbye_message or "",
'url': url or _("(missing url)"),
'db': cr.dbname,
'login': user.login,
'password': user.password,
'name': user.name
}
if wizard_user.in_portal:
subject = _(WELCOME_EMAIL_SUBJECT) % data
body = _(WELCOME_EMAIL_BODY) % data
else:
subject = _(GOODBYE_EMAIL_SUBJECT) % data
body = _(GOODBYE_EMAIL_BODY) % data
mail_mail = self.pool.get('mail.mail')
mail_values = {
'email_from': this_user.email,
'email_to': user.email,
'subject': subject,
'body_html': '<pre>%s</pre>' % body,
'state': 'outgoing',
}
return mail_mail.create(cr, uid, mail_values, context=this_context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -3,28 +3,34 @@
<data>
<!-- wizard action on res.partner -->
<act_window id="partner_wizard_action"
name="Add Portal Access"
name="Portal Access Management"
src_model="res.partner"
res_model="res.portal.wizard"
res_model="portal.wizard"
view_type="form" view_mode="form"
key2="client_action_multi" target="new"
groups="group_portal_officer"/>
groups="base.group_partner_manager"/>
<!-- wizard view -->
<record id="wizard_view" model="ir.ui.view">
<field name="name">Add Portal Access</field>
<field name="model">res.portal.wizard</field>
<field name="name">Portal Access Management</field>
<field name="model">portal.wizard</field>
<field name="arch" type="xml">
<form string="Add Portal Access" version="7.0">
<group col="4">
<field name="portal_id" widget="selection"/>
<form string="Portal Access Management" version="7.0">
<group>
<field name="portal_id" widget="selection" on_change="onchange_portal_id(portal_id, context)"/>
</group>
<div>
Select which contacts should belong to the portal in the list below.
The email address of each selected contact must be valid and unique.
If necessary, you can fix any contact's email address directly in the list.
</div>
<field name="user_ids"/>
<label string="The following text will be included in the welcome email sent to users."/>
<field name="message"/>
<field name="welcome_message"
placeholder="This text is included in the email sent to new portal users."/>
<field name="goodbye_message"
placeholder="This text is included in the email sent to users withdrawn from the portal."/>
<footer>
<button string="Send Invitations"
name="action_create" type="object" class="oe_highlight" />
<button string="Apply" name="action_apply" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
@ -35,32 +41,15 @@
<!-- wizard user list view -->
<record id="wizard_user_tree_view" model="ir.ui.view">
<field name="name">Portal Users</field>
<field name="model">res.portal.wizard.user</field>
<field name="model">portal.wizard.user</field>
<field name="arch" type="xml">
<!-- the attribute 'editable' is set below to make the elements
editable in the web client 6.0 -->
<tree string="Portal Users" editable="bottom">
<field name="name"/>
<field name="email"/>
<!-- the contact list is editable, but one cannot add or delete rows -->
<tree string="Contacts" editable="bottom" create="false" delete="false">
<field name="partner_id"/>
<field name="email"/>
<field name="in_portal"/>
</tree>
</field>
</record>
<!-- wizard user form view -->
<record id="wizard_user_form_view" model="ir.ui.view">
<field name="name">Portal User</field>
<field name="model">res.portal.wizard.user</field>
<field name="arch" type="xml">
<form string="Portal User" version="7.0">
<group colspan="2" col="2">
<field name="name"/>
<field name="email"/>
<field name="lang"/>
<field name="partner_id"/>
</group>
</form>
</field>
</record>
</data>
</openerp>

View File

@ -44,9 +44,6 @@ class share_wizard_portal(osv.TransientModel):
'group_ids': fields.many2many('res.groups', 'share_wizard_res_group_rel', 'share_id', 'group_id', 'Existing groups', domain=[('share', '=', False)]),
}
def is_portal_manager(self, cr, uid, context=None):
return self.has_group(cr, uid, module='portal', group_xml_id='group_portal_manager', context=context)
def _check_preconditions(self, cr, uid, wizard_data, context=None):
if wizard_data.user_type == 'existing':
self._assert(wizard_data.user_ids,
@ -122,16 +119,14 @@ class share_wizard_portal(osv.TransientModel):
# alter the rules of the groups so they can see the shared data
if wizard_data.group_ids:
# get the list of portals and the related groups to install their menus.
Portals = self.pool.get('res.portal')
all_portals = Portals.browse(cr, UID_ROOT, Portals.search(cr, UID_ROOT, [])) #no context!
all_portal_group_ids = [p.group_id.id for p in all_portals]
res_groups = self.pool.get('res.groups')
all_portal_group_ids = res_groups.search(cr, UID_ROOT, [('is_portal', '=', True)])
# populate result lines with the users of each group and
# setup the menu for portal groups
for group in wizard_data.group_ids:
if group.id in all_portal_group_ids:
portal = all_portals[all_portal_group_ids.index(group.id)]
self._create_shared_data_menu(cr, uid, wizard_data, portal, context=context)
self._create_shared_data_menu(cr, uid, wizard_data, group.id, context=context)
for user in group.users:
new_line = {'user_id': user.id,

View File

@ -36,12 +36,12 @@
<field name="inherit_id" ref="share.share_step2_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='result_line_ids']//field[@name='login']" position="after">
<field name="share_url" groups="portal.group_portal_manager"/>
<field name="share_url" groups="base.group_no_one"/>
</xpath>
<xpath expr="//field[@name='result_line_ids']" position="after">
<newline/>
<group string="Details">
<field name="share_root_url" groups="portal.group_portal_manager"/>
<group string="Details" groups="base.group_no_one">
<field name="share_root_url"/>
</group>
</xpath>
</field>

View File

@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_crm_claim,crm.claim,crm_claim.model_crm_claim,portal.group_portal_member,1,0,0,0
access_crm_claim_stage,crm.claim.stage,crm_claim.model_crm_claim_stage,portal.group_portal_member,1,0,0,0
access_crm_claim,crm.claim,crm_claim.model_crm_claim,portal.group_portal,1,0,0,0
access_crm_claim_stage,crm.claim.stage,crm_claim.model_crm_claim_stage,portal.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_crm_claim crm.claim crm_claim.model_crm_claim portal.group_portal_member portal.group_portal 1 0 0 0
3 access_crm_claim_stage crm.claim.stage crm_claim.model_crm_claim_stage portal.group_portal_member portal.group_portal 1 0 0 0

View File

@ -6,7 +6,7 @@
<field name="name">Portal Personal Claims</field>
<field ref="crm_claim.model_crm_claim" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
</data>

View File

@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event,event,event.model_event_event,portal.group_portal_member,1,0,0,0
access_registration,registration,event.model_event_registration,portal.group_portal_member,1,0,0,0
access_event,event,event.model_event_event,portal.group_portal,1,0,0,0
access_registration,registration,event.model_event_registration,portal.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_event event event.model_event_event portal.group_portal_member portal.group_portal 1 0 0 0
3 access_registration registration event.model_event_registration portal.group_portal_member portal.group_portal 1 0 0 0

View File

@ -6,14 +6,14 @@
<field name="name">Portal Visible Events</field>
<field ref="event.model_event_event" name="model_id"/>
<field name="domain_force">[('visibility', '=', 'public')]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
<record id="portal_registration_rule" model="ir.rule">
<field name="name">Portal Personal Registrations</field>
<field ref="event.model_event_registration" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
</data>

View File

@ -1,6 +1,6 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_hr_employee_user,hr.employee user,hr.model_hr_employee,portal.group_portal_member,1,0,0,0
access_res_partner,res.partner,base.model_res_partner,portal.group_portal_member,1,0,0,0
access_res_partner_address,res.partner_address,base.model_res_partner_address,portal.group_portal_member,1,0,0,0
access_res_partner_category,res.partner_category,base.model_res_partner_category,portal.group_portal_member,1,0,0,0
access_res_partner_title,res.partner_title,base.model_res_partner_title,portal.group_portal_member,1,0,0,0
access_hr_employee_user,hr.employee user,hr.model_hr_employee,portal.group_portal,1,0,0,0
access_res_partner,res.partner,base.model_res_partner,portal.group_portal,1,0,0,0
access_res_partner_address,res.partner_address,base.model_res_partner_address,portal.group_portal,1,0,0,0
access_res_partner_category,res.partner_category,base.model_res_partner_category,portal.group_portal,1,0,0,0
access_res_partner_title,res.partner_title,base.model_res_partner_title,portal.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_hr_employee_user hr.employee user hr.model_hr_employee portal.group_portal_member portal.group_portal 1 0 0 0
3 access_res_partner res.partner base.model_res_partner portal.group_portal_member portal.group_portal 1 0 0 0
4 access_res_partner_address res.partner_address base.model_res_partner_address portal.group_portal_member portal.group_portal 1 0 0 0
5 access_res_partner_category res.partner_category base.model_res_partner_category portal.group_portal_member portal.group_portal 1 0 0 0
6 access_res_partner_title res.partner_title base.model_res_partner_title portal.group_portal_member portal.group_portal 1 0 0 0

View File

@ -1,5 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_task,tasks,project.model_project_task,portal.group_portal_member,1,0,0,0
access_task_type,task_type,project.model_project_task_type,portal.group_portal_member,1,0,0,0
access_task_work,task_work,project.model_project_task_work,portal.group_portal_member,1,0,0,0
access_project_category,project_category,project.model_project_category,portal.group_portal_member,1,0,0,0
access_task,tasks,project.model_project_task,portal.group_portal,1,0,0,0
access_task_type,task_type,project.model_project_task_type,portal.group_portal,1,0,0,0
access_task_work,task_work,project.model_project_task_work,portal.group_portal,1,0,0,0
access_project_category,project_category,project.model_project_category,portal.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_task tasks project.model_project_task portal.group_portal_member portal.group_portal 1 0 0 0
3 access_task_type task_type project.model_project_task_type portal.group_portal_member portal.group_portal 1 0 0 0
4 access_task_work task_work project.model_project_task_work portal.group_portal_member portal.group_portal 1 0 0 0
5 access_project_category project_category project.model_project_category portal.group_portal_member portal.group_portal 1 0 0 0

View File

@ -6,7 +6,7 @@
<field name="name">Portal Personal Task</field>
<field ref="project.model_project_task" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
</data>

View File

@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_issues,project_issue,project_issue.model_project_issue,portal.group_portal_member,1,0,0,0
access_case_section,crm_case_section,crm.model_crm_case_section,portal.group_portal_member,1,0,0,0
access_issues,project_issue,project_issue.model_project_issue,portal.group_portal,1,0,0,0
access_case_section,crm_case_section,crm.model_crm_case_section,portal.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_issues project_issue project_issue.model_project_issue portal.group_portal_member portal.group_portal 1 0 0 0
3 access_case_section crm_case_section crm.model_crm_case_section portal.group_portal_member portal.group_portal 1 0 0 0

View File

@ -6,7 +6,7 @@
<field name="name">Portal Personal Issues</field>
<field ref="project_issue.model_project_issue" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
</data>

View File

@ -1,33 +1,33 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_order,sale.order,sale.model_sale_order,portal.group_portal_member,1,0,0,0
access_sale_order_line,sale.order.line,sale.model_sale_order_line,portal.group_portal_member,1,0,0,0
access_stock_picking,stock.picking,stock.model_stock_picking,portal.group_portal_member,1,0,0,0
access_stock_picking.out,stock.picking.out,stock.model_stock_picking_out,portal.group_portal_member,1,0,0,0
access_stock_move,stock.move,stock.model_stock_move,portal.group_portal_member,1,0,0,0
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,procurement.model_stock_warehouse_orderpoint,portal.group_portal_member,1,0,0,0
access_account_invoice,account.invoice,account.model_account_invoice,portal.group_portal_member,1,0,0,0
access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,portal.group_portal_member,1,0,0,0
access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,portal.group_portal_member,1,0,0,0
access_account_journal,account.journal,account.model_account_journal,portal.group_portal_member,1,0,0,0
access_account_voucher,account.voucher,account_voucher.model_account_voucher,portal.group_portal_member,1,0,0,0
access_account_voucher_line,account.voucher.line,account_voucher.model_account_voucher_line,portal.group_portal_member,1,0,0,0
access_account_move,account.move,account.model_account_move,portal.group_portal_member,1,0,0,0
access_account_move_line,account.move.line,account.model_account_move_line,portal.group_portal_member,1,0,0,0
access_account_move_reconcile,account.move.reconcile,account.model_account_move_reconcile,portal.group_portal_member,1,0,0,0
access_account_fiscalyear,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,portal.group_portal_member,1,0,0,0
access_sale_shop,sale.shop,sale.model_sale_shop,portal.group_portal_member,1,0,0,0
access_product_list,product.pricelist,product.model_product_pricelist,portal.group_portal_member,1,0,0,0
access_product,product.product,product.model_product_product,portal.group_portal_member,1,0,0,0
access_res_partner,res.partner,base.model_res_partner,portal.group_portal_member,1,0,0,0
access_product_uom,product.uom,product.model_product_uom,portal.group_portal_member,1,0,0,0
access_account_tax,account.tax,account.model_account_tax,portal.group_portal_member,1,0,0,0
access_mrp_property,mrp.property,procurement.model_mrp_property,portal.group_portal_member,1,0,0,0
access_product_template,product.template,product.model_product_template,portal.group_portal_member,1,0,0,0
access_stock_warehouse,stock.warehouse,stock.model_stock_warehouse,portal.group_portal_member,1,0,0,0
access_stock_location,stock.location,stock.model_stock_location,portal.group_portal_member,1,0,0,0
access_account_fiscalyear,account.fiscalyear,account.model_account_fiscalyear,portal.group_portal_member,1,0,0,0
access_res_partner_category,res.partner.category,base.model_res_partner_category,portal.group_portal_member,1,0,0,0
access_product_supplierinfo,product.supplierinfo,product.model_product_supplierinfo,portal.group_portal_member,1,0,0,0
access_product_packaging,product.packaging,product.model_product_packaging,portal.group_portal_member,1,0,0,0
access_account_period,account.period,account.model_account_period,portal.group_portal_member,1,0,0,0
access_account_account,account.account,account.model_account_account,portal.group_portal_member,1,0,0,0
access_sale_order,sale.order,sale.model_sale_order,portal.group_portal,1,0,0,0
access_sale_order_line,sale.order.line,sale.model_sale_order_line,portal.group_portal,1,0,0,0
access_stock_picking,stock.picking,stock.model_stock_picking,portal.group_portal,1,0,0,0
access_stock_picking.out,stock.picking.out,stock.model_stock_picking_out,portal.group_portal,1,0,0,0
access_stock_move,stock.move,stock.model_stock_move,portal.group_portal,1,0,0,0
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,procurement.model_stock_warehouse_orderpoint,portal.group_portal,1,0,0,0
access_account_invoice,account.invoice,account.model_account_invoice,portal.group_portal,1,0,0,0
access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,portal.group_portal,1,0,0,0
access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,portal.group_portal,1,0,0,0
access_account_journal,account.journal,account.model_account_journal,portal.group_portal,1,0,0,0
access_account_voucher,account.voucher,account_voucher.model_account_voucher,portal.group_portal,1,0,0,0
access_account_voucher_line,account.voucher.line,account_voucher.model_account_voucher_line,portal.group_portal,1,0,0,0
access_account_move,account.move,account.model_account_move,portal.group_portal,1,0,0,0
access_account_move_line,account.move.line,account.model_account_move_line,portal.group_portal,1,0,0,0
access_account_move_reconcile,account.move.reconcile,account.model_account_move_reconcile,portal.group_portal,1,0,0,0
access_account_fiscalyear,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,portal.group_portal,1,0,0,0
access_sale_shop,sale.shop,sale.model_sale_shop,portal.group_portal,1,0,0,0
access_product_list,product.pricelist,product.model_product_pricelist,portal.group_portal,1,0,0,0
access_product,product.product,product.model_product_product,portal.group_portal,1,0,0,0
access_res_partner,res.partner,base.model_res_partner,portal.group_portal,1,0,0,0
access_product_uom,product.uom,product.model_product_uom,portal.group_portal,1,0,0,0
access_account_tax,account.tax,account.model_account_tax,portal.group_portal,1,0,0,0
access_mrp_property,mrp.property,procurement.model_mrp_property,portal.group_portal,1,0,0,0
access_product_template,product.template,product.model_product_template,portal.group_portal,1,0,0,0
access_stock_warehouse,stock.warehouse,stock.model_stock_warehouse,portal.group_portal,1,0,0,0
access_stock_location,stock.location,stock.model_stock_location,portal.group_portal,1,0,0,0
access_account_fiscalyear,account.fiscalyear,account.model_account_fiscalyear,portal.group_portal,1,0,0,0
access_res_partner_category,res.partner.category,base.model_res_partner_category,portal.group_portal,1,0,0,0
access_product_supplierinfo,product.supplierinfo,product.model_product_supplierinfo,portal.group_portal,1,0,0,0
access_product_packaging,product.packaging,product.model_product_packaging,portal.group_portal,1,0,0,0
access_account_period,account.period,account.model_account_period,portal.group_portal,1,0,0,0
access_account_account,account.account,account.model_account_account,portal.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_order sale.order sale.model_sale_order portal.group_portal_member portal.group_portal 1 0 0 0
3 access_sale_order_line sale.order.line sale.model_sale_order_line portal.group_portal_member portal.group_portal 1 0 0 0
4 access_stock_picking stock.picking stock.model_stock_picking portal.group_portal_member portal.group_portal 1 0 0 0
5 access_stock_picking.out stock.picking.out stock.model_stock_picking_out portal.group_portal_member portal.group_portal 1 0 0 0
6 access_stock_move stock.move stock.model_stock_move portal.group_portal_member portal.group_portal 1 0 0 0
7 access_stock_warehouse_orderpoint stock.warehouse.orderpoint procurement.model_stock_warehouse_orderpoint portal.group_portal_member portal.group_portal 1 0 0 0
8 access_account_invoice account.invoice account.model_account_invoice portal.group_portal_member portal.group_portal 1 0 0 0
9 access_account_invoice_tax account.invoice.tax account.model_account_invoice_tax portal.group_portal_member portal.group_portal 1 0 0 0
10 access_account_invoice_line account.invoice.line account.model_account_invoice_line portal.group_portal_member portal.group_portal 1 0 0 0
11 access_account_journal account.journal account.model_account_journal portal.group_portal_member portal.group_portal 1 0 0 0
12 access_account_voucher account.voucher account_voucher.model_account_voucher portal.group_portal_member portal.group_portal 1 0 0 0
13 access_account_voucher_line account.voucher.line account_voucher.model_account_voucher_line portal.group_portal_member portal.group_portal 1 0 0 0
14 access_account_move account.move account.model_account_move portal.group_portal_member portal.group_portal 1 0 0 0
15 access_account_move_line account.move.line account.model_account_move_line portal.group_portal_member portal.group_portal 1 0 0 0
16 access_account_move_reconcile account.move.reconcile account.model_account_move_reconcile portal.group_portal_member portal.group_portal 1 0 0 0
17 access_account_fiscalyear account.sequence.fiscalyear account.model_account_sequence_fiscalyear portal.group_portal_member portal.group_portal 1 0 0 0
18 access_sale_shop sale.shop sale.model_sale_shop portal.group_portal_member portal.group_portal 1 0 0 0
19 access_product_list product.pricelist product.model_product_pricelist portal.group_portal_member portal.group_portal 1 0 0 0
20 access_product product.product product.model_product_product portal.group_portal_member portal.group_portal 1 0 0 0
21 access_res_partner res.partner base.model_res_partner portal.group_portal_member portal.group_portal 1 0 0 0
22 access_product_uom product.uom product.model_product_uom portal.group_portal_member portal.group_portal 1 0 0 0
23 access_account_tax account.tax account.model_account_tax portal.group_portal_member portal.group_portal 1 0 0 0
24 access_mrp_property mrp.property procurement.model_mrp_property portal.group_portal_member portal.group_portal 1 0 0 0
25 access_product_template product.template product.model_product_template portal.group_portal_member portal.group_portal 1 0 0 0
26 access_stock_warehouse stock.warehouse stock.model_stock_warehouse portal.group_portal_member portal.group_portal 1 0 0 0
27 access_stock_location stock.location stock.model_stock_location portal.group_portal_member portal.group_portal 1 0 0 0
28 access_account_fiscalyear account.fiscalyear account.model_account_fiscalyear portal.group_portal_member portal.group_portal 1 0 0 0
29 access_res_partner_category res.partner.category base.model_res_partner_category portal.group_portal_member portal.group_portal 1 0 0 0
30 access_product_supplierinfo product.supplierinfo product.model_product_supplierinfo portal.group_portal_member portal.group_portal 1 0 0 0
31 access_product_packaging product.packaging product.model_product_packaging portal.group_portal_member portal.group_portal 1 0 0 0
32 access_account_period account.period account.model_account_period portal.group_portal_member portal.group_portal 1 0 0 0
33 access_account_account account.account account.model_account_account portal.group_portal_member portal.group_portal 1 0 0 0

View File

@ -7,42 +7,42 @@
<field name="name">Portal Personal Quotations/Sales Orders</field>
<field ref="sale.model_sale_order" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
<record id="portal_stock_picking_user_rule" model="ir.rule">
<field name="name">Portal Personal Delivery Orders</field>
<field ref="stock.model_stock_picking" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
<record id="portal_stock_picking_user_rule" model="ir.rule">
<field name="name">Portal Personal Delivery Orders Out</field>
<field ref="stock.model_stock_picking_out" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
<record id="portal_account_invoice_user_rule" model="ir.rule">
<field name="name">Portal Personal Account Invoices</field>
<field ref="account.model_account_invoice" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
<record id="portal_personal_payment" model="ir.rule">
<field name="name">Portal Personal Payments</field>
<field ref="account_voucher.model_account_voucher" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
<record id="portal_personal_contact" model="ir.rule">
<field name="name">Portal Personal Contacts</field>
<field ref="base.model_res_partner" name="model_id"/>
<field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('portal.group_portal_member'))]"/>
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
</record>
</data>

View File

@ -25,13 +25,13 @@
<record model="ir.ui.view" id="res_groups_search_sharing">
<field name="name">res.groups.search.share</field>
<field name="model">res.groups</field>
<field name="priority" eval="8"/>
<field name="inherit_id" ref="base.view_groups_search"/>
<field name="arch" type="xml">
<search string="Groups">
<field name="name" string="Group"/>
<field name="share"/>
<filter name="no_share" string="Regular groups only (no share groups)" icon="terp-partner" domain="[('share','=',False)]"/>
</search>
<field name="name" position="after">
<filter name="share" string="Share Groups" domain="[('share','=',True)]"/>
<filter name="no_share" string="Non-Share Groups" domain="[('share','=',False)]"/>
<separator orientation="vertical"/>
</field>
</field>
</record>

View File

@ -38,7 +38,6 @@ class stock_partial_picking_line(osv.TransientModel):
res[tracklot.id] = tracking
return res
_name = "stock.partial.picking.line"
_rec_name = 'product_id'
_columns = {
@ -56,6 +55,14 @@ class stock_partial_picking_line(osv.TransientModel):
'tracking': fields.function(_tracking, string='Tracking', type='boolean'),
}
def onchange_product_id(self, cr, uid, ids, product_id, context=None):
uom_id = False
if product_id:
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
uom_id = product.uom_id.id
return {'value': {'product_uom': uom_id}}
class stock_partial_picking(osv.osv_memory):
_name = "stock.partial.picking"
_description = "Partial Picking Processing Wizard"

View File

@ -19,7 +19,7 @@
<separator string="Transfer Products" name="product_separator"/>
<field name="move_ids" context="{'hide_tracking': hide_tracking}">
<tree editable="bottom" string="Product Moves">
<field name="product_id" />
<field name="product_id" on_change="onchange_product_id(product_id)"/>
<field name="quantity" />
<field name="product_uom" groups="product.group_uom"/>
<field name="tracking" invisible="1"/>