Browse Source

Merge pull request #118 from hbrunn/6.1-travis

[FIX] coding style
pull/266/head
Pedro M. Baeza 10 years ago
parent
commit
78c07176dc
  1. 3
      .travis.yml
  2. 10
      dbfilter_from_header/__init__.py
  3. 2
      email_template_template/__init__.py
  4. 25
      email_template_template/__openerp__.py
  5. 2
      email_template_template/model/__init__.py
  6. 3
      email_template_template/model/email_template.py
  7. 7
      fetchmail_attach_from_folder/__init__.py
  8. 5
      fetchmail_attach_from_folder/__openerp__.py
  9. 9
      fetchmail_attach_from_folder/match_algorithm/__init__.py
  10. 12
      fetchmail_attach_from_folder/match_algorithm/base.py
  11. 2
      fetchmail_attach_from_folder/match_algorithm/email_domain.py
  12. 3
      fetchmail_attach_from_folder/match_algorithm/email_exact.py
  13. 8
      fetchmail_attach_from_folder/match_algorithm/openerp_standard.py
  14. 5
      fetchmail_attach_from_folder/model/__init__.py
  15. 19
      fetchmail_attach_from_folder/model/fetchmail_server.py
  16. 3
      fetchmail_attach_from_folder/model/fetchmail_server_folder.py
  17. 3
      fetchmail_attach_from_folder/wizard/__init__.py
  18. 58
      fetchmail_attach_from_folder/wizard/attach_mail_manually.py
  19. 2
      mail_client_view/__init__.py
  20. 2
      mail_client_view/model/__init__.py
  21. 5
      mail_client_view/model/mail_message.py
  22. 11
      mail_environment/__openerp__.py
  23. 54
      mail_environment/env_mail.py
  24. 8
      mass_editing/__init__.py
  25. 11
      mass_editing/__openerp__.py
  26. 57
      mass_editing/mass_editing.py
  27. 5
      mass_editing/wizard/__init__.py
  28. 266
      mass_editing/wizard/mass_editing_wizard.py
  29. 6
      security_protector/__openerp__.py
  30. 23
      security_protector/security_protector.py
  31. 3
      server_env_base_external_referentials/__init__.py
  32. 11
      server_env_base_external_referentials/__openerp__.py
  33. 20
      server_env_base_external_referentials/base_external_referentials.py
  34. 10
      server_environment/serv_config.py
  35. 2
      super_calendar/__init__.py
  36. 31
      super_calendar/__openerp__.py
  37. 107
      super_calendar/super_calendar.py
  38. 2
      unserialize_field/__init__.py
  39. 9
      unserialize_field/ir_model_fields.py
  40. 2
      view_groups_id/__init__.py
  41. 5
      view_groups_id/__openerp__.py
  42. 2
      view_groups_id/model/__init__.py
  43. 14
      view_groups_id/model/ir_ui_view.py

3
.travis.yml

@ -4,8 +4,7 @@ python:
- "2.7"
env:
- VERSION="6.1" ODOO_REPO="odoo/odoo"
- VERSION="6.1" UNIT_TEST="1"
- VERSION="6.1" ODOO_REPO="odoo/odoo" EXCLUDE="server_environment"
virtualenv:
system_site_packages: true

10
dbfilter_from_header/__init__.py

@ -24,12 +24,16 @@ from openerp.addons.web.common.http import jsonrequest
get_list_org = Database.get_list.__closure__[0].cell_contents
@jsonrequest
def get_list(self, req):
db_filter = req.httprequest.environ.get('HTTP_X_OPENERP_DBFILTER', '.*')
dbs = get_list_org(self, req)
return {'db_list': [db for db in
dbs.get('db_list', [])
if re.match(db_filter, db)]}
return {
'db_list': [
db for db in dbs.get('db_list', [])
if re.match(db_filter, db)
]
}
Database.get_list = get_list

2
email_template_template/__init__.py

@ -1 +1 @@
import model
from . import model

25
email_template_template/__openerp__.py

@ -26,11 +26,11 @@
'complexity': "expert",
"description": """If an organisation's email layout is a bit more
complicated, changes can be tedious when having to do that across several email
templates. So this addon allows to define templates for mails that is referenced
by other mail templates.
This way we can put the layout parts into the template template and only content
in the other templates. Changing the layout is then only a matter of changing
the template template.
templates. So this addon allows to define templates for mails that is
referenced by other mail templates.
This way we can put the layout parts into the template template and only
content in the other templates. Changing the layout is then only a matter of
changing the template template.
Usage:
@ -46,7 +46,8 @@ For example, create a template template
-----
Example Corp logo
Example Corp header
${object.body_text} <- this gets evaluated to the body_text of a template using this template template
${object.body_text} <- this gets evaluated to the body_text of a template using
this template template
Example Corp
Example street 42
Example city
@ -58,7 +59,8 @@ Then in your template you write
-----
Dear ${object.partner_id.name},
Your order has been booked on date ${object.date} for a total amount of ${object.sum}.
Your order has been booked on date ${object.date} for a total amount of
${object.sum}.
-----
And it will be evaluated to
@ -75,12 +77,17 @@ Example city
Example Corp footer
-----
Given the way evaluation works internally (body_text of the template template is evaluated two times, first with the instance of email.template of your own template, then with the object your template refers to), you can do some trickery if you know that a template template is always used with the same kind of model (that is, models that have the same field name):
Given the way evaluation works internally (body_text of the template template
is evaluated two times, first with the instance of email.template of your own
template, then with the object your template refers to), you can do some
trickery if you know that a template template is always used with the same kind
of model (that is, models that have the same field name):
In your template template:
------
Dear ${'${object.name}'}, <-- gets evaluated to "${object.name}" in the first step, then to the content of object.name
Dear ${'${object.name}'}, <-- gets evaluated to "${object.name}" in the first
step, then to the content of object.name
${object.body_html}
Best,
Example Corp

2
email_template_template/model/__init__.py

@ -18,4 +18,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import email_template
from . import email_template

3
email_template_template/model/email_template.py

@ -43,7 +43,8 @@ class email_template(Model):
def get_email_template(self, cr, uid, template_id=False, record_id=None,
context=None):
this = super(email_template, self).get_email_template(
this = super(
email_template, self).get_email_template(
cr, uid, template_id, record_id, context)
if this.email_template_id and not this.is_template_template:

7
fetchmail_attach_from_folder/__init__.py

@ -19,7 +19,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import match_algorithm
import model
import wizard
from . import match_algorithm
from . import model
from . import wizard

5
fetchmail_attach_from_folder/__openerp__.py

@ -24,8 +24,9 @@
'name': 'Attach mails in an IMAP folder to existing objects',
'version': '1.0.1',
'description': """
Adds the possibility to attach emails from a certain IMAP folder to objects,
ie partners. Matching is done via several algorithms, ie email address.
Adds the possibility to attach emails from a certain IMAP folder to
objects, ie partners. Matching is done via several algorithms, ie email
address.
This gives a simple possibility to archive emails in OpenERP without a mail
client integration.

9
fetchmail_attach_from_folder/match_algorithm/__init__.py

@ -19,8 +19,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base
import email_exact
import email_domain
import openerp_standard
from . import base
from . import email_exact
from . import email_domain
from . import openerp_standard

12
fetchmail_attach_from_folder/match_algorithm/base.py

@ -20,16 +20,16 @@
#
##############################################################################
class base(object):
name = None
'''Name shown to the user'''
'Name shown to the user'
required_fields = []
'''Fields on fetchmail_server folder that are required for this algorithm'''
'Fields on fetchmail_server folder that are required for this algorithm'
readonly_fields = []
'''Fields on fetchmail_server folder that are readonly for this algorithm'''
'Fields on fetchmail_server folder that are readonly for this algorithm'
def search_matches(self, cr, uid, conf, mail_message, mail_message_org):
'''Returns ids found for model with mail_message'''
@ -39,5 +39,5 @@ class base(object):
self, cr, uid, connection, object_id, folder,
mail_message, mail_message_org, msgid, context=None):
'''Do whatever it takes to handle a match'''
return folder.server_id.attach_mail(connection, object_id, folder,
mail_message, msgid)
return folder.server_id.attach_mail(
connection, object_id, folder, mail_message, msgid)

2
fetchmail_attach_from_folder/match_algorithm/email_domain.py

@ -19,8 +19,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from .email_exact import email_exact
from email_exact import email_exact
class email_domain(email_exact):
'''Search objects by domain name of email address.

3
fetchmail_attach_from_folder/match_algorithm/email_exact.py

@ -20,10 +20,11 @@
#
##############################################################################
from base import base
from .base import base
from openerp.tools.safe_eval import safe_eval
from openerp.addons.mail.mail_message import to_email
class email_exact(base):
'''Search for exactly the mailadress as noted in the email'''

8
fetchmail_attach_from_folder/match_algorithm/openerp_standard.py

@ -19,17 +19,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from .base import base
from base import base
from openerp.tools.safe_eval import safe_eval
class openerp_standard(base):
'''No search at all. Use OpenERP's standard mechanism to attach mails to
mail.thread objects. Note that this algorithm always matches.'''
name = 'OpenERP standard'
readonly_fields = ['model_field', 'mail_field', 'match_first', 'domain',
'model_order', 'flag_nonmatching']
readonly_fields = [
'model_field', 'mail_field', 'match_first', 'domain', 'model_order',
'flag_nonmatching']
def search_matches(self, cr, uid, conf, mail_message, mail_message_org):
'''Always match. Duplicates will be fished out by message_id'''

5
fetchmail_attach_from_folder/model/__init__.py

@ -19,6 +19,5 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import fetchmail_server
import fetchmail_server_folder
from . import fetchmail_server
from . import fetchmail_server_folder

19
fetchmail_attach_from_folder/model/fetchmail_server.py

@ -23,12 +23,11 @@
import base64
import simplejson
from lxml import etree
from openerp.osv.orm import Model, except_orm, browse_null
from openerp.osv.orm import Model, except_orm
from openerp.tools.translate import _
from openerp.osv import fields
from openerp.addons.fetchmail.fetchmail import logger
from openerp.tools.misc import UnquoteEvalContext
from openerp.tools.safe_eval import safe_eval
class fetchmail_server(Model):
@ -45,7 +44,7 @@ class fetchmail_server(Model):
def __init__(self, pool, cr):
self._columns['object_id'].required = False
return super(fetchmail_server, self).__init__(pool, cr)
super(fetchmail_server, self).__init__(pool, cr)
def onchange_server_type(
self, cr, uid, ids, server_type=False, ssl=False,
@ -110,7 +109,8 @@ class fetchmail_server(Model):
matched_object_ids += this.apply_matching(
connection, folder, msgid, match_algorithm)
logger.info('finished checking for emails in %s server %s',
logger.info(
'finished checking for emails in %s server %s',
folder.path, this.name)
return matched_object_ids
@ -130,15 +130,16 @@ class fetchmail_server(Model):
if result != 'OK':
logger.error(
'Could not fetch %s in %s on %s' % (
msgid, folder.path, this.server))
'Could not fetch %s in %s on %s',
msgid, folder.path, this.server)
continue
mail_message = self.pool.get('mail.message').parse_message(
msgdata[0][1], this.original)
if self.pool.get('mail.message').search(cr, uid, [
('message_id', '=', mail_message['message-id'])]):
if self.pool.get('mail.message').search(
cr, uid,
[('message_id', '=', mail_message['message-id'])]):
continue
found_ids = match_algorithm.search_matches(
@ -155,7 +156,7 @@ class fetchmail_server(Model):
msgdata[0][1], msgid, context)
cr.execute('release savepoint apply_matching')
matched_object_ids += found_ids[:1]
except Exception, e:
except Exception:
cr.execute('rollback to savepoint apply_matching')
logger.exception(
"Failed to fetch mail %s from %s",

3
fetchmail_attach_from_folder/model/fetchmail_server_folder.py

@ -31,7 +31,8 @@ class fetchmail_server_folder(Model):
def _get_match_algorithms(self):
def get_all_subclasses(cls):
return cls.__subclasses__() + [subsub
return cls.__subclasses__() + [
subsub
for sub in cls.__subclasses__()
for subsub in get_all_subclasses(sub)]
return dict([(cls.__name__, cls) for cls in get_all_subclasses(

3
fetchmail_attach_from_folder/wizard/__init__.py

@ -19,5 +19,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import attach_mail_manually
from . import attach_mail_manually

58
fetchmail_attach_from_folder/wizard/attach_mail_manually.py

@ -20,6 +20,7 @@
#
##############################################################################
import logging
from openerp.osv import fields
from openerp.osv.orm import TransientModel
@ -28,8 +29,8 @@ class attach_mail_manually(TransientModel):
_name = 'fetchmail.attach.mail.manually'
_columns = {
'folder_id': fields.many2one('fetchmail.server.folder', 'Folder',
readonly=True),
'folder_id': fields.many2one(
'fetchmail.server.folder', 'Folder', readonly=True),
'mail_ids': fields.one2many(
'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'),
}
@ -38,31 +39,38 @@ class attach_mail_manually(TransientModel):
if context is None:
context = {}
defaults = super(attach_mail_manually, self).default_get(cr, uid,
fields_list, context)
defaults = super(attach_mail_manually, self).default_get(
cr, uid, fields_list, context)
for folder in self.pool.get('fetchmail.server.folder').browse(cr, uid,
[context.get('default_folder_id')], context):
for folder in self.pool.get('fetchmail.server.folder').browse(
cr, uid, [context.get('default_folder_id')], context):
defaults['mail_ids'] = []
connection = folder.server_id.connect()
connection.select(folder.path)
result, msgids = connection.search(None,
result, msgids = connection.search(
None,
'FLAGGED' if folder.flag_nonmatching else 'UNDELETED')
if result != 'OK':
logger.error('Could not search mailbox %s on %s' % (
folder.path, this.server))
logging.error(
'Could not search mailbox %s on %s',
folder.path,
folder.server_id.server)
continue
attach_mail_manually_mail._columns['object_id'].selection = [
(folder.model_id.model, folder.model_id.name)]
(folder.model_id.model, folder.model_id.name)
]
for msgid in msgids[0].split():
result, msgdata = connection.fetch(msgid, '(RFC822)')
if result != 'OK':
logger.error('Could not fetch %s in %s on %s' % (
msgid, folder.path, this.server))
logging.error(
'Could not fetch %s in %s on %s',
msgid, folder.path, folder.server_id.server)
continue
mail_message = self.pool.get('mail.message').parse_message(
msgdata[0][1])
defaults['mail_ids'].append((0, 0, {
defaults['mail_ids'].append(
(0, 0,
{
'msgid': msgid,
'subject': mail_message.get('subject', ''),
'date': mail_message.get('date', ''),
@ -79,32 +87,38 @@ class attach_mail_manually(TransientModel):
connection.select(this.folder_id.path)
result, msgdata = connection.fetch(mail.msgid, '(RFC822)')
if result != 'OK':
logger.error('Could not fetch %s in %s on %s' % (
msgid, folder.path, this.server))
logging.error(
'Could not fetch %s in %s on %s',
mail.msgid, this.folder_id.path,
this.folder_id.server_id.server)
continue
mail_message = self.pool.get('mail.message').parse_message(
msgdata[0][1], this.folder_id.server_id.original)
this.folder_id.server_id.attach_mail(connection,
this.folder_id.server_id.attach_mail(
connection,
mail.object_id.id, this.folder_id, mail_message,
mail.msgid)
connection.close()
return {'type': 'ir.actions.act_window_close'}
class attach_mail_manually_mail(TransientModel):
_name = 'fetchmail.attach.mail.manually.mail'
_columns = {
'wizard_id': fields.many2one('fetchmail.attach.mail.manually',
readonly=True),
'wizard_id': fields.many2one(
'fetchmail.attach.mail.manually', readonly=True),
'msgid': fields.char('Message id', size=16, readonly=True),
'subject': fields.char('Subject', size=128, readonly=True),
'date': fields.datetime('Date', readonly=True),
'object_id': fields.reference('Object',
'object_id': fields.reference(
'Object',
selection=lambda self, cr, uid, context:
[(m.model, m.name) for m in
self.pool.get('ir.model').browse(cr, uid,
self.pool.get('ir.model').search(cr, uid, []),
context)], size=128),
self.pool.get('ir.model').browse(
cr, uid, self.pool.get('ir.model').search(cr, uid, []),
context)],
size=128),
}

2
mail_client_view/__init__.py

@ -19,4 +19,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import model
from . import model

2
mail_client_view/model/__init__.py

@ -1 +1 @@
import mail_message
from . import mail_message

5
mail_client_view/model/mail_message.py

@ -25,7 +25,7 @@ class mail_message(Model):
def create(self, cr, user, vals, context=None):
# Set newly received messages as needing action, unless an
# explicit value for action_needed has been passed.
if ((not 'action_needed' in vals)
if ('action_needed' not in vals
and ('state' in vals) and (vals['state'] == 'received')):
vals['action_needed'] = True
mm_id = super(mail_message, self).create(
@ -33,7 +33,8 @@ class mail_message(Model):
return mm_id
_columns = {
'action_needed': fields.boolean('Action needed',
'action_needed': fields.boolean(
'Action needed',
help='Action needed is True whenever a new mail is received, or'
' when a user flags a message as needing attention.'),
}

11
mail_environment/__openerp__.py

@ -26,8 +26,10 @@
'description': """
Extend mail and fetch mail with server environment module.
In config files, sections outgoint_mail and incoming_mails are default values for all Outgoing Mail Servers and Fetchmail Servers.
For each server, you can (re)define values with a section named "outgoing_mail.resource_name" where resource_name is the name of your server.
In config files, sections outgoint_mail and incoming_mails are default values
for all Outgoing Mail Servers and Fetchmail Servers.
For each server, you can (re)define values with a section named
"outgoing_mail.resource_name" where resource_name is the name of your server.
Exemple of config file :
@ -57,7 +59,10 @@ password = openerp
'author': 'Camptocamp',
'license': 'AGPL-3',
'website': 'http://openerp.camptocamp.com',
'depends': ['mail', 'fetchmail', 'server_environment', 'server_environment_files', 'crm'],
'depends': [
'mail', 'fetchmail', 'server_environment', 'server_environment_files',
'crm'
],
'init_xml': [],
'update_xml': ['mail_view.xml'],
'demo_xml': [],

54
mail_environment/env_mail.py

@ -41,7 +41,8 @@ class IrMail(osv.osv):
if serv_config.has_section(global_section_name):
config_vals.update((serv_config.items(global_section_name)))
custom_section_name = '.'.join((global_section_name, mail_server.name))
custom_section_name = '.'.join(
(global_section_name, mail_server.name))
if serv_config.has_section(custom_section_name):
config_vals.update(serv_config.items(custom_section_name))
@ -63,32 +64,39 @@ class IrMail(osv.osv):
string='SMTP Port',
type="integer",
multi='outgoing_mail_config',
help="SMTP Port. Usually 465 for SSL, and 25 or 587 for other cases.",
help="SMTP Port. Usually 465 for SSL, "
"and 25 or 587 for other cases.",
size=5),
'smtp_user': fields.function(_get_smtp_conf,
method=True,
string='Username',
type="char",
multi='outgoing_mail_config',
help="Optional username for SMTP authentication",
help="Optional username for SMTP "
"authentication",
size=64),
'smtp_pass': fields.function(_get_smtp_conf,
method=True,
string='Password',
type="char",
multi='outgoing_mail_config',
help="Optional password for SMTP authentication",
help="Optional password for SMTP "
"authentication",
size=64),
'smtp_encryption' :fields.function(_get_smtp_conf,
'smtp_encryption': fields.function(
_get_smtp_conf,
method=True,
string='smtp_encryption',
type="char",
multi='outgoing_mail_config',
help="Choose the connection encryption scheme:\n"
"- none: SMTP sessions are done in cleartext.\n"
"- starttls: TLS encryption is requested at start of SMTP session (Recommended)\n"
"- ssl: SMTP sessions are encrypted with SSL/TLS through a dedicated port (default: 465)",
size=64)}
"- starttls: TLS encryption is requested at start of SMTP session "
"(Recommended)\n"
"- ssl: SMTP sessions are encrypted with SSL/TLS through a "
"dedicated port (default: 465)",
size=64),
}
IrMail()
@ -105,10 +113,12 @@ class FetchmailServer(osv.osv):
for fetchmail in self.browse(cursor, uid, ids):
global_section_name = 'incoming_mail'
key_types = {'port': int,
key_types = {
'port': int,
'is_ssl': lambda a: bool(int(a)),
'attach': lambda a: bool(int(a)),
'original': lambda a: bool(int(a)),}
'original': lambda a: bool(int(a)),
}
# default vals
config_vals = {'port': 993,
@ -118,7 +128,8 @@ class FetchmailServer(osv.osv):
if serv_config.has_section(global_section_name):
config_vals.update(serv_config.items(global_section_name))
custom_section_name = '.'.join((global_section_name, fetchmail.name))
custom_section_name = '.'.join(
(global_section_name, fetchmail.name))
if serv_config.has_section(custom_section_name):
config_vals.update(serv_config.items(custom_section_name))
@ -134,7 +145,8 @@ class FetchmailServer(osv.osv):
string='Server',
type="char",
multi='income_mail_config',
size=256, help="Hostname or IP of the mail server"),
size=256,
help="Hostname or IP of the mail server"),
'port': fields.function(_get_incom_conf,
method=True,
string='Port',
@ -153,22 +165,28 @@ class FetchmailServer(osv.osv):
string='Is SSL',
type="boolean",
multi='income_mail_config',
help='Connections are encrypted with SSL/TLS through'
' a dedicated port (default: IMAPS=993, POP3S=995)'),
help='Connections are encrypted with '
'SSL/TLS through a dedicated port (default: '
'IMAPS=993, POP3S=995)'),
'attach': fields.function(_get_incom_conf,
method=True,
string='Keep Attachments',
type="boolean",
multi='income_mail_config',
help="Whether attachments should be downloaded. "
"If not enabled, incoming emails will be stripped of any attachments before being processed"),
help="Whether attachments should be "
"downloaded. If not enabled, incoming "
"emails will be stripped of any attachments "
"before being processed"),
'original': fields.function(_get_incom_conf,
method=True,
string='Keep Original',
type="boolean",
multi='income_mail_config',
help="Whether a full original copy of each email should be kept for reference"
"and attached to each processed message. This will usually double the size of your message database."),
help="Whether a full original copy of "
"each email should be kept for reference"
"and attached to each processed message. "
"This will usually double the size of "
"your message database."),
'user': fields.function(_get_incom_conf,
method=True,
string='Username',

8
mass_editing/__init__.py

@ -2,7 +2,8 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>)
# Copyright (C) 2012 Serpent Consulting Services
# (<http://www.serpentcs.com>)
# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
@ -20,8 +21,7 @@
#
##############################################################################
import mass_editing
import wizard
from . import mass_editing
from . import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

11
mass_editing/__openerp__.py

@ -2,7 +2,8 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>)
# Copyright (C) 2012 Serpent Consulting Services
# (<http://www.serpentcs.com>)
# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
@ -19,19 +20,19 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
##############################################################################
{
"name": "Mass Editing",
"version": "1.1",
"author": "Serpent Consulting Services",
"category": "Tools",
"website": "http://www.serpentcs.com",
"description": """This module provides the functionality to add, update or remove the values of more than one records on the fly at the same time.
"description": """This module provides the functionality to add, update or
remove the values of more than one records on the fly at the same time.
You can configure mass editing for any OpenERP model.
The video explaining the feature is available at http://t.co/wukYMx1A
The menu is now Under Settings/Configuration.
For more details/customization/feedback contact us on contact@serpentcs.com.
For more details/customization/feedback contact us on
contact@serpentcs.com.
""",
'depends': ['base'],
'init_xml': [],

57
mass_editing/mass_editing.py

@ -2,7 +2,8 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>)
# Copyright (C) 2012 Serpent Consulting Services
# (<http://www.serpentcs.com>)
# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
@ -19,22 +20,26 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
##############################################################################
from osv import fields, osv
from tools.translate import _
class mass_object(osv.osv):
_name = "mass.object"
_columns = {
'name': fields.char("Name", size=64, required=True, select=1),
'model_id' : fields.many2one('ir.model', 'Model', required=True, select=1),
'field_ids' : fields.many2many('ir.model.fields', 'mass_field_rel', 'mass_id', 'field_id', 'Fields'),
'ref_ir_act_window':fields.many2one('ir.actions.act_window', 'Sidebar action', readonly=True,
'model_id': fields.many2one(
'ir.model', 'Model', required=True, select=1),
'field_ids': fields.many2many(
'ir.model.fields', 'mass_field_rel', 'mass_id', 'field_id',
'Fields'),
'ref_ir_act_window': fields.many2one(
'ir.actions.act_window', 'Sidebar action', readonly=True,
help="Sidebar action to make this template available on records "
"of the related document model"),
'ref_ir_value':fields.many2one('ir.values', 'Sidebar button', readonly=True,
'ref_ir_value': fields.many2one(
'ir.values', 'Sidebar button', readonly=True,
help="Sidebar button to open the sidebar action"),
'model_ids': fields.many2many('ir.model', string='Model List')
}
@ -48,7 +53,8 @@ class mass_object(osv.osv):
active_model_obj = self.pool.get(model_data.model)
if active_model_obj._inherits:
for key, val in active_model_obj._inherits.items():
found_model_ids = model_obj.search(cr, uid, [('model', '=', key)])
found_model_ids = model_obj.search(
cr, uid, [('model', '=', key)])
if found_model_ids:
model_ids.append(found_model_ids[0])
return {'value': {'model_ids': [(6, 0, model_ids)]}}
@ -56,11 +62,12 @@ class mass_object(osv.osv):
def create_action(self, cr, uid, ids, context=None):
vals = {}
action_obj = self.pool.get('ir.actions.act_window')
data_obj = self.pool.get('ir.model.data')
for data in self.browse(cr, uid, ids, context=context):
src_obj = data.model_id.model
button_name = _('Mass Editing (%s)') % data.name
vals['ref_ir_act_window'] = action_obj.create(cr, uid, {
vals['ref_ir_act_window'] = action_obj.create(
cr, uid,
{
'name': button_name,
'type': 'ir.actions.act_window',
'res_model': 'mass.editing.wizard',
@ -70,30 +77,42 @@ class mass_object(osv.osv):
'view_mode': 'form,tree',
'target': 'new',
'auto_refresh': 1
}, context)
vals['ref_ir_value'] = self.pool.get('ir.values').create(cr, uid, {
},
context)
vals['ref_ir_value'] = self.pool.get('ir.values').create(
cr, uid,
{
'name': button_name,
'model': src_obj,
'key2': 'client_action_multi',
'value': "ir.actions.act_window," + str(vals['ref_ir_act_window']),
'value': "ir.actions.act_window," + str(
vals['ref_ir_act_window']),
'object': True,
}, context)
self.write(cr, uid, ids, {
},
context)
self.write(
cr, uid, ids,
{
'ref_ir_act_window': vals.get('ref_ir_act_window', False),
'ref_ir_value': vals.get('ref_ir_value', False),
}, context)
},
context)
return True
def unlink_action(self, cr, uid, ids, context=None):
for template in self.browse(cr, uid, ids, context=context):
try:
if template.ref_ir_act_window:
self.pool.get('ir.actions.act_window').unlink(cr, uid, template.ref_ir_act_window.id, context)
self.pool.get('ir.actions.act_window').unlink(
cr, uid, template.ref_ir_act_window.id, context)
if template.ref_ir_value:
ir_values_obj = self.pool.get('ir.values')
ir_values_obj.unlink(cr, uid, template.ref_ir_value.id, context)
ir_values_obj.unlink(
cr, uid, template.ref_ir_value.id, context)
except:
raise osv.except_osv(_("Warning"), _("Deletion of the action record failed."))
raise osv.except_osv(
_("Warning"),
_("Deletion of the action record failed."))
return True
def unlink(self, cr, uid, ids, context=None):

5
mass_editing/wizard/__init__.py

@ -2,7 +2,8 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>)
# Copyright (C) 2012 Serpent Consulting Services
# (<http://www.serpentcs.com>)
# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
@ -20,6 +21,6 @@
#
##############################################################################
import mass_editing_wizard
from . import mass_editing_wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

266
mass_editing/wizard/mass_editing_wizard.py

@ -2,7 +2,8 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>)
# Copyright (C) 2012 Serpent Consulting Services
# (<http://www.serpentcs.com>)
# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
@ -21,74 +22,250 @@
##############################################################################
from osv import osv
from osv import fields
from lxml import etree
import tools
class mass_editing_wizard(osv.osv_memory):
_name = 'mass.editing.wizard'
_columns = {
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
result = super(mass_editing_wizard, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
def fields_view_get(self, cr, uid, view_id=None, view_type='form',
context=None, toolbar=False, submenu=False):
result = super(mass_editing_wizard, self).fields_view_get(
cr, uid, view_id, view_type, context, toolbar, submenu)
if context.get('mass_editing_object'):
mass_object = self.pool.get('mass.object')
editing_data = mass_object.browse(cr, uid, context.get('mass_editing_object'), context)
editing_data = mass_object.browse(
cr, uid, context.get('mass_editing_object'), context)
all_fields = {}
xml_form = etree.Element('form', {'string': tools.ustr(editing_data.name)})
xml_form = etree.Element(
'form', {'string': tools.ustr(editing_data.name)})
xml_group = etree.SubElement(xml_form, 'group', {'colspan': '4'})
etree.SubElement(xml_group, 'label', {'string': '','colspan': '2'})
etree.SubElement(
xml_group, 'label', {'string': '', 'colspan': '2'})
xml_group = etree.SubElement(xml_form, 'group', {'colspan': '4'})
model_obj = self.pool.get(context.get('active_model'))
for field in editing_data.field_ids:
if field.ttype == "many2many":
field_info = model_obj.fields_get(cr, uid, [field.name], context)
field_info = model_obj.fields_get(
cr, uid, [field.name], context)
all_fields[field.name] = field_info[field.name]
all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove_m2m','Remove'),('add','Add')]}
xml_group = etree.SubElement(xml_group, 'group', {'colspan': '4'})
etree.SubElement(xml_group, 'separator', {'string': field_info[field.name]['string'],'colspan': '2'})
etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name,'colspan': '2','nolabel':'1'})
etree.SubElement(xml_group, 'field', {'name': field.name, 'colspan':'4', 'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove_m2m')]}"})
all_fields["selection_" + field.name] = {
'type': 'selection',
'string': field_info[field.name]['string'],
'selection': [
('set', 'Set'),
('remove_m2m', 'Remove'),
('add', 'Add')
]
}
xml_group = etree.SubElement(
xml_group, 'group', {'colspan': '4'})
etree.SubElement(
xml_group, 'separator',
{
'string': field_info[field.name]['string'],
'colspan': '2'
})
etree.SubElement(
xml_group, 'field',
{
'name': "selection_" + field.name,
'colspan': '2',
'nolabel': '1'
})
etree.SubElement(
xml_group, 'field',
{
'name': field.name,
'colspan': '4',
'nolabel': '1',
'attrs': "{'invisible':[('selection_" + field.name
+ "','=','remove_m2m')]}"
})
elif field.ttype == "many2one":
field_info = model_obj.fields_get(cr, uid, [field.name], context)
field_info = model_obj.fields_get(
cr, uid, [field.name], context)
if field_info:
all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]}
all_fields[field.name] = {'type':field.ttype, 'string': field.field_description, 'relation': field.relation}
etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name, 'colspan':'2'})
etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1','colspan':'2', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}"})
all_fields["selection_" + field.name] = {
'type': 'selection',
'string': field_info[field.name]['string'],
'selection': [
('set', 'Set'),
('remove', 'Remove')
]
}
all_fields[field.name] = {
'type': field.ttype,
'string': field.field_description,
'relation': field.relation
}
etree.SubElement(
xml_group, 'field',
{
'name': "selection_" + field.name,
'colspan': '2'
})
etree.SubElement(
xml_group, 'field',
{
'name': field.name,
'nolabel': '1',
'colspan': '2',
'attrs': "{'invisible':[('selection_" +
field.name + "','=','remove')]}"
})
elif field.ttype == "char":
field_info = model_obj.fields_get(cr, uid, [field.name], context)
all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]}
all_fields[field.name] = {'type':field.ttype, 'string': field.field_description, 'size': field.size or 256}
etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name,'colspan':'2', 'colspan':'2'})
etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}", 'colspan':'2'})
field_info = model_obj.fields_get(
cr, uid, [field.name], context)
all_fields["selection_" + field.name] = {
'type': 'selection',
'string': field_info[field.name]['string'],
'selection': [
('set', 'Set'),
('remove', 'Remove')
]
}
all_fields[field.name] = {
'type': field.ttype,
'string': field.field_description,
'size': field.size or 256
}
etree.SubElement(
xml_group, 'field',
{
'name': "selection_" + field.name,
'colspan': '2',
})
etree.SubElement(
xml_group, 'field',
{
'name': field.name,
'nolabel': '1',
'attrs': "{'invisible':[('selection_" +
field.name + "','=','remove')]}",
'colspan': '2'
})
elif field.ttype == 'selection':
field_info = model_obj.fields_get(cr, uid, [field.name], context)
all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]}
field_info = model_obj.fields_get(cr, uid, [field.name], context)
etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name, 'colspan':'2'})
etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1','colspan':'2', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}"})
all_fields[field.name] = {'type':field.ttype, 'string': field.field_description, 'selection': field_info[field.name]['selection']}
field_info = model_obj.fields_get(
cr, uid, [field.name], context)
all_fields["selection_" + field.name] = {
'type': 'selection',
'string': field_info[field.name]['string'],
'selection': [
('set', 'Set'),
('remove', 'Remove')
]
}
field_info = model_obj.fields_get(
cr, uid, [field.name], context)
etree.SubElement(
xml_group, 'field',
{
'name': "selection_" + field.name,
'colspan': '2'
})
etree.SubElement(
xml_group, 'field',
{
'name': field.name,
'nolabel': '1',
'colspan': '2',
'attrs': "{'invisible':[('selection_" +
field.name + "','=','remove')]}"
})
all_fields[field.name] = {
'type': field.ttype,
'string': field.field_description,
'selection': field_info[field.name]['selection']
}
else:
field_info = model_obj.fields_get(cr, uid, [field.name], context)
all_fields[field.name] = {'type':field.ttype, 'string': field.field_description}
all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]}
field_info = model_obj.fields_get(
cr, uid, [field.name], context)
all_fields[field.name] = {
'type': field.ttype,
'string': field.field_description
}
all_fields["selection_" + field.name] = {
'type': 'selection',
'string': field_info[field.name]['string'],
'selection': [
('set', 'Set'),
('remove', 'Remove')
]
}
if field.ttype == 'text':
xml_group = etree.SubElement(xml_group, 'group', {'colspan': '6'})
etree.SubElement(xml_group, 'separator', {'string': all_fields[field.name]['string'],'colspan': '2'})
etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name,'colspan': '2','nolabel':'1'})
etree.SubElement(xml_group, 'field', {'name': field.name, 'colspan':'4', 'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}"})
xml_group = etree.SubElement(
xml_group, 'group', {'colspan': '6'})
etree.SubElement(
xml_group, 'separator',
{
'string': all_fields[field.name]['string'],
'colspan': '2'
})
etree.SubElement(
xml_group, 'field',
{
'name': "selection_" + field.name,
'colspan': '2',
'nolabel': '1',
})
etree.SubElement(
xml_group, 'field',
{
'name': field.name,
'colspan': '4',
'nolabel': '1',
'attrs': "{'invisible':[('selection_" +
field.name + "','=','remove')]}"
})
else:
all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]}
etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name, 'colspan': '2',})
etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}",'colspan': '2',})
all_fields["selection_" + field.name] = {
'type': 'selection',
'string': field_info[field.name]['string'],
'selection': [
('set', 'Set'),
('remove', 'Remove')
]
}
etree.SubElement(
xml_group, 'field',
{
'name': "selection_" + field.name,
'colspan': '2',
})
etree.SubElement(
xml_group, 'field',
{
'name': field.name,
'nolabel': '1',
'attrs': "{'invisible':[('selection_" +
field.name + "','=','remove')]}",
'colspan': '2',
})
etree.SubElement(xml_form, 'separator', {'string' : '','colspan': '6'})
xml_group3 = etree.SubElement(xml_form, 'group', {'col': '2', 'colspan': '4'})
etree.SubElement(xml_group3, 'button', {'string' :'Close','icon': "gtk-close", 'special' :'cancel'})
etree.SubElement(xml_group3, 'button', {'string' :'Apply','icon': "gtk-execute", 'type' :'object','name':"action_apply"})
etree.SubElement(
xml_form, 'separator', {'string': '', 'colspan': '6'})
xml_group3 = etree.SubElement(
xml_form, 'group', {'col': '2', 'colspan': '4'})
etree.SubElement(
xml_group3, 'button',
{
'string': 'Close',
'icon': "gtk-close",
'special': 'cancel'
})
etree.SubElement(
xml_group3, 'button',
{
'string': 'Apply',
'icon': "gtk-execute",
'type': 'object',
'name': "action_apply"
})
root = xml_form.getroottree()
result['arch'] = etree.tostring(root)
@ -117,7 +294,8 @@ class mass_editing_wizard(osv.osv_memory):
m2m_list.append((4, m2m_id))
model_vals[model_field] = m2m_list
if model_vals:
model_obj.write(cr, uid, context['active_ids'], model_vals, context)
model_obj.write(
cr, uid, context['active_ids'], model_vals, context)
result = super(mass_editing_wizard, self).create(cr, uid, {}, context)
return result

6
security_protector/__openerp__.py

@ -9,9 +9,11 @@
'description': """
Prevent security to be changed when module is updated
This module overwrite ir model acces write delete function.
Only acces edited trough the UI or with manual_security_override in context set to True will be altered.
Only acces edited trough the UI or with manual_security_override in context
set to True will be altered.
When you try to delete a acces write it simply set all perms to false
you can deactivate this behavior in ir.config_parameter by chanching the protect_security? key to 0
you can deactivate this behavior in ir.config_parameter by chanching the
protect_security? key to 0
""",
'author': 'Camptocamp',
'website': 'http://openerp.camptocamp.com',

23
security_protector/security_protector.py

@ -3,7 +3,8 @@
#
# Author Nicolas Bessi. Copyright Camptocamp SA
##############################################################################
from osv import fields, osv
from osv import osv
class IrModelAccess(osv.osv):
"We inherit ir model access to add specific write unlink and copy behavior"
@ -12,12 +13,12 @@ class IrModelAccess(osv.osv):
def _acces_can_be_modified(self, cr, uid, context=None):
context = context or {}
on = self.pool.get('ir.config_parameter').get_param(cr, uid, 'protect_security?', default=False, context=context)
on = self.pool.get('ir.config_parameter').get_param(
cr, uid, 'protect_security?', default=False, context=context)
if on in (1, "1", "YES", True):
if context.get('manual_security_override', False):
return True
return False
else:
return True
@ -25,22 +26,26 @@ class IrModelAccess(osv.osv):
res = True
context = context or {}
if self._acces_can_be_modified(cr, uid, context=context):
res = super(IrModelAccess, self).write(cr, uid, ids, vals, context=context)
res = super(IrModelAccess, self).write(
cr, uid, ids, vals, context=context)
return res
def unlink(self, cr, uid, ids, context=None):
res = True
context = context or {}
# I'm note sur about this one maybe we should do nothing
if self._acces_can_be_modified(cr, uid, context=context):
vals = {'perm_read':False,
vals = {
'perm_read': False,
'perm_write': False,
'perm_unlink': False,
'perm_create': False}
super(IrModelAccess, self).write(cr, uid, ids, vals, context=context)
'perm_create': False
}
super(IrModelAccess, self).write(
cr, uid, ids, vals, context=context)
else:
res = super(IrModelAccess, self).unlink(cr, uid, ids, context=context)
res = super(IrModelAccess, self).unlink(
cr, uid, ids, context=context)
return res

3
server_env_base_external_referentials/__init__.py

@ -18,5 +18,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base_external_referentials
from . import base_external_referentials

11
server_env_base_external_referentials/__openerp__.py

@ -25,10 +25,13 @@
"depends": ["base", 'server_environment', 'base_external_referentials'],
"author": "Camptocamp",
'license': 'AGPL-3',
"description": """This module is based on the server_environment module to use files for configuration.
Thus we can have a different file for each environment (dev, test, staging, prod).
This module define the config variables for the base_external_referential module.
In the configuration file, you can configure the url, login and password of the referentials
"description": """This module is based on the server_environment module to
use files for configuration. Thus we can have a different file for each
environment (dev, test, staging, prod).
This module define the config variables for the base_external_referential
module.
In the configuration file, you can configure the url, login and password of the
referentials.
Exemple of the section to put in the configuration file :

20
server_env_base_external_referentials/base_external_referentials.py

@ -24,30 +24,36 @@ from server_environment import serv_config
import logging
class external_referential(osv.osv):
_inherit = 'external.referential'
def _get_environment_config_by_name(self, cr, uid, ids, field_names, arg, context):
def _get_environment_config_by_name(self, cr, uid, ids, field_names, arg,
context):
values = {}
for referential in self.browse(cr, uid, ids, context):
values[referential.id] = {}
for field_name in field_names:
section_name = '.'.join((self._name.replace('.', '_'), referential.name))
section_name = '.'.join((self._name.replace('.', '_'),
referential.name))
try:
value = serv_config.get(section_name, field_name)
values[referential.id].update({field_name: value})
except:
logger = logging.getLogger(__name__)
logger.exception('error trying to read field %s in section %s', field_name, section_name)
logger.exception(
'error trying to read field %s in section %s',
field_name, section_name)
return values
_columns = {
'location': fields.function(_get_environment_config_by_name, type='char', size=200,
'location': fields.function(
_get_environment_config_by_name, type='char', size=200,
method=True, string='Location', multi='connection_config'),
'apiusername': fields.function(_get_environment_config_by_name, type='char', size=64,
'apiusername': fields.function(
_get_environment_config_by_name, type='char', size=64,
method=True, string='User Name', multi='connection_config'),
'apipass': fields.function(_get_environment_config_by_name, type='char', size=64,
'apipass': fields.function(
_get_environment_config_by_name, type='char', size=64,
method=True, string='Password', multi='connection_config'),
}

10
server_environment/serv_config.py

@ -23,7 +23,7 @@ import os
import ConfigParser
from lxml import etree
from openerp.osv import osv, fields, orm
from openerp.osv import fields, orm
from openerp.tools.config import config as system_base_config
from .system_info import get_server_environment
@ -52,8 +52,11 @@ if not os.path.exists(ck_path) :
"please add a folder %s" % ck_path
)
def setboolean(obj, attr, _bool=_boolean_states):
def setboolean(obj, attr, _bool=None):
"""Replace the attribute with a boolean."""
if _bool is None:
_bool = _boolean_states
res = _bool[getattr(obj, attr).lower()]
setattr(obj, attr, res)
return res
@ -115,7 +118,7 @@ class ServerConfiguration(orm.TransientModel):
_conf_defaults = _Defaults()
def __init__(self, pool, cr):
res = super(ServerConfiguration, self).__init__(pool, cr)
super(ServerConfiguration, self).__init__(pool, cr)
self.running_env = system_base_config['running_env']
# Only show passwords in development
self.show_passwords = self.running_env in ('dev',)
@ -187,7 +190,6 @@ class ServerConfiguration(orm.TransientModel):
res['fields'] = xfields
return res
def default_get(self, cr, uid, fields_list, context=None):
res = {}
for key in self._conf_defaults:

2
super_calendar/__init__.py

@ -18,4 +18,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import super_calendar
from . import super_calendar

31
super_calendar/__openerp__.py

@ -26,9 +26,13 @@
'description': """
This module allows to create configurable calendars.
Through the 'calendar configurator' object, you can specify which models have to be merged in the super calendar. For each model, you have to define the 'description' and 'date_start' fields at least. Then you can define 'duration' and the 'user_id' fields.
Through the 'calendar configurator' object, you can specify which models have
to be merged in the super calendar. For each model, you have to define the
'description' and 'date_start' fields at least. Then you can define 'duration'
and the 'user_id' fields.
The 'super.calendar' object contains the the merged calendars. The 'super.calendar' can be updated by 'ir.cron' or manually.
The 'super.calendar' object contains the the merged calendars. The
'super.calendar' can be updated by 'ir.cron' or manually.
Configuration
=============
@ -37,29 +41,38 @@ After installing the module you can go to
Super calendar Configuration Configurators
and create a new configurator. For instance, if you want to see meetings and phone calls, you can create the following lines
and create a new configurator. For instance, if you want to see meetings and
phone calls, you can create the following lines
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/meetings.png
:width: 400 px
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/phone_calls.png
.. image::
http://planet.domsense.com/wp-content/uploads/2012/04/phone_calls.png
:width: 400 px
Then, you can use the Generate Calendar button or wait for the scheduled action (Generate Calendar Records) to be run.
Then, you can use the Generate Calendar button or wait for the scheduled
action (Generate Calendar Records) to be run.
When the calendar is generated, you can visualize it by the super calendar main menu.
When the calendar is generated, you can visualize it by the super calendar
main menu.
Here is a sample monthly calendar:
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/month_calendar.png
.. image::
http://planet.domsense.com/wp-content/uploads/2012/04/month_calendar.png
:width: 400 px
And here is the weekly one:
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/week_calendar.png
.. image::
http://planet.domsense.com/wp-content/uploads/2012/04/week_calendar.png
:width: 400 px
As you can see, several filters are available. A typical usage consists in filtering by Configurator (if you have several configurators, Scheduled calls and meetings can be one of them) and by your user. Once you filtered, you can save the filter as Advanced filter or even add it to a dashboard.
As you can see, several filters are available. A typical usage consists in
filtering by Configurator (if you have several configurators, Scheduled
calls and meetings can be one of them) and by your user. Once you filtered,
you can save the filter as Advanced filter or even add it to a dashboard.
""",
'author': 'Agile Business Group',
'website': 'http://www.agilebg.com',

107
super_calendar/super_calendar.py

@ -27,18 +27,21 @@ from datetime import datetime
from openerp import tools
from openerp.tools import safe_eval as eval
def _models_get(self, cr, uid, context=None):
obj = self.pool.get('ir.model')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['model', 'name'], context)
return [(r['model'], r['name']) for r in res]
class super_calendar_configurator(orm.Model):
_logger = logging.getLogger('super.calendar')
_name = 'super.calendar.configurator'
_columns = {
'name': fields.char('Name', size=64, required=True),
'line_ids': fields.one2many('super.calendar.configurator.line', 'configurator_id', 'Lines'),
'line_ids': fields.one2many(
'super.calendar.configurator.line', 'configurator_id', 'Lines'),
}
def generate_calendar_records(self, cr, uid, ids, context=None):
@ -46,33 +49,55 @@ class super_calendar_configurator(orm.Model):
super_calendar_pool = self.pool.get('super.calendar')
# removing old records
super_calendar_ids = super_calendar_pool.search(cr, uid, [], context=context)
super_calendar_pool.unlink(cr, uid, super_calendar_ids, context=context)
super_calendar_ids = super_calendar_pool.search(
cr, uid, [], context=context)
super_calendar_pool.unlink(
cr, uid, super_calendar_ids, context=context)
for configurator in self.browse(cr, uid, configurator_ids, context):
for line in configurator.line_ids:
current_pool = self.pool.get(line.name.model)
current_record_ids = current_pool.search(cr, uid, line.domain and eval(line.domain) or [], context=context)
current_record_ids = current_pool.search(
cr, uid, line.domain and eval(line.domain) or [],
context=context)
for current_record_id in current_record_ids:
current_record = current_pool.browse(cr, uid, current_record_id, context=context)
current_record = current_pool.browse(
cr, uid, current_record_id, context=context)
if line.user_field_id and \
current_record[line.user_field_id.name] and current_record[line.user_field_id.name]._table_name != 'res.users':
raise osv.except_osv(_('Error'),
_("The 'User' field of record %s (%s) does not refer to res.users")
% (current_record[line.description_field_id.name], line.name.model))
current_record[line.user_field_id.name] and\
current_record[line.user_field_id.name]._table_name \
!= 'res.users':
raise osv.except_osv(
_('Error'),
_("The 'User' field of record %s (%s) does not "
"refer to res.users")
% (
current_record[line.description_field_id.name],
line.name.model)
)
if (((line.description_field_id
and current_record[line.description_field_id.name])
or line.description_code)
and current_record[line.date_start_field_id.name]):
duration = False
if not line.duration_field_id and line.date_stop_field_id and current_record[line.date_start_field_id.name] and current_record[line.date_stop_field_id.name]:
date_start= datetime.strptime(current_record[line.date_start_field_id.name], tools.DEFAULT_SERVER_DATETIME_FORMAT)
date_stop= datetime.strptime(current_record[line.date_stop_field_id.name], tools.DEFAULT_SERVER_DATETIME_FORMAT)
duration = (date_stop - date_start).total_seconds() / 3600
if not line.duration_field_id and\
line.date_stop_field_id and\
current_record[line.date_start_field_id.name] and\
current_record[line.date_stop_field_id.name]:
date_start = datetime.strptime(
current_record[line.date_start_field_id.name],
tools.DEFAULT_SERVER_DATETIME_FORMAT)
date_stop = datetime.strptime(
current_record[line.date_stop_field_id.name],
tools.DEFAULT_SERVER_DATETIME_FORMAT)
duration = (date_stop - date_start).total_seconds()
duration /= 3600
elif line.duration_field_id:
duration = current_record[line.duration_field_id.name]
duration = current_record[
line.duration_field_id.name]
if line.description_type != 'code':
name = current_record[line.description_field_id.name]
name = current_record[
line.description_field_id.name]
else:
parse_dict = {'o': current_record}
mytemplate = Template(line.description_code)
@ -80,14 +105,20 @@ class super_calendar_configurator(orm.Model):
super_calendar_values = {
'name': name,
'model_description': line.description,
'date_start': current_record[line.date_start_field_id.name],
'date_start': current_record[
line.date_start_field_id.name],
'duration': duration,
'user_id': line.user_field_id and current_record[line.user_field_id.name] and current_record[line.user_field_id.name].id or False,
'user_id': line.user_field_id and
current_record[line.user_field_id.name] and
current_record[line.user_field_id.name].id or
False,
'configurator_id': configurator.id,
'res_id': line.name.model+','+str(current_record['id']),
'res_id': line.name.model + ',' +
str(current_record['id']),
'model_id': line.name.id,
}
super_calendar_pool.create(cr, uid, super_calendar_values, context=context)
super_calendar_pool.create(
cr, uid, super_calendar_values, context=context)
self._logger.info('Calendar generated')
return True
@ -98,22 +129,33 @@ class super_calendar_configurator_line(orm.Model):
'name': fields.many2one('ir.model', 'Model', required=True),
'description': fields.char('Description', size=128, required=True),
'domain': fields.char('Domain', size=512),
'configurator_id': fields.many2one('super.calendar.configurator', 'Configurator'),
'description_type': fields.selection([
'configurator_id': fields.many2one(
'super.calendar.configurator', 'Configurator'),
'description_type': fields.selection(
[
('field', 'Field'),
('code', 'Code'),
], string="Description Type"),
'description_field_id': fields.many2one('ir.model.fields', 'Description field',
'description_field_id': fields.many2one(
'ir.model.fields', 'Description field',
domain="[('model_id', '=', name),('ttype', '=', 'char')]"),
'description_code': fields.text('Description field', help="Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'"),
'date_start_field_id': fields.many2one('ir.model.fields', 'Start date field',
domain="['&','|',('ttype', '=', 'datetime'),('ttype', '=', 'date'),('model_id', '=', name)]",
'description_code': fields.text(
'Description field',
help="Use '${o}' to refer to the involved object. "
"E.g.: '${o.project_id.name}'"),
'date_start_field_id': fields.many2one(
'ir.model.fields', 'Start date field',
domain="['&','|',('ttype', '=', 'datetime'),"
"('ttype', '=', 'date'),('model_id', '=', name)]",
required=True),
'date_stop_field_id': fields.many2one('ir.model.fields', 'End date field',
'date_stop_field_id': fields.many2one(
'ir.model.fields', 'End date field',
domain="['&',('ttype', '=', 'datetime'),('model_id', '=', name)]"),
'duration_field_id': fields.many2one('ir.model.fields', 'Duration field',
'duration_field_id': fields.many2one(
'ir.model.fields', 'Duration field',
domain="['&',('ttype', '=', 'float'),('model_id', '=', name)]"),
'user_field_id': fields.many2one('ir.model.fields', 'User field',
'user_field_id': fields.many2one(
'ir.model.fields', 'User field',
domain="['&',('ttype', '=', 'many2one'),('model_id', '=', name)]"),
}
@ -122,11 +164,14 @@ class super_calendar(orm.Model):
_name = 'super.calendar'
_columns = {
'name': fields.char('Description', size=512, required=True),
'model_description': fields.char('Model Description', size=128, required=True),
'model_description': fields.char(
'Model Description', size=128, required=True),
'date_start': fields.datetime('Start date', required=True),
'duration': fields.float('Duration'),
'user_id': fields.many2one('res.users', 'User'),
'configurator_id': fields.many2one('super.calendar.configurator', 'Configurator'),
'res_id': fields.reference('Resource', selection=_models_get, size=128),
'configurator_id': fields.many2one(
'super.calendar.configurator', 'Configurator'),
'res_id': fields.reference(
'Resource', selection=_models_get, size=128),
'model_id': fields.many2one('ir.model', 'Model'),
}

2
unserialize_field/__init__.py

@ -19,4 +19,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import ir_model_fields
from . import ir_model_fields

9
unserialize_field/ir_model_fields.py

@ -47,10 +47,12 @@ class ir_model_fields(orm.Model):
offset=offset * step, limit=step, context=context)
if not ids:
break
for data in pool_obj.read(cr, uid, ids,
for data in pool_obj.read(
cr, uid, ids,
[this.serialization_field_id.name],
context=context):
self.unserialize_field(cr, uid, pool_obj, data,
self.unserialize_field(
cr, uid, pool_obj, data,
this.serialization_field_id.name,
this.name, context=context)
offset += 1
@ -98,7 +100,7 @@ class ir_model_fields(orm.Model):
serialization_field_name, field_name,
context=None):
serialized_values = read_record[serialization_field_name]
if not field_name in serialized_values:
if field_name not in serialized_values:
return False
value = serialized_values.pop(field_name)
@ -112,4 +114,3 @@ class ir_model_fields(orm.Model):
serialization_field_name: serialized_values,
},
context=context)

2
view_groups_id/__init__.py

@ -19,4 +19,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import model
from . import model

5
view_groups_id/__openerp__.py

@ -19,7 +19,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'group_ids for ir.ui.view',
'version': '1.0',
@ -40,13 +39,9 @@
"depends": [
'base',
],
'css': [
],
'data': [
'view/ir_ui_view.xml',
],
'js': [
],
'installable': True,
'active': False,
'certificate': '',

2
view_groups_id/model/__init__.py

@ -19,4 +19,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import ir_ui_view
from . import ir_ui_view

14
view_groups_id/model/ir_ui_view.py

@ -44,12 +44,14 @@ class ir_ui_view(Model):
user_groups = frozenset(self.pool.get('res.users').browse(
cr, SUPERUSER_ID, uid, context).groups_id)
view_ids = [v[1] for v in
super(ir_ui_view, self).get_inheriting_views_arch(
cr, uid, view_id, model, context=context)]
view_ids = [
v[1] for v in super(ir_ui_view, self).get_inheriting_views_arch(
cr, uid, view_id, model, context=context)
]
# filter views based on user groups
return [(view.arch, view.id)
return [
(view.arch, view.id)
for view in self.browse(cr, SUPERUSER_ID, view_ids, context)
if not (view.groups_id and
user_groups.isdisjoint(view.groups_id))]
if not (view.groups_id and user_groups.isdisjoint(view.groups_id))
]
Loading…
Cancel
Save