diff --git a/.travis.yml b/.travis.yml index 3492814e9..881318d20 100644 --- a/.travis.yml +++ b/.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 diff --git a/dbfilter_from_header/__init__.py b/dbfilter_from_header/__init__.py index e4a4a78f1..78fcf0a8c 100644 --- a/dbfilter_from_header/__init__.py +++ b/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 diff --git a/dbfilter_from_header/__openerp__.py b/dbfilter_from_header/__openerp__.py index 7baf1f9e7..4570e55d5 100644 --- a/dbfilter_from_header/__openerp__.py +++ b/dbfilter_from_header/__openerp__.py @@ -19,14 +19,14 @@ # ############################################################################## { - "name" : "dbfilter_from_header", - "version" : "1.0", - "author" : "Therp BV", + "name": "dbfilter_from_header", + "version": "1.0", + "author": "Therp BV", "complexity": "normal", "description": """ This addon lets you pass a dbfilter as a HTTP header. - This is interesting for setups where database names can't be mapped to + This is interesting for setups where database names can't be mapped to proxied host names. In nginx, use @@ -34,11 +34,11 @@ The addon has to be loaded as server-wide module. """, - "category" : "Tools", - "depends" : [ + "category": "Tools", + "depends": [ 'web', ], - "data" : [ + "data": [ ], "js": [ ], @@ -46,7 +46,7 @@ ], "auto_install": False, "installable": True, - "external_dependencies" : { - 'python' : [], + "external_dependencies": { + 'python': [], }, } diff --git a/email_template_template/__init__.py b/email_template_template/__init__.py index 16e8b082f..9186ee3ad 100644 --- a/email_template_template/__init__.py +++ b/email_template_template/__init__.py @@ -1 +1 @@ -import model +from . import model diff --git a/email_template_template/__openerp__.py b/email_template_template/__openerp__.py index 05818916b..3b7b942a1 100644 --- a/email_template_template/__openerp__.py +++ b/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 diff --git a/email_template_template/model/__init__.py b/email_template_template/model/__init__.py index 4f09daed4..c526fd7c1 100644 --- a/email_template_template/model/__init__.py +++ b/email_template_template/model/__init__.py @@ -18,4 +18,4 @@ # along with this program. If not, see . # ############################################################################## -import email_template +from . import email_template diff --git a/email_template_template/model/email_template.py b/email_template_template/model/email_template.py index 6b7817b3c..27bf8c1f6 100644 --- a/email_template_template/model/email_template.py +++ b/email_template_template/model/email_template.py @@ -27,7 +27,7 @@ class email_template(Model): def _get_is_template_template(self, cr, uid, ids, fields_name, arg, context=None): - cr.execute('''select + cr.execute('''select id, (select count(*) > 0 from email_template e where email_template_id=email_template.id) from email_template @@ -39,18 +39,19 @@ class email_template(Model): 'is_template_template': fields.function( _get_is_template_template, type='boolean', string='Is a template template'), - } + } 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: for field in ['body_html', 'body_text']: if this[field] and this.email_template_id[field]: this._data[this.id][field] = self.render_template( - cr, uid, this.email_template_id[field], - this.email_template_id.model, - this.id, this._context) + cr, uid, this.email_template_id[field], + this.email_template_id.model, + this.id, this._context) return this diff --git a/fetchmail_attach_from_folder/__init__.py b/fetchmail_attach_from_folder/__init__.py index 1c91fe478..672edbb4e 100644 --- a/fetchmail_attach_from_folder/__init__.py +++ b/fetchmail_attach_from_folder/__init__.py @@ -19,7 +19,6 @@ # along with this program. If not, see . # ############################################################################## - -import match_algorithm -import model -import wizard +from . import match_algorithm +from . import model +from . import wizard diff --git a/fetchmail_attach_from_folder/__openerp__.py b/fetchmail_attach_from_folder/__openerp__.py index e643f0962..6e16b690a 100644 --- a/fetchmail_attach_from_folder/__openerp__.py +++ b/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. @@ -38,7 +39,7 @@ 'view/fetchmail_server.xml', 'wizard/attach_mail_manually.xml', 'security/ir.model.access.csv', - ], + ], 'js': [], 'installable': True, 'active': False, diff --git a/fetchmail_attach_from_folder/match_algorithm/__init__.py b/fetchmail_attach_from_folder/match_algorithm/__init__.py index ff3610863..bc9a39eee 100644 --- a/fetchmail_attach_from_folder/match_algorithm/__init__.py +++ b/fetchmail_attach_from_folder/match_algorithm/__init__.py @@ -19,8 +19,7 @@ # along with this program. If not, see . # ############################################################################## - -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 diff --git a/fetchmail_attach_from_folder/match_algorithm/base.py b/fetchmail_attach_from_folder/match_algorithm/base.py index 5116c929a..87c3df678 100644 --- a/fetchmail_attach_from_folder/match_algorithm/base.py +++ b/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) diff --git a/fetchmail_attach_from_folder/match_algorithm/email_domain.py b/fetchmail_attach_from_folder/match_algorithm/email_domain.py index 66ab66286..80476c565 100644 --- a/fetchmail_attach_from_folder/match_algorithm/email_domain.py +++ b/fetchmail_attach_from_folder/match_algorithm/email_domain.py @@ -19,8 +19,8 @@ # along with this program. If not, see . # ############################################################################## +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. @@ -29,16 +29,16 @@ class email_domain(email_exact): def search_matches(self, cr, uid, conf, mail_message, mail_message_org): ids = super(email_domain, self).search_matches( - cr, uid, conf, mail_message, mail_message_org) + cr, uid, conf, mail_message, mail_message_org) if not ids: domains = [] for addr in self._get_mailaddresses(conf, mail_message): domains.append(addr.split('@')[-1]) ids = conf.pool.get(conf.model_id.model).search( - cr, uid, - self._get_mailaddress_search_domain( - conf, mail_message, - operator='like', - values=['%@'+domain for domain in set(domains)]), - order=conf.model_order) + cr, uid, + self._get_mailaddress_search_domain( + conf, mail_message, + operator='like', + values=['%@' + domain for domain in set(domains)]), + order=conf.model_order) return ids diff --git a/fetchmail_attach_from_folder/match_algorithm/email_exact.py b/fetchmail_attach_from_folder/match_algorithm/email_exact.py index b3fabaf5e..637083793 100644 --- a/fetchmail_attach_from_folder/match_algorithm/email_exact.py +++ b/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''' @@ -36,17 +37,17 @@ class email_exact(base): for field in fields: if field in mail_message: mailaddresses += to_email(mail_message[field]) - return [ addr.lower() for addr in mailaddresses ] + return [addr.lower() for addr in mailaddresses] def _get_mailaddress_search_domain( self, conf, mail_message, operator='=', values=None): mailaddresses = values or self._get_mailaddresses( - conf, mail_message) + conf, mail_message) if not mailaddresses: return [(0, '=', 1)] search_domain = ((['|'] * (len(mailaddresses) - 1)) + [ - (conf.model_field, operator, addr) for addr in mailaddresses] + - safe_eval(conf.domain or '[]')) + (conf.model_field, operator, addr) for addr in mailaddresses] + + safe_eval(conf.domain or '[]')) return search_domain def search_matches(self, cr, uid, conf, mail_message, mail_message_org): diff --git a/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py b/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py index 24a233d0d..95e49e9f5 100644 --- a/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py +++ b/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py @@ -19,17 +19,17 @@ # along with this program. If not, see . # ############################################################################## +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''' @@ -39,11 +39,11 @@ class openerp_standard(base): self, cr, uid, connection, object_id, folder, mail_message, mail_message_org, msgid, context): result = folder.pool.get('mail.thread').message_process( - cr, uid, - folder.model_id.model, mail_message_org, - save_original=folder.server_id.original, - strip_attachments=(not folder.server_id.attach), - context=context) + cr, uid, + folder.model_id.model, mail_message_org, + save_original=folder.server_id.original, + strip_attachments=(not folder.server_id.attach), + context=context) if folder.delete_matching: connection.store(msgid, '+FLAGS', '\\DELETED') diff --git a/fetchmail_attach_from_folder/model/__init__.py b/fetchmail_attach_from_folder/model/__init__.py index d7e030949..85693e3c0 100644 --- a/fetchmail_attach_from_folder/model/__init__.py +++ b/fetchmail_attach_from_folder/model/__init__.py @@ -19,6 +19,5 @@ # along with this program. If not, see . # ############################################################################## - -import fetchmail_server -import fetchmail_server_folder +from . import fetchmail_server +from . import fetchmail_server_folder diff --git a/fetchmail_attach_from_folder/model/fetchmail_server.py b/fetchmail_attach_from_folder/model/fetchmail_server.py index ddc43ed05..efd5262d4 100644 --- a/fetchmail_attach_from_folder/model/fetchmail_server.py +++ b/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): @@ -36,7 +35,7 @@ class fetchmail_server(Model): _columns = { 'folder_ids': fields.one2many( - 'fetchmail.server.folder', 'server_id', 'Folders'), + 'fetchmail.server.folder', 'server_id', 'Folders'), } _defaults = { @@ -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, @@ -96,22 +95,23 @@ class fetchmail_server(Model): if connection.select(folder.path)[0] != 'OK': logger.error( 'Could not open mailbox %s on %s' % ( - folder.path, this.server)) + folder.path, this.server)) connection.select() continue result, msgids = this.get_msgids(connection) if result != 'OK': logger.error( 'Could not search mailbox %s on %s' % ( - folder.path, this.server)) + folder.path, this.server)) continue for msgid in msgids[0].split(): matched_object_ids += this.apply_matching( - connection, folder, msgid, match_algorithm) + connection, folder, msgid, match_algorithm) - logger.info('finished checking for emails in %s server %s', - folder.path, this.name) + 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", @@ -180,48 +181,48 @@ class fetchmail_server(Model): partner_id = self.pool.get( folder.model_id.model).browse( cr, uid, object_id, context - ).partner_id.id + ).partner_id.id - attachments=[] + attachments = [] if this.attach and mail_message.get('attachments'): for attachment in mail_message['attachments']: fname, fcontent = attachment if isinstance(fcontent, unicode): fcontent = fcontent.encode('utf-8') data_attach = { - 'name': fname, - 'datas': base64.b64encode(str(fcontent)), - 'datas_fname': fname, - 'description': _('Mail attachment'), - 'res_model': folder.model_id.model, - 'res_id': object_id, - } + 'name': fname, + 'datas': base64.b64encode(str(fcontent)), + 'datas_fname': fname, + 'description': _('Mail attachment'), + 'res_model': folder.model_id.model, + 'res_id': object_id, + } attachments.append( self.pool.get('ir.attachment').create( cr, uid, data_attach, context=context)) mail_message_ids.append( - self.pool.get('mail.message').create( - cr, uid, - { - 'partner_id': partner_id, - 'model': folder.model_id.model, - 'res_id': object_id, - 'body_text': mail_message.get('body'), - 'body_html': mail_message.get('body_html'), - 'subject': mail_message.get('subject') or '', - 'email_to': mail_message.get('to'), - 'email_from': mail_message.get('from'), - 'email_cc': mail_message.get('cc'), - 'reply_to': mail_message.get('reply'), - 'date': mail_message.get('date'), - 'message_id': mail_message.get('message-id'), - 'subtype': mail_message.get('subtype'), - 'headers': mail_message.get('headers'), - 'state': folder.msg_state, - 'attachment_ids': [(6, 0, attachments)], - }, - context)) + self.pool.get('mail.message').create( + cr, uid, + { + 'partner_id': partner_id, + 'model': folder.model_id.model, + 'res_id': object_id, + 'body_text': mail_message.get('body'), + 'body_html': mail_message.get('body_html'), + 'subject': mail_message.get('subject') or '', + 'email_to': mail_message.get('to'), + 'email_from': mail_message.get('from'), + 'email_cc': mail_message.get('cc'), + 'reply_to': mail_message.get('reply'), + 'date': mail_message.get('date'), + 'message_id': mail_message.get('message-id'), + 'subtype': mail_message.get('subtype'), + 'headers': mail_message.get('headers'), + 'state': folder.msg_state, + 'attachment_ids': [(6, 0, attachments)], + }, + context)) if folder.delete_matching: connection.store(msgid, '+FLAGS', '\\DELETED') diff --git a/fetchmail_attach_from_folder/model/fetchmail_server_folder.py b/fetchmail_attach_from_folder/model/fetchmail_server_folder.py index ea0c07a7b..a54d3255f 100644 --- a/fetchmail_attach_from_folder/model/fetchmail_server_folder.py +++ b/fetchmail_attach_from_folder/model/fetchmail_server_folder.py @@ -31,9 +31,10 @@ class fetchmail_server_folder(Model): def _get_match_algorithms(self): def get_all_subclasses(cls): - return cls.__subclasses__() + [subsub - for sub in cls.__subclasses__() - for subsub in get_all_subclasses(sub)] + 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( match_algorithm.base.base)]) @@ -47,55 +48,55 @@ class fetchmail_server_folder(Model): _columns = { 'sequence': fields.integer('Sequence'), 'path': fields.char( - 'Path', size=256, help='The path to your mail ' - "folder. Typically would be something like 'INBOX.myfolder'", - required=True), + 'Path', size=256, help='The path to your mail ' + "folder. Typically would be something like 'INBOX.myfolder'", + required=True), 'model_id': fields.many2one( - 'ir.model', 'Model', required=True, - help='The model to attach emails to'), + 'ir.model', 'Model', required=True, + help='The model to attach emails to'), 'model_field': fields.char( - 'Field (model)', size=128, - help='The field in your model that contains the field to match ' - 'against.\n' - 'Examples:\n' - "'email' if your model is res.partner, or " - "'partner_id.email' if you're matching sale orders"), + 'Field (model)', size=128, + help='The field in your model that contains the field to match ' + 'against.\n' + 'Examples:\n' + "'email' if your model is res.partner, or " + "'partner_id.email' if you're matching sale orders"), 'model_order': fields.char( - 'Order (model)', size=128, - help='Fields to order by, this mostly useful in conjunction ' - "with 'Use 1st match'"), + 'Order (model)', size=128, + help='Fields to order by, this mostly useful in conjunction ' + "with 'Use 1st match'"), 'match_algorithm': fields.selection( - _get_match_algorithms_sel, - 'Match algorithm', required=True, translate=True, - help='The algorithm used to determine which object an email ' - 'matches.'), + _get_match_algorithms_sel, + 'Match algorithm', required=True, translate=True, + help='The algorithm used to determine which object an email ' + 'matches.'), 'mail_field': fields.char( - 'Field (email)', size=128, - help='The field in the email used for matching. Typically ' - "this is 'to' or 'from'"), + 'Field (email)', size=128, + help='The field in the email used for matching. Typically ' + "this is 'to' or 'from'"), 'server_id': fields.many2one('fetchmail.server', 'Server'), 'delete_matching': fields.boolean( - 'Delete matches', - help='Delete matched emails from server'), + 'Delete matches', + help='Delete matched emails from server'), 'flag_nonmatching': fields.boolean( - 'Flag nonmatching', - help="Flag emails in the server that don't match any object " - 'in OpenERP'), + 'Flag nonmatching', + help="Flag emails in the server that don't match any object " + 'in OpenERP'), 'match_first': fields.boolean( - 'Use 1st match', - help='If there are multiple matches, use the first one. If ' - 'not checked, multiple matches count as no match at all'), + 'Use 1st match', + help='If there are multiple matches, use the first one. If ' + 'not checked, multiple matches count as no match at all'), 'domain': fields.char( - 'Domain', size=128, help='Fill in a search ' - 'filter to narrow down objects to match'), + 'Domain', size=128, help='Fill in a search ' + 'filter to narrow down objects to match'), 'msg_state': fields.selection( - [ - ('sent', 'Sent'), - ('received', 'Received'), - ], - 'Message state', - help='The state messages fetched from this folder should be ' - 'assigned in OpenERP'), + [ + ('sent', 'Sent'), + ('received', 'Received'), + ], + 'Message state', + help='The state messages fetched from this folder should be ' + 'assigned in OpenERP'), } _defaults = { diff --git a/fetchmail_attach_from_folder/wizard/__init__.py b/fetchmail_attach_from_folder/wizard/__init__.py index 376a5b392..3f6e3da54 100644 --- a/fetchmail_attach_from_folder/wizard/__init__.py +++ b/fetchmail_attach_from_folder/wizard/__init__.py @@ -19,5 +19,4 @@ # along with this program. If not, see . # ############################################################################## - -import attach_mail_manually +from . import attach_mail_manually diff --git a/fetchmail_attach_from_folder/wizard/attach_mail_manually.py b/fetchmail_attach_from_folder/wizard/attach_mail_manually.py index 7d03e75d7..fa10d01f5 100644 --- a/fetchmail_attach_from_folder/wizard/attach_mail_manually.py +++ b/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,46 +29,53 @@ class attach_mail_manually(TransientModel): _name = 'fetchmail.attach.mail.manually' _columns = { - 'folder_id': fields.many2one('fetchmail.server.folder', 'Folder', - readonly=True), - 'mail_ids': fields.one2many( - 'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'), - } + 'folder_id': fields.many2one( + 'fetchmail.server.folder', 'Folder', readonly=True), + 'mail_ids': fields.one2many( + 'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'), + } def default_get(self, cr, uid, fields_list, context=None): 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): - defaults['mail_ids']=[] + 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, - 'FLAGGED' if folder.flag_nonmatching else 'UNDELETED') + 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)] + attach_mail_manually_mail._columns['object_id'].selection = [ + (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, { - 'msgid': msgid, - 'subject': mail_message.get('subject', ''), - 'date': mail_message.get('date', ''), - 'object_id': folder.model_id.model+',False' - })) + msgdata[0][1]) + defaults['mail_ids'].append( + (0, 0, + { + 'msgid': msgid, + 'subject': mail_message.get('subject', ''), + 'date': mail_message.get('date', ''), + 'object_id': folder.model_id.model + ',False' + })) connection.close() return defaults @@ -77,34 +85,40 @@ class attach_mail_manually(TransientModel): for mail in this.mail_ids: connection = this.folder_id.server_id.connect() 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)) - continue - - mail_message = self.pool.get('mail.message').parse_message( - msgdata[0][1], this.folder_id.server_id.original) + result, msgdata = connection.fetch(mail.msgid, '(RFC822)') + if result != 'OK': + logging.error( + 'Could not fetch %s in %s on %s', + mail.msgid, this.folder_id.path, + this.folder_id.server_id.server) + continue - this.folder_id.server_id.attach_mail(connection, - mail.object_id.id, this.folder_id, mail_message, - mail.msgid) + 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, + 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), - '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', - 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), - } + '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', + 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), + } diff --git a/mail_client_view/__init__.py b/mail_client_view/__init__.py index 1483b2269..ecadcc3c2 100644 --- a/mail_client_view/__init__.py +++ b/mail_client_view/__init__.py @@ -19,4 +19,4 @@ # along with this program. If not, see . # ############################################################################## -import model +from . import model diff --git a/mail_client_view/__openerp__.py b/mail_client_view/__openerp__.py index a9fbdb959..b00cef277 100644 --- a/mail_client_view/__openerp__.py +++ b/mail_client_view/__openerp__.py @@ -27,7 +27,7 @@ Adds a menu to the customer address book that enables ordinary users to look at customer or other mail. Also adds an 'action needed' boolean to mail messages, to quickly select all mails that still have to be acted on. - + The action_needed flag will be shown to users in a tree view as a red circle, no action needed will be green. In a form users either have the button 'confirm action done' (if action needed), or the button 'set @@ -40,7 +40,7 @@ 'data': [ 'view/mail_user_menu.xml', 'view/mail_user_view.xml', - ], + ], 'js': [], 'installable': True, 'active': False, diff --git a/mail_client_view/model/__init__.py b/mail_client_view/model/__init__.py index afbe2318c..a2bc21ba5 100644 --- a/mail_client_view/model/__init__.py +++ b/mail_client_view/model/__init__.py @@ -1 +1 @@ -import mail_message +from . import mail_message diff --git a/mail_client_view/model/mail_message.py b/mail_client_view/model/mail_message.py index eb5fdd5ba..e2761dda7 100644 --- a/mail_client_view/model/mail_message.py +++ b/mail_client_view/model/mail_message.py @@ -13,7 +13,7 @@ from openerp.osv import fields class mail_message(Model): '''Extend mail_message with action_needed flag''' _inherit = 'mail.message' - + def set_action_needed_off(self, cr, user, ids, context=None): self.write(cr, user, ids, {'action_needed': False}, context=context) return True @@ -21,19 +21,20 @@ class mail_message(Model): def set_action_needed_on(self, cr, user, ids, context=None): self.write(cr, user, ids, {'action_needed': True}, context=context) return True - + 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) - and ('state' in vals) and (vals['state'] == 'received')): + 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( cr, user, vals, context=context) 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.'), } diff --git a/mail_environment/__openerp__.py b/mail_environment/__openerp__.py index 5da871afb..8ccaae570 100644 --- a/mail_environment/__openerp__.py +++ b/mail_environment/__openerp__.py @@ -26,15 +26,17 @@ '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 : [outgoing_mail] smtp_host = smtp.myserver.com smtp_port = 587 -smtp_user = +smtp_user = smtp_pass = smtp_encryption = ssl @@ -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': [], diff --git a/mail_environment/env_mail.py b/mail_environment/env_mail.py index 59d5f5fe9..921f27e54 100644 --- a/mail_environment/env_mail.py +++ b/mail_environment/env_mail.py @@ -27,7 +27,7 @@ from server_environment import serv_config class IrMail(osv.osv): _inherit = "ir.mail_server" - + def _get_smtp_conf(self, cursor, uid, ids, name, args, context=None): """ Return configuration @@ -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)) @@ -52,7 +53,7 @@ class IrMail(osv.osv): return res _columns = { - 'smtp_host': fields.function(_get_smtp_conf, + 'smtp_host': fields.function(_get_smtp_conf, method=True, string='SMTP Server', type="char", @@ -63,33 +64,40 @@ 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, - 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)} - + '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), + } + 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, - 'is_ssl': lambda a: bool(int(a)), - 'attach': lambda a: bool(int(a)), - 'original': lambda a: bool(int(a)),} + key_types = { + 'port': int, + 'is_ssl': lambda a: bool(int(a)), + 'attach': 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', @@ -181,4 +199,4 @@ class FetchmailServer(osv.osv): type="char", multi='income_mail_config', size=64)} -FetchmailServer() +FetchmailServer() diff --git a/mass_editing/__init__.py b/mass_editing/__init__.py index 448eb3c9f..85f8b6dd8 100644 --- a/mass_editing/__init__.py +++ b/mass_editing/__init__.py @@ -2,7 +2,8 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2012 Serpent Consulting Services () +# Copyright (C) 2012 Serpent Consulting Services +# () # Copyright (C) 2010-Today OpenERP SA () # # 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: - diff --git a/mass_editing/__openerp__.py b/mass_editing/__openerp__.py index 406caa2f2..8f7611bbf 100644 --- a/mass_editing/__openerp__.py +++ b/mass_editing/__openerp__.py @@ -2,7 +2,8 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2012 Serpent Consulting Services () +# Copyright (C) 2012 Serpent Consulting Services +# () # Copyright (C) 2010-Today OpenERP SA () # # This program is free software: you can redistribute it and/or modify @@ -19,19 +20,19 @@ # along with this program. If not, see # ############################################################################## - - { - "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. - You can configure mass editing for any OpenERP model. + "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. + 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': [], diff --git a/mass_editing/mass_editing.py b/mass_editing/mass_editing.py index aa1c4a9c4..3b7c9a4f6 100644 --- a/mass_editing/mass_editing.py +++ b/mass_editing/mass_editing.py @@ -2,7 +2,8 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2012 Serpent Consulting Services () +# Copyright (C) 2012 Serpent Consulting Services +# () # Copyright (C) 2010-Today OpenERP SA () # # This program is free software: you can redistribute it and/or modify @@ -19,23 +20,27 @@ # along with this program. If not, see # ############################################################################## - - 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, - 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, - help="Sidebar button to open the sidebar action"), + '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, + 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, + 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,44 +62,57 @@ 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, { - 'name': button_name, - 'type': 'ir.actions.act_window', - 'res_model': 'mass.editing.wizard', - 'src_model': src_obj, - 'view_type': 'form', - 'context': "{'mass_editing_object' : %d}" % (data.id), - 'view_mode':'form,tree', - 'target': 'new', - 'auto_refresh':1 - }, 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']), - 'object': True, - }, 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) + vals['ref_ir_act_window'] = action_obj.create( + cr, uid, + { + 'name': button_name, + 'type': 'ir.actions.act_window', + 'res_model': 'mass.editing.wizard', + 'src_model': src_obj, + 'view_type': 'form', + 'context': "{'mass_editing_object' : %d}" % (data.id), + 'view_mode': 'form,tree', + 'target': 'new', + 'auto_refresh': 1 + }, + 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']), + 'object': True, + }, + 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) 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): diff --git a/mass_editing/wizard/__init__.py b/mass_editing/wizard/__init__.py index 61983e5c5..d11a4208d 100644 --- a/mass_editing/wizard/__init__.py +++ b/mass_editing/wizard/__init__.py @@ -2,7 +2,8 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2012 Serpent Consulting Services () +# Copyright (C) 2012 Serpent Consulting Services +# () # Copyright (C) 2010-Today OpenERP SA () # # 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: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/mass_editing/wizard/mass_editing_wizard.py b/mass_editing/wizard/mass_editing_wizard.py index 910aa4791..8fc8a526e 100644 --- a/mass_editing/wizard/mass_editing_wizard.py +++ b/mass_editing/wizard/mass_editing_wizard.py @@ -2,7 +2,8 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2012 Serpent Consulting Services () +# Copyright (C) 2012 Serpent Consulting Services +# () # Copyright (C) 2010-Today OpenERP SA () # # 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) + mass_object = self.pool.get('mass.object') + 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,12 +294,13 @@ 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 def action_apply(self, cr, uid, ids, context=None): - return {'type': 'ir.actions.act_window_close'} + return {'type': 'ir.actions.act_window_close'} mass_editing_wizard() diff --git a/security_protector/__init__.py b/security_protector/__init__.py index fca2713dc..383ae8ffc 100644 --- a/security_protector/__init__.py +++ b/security_protector/__init__.py @@ -1 +1 @@ -from . import security_protector \ No newline at end of file +from . import security_protector diff --git a/security_protector/__openerp__.py b/security_protector/__openerp__.py index 6cd3bb183..fce7d079f 100644 --- a/security_protector/__openerp__.py +++ b/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', diff --git a/security_protector/security_protector.py b/security_protector/security_protector.py index b082d16f4..98aaa8764 100644 --- a/security_protector/security_protector.py +++ b/security_protector/security_protector.py @@ -3,45 +3,50 @@ # # 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" _name = 'ir.model.access' _inherit = "ir.model.access" - + 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 - + def write(self, cr, uid, ids, vals, context=None): - res =True + 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, - 'perm_write': False, - 'perm_unlink': False, - 'perm_create': False} - super(IrModelAccess, self).write(cr, uid, ids, vals, context=context) - else: - res = super(IrModelAccess, self).unlink(cr, uid, ids, context=context) + if self._acces_can_be_modified(cr, uid, context=context): + vals = { + 'perm_read': False, + 'perm_write': False, + 'perm_unlink': False, + 'perm_create': False + } + super(IrModelAccess, self).write( + cr, uid, ids, vals, context=context) + else: + res = super(IrModelAccess, self).unlink( + cr, uid, ids, context=context) return res - -IrModelAccess() \ No newline at end of file + +IrModelAccess() diff --git a/server_env_base_external_referentials/__init__.py b/server_env_base_external_referentials/__init__.py index 3934b6ed9..3829d1b8b 100644 --- a/server_env_base_external_referentials/__init__.py +++ b/server_env_base_external_referentials/__init__.py @@ -18,5 +18,4 @@ # along with this program. If not, see . # ############################################################################## - -import base_external_referentials +from . import base_external_referentials diff --git a/server_env_base_external_referentials/__openerp__.py b/server_env_base_external_referentials/__openerp__.py index 9390fa3b1..1f56f0067 100644 --- a/server_env_base_external_referentials/__openerp__.py +++ b/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 : diff --git a/server_env_base_external_referentials/base_external_referentials.py b/server_env_base_external_referentials/base_external_referentials.py index 091df55ee..267263708 100644 --- a/server_env_base_external_referentials/base_external_referentials.py +++ b/server_env_base_external_referentials/base_external_referentials.py @@ -24,31 +24,37 @@ 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, - method=True, string='Location', multi='connection_config'), - '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, - method=True, string='Password', multi='connection_config'), + '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, + method=True, string='User Name', multi='connection_config'), + 'apipass': fields.function( + _get_environment_config_by_name, type='char', size=64, + method=True, string='Password', multi='connection_config'), } external_referential() diff --git a/server_environment/serv_config.py b/server_environment/serv_config.py index 6d9181818..e1a059bf5 100644 --- a/server_environment/serv_config.py +++ b/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 @@ -46,14 +46,17 @@ if not system_base_config.get('running_env', False): ck_path = os.path.join(_dir, system_base_config['running_env']) -if not os.path.exists(ck_path) : +if not os.path.exists(ck_path): raise Exception( "Provided server environment does not exist, " "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',) @@ -170,7 +173,7 @@ class ServerConfiguration(orm.TransientModel): self._arch = etree.fromstring(arch) def fields_view_get(self, cr, uid, view_id=None, view_type='form', - context=None, toolbar=False, submenu=False): + context=None, toolbar=False, submenu=False): """Overwrite the default method to render the custom view.""" res = super(ServerConfiguration, self).fields_view_get(cr, uid, view_id, @@ -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: diff --git a/server_environment_files/__init__.py b/server_environment_files/__init__.py index 31fea2953..98a6c9725 100644 --- a/server_environment_files/__init__.py +++ b/server_environment_files/__init__.py @@ -17,4 +17,4 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -############################################################################## \ No newline at end of file +############################################################################## diff --git a/super_calendar/__init__.py b/super_calendar/__init__.py index 6fe2100cc..a6561e3b0 100644 --- a/super_calendar/__init__.py +++ b/super_calendar/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # Copyright (C) 2012 Agile Business Group sagl () # Copyright (C) 2012 Domsense srl () # @@ -18,4 +18,4 @@ # along with this program. If not, see . # ############################################################################## -import super_calendar +from . import super_calendar diff --git a/super_calendar/__openerp__.py b/super_calendar/__openerp__.py index 16c25ad99..0cf94f798 100644 --- a/super_calendar/__openerp__.py +++ b/super_calendar/__openerp__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # Copyright (C) 2012 Agile Business Group sagl () # Copyright (C) 2012 Domsense srl () # @@ -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,39 +41,48 @@ 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', 'license': 'AGPL-3', - 'depends' : ['base'], - "data" : [ + 'depends': ['base'], + "data": [ 'super_calendar_view.xml', 'cron_data.xml', 'security/ir.model.access.csv', - ], + ], 'demo': [], 'test': [], 'installable': True, diff --git a/super_calendar/super_calendar.py b/super_calendar/super_calendar.py index 356da63c7..caa47d5e1 100644 --- a/super_calendar/super_calendar.py +++ b/super_calendar/super_calendar.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # Copyright (C) 2012 Agile Business Group sagl () # Copyright (C) 2012 Domsense srl () # @@ -27,106 +27,151 @@ 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 = { + _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): configurator_ids = self.search(cr, uid, []) 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]): + 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) - name= mytemplate.render(**parse_dict) + name = mytemplate.render(**parse_dict) 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 class super_calendar_configurator_line(orm.Model): _name = 'super.calendar.configurator.line' - _columns = { + _columns = { '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([ - ('field', 'Field'), - ('code', 'Code'), + '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)]"), - } - + } + class super_calendar(orm.Model): _name = 'super.calendar' - _columns = { + _columns = { 'name': fields.char('Description', size=512, required=True), - 'model_description': fields.char('Model Description', size=128, required=True), - 'date_start':fields.datetime('Start date', required=True), - 'duration':fields.float('Duration'), + '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'), - } + } diff --git a/unserialize_field/__init__.py b/unserialize_field/__init__.py index 81f4e3698..f8874d30d 100644 --- a/unserialize_field/__init__.py +++ b/unserialize_field/__init__.py @@ -19,4 +19,4 @@ # along with this program. If not, see . # ############################################################################## -import ir_model_fields +from . import ir_model_fields diff --git a/unserialize_field/ir_model_fields.py b/unserialize_field/ir_model_fields.py index c5b5699f3..b547313f5 100644 --- a/unserialize_field/ir_model_fields.py +++ b/unserialize_field/ir_model_fields.py @@ -42,20 +42,22 @@ class ir_model_fields(orm.Model): context=context) while True: ids = pool_obj.search( - cr, uid, + cr, uid, [(this.serialization_field_id.name, '!=', '{}')], - offset=offset*step, limit=step, context=context) + offset=offset * step, limit=step, context=context) if not ids: break - for data in pool_obj.read(cr, uid, ids, - [this.serialization_field_id.name], - context=context): - self.unserialize_field(cr, uid, pool_obj, data, - this.serialization_field_id.name, - this.name, context=context) - offset += 1 + for data in pool_obj.read( + cr, uid, ids, + [this.serialization_field_id.name], + context=context): + self.unserialize_field( + cr, uid, pool_obj, data, + this.serialization_field_id.name, + this.name, context=context) + offset += 1 finally: - cr.commit = commit_org + cr.commit = commit_org return True @@ -82,7 +84,7 @@ class ir_model_fields(orm.Model): raise orm.except_orm( _("Error"), _("One2many fields are not handled yet")) - + # ORM prohibits to change the 'storing system' of the field cr.execute(""" UPDATE ir_model_fields @@ -98,18 +100,17 @@ 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) + value = serialized_values.pop(field_name) if pool_obj._columns[field_name]._type in ('many2many', 'one2many'): value = [(6, 0, value)] return pool_obj.write( - cr, uid, read_record['id'], - { - field_name: value, - serialization_field_name: serialized_values, - }, - context=context) - + cr, uid, read_record['id'], + { + field_name: value, + serialization_field_name: serialized_values, + }, + context=context) diff --git a/view_groups_id/__init__.py b/view_groups_id/__init__.py index 1483b2269..ecadcc3c2 100644 --- a/view_groups_id/__init__.py +++ b/view_groups_id/__init__.py @@ -19,4 +19,4 @@ # along with this program. If not, see . # ############################################################################## -import model +from . import model diff --git a/view_groups_id/__openerp__.py b/view_groups_id/__openerp__.py index 0ebec9eca..93f0d8194 100644 --- a/view_groups_id/__openerp__.py +++ b/view_groups_id/__openerp__.py @@ -19,13 +19,12 @@ # along with this program. If not, see . # ############################################################################## - { 'name': 'group_ids for ir.ui.view', 'version': '1.0', 'description': """This addon is a backport of OpenERP 7.0's groups_id for views. - + The greatness lies in the fact that with that, you can have specific inherited views for specific groups, so you can radically change a view for some groups without having to redefine any of the window actions @@ -39,14 +38,10 @@ "category": "Dependency", "depends": [ 'base', - ], - 'css': [ - ], + ], 'data': [ 'view/ir_ui_view.xml', - ], - 'js': [ - ], + ], 'installable': True, 'active': False, 'certificate': '', diff --git a/view_groups_id/model/__init__.py b/view_groups_id/model/__init__.py index c950c9172..3982f86fd 100644 --- a/view_groups_id/model/__init__.py +++ b/view_groups_id/model/__init__.py @@ -19,4 +19,4 @@ # along with this program. If not, see . # ############################################################################## -import ir_ui_view +from . import ir_ui_view diff --git a/view_groups_id/model/ir_ui_view.py b/view_groups_id/model/ir_ui_view.py index 3121c9e6f..44af319be 100644 --- a/view_groups_id/model/ir_ui_view.py +++ b/view_groups_id/model/ir_ui_view.py @@ -33,23 +33,25 @@ class ir_ui_view(Model): _inherit = 'ir.ui.view' _columns = { - 'groups_id': fields.many2many( - 'res.groups', 'ir_ui_view_group_rel', 'view_id', 'group_id', - string='Groups', help="If this field is empty, the view " - "applies to all users. Otherwise, the view applies to the " - "users of those groups only."), - } + 'groups_id': fields.many2many( + 'res.groups', 'ir_ui_view_group_rel', 'view_id', 'group_id', + string='Groups', help="If this field is empty, the view " + "applies to all users. Otherwise, the view applies to the " + "users of those groups only."), + } def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None): 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) - for view in self.browse(cr, SUPERUSER_ID, view_ids, context) - if not (view.groups_id and - user_groups.isdisjoint(view.groups_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)) + ]