class Module(models.Model): _name = 'builder.ir.module.module' @api.model def _get_categories(self): return [(c.name, c.name) for c in self.env['ir.module.category'].search([])] name = fields.Char("Technical Name", required=True, select=True) category_id = fields.Selection(simple_selection('ir.module.category', 'name') , 'Category') shortdesc = fields.Char('Module Name', translate=True, required=True) summary = fields.Char('Summary', translate=True) description = fields.Text("Description", translate=True) description_html = fields.Html(string='Description HTML', sanitize=False) author = fields.Char("Author", required=True) maintainer = fields.Char('Maintainer') contributors = fields.Text('Contributors') website = fields.Char("Website") version = fields.Char('Version', default='0.1') mirror = fields.Text('CodeMirror') url = fields.Char('URL') sequence = fields.Integer('Sequence') # dependencies_id = fields.One2many('programming.module.dependency', 'module_id', 'Dependencies') auto_install = fields.Boolean('Automatic Installation', help='An auto-installable module is automatically installed by the ' 'system when all its dependencies are satisfied. ' 'If the module has no dependency, it is always installed.') license = fields.Selection([ ('GPL-2', 'GPL Version 2'), ('GPL-2 or any later version', 'GPL-2 or later version'), ('GPL-3', 'GPL Version 3'), ('GPL-3 or any later version', 'GPL-3 or later version'), ('AGPL-3', 'Affero GPL-3'), ('Other OSI approved licence', 'Other OSI Approved Licence'), ('Other proprietary', 'Other Proprietary') ], string='License', default='AGPL-3') application = fields.Boolean('Application') icon_image = fields.Binary(string='Icon') icon_image_name = fields.Char('Icon Filename') menus_by_module = fields.Text(string='Menus') reports_by_module = fields.Text(string='Reports') views_by_module = fields.Text(string='Views') demo = fields.Boolean('Has Demo Data') post_install_action = fields.Reference([ ('builder.ir.actions.act_window', 'Window'), # ('builder.ir.actions.act_url', 'URL'), ], 'After Install Action') models_count = fields.Integer("Models Count", compute='_compute_models_count', store=False, search=True) dependency_ids = fields.One2many( comodel_name='builder.ir.module.dependency', inverse_name='module_id', string='Dependencies', copy=True ) model_ids = fields.One2many('builder.ir.model', 'module_id', 'Models', copy=True) view_ids = fields.One2many('builder.ir.ui.view', 'module_id', 'Views', copy=True) menu_ids = fields.One2many('builder.ir.ui.menu', 'module_id', 'Menus', copy=True) group_ids = fields.One2many('builder.res.groups', 'module_id', 'Groups', copy=True) model_access_ids = fields.One2many('builder.ir.model.access', 'module_id', 'ACLs', copy=True) rule_ids = fields.One2many('builder.ir.rule', 'module_id', 'Rules', copy=True) cron_job_ids = fields.One2many('builder.ir.cron', 'module_id', 'Cron Jobs', copy=True) action_ids = fields.One2many('builder.ir.actions.actions', 'module_id', 'Actions', copy=True) action_window_ids = fields.One2many('builder.ir.actions.act_window', 'module_id', 'Window Actions', copy=True) action_url_ids = fields.One2many('builder.ir.actions.act_url', 'module_id', 'URL Actions', copy=True) workflow_ids = fields.One2many('builder.workflow', 'module_id', 'Workflows', copy=True) backend_asset_ids = fields.One2many('builder.web.asset', 'module_id', 'Assets', copy=True) data_file_ids = fields.One2many('builder.data.file', 'module_id', 'Data Files', copy=True) snippet_bookmarklet_url = fields.Char('Link', compute='_compute_snippet_bookmarklet_url') @api.model def _get_default_author(self): return self.env.user.name if self.env.user else None _defaults = { 'author': _get_default_author } @api.one def copy(self, default=None): default = dict(default or {}) default['shortdesc'] = _('%s (copy)') % self.shortdesc return super(Module, self).copy(default) @api.onchange('shortdesc') def _compute_name(self): if not self.name and self.shortdesc: self.name = self.shortdesc.lower().replace(' ', '_').replace('.', '_') @api.one @api.depends('name') def _compute_snippet_bookmarklet_url(self): base_url = self.env['ir.config_parameter'].get_param('web.base.url') link = """ javascript:(function(){ function script(url, callback){ var new_script = document.createElement('script'); new_script.src = url + '?__stamp=' + Math.random(); new_script.onload = new_script.onreadystatechange = callback; document.getElementsByTagName('head')[0].appendChild(new_script); new_script.type='text/javascript'; }; window.odooUrl = '$base_url'; window.newSnippetUrl = '$base_url/builder/$module/snippet/add'; script('$base_url/builder/static/src/js/snippet_loader.js'); })(); """ self.snippet_bookmarklet_url = Template(link).substitute(base_url=base_url, module=self.name) @api.multi def dependencies_as_list(self): return [str(dep.name) for dep in self.dependency_ids] @api.one def add_dependency(self, names): if not names: return dependency_obj = self.env['builder.ir.module.dependency'] if not isinstance(names, list): names = [names] for name in names: if not dependency_obj.search([('module_id', '=', self.id), ('dependency_module_name', '=', name)]).id: dependency_obj.create({ 'module_id': self.id, 'type': 'manual', 'dependency_module_name': name }) @api.one @api.depends('model_ids') def _compute_models_count(self): self.models_count = len(self.model_ids) @api.multi def action_base_files(self): search = self.env.ref('builder.view_builder_data_file_filter', False) return { 'name': _('Files'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'kanban,tree,form', 'res_model': 'builder.data.file', 'views': [(False, 'kanban'),(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], 'search_view_id': search.id if search else False, # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_models(self): tree_view = self.env.ref('builder.builder_ir_model_tree_view', False) form_view = self.env.ref('builder.builder_ir_model_form_view', False) return { 'name': _('Models'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form,diagram', 'res_model': 'builder.ir.model', 'views': [(tree_view and tree_view.id or False, 'tree'), (form_view and form_view.id or False, 'form')], 'view_id': tree_view and tree_view.id, 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_views(self): tree_view = self.env.ref('builder.builder_ir_ui_view_tree', False) form_view = self.env.ref('builder.builder_ir_ui_view_form', False) return { 'name': _('Views'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.ir.ui.view', 'views': [(tree_view.id if tree_view else False, 'tree'), (form_view.id if form_view else False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_actions(self): return { 'name': _('Actions'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.ir.actions.act_window', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_menus(self): return { 'name': _('Menus'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.ir.ui.menu', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_groups(self): return { 'name': _('Groups'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.res.groups', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_model_access(self): return { 'name': _('Access Control Rules'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.ir.model.access', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_rules(self): return { 'name': _('Model Rules'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.ir.rule', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_workflows(self): return { 'name': _('Workflows'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.workflow', 'views': [(False, 'tree'), (False, 'form'), (False, 'diagram')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_config_models(self): return { 'name': _('Configuration Models'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.res.config.settings', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_cron_jobs(self): return { 'name': _('Cron Jobs'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.ir.cron', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_backend_assets(self): return { 'name': _('Backend Assets'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.web.asset', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_website_pages(self): return { 'name': _('Pages'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.website.page', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_website_assets(self): return { 'name': _('Assets'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.website.asset', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_website_themes(self): return { 'name': _('Themes'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.website.theme', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_website_media_item(self): return { 'name': _('Media Manager'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.website.media.item', 'views': [(False, 'kanban'), (False, 'tree')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_website_menus(self): return { 'name': _('Website Menus'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.website.menu', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_website_snippets(self): return { 'name': _('Snippets'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'builder.website.snippet', 'views': [(False, 'tree'), (False, 'form')], 'domain': [('module_id', '=', self.id)], # 'target': 'current', 'context': { 'default_module_id': self.id }, } @api.multi def action_diagram(self): diagram_view = self.env.ref('builder.view_builder_model_diagram', False) return { 'name': _('UML Diagram'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'diagram', 'res_model': 'builder.ir.module.module', 'views': [(diagram_view and diagram_view.id or False, 'diagram'), ], 'view_id': diagram_view and diagram_view.id, 'res_id': self.id, 'target': 'new', # 'flags': {'form': {'action_buttons': True, 'options': {'mode': 'edit'}}}, 'context': { 'default_module_id': self.id, 'diagram_view': True }, } def action_edit_description_html(self, cr, uid, ids, context=None): if not len(ids) == 1: raise ValueError('One and only one ID allowed for this action') url = '/builder/page/designer?model={model}&res_id={id}&enable_editor=1'.format(id=ids[0], model=self._name) return { 'name': _('Edit Template'), 'type': 'ir.actions.act_url', 'url': url, 'target': 'self', } def import_models(self, model): pass @api.multi def _export_zip(self): return self.get_zipped_module() @api.multi def _export_odoo(self): return json.JsonExport(self.env).export(self) @api.model def _import_odoo(self, importer): return json.JsonImport(self.env).build(self, decodestring(importer.file))
class TestModel(models.Model): _name = 'test.model' _inherit = ['mail.thread'] _columns = {} # deprecated columns _defaults = {} # deprecated defaults length = fields.Integer() # Deprecated length by js errors name = fields.Char( _(u"Näme"), # Don't need translate help=u"My hëlp", required=False, compute='_compute_name', # good compute method name search='_search_name', # good search method name inverse='_inverse_name', # good inverse method name ) # Imported openerp.fields use Char (Upper case) other_field = fields.char( name=_("Other field"), copy=True, compute='my_method_compute', # bad compute method name search='my_method_search', # bad search method name inverse='my_method_inverse', # bad inverse method name ) compute_none = fields.Char(compute=None) other_field2 = fields.char( 'Other Field2', copy=True, ) # This is a inherit overwrite field then don't should show errors related # with creation of fields. def method_date(self): date = fields.Date.to_string( fields.Datetime.context_timestamp(self, timestamp=fields.Datetime.now()) ) return date my_ok_field = fields.Float( "My correctly named field", digits=(6, 6), # OK: Valid field parameter index=True, # OK: Valid field parameter help="My ok field", ) my_ko_field = fields.Float( digits_compute=lambda cr: (6, 6), # Deprecated field parameter select=True, # Deprecated field parameter help="My ko field", string="My Ko Field", # String parameter equal to name of variable ) """The name of the variable is equal to the string parameter Tested all fields.*""" boolean_variable_1 = fields.Boolean(string='Boolean Variable 1', help="Help") boolean_variable_2 = fields.Boolean("Boolean Variable 2", help="Help") char_variable_1 = fields.Char(string='Char Variable 1', help="Help") char_variable_2 = fields.Char("Char Variable 2", help="Help") text_variable_1 = fields.Text(string='Text Variable 1', help="Help") text_variable_2 = fields.Text("Text Variable 2", help="Help") html_variable_1 = fields.Html(string='Html Variable 1', help="Help") html_variable_2 = fields.Html("Html Variable 2", help="Help") integer_variable_1 = fields.Integer(string='Integer Variable 1', help="Help") integer_variable_2 = fields.Integer("Integer Variable 2", help="Help") float_variable_1 = fields.Float(string='Float Variable 1', help="Help") float_variable_2 = fields.Float("Float Variable 2", help="Help") date_variable_1 = fields.Date(string='Date Variable 1', help="Help") date_variable_2 = fields.Date("Date Variable 2", help="Help") date_time_variable_1 = fields.DateTime(string='Date Time Variable 1', help="Help") date_time_variable_2 = fields.DateTime("Date Time Variable 2", help="Help") binary_variable_1 = fields.Binary(string='Binary Variable 1', help="Help") binary_variable_2 = fields.Binary("Binary Variable 2", help="Help") selection_variable_1 = fields.Selection(selection=[('a', 'A')], string='Selection Variable 1', help="Help") selection_variable_2 = fields.Selection([('a', 'A')], "Selection Variable 2", help="Help") reference_variable_1 = fields.Reference(selection=[('res.user', 'User')], string="Reference Variable 1", help="Help") reference_variable_2 = fields.Reference([('res.user', 'User')], "Reference Variable 2", help="Help") many_2_one_variable_1 = fields.Many2one(comodel_name='res.users', string='Many 2 One Variable 1', help="Help") many_2_one_variable_2 = fields.Many2one('res.users', "Many 2 One Variable 2", help="Help") one_2_many_variable_1 = fields.One2many(comodel_name='res.users', inverse_name='rel_id', string='One 2 Many Variable 1', help="Help") one_2_many_variable_2 = fields.One2many('res.users', 'rel_id', "One 2 Many Variable 2", help="Help") many_2_many_variable_1 = fields.Many2many(comodel_name='res.users', relation='table_name', column1='col_name', column2='other_col_name', string='Many 2 Many Variable 1', help="Help") many_2_many_variable_2 = fields.Many2many('res.users', 'table_name', 'col_name', 'other_col_name', "Many 2 Many Variable 2", help="Help") field_case_sensitive = fields.Char( 'Field Case SENSITIVE', help="Field case sensitive" ) name_equal_to_string = fields.Float( "Name equal to string", help="Name Equal To String" ) many_2_one = fields.Many2one( 'res.users', "Many 2 One", help="Many 2 one" ) many_2_many = fields.Many2many( 'res.users', 'relation', 'fk_column_from', 'fk_column_to', "Many 2 many", help="Many 2 Many" ) def my_method1(self, variable1): # Shouldn't show error of field-argument-translate self.my_method2(_('hello world')) # Message post without translation function self.message_post(subject='Subject not translatable', body='Body not translatable %s' % variable1) self.message_post(subject='Subject not translatable %(variable)s' % {'variable': variable1}, body='Body not translatable {}'.format(variable1), message_type='notification') self.message_post('Body not translatable', 'Subject not translatable {a}'.format(a=variable1)) self.message_post('Body not translatable %s' % variable1, 'Subject not translatable %(variable)s' % {'variable': variable1}) self.message_post('Body not translatable', subject='Subject not translatable') self.message_post(body='<h1>%s</h1><p>%s</p>' % ( _('Paragraph translatable'), 'Paragraph not translatable')) # Message post with translation function self.message_post(subject=_('Subject translatable'), body=_('Body translatable')) self.message_post(_('Body translatable'), _('Subject translatable')) self.message_post(_('Body translatable'), subject=_('Subject translatable')) self.message_post(_('A CDR has been recovered for %s') % (variable1,)) self.message_post(_('A CDR has been recovered for %s') % variable1) self.message_post(_('Var {a}').format(a=variable1)) self.message_post(_('Var %(variable)s') % {'variable': variable1}) self.message_post(subject=_('Subject translatable'), body=_('Body translatable %s') % variable1) self.message_post(subject=_('Subject translatable %(variable)s') % {'variable': variable1}, message_type='notification') self.message_post(_('Body translatable'), _('Subject translatable {a}').format(a=variable1)) self.message_post(_('Body translatable %s') % variable1, _('Subject translatable %(variable)s') % {'variable': variable1}) self.message_post('<p>%s</p>' % _('Body translatable')) self.message_post(body='<p>%s</p>' % _('Body translatable')) # There is no way to know if the variable is translated, then ignoring self.message_post(variable1) self.message_post(body=variable1 + variable1) self.message_post(body=(variable1 + variable1)) self.message_post(body=variable1 % variable1) self.message_post(body=(variable1 % variable1)) # translation function with variables in the term variable2 = variable1 self.message_post(_('Variable not translatable: %s' % variable1)) self.message_post(_('Variables not translatable: %s, %s' % ( variable1, variable2))) self.message_post(body=_('Variable not translatable: %s' % variable1)) self.message_post(body=_('Variables not translatable: %s %s' % ( variable1, variable2))) error_msg = _('Variable not translatable: %s' % variable1) error_msg = _('Variables not translatable: %s, %s' % ( variable1, variable2)) error_msg = _('Variable not translatable: {}'.format(variable1)) error_msg = _('Variables not translatable: {}, {variable2}'.format( variable1, variable2=variable2)) # string with parameters without name # so you can't change the order in the translation _('%s %d') % ('hello', 3) _('%s %s') % ('hello', 'world') # Valid cases _('%(strname)s') % {'strname': 'hello'} _('%(strname)s %(intname)d') % {'strname': 'hello', 'intname': 3} _('%s') % 'hello' _('%d') % 3 return error_msg def my_method2(self, variable2): return variable2 def my_method3(self, cr): cr.commit() # Dangerous use of commit old api self.env.cr.commit() # Dangerous use of commit self._cr.commit() # Dangerous use of commit self.cr.commit() # Dangerous use of commit return cr def my_method4(self, variable2): self.env.cr2.commit() # This should not be detected return variable2 def my_method5(self, variable2): self.env.cr.commit2() # This should not be detected return variable2 def my_method6(self): user_id = 1 if user_id != 99: # Method without translation raise UserError('String without translation') def my_method7(self): user_id = 1 if user_id != 99: # Method with translation raise UserError(_('String with translation')) def my_method8(self): user_id = 1 if user_id != 99: str_error = 'String with translation 2' # Don't check raise UserError(str_error) def my_method9(self): user_id = 1 if user_id != 99: # Method without translation raise UserError("String without translation 2") def my_method10(self): # A example of built-in raise without parameters # Shouldn't show error from lint raise ZeroDivisionError raise ZeroDivisionError() def my_method11(self): # A example of built-in raise with parameters # Shouldn't show error from lint raise ZeroDivisionError("String without translation") # raise without class-exception to increase coverage raise raise "obsolete case" def my_method12(self): # Should show error raise exceptions.Warning( 'String with params format {p1}'.format(p1='v1')) raise exceptions.Warning( 'qp2w String with params format %(p1)s' % {'p1': 'v1'}) def my_method13(self): # Shouldn't show error raise exceptions.Warning(_( 'String with params format {p1}').format(p1='v1')) raise exceptions.Warning(_( 'String with params format {p1}'.format(p1='v1'))) raise exceptions.Warning(_( 'String with params format %(p1)s') % {'p1': 'v1'}) raise exceptions.Warning(_( 'String with params format %(p1)s' % {'p1': 'v1'})) def old_api_method_alias(self, cursor, user, ids, context=None): # old api pass def sql_method(self, ids, cr): # Use of query parameters: nothing wrong here self._cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) self.env.cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) self.cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) def sql_injection_ignored_cases(self, ids, cr2): # This cr.execute2 or cr2.execute should not be detected self._cr.execute2( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) cr2.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) # Ignore when the query is built using private attributes self._cr.execute( 'DELETE FROM %s WHERE id IN %%s' % self._table, (tuple(ids),)) # Ignore string parsed with "".format() if args are psycopg2.sql.* calls query = "SELECT * FROM table" # imported from pyscopg2 import sql self._cr.execute( sql.SQL("""CREATE or REPLACE VIEW {} as ({})""").format( sql.Identifier(self._table), sql.SQL(query) )) self._cr.execute( sql.SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=sql.Identifier(self._table), query=sql.SQL(query), )) # imported from pyscopg2.sql import SQL, Identifier self._cr.execute( SQL("""CREATE or REPLACE VIEW {} as ({})""").format( Identifier(self._table), SQL(query), )) self._cr.execute( SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=Identifier(self._table), query=SQL(query), )) # imported from pyscopg2 direclty self._cr.execute( psycopg2.SQL("""CREATE or REPLACE VIEW {} as ({})""").format( psycopg2.sql.Identifier(self._table), psycopg2.sql.SQL(query), )) self._cr.execute( psycopg2.sql.SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=Identifier(self._table), query=SQL(query), )) # Variables build using pyscopg2.sql.* callers table = Identifier('table_name') sql_query = SQL(query) # format params self._cr.execute( SQL("""CREATE or REPLACE VIEW {} as ({})""").format( table, sql_query, )) # format dict self._cr.execute( SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=table, query=sql_query, )) # old api def sql_injection_modulo_operator(self, cr, uid, ids, context=None): # Use of % operator: risky self._cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) self.env.cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) self.cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) operator = 'WHERE' self._cr.execute( 'SELECT name FROM account %s id IN %%s' % operator, ids) var = 'SELECT name FROM account WHERE id IN %s' values = ([1, 2, 3, ], ) self._cr.execute(var % values) def sql_injection_executemany(self, ids, cr, v1, v2): # Check executemany() as well self.cr.executemany( 'INSERT INTO account VALUES (%s, %s)' % (v1, v2)) def sql_injection_format(self, ids, cr): # Use of .format(): risky self.cr.execute( 'SELECT name FROM account WHERE id IN {}'.format(ids)) def sql_injection_plus_operator(self, ids, cr): # Use of +: risky self.cr.execute( 'SELECT name FROM account WHERE id IN ' + str(tuple(ids))) operator = 'WHERE' self._cr.execute( 'SELECT name FROM account ' + operator + ' id IN %s', ids) self.cr.execute( ('SELECT name FROM account ' + operator + ' id IN (1)')) self.cr.execute( 'SELECT name FROM account ' + operator + ' id IN %s' % (tuple(ids),)) self.cr.execute( ('SELECT name FROM account ' + operator + ' id IN %s') % (tuple(ids),)) def sql_injection_before(self, ids): # query built before execute: risky as well var = 'SELECT name FROM account WHERE id IN %s' % tuple(ids) self._cr.execute(var) var[1] = 'SELECT name FROM account WHERE id IN %s' % tuple(ids) self._cr.execute(var[1]) def sql_no_injection_private_attributes(self, _variable, variable): # Skip sql-injection using private attributes self._cr.execute( "CREATE VIEW %s AS (SELECT * FROM res_partner)" % self._table) # Real sql-injection cases self._cr.execute( "CREATE VIEW %s AS (SELECT * FROM res_partner)" % self.table) self._cr.execute( "CREATE VIEW %s AS (SELECT * FROM res_partner)" % _variable) self._cr.execute( "CREATE VIEW %s AS (SELECT * FROM res_partner)" % variable)
class cloud_service_api_fournisseur_aws(models.Model): _inherit = 'cloud.service.api.fournisseur' api_ref = fields.Reference(selection_add=[('cloud.service.api.aws', 'api aws')])
class Task(models.Model): _name = 'workflow.task' _inherit = ['mail.thread'] _description = "Workflow Task" @api.model def _select_objects(self): model_obj = self.env['ir.model'] models = model_obj.search([]) return [(r.model, r.name) for r in models] + [('', '')] name = fields.Char(related='activity_id.name') workitem = fields.Many2one(comodel_name='workflow.workitem') activity_id = fields.Many2one(comodel_name='workflow.activity', string='Activity', required=True) description = fields.Text() user_id = fields.Many2one(comodel_name='res.users', string='Assigned User', track_visibility='onchange') state = fields.Selection([('new', 'Todo'), ('started', 'In progress'), ('closed', 'Closed')], default='new', track_visibility='onchange') date_deadline = fields.Date(string="Deadline", track_visibility='onchange') date_critical = fields.Date( help="""The created task will appear in red in the task tree view after this date""") date_started = fields.Datetime(string="Started on", track_visibility='onchange') date_closed = fields.Datetime(string="Closed on", track_visibility='onchange') res_type = fields.Selection(selection=_select_objects, string='Type', required=True) res_id = fields.Integer(string='ID', required=True) ref_object = fields.Reference(string='Objet', selection=_select_objects, store=True, compute='_get_ref_object') ref_object_name = fields.Char(search='_search_ref_object', compute='_dummy_compute', string="Related object") action_ids = fields.One2many(comodel_name='workflow.activity.action', compute='_get_action_ids') pretty_res_type = fields.Char(compute='_get_pretty_res_type') def fields_get(self, cr, user, allfields=None, context=None, write_access=True, attributes=None): res = super(Task, self).fields_get(cr, user, allfields, context, write_access, attributes) # remove ref_object from searchable field into the advanced search # since the field to use is ref_object_name if 'ref_object' in res: res['ref_object']['searchable'] = False return res @api.multi @api.depends('res_type') def _get_pretty_res_type(self): for record in self: model = self.env['ir.model']\ .search([('model', '=', record.res_type)]) record.pretty_res_type = model.name def _search_ref_object(self, operator, value): self._cr.execute("""SELECT distinct res_type FROM workflow_task""") models = self._cr.fetchall() all_task_ids = [] for model in models: model = model[0] self._cr.execute( """SELECT distinct res_id FROM workflow_task WHERE res_type=%s""", (model, )) mids = [r[0] for r in self._cr.fetchall()] if not self.env[model].check_access_rights('read', raise_exception=False): continue ns_result = self.env[model].name_search(name=value, operator=operator, args=[('id', 'in', mids)]) obj_ids = [r[0] for r in ns_result] tids = self.search([('res_type', '=', model), ('res_id', 'in', obj_ids)]) all_task_ids.extend(tids._ids) return [('id', 'in', all_task_ids)] @api.depends('ref_object') @api.multi def _dummy_compute(self): for record in self: record.ref_object_name = record.ref_object @api.multi def _get_action_ids(self): for record in self: if record.activity_id.use_action_task and\ record.activity_id._check_action_security(record.res_type, record.res_id): record.action_ids = record.activity_id.action_ids @api.multi def start_task(self): for record in self: record.date_started = fields.Datetime.now() record.state = 'started' record.user_id = self.env.uid @api.multi def close_task(self): for record in self: record.date_closed = fields.Datetime.now() record.state = 'closed' record.user_id = False @api.depends('res_type', 'res_id') @api.one def _get_ref_object(self): if self.res_type and self.res_id: self.ref_object = '%s,%s' % (self.res_type, str(self.res_id)) @api.model def check_base_security(self, res_model, res_ids, mode): ima = self.env['ir.model.access'] ima.check(res_model, mode) self.pool[res_model].check_access_rule(self._cr, self._uid, res_ids, mode, context=self.env.context) @api.multi def _check_activity_security(self): self._cr.execute( """SELECT id, res_type, res_id, activity_id FROM workflow_task WHERE id = ANY(%s)""", (list(self._ids), )) targets = self._cr.dictfetchall() res = {} for task_dict in targets: if not self.pool['workflow.activity'].\ _check_action_security(self._cr, self._uid, [task_dict['activity_id']], task_dict['res_type'], task_dict['res_id']): res[task_dict['id']] = False else: res[task_dict['id']] = True return res @api.multi def check(self, mode, values=None): """Restricts the access to a workflow task, according to referred model. """ res_ids = {} if self._ids: self._cr.execute( """SELECT DISTINCT res_type, res_id FROM workflow_task WHERE id = ANY (%s)""", (list(self._ids), )) for rmod, rid in self._cr.fetchall(): res_ids.setdefault(rmod, set()).add(rid) if values: if values.get('res_type') and values.get('res_id'): res_ids.setdefault(values['res_type'], set())\ .add(values['res_id']) for model, mids in res_ids.items(): existing_ids = self.pool[model].exists(self._cr, self._uid, mids) self.check_base_security(model, existing_ids, mode) if not self._uid == SUPERUSER_ID and\ not self.env['res.users'].has_group('base.group_user'): raise exceptions.AccessError( _("Sorry, you are not allowed to access this document.")) def _search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False, access_rights_uid=None): ids = super(Task, self)._search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False, access_rights_uid=access_rights_uid) if not ids: if count: return 0 return [] orig_ids = ids ids = set(ids) cr.execute( """SELECT id, res_type, res_id FROM workflow_task WHERE id = ANY(%s)""", (list(ids), )) targets = cr.dictfetchall() model_tasks = {} for target_dict in targets: if not target_dict['res_type']: continue # model_tasks = { 'model': { 'res_id': [id1,id2] } } model_tasks.setdefault(target_dict['res_type'], {})\ .setdefault(target_dict['res_id'] or 0, set())\ .add(target_dict['id']) # To avoid multiple queries for each task found, checks are # performed in batch as much as possible. ima = self.pool.get('ir.model.access') for model, targets in model_tasks.iteritems(): if model not in self.pool: continue if not ima.check(cr, uid, model, 'read', False): # remove all corresponding task ids for attach_id in itertools.chain(*targets.values()): ids.remove(attach_id) continue # skip ir.rule processing,these ones are out already # filter ids according to what access rules permit target_ids = targets.keys() allowed_ids = [0] + self.pool[model].search( cr, uid, [('id', 'in', target_ids)], context=context) disallowed_ids = set(target_ids).difference(allowed_ids) for res_id in disallowed_ids: for attach_id in targets[res_id]: ids.remove(attach_id) # activity_security = self._check_activity_security(cr, uid, ids, # context=context) # for task_id, res in activity_security.iteritems(): # if not res: # ids.remove(task_id) # sort result according to the original sort ordering result = [id for id in orig_ids if id in ids] ids = super(Task, self)._search(cr, uid, [('id', 'in', result)], offset=offset, limit=limit, order=order, context=context, count=False, access_rights_uid=access_rights_uid) return len(ids) if count else list(ids) @api.multi def read(self, fields=None, load='_classic_read'): self.check('read') return super(Task, self).read(fields=fields, load=load) @api.multi def write(self, vals): # If mode is write, it's impossible to start the task self.check('read', values=vals) return super(Task, self).write(vals) @api.multi def copy(self, default=None): self.check('write') return super(Task, self).copy(default=default) @api.multi def unlink(self): self.check('unlink') return super(Task, self).unlink() @api.model @api.returns('self', lambda value: value.id) def create(self, values): self.check('write', values=values) return super(Task, self).create(values)
class NeedSyncLine(models.Model): _name = "need.sync.line" _description = "Need Sync Line Based" name = fields.Char(string="Sync", compute="_get_name") need_sync = fields.Many2one(comodel_name="need.sync", string="Need Sync", index=True, ondelete="cascade") need_sync_connection = fields.Many2one(comodel_name="need.sync.connection", string="Connection", index=True) need_sync_date = fields.Datetime(related="need_sync.need_sync_date") model = fields.Selection(related="need_sync.model", store=True, index=True) res_id = fields.Integer(related="need_sync.res_id", store=True, index=True) record = fields.Reference(related="need_sync.record", store=True, index=True) sync_needed = fields.Boolean(string="Sync Needed", compute="_compute_need_sync", store=True, index=True, help="Synchronization Required") last_sync_date = fields.Datetime(string="Last Sync Datetime") confirmed_date = fields.Datetime(string="Last Confirm Datetime") published = fields.Boolean(string="Published", default=True, index=True) _sql_constraints = {('connection_need_sync_uniq', 'unique(need_sync, need_sync_connection)', 'Only one need sync per connection')} @api.one @api.depends('need_sync.res_id', 'need_sync.model', 'need_sync_connection.name') def _get_name(self): object = self.env[self.need_sync.model].browse(self.need_sync.res_id) if object and 'name' in object._fields: object_name = object.name else: object_name = "No object name defined" if self.need_sync_connection: connection_name = self.need_sync_connection.name else: connection_name = 'No Connection Name' self.name = '%s (%s)' % (object_name, connection_name) @api.one @api.depends('need_sync.need_sync_date', 'last_sync_date', 'confirmed_date', 'published') def _compute_need_sync(self): if self.published == True: if self.need_sync_date > self.last_sync_date: self.sync_needed = True elif self.need_sync_date and not self.last_sync_date: self.sync_needed = True elif self.sync_needed == True: self.sync_needed = False else: self.sync_needed = False @api.multi def _create_need_sync(self, need_sync, need_sync_connection): if need_sync and need_sync_connection: self.create({ 'need_sync': need_sync.id, 'need_sync_connection': need_sync_connection.id }) @api.multi def map_need_sync(self, model, res_ids, need_sync_connection): if isinstance(res_ids, (long, int)): res_ids = [res_ids] need_sync_lines = self.search([('model', '=', model), ('res_id', 'in', res_ids), ('need_sync_connection', '=', need_sync_connection.id)]) need_sync_line_res_ids = [x.res_id for x in need_sync_lines] create_sync_line_ids = list(set(res_ids) - set(need_sync_line_res_ids)) if create_sync_line_ids: for res_id in create_sync_line_ids: need_sync = self.env['need.sync'].search([ ('model', '=', model), ('res_id', '=', res_id), ]) self._create_need_sync(need_sync, need_sync_connection) return True
class wx_menu(models.Model): _name = 'wx.menu' _description = u'微信菜单' #_order = #_inherit = [] name = fields.Char('名称', ) left_ids = fields.One2many('wx.menu.item.left', 'menu_id', '左') middle_ids = fields.One2many('wx.menu.item.middle', 'menu_id', '中') right_ids = fields.One2many('wx.menu.item.right', 'menu_id', '右') left = fields.Char('左菜单') left_action = fields.Reference(string='动作', selection=MENU_ACTION_OPTION) middle = fields.Char('中菜单') middle_action = fields.Reference(string='动作', selection=MENU_ACTION_OPTION) right = fields.Char('右菜单') right_action = fields.Reference(string='动作', selection=MENU_ACTION_OPTION) sequence = fields.Integer('Sequence', help="sequence") #_defaults = { #} _order = 'sequence' def _get_menu_action(self, name, action): if action and action._name == 'wx.action.act_url': m_dict = {'type': 'view', 'name': name, 'url': action.url} else: m_dict = { 'type': 'click', 'name': name, 'key': action and action._name + ',' + str(action.id) or ',0' } return m_dict def _get_menu_item(self, name, action, childs): if childs: child_list = [] for child in childs: child_dict = self._get_menu_action(child.name, child.action) child_list.append(child_dict) return {'name': name, 'sub_button': child_list} else: return self._get_menu_action(name, action) @api.one def do_active(self): buttons = [] if self.left: buttons.append( self._get_menu_item(self.left, self.left_action, self.left_ids)) if self.middle: buttons.append( self._get_menu_item(self.middle, self.middle_action, self.middle_ids)) if self.right: buttons.append( self._get_menu_item(self.right, self.right_action, self.right_ids)) menu_data = {'button': buttons} wxclient.create_menu(menu_data)
class ConnectorCheckpoint(models.Model): _name = 'connector.checkpoint' _description = 'Connector Checkpoint' _inherit = ['mail.thread', 'ir.needaction_mixin'] @api.model def _reference_models(self): models = self.env['ir.model'].search([('state', '!=', 'manual')]) return [(model.model, model.name) for model in models if not model.model.startswith('ir.')] @api.depends('model_id', 'record_id') def _compute_record(self): for item in self: if not (item.model_id and item.record_id): item.record = None continue item.record = item.model_id.model + ',' + str(item.record_id) @api.depends('model_id', 'record_id') def _compute_name(self): for item in self: if item.message: item.name = item.message else: model = self.env[item.model_id.model] item.name = model.browse(item.record_id).display_name @api.model def _search_record(self, operator, value): model_model = self.env['ir.model'] sql = "SELECT DISTINCT model_id FROM connector_checkpoint" self.env.cr.execute(sql) model_ids = [row[0] for row in self.env.cr.fetchall()] models = model_model.browse(model_ids) ids = set() for model in models: model_id = model.id model_name = model.model model_obj = self.env[model_name] results = model_obj.name_search(name=value, operator=operator) res_ids = [res[0] for res in results] checks = self.search([('model_id', '=', model_id), ('record_id', 'in', res_ids)]) ids.update(checks.ids) if not ids: return [('id', '=', '0')] return [('id', 'in', tuple(ids))] record = fields.Reference( compute='_compute_record', selection='_reference_models', help="The record to review.", readonly=True, ) name = fields.Char( compute='_compute_name', search='_search_record', string='Record Name', help="Name of the record to review", readonly=True, ) record_id = fields.Integer(string='Record ID', required=False, readonly=True) model_id = fields.Many2one(comodel_name='ir.model', string='Model', required=False, readonly=True) backend_id = fields.Reference( string='Imported from', selection='_reference_models', readonly=True, required=True, help="The record has been imported from this backend", select=True, ) state = fields.Selection( selection=[('need_review', 'Need Review'), ('reviewed', 'Reviewed')], string='Status', required=True, readonly=True, default='need_review', ) message = fields.Char( string='Message', help="Review message", readonly=True, required=False, ) _sql_constraints = [ ('required_fields', "CHECK (record_id IS NOT NULL OR message IS NOT NULL)", _("Provide relation to a record or a message.")), ] @api.multi def reviewed(self): return self.write({'state': 'reviewed'}) @api.multi def _subscribe_users(self): """ Subscribe all users having the 'Connector Manager' group """ group = self.env.ref('connector.group_connector_manager') if not group: return users = self.env['res.users'].search([('groups_id', '=', group.id)]) self.message_subscribe_users(user_ids=users.ids) @api.model def create(self, vals): record = super(ConnectorCheckpoint, self).create(vals) record._subscribe_users() if record.message: msg = record.message else: msg = _('A %s needs a review.') % record.model_id.name record.message_post( body=msg, subtype='mail.mt_comment', ) return record @api.model def create_from_name(self, model_name, record_id, backend_model_name, backend_id, message=''): model_model = self.env['ir.model'] model = model_model.search([('model', '=', model_name)], limit=1) assert model, "The model %s does not exist" % model_name backend = backend_model_name + ',' + str(backend_id) return self.create({ 'model_id': model.id, 'record_id': record_id, 'backend_id': backend, 'message': message }) @api.model def create_from_message(self, backend_model_name, backend_id, message): backend = backend_model_name + ',' + str(backend_id) return self.create({'message': message, 'backend_id': backend}) @api.model def _needaction_domain_get(self): """ Returns the domain to filter records that require an action :return: domain or False is no action """ return [('state', '=', 'need_review')]
class connector_checkpoint(models.Model): _name = 'connector.checkpoint' _description = 'Connector Checkpoint' _inherit = ['mail.thread', 'ir.needaction_mixin'] def _get_models(self): """ All models are allowed as reference, anyway the fields.reference are readonly. """ model_obj = self.env['ir.model'].browse() models = model_obj.read(fields=['model', 'name']) return [(m['model'], m['name']) for m in models] def _get_ref(self): res = {} for check in self.browse(): res[check.id] = check.model_id.model + ',' + str(check.record_id) return res def _get_record_name(self): res = {} for check in self.browse(): model_obj = self.env[check.model_id.model].browse(check.record_id) res[check.id] = model_obj.name_get()[0][1] return res def _search_record(self, args): ids = set() sql = "SELECT DISTINCT model_id FROM connector_checkpoint" rows = self.cr.execute(sql).fecthall() model_ids = [row[0] for row in rows] model_obj = self.evn['ir.model'].browse(model_ids) models = model_obj.read(fields=['model']) for criteria in args: __, operator, value = criteria for model in models: model_id = model['id'] model_name = model['model'] model_obj = self.registry[model_name] results = model_obj.name_search(name=value, operator=operator) res_ids = [res[0] for res in results] check_ids = self.search(self.cr, self.uid, args=[('model_id', '=', model_id), ('record_id', 'in', res_ids)], context=self.context) ids.update(check_ids) if not ids: return [('id', '=', '0')] return [('id', 'in', tuple(ids))] record = fields.Reference(compute='_get_ref', type='reference', string='Record', selection=_get_models, help="The record to review.", size=128, readonly=True) name = fields.Char(compute='_get_record_name', fnct_search=_search_record, type='char', string='Record Name', help="Name of the record to review", readonly=True) record_id = fields.Integer(string='Record ID', required=True, readonly=True) model_id = fields.Many2one(comodel_name='ir.model', string='Model', required=True, readonly=True) backend_id = fields.Reference( string='Imported from', selection=_get_models, size=128, readonly=True, required=True, help="The record has been imported from this backend", select=1) state = fields.Selection(selection=[('need_review', 'Need Review'), ('reviewed', 'Reviewed')], string='Status', required=True, readonly=True) _defaults = { 'state': 'need_review', } def reviewed(self): return self.write({'state': 'reviewed'}) def _subscribe_users(self, ids): """ Subscribe all users having the 'Connector Manager' group """ group_ref = self.env['ir.model.data'].get_object_reference( self.cr, self.uid, 'connector8', 'group_connector_manager') if not group_ref: return group_id = group_ref[1] user_ids = self.registry['res.users'].search( self.cr, self.uid, [('groups_id', '=', group_id)], context=self.context) self.message_subscribe_users(self.cr, self.uid, ids, user_ids=user_ids, context=self.context) def create(self, vals): obj_id = super(connector_checkpoint, self).create(vals) self._subscribe_users([obj_id]) cp = self.browse(obj_id) msg = _('A %s needs a review.') % cp.model_id.name self.message_post(self.cr, self.uid, obj_id, body=msg, subtype='mail.mt_comment', context=self.context) return obj_id def create_from_name(self, cr, uid, model_name, record_id, backend_model_name, backend_id, context=None): model_obj = self.registry['ir.model'] model_ids = model_obj.search(cr, uid, [('model', '=', model_name)], context=context) assert model_ids, "The model %s does not exist" % model_name backend = backend_model_name + ',' + str(backend_id) return self.create({ 'model_id': model_ids[0], 'record_id': record_id, 'backend_id': backend }) def _needaction_domain_get(self, cr, uid, context=None): """ Returns the domain to filter records that require an action :return: domain or False is no action """ return [('state', '=', 'need_review')]
class automation_task(models.Model): _name = "automation.task" _description = "Automation Task" _order = "id asc" name = fields.Char("Name", required=True, readonly=True, states={'draft': [('readonly', False)]}) state_change = fields.Datetime("State Change", default=lambda self: util.currentDateTime(), required=True, readonly=True, copy=False) state = fields.Selection([("draft", "Draft"), ("queued", "Queued"), ("run", "Running"), ("cancel", "Canceled"), ("failed", "Failed"), ("done", "Done")], required=True, index=True, readonly=True, default="draft", copy=False) progress = fields.Float("Progress", readonly=True, compute="_progress") error = fields.Text("Error", readonly=True, copy=False) owner_id = fields.Many2one("res.users", "Owner", required=True, default=lambda self: self._uid, index=True, readonly=True) res_model = fields.Char("Resource Model", index=True, readonly=True) res_id = fields.Integer("Resource ID", index=True, readonly=True) res_ref = fields.Reference(_list_all_models, string="Resource", compute="_res_ref", readonly=True) cron_id = fields.Many2one("ir.cron", "Scheduled Job", index=True, ondelete="set null", copy=False, readonly=True) total_logs = fields.Integer("Total Logs", compute="_total_logs") total_stages = fields.Integer("Total Stages", compute="_total_stages") total_warnings = fields.Integer("Total Warnings", compute="_total_warnings") task_id = fields.Many2one("automation.task", "Task", compute="_task_id") after_once_task_id = fields.Many2one( "automation.task", "Task After (Once)", help= "Start this task after that task has finished successfully only once", readonly=True, ondelete="restrict") @api.one def _task_id(self): self.task_id = self @api.multi def _progress(self): res = dict.fromkeys(self.ids, 0.0) cr = self._cr # search stages cr.execute( "SELECT id FROM automation_task_stage WHERE task_id IN %s AND parent_id IS NULL", (tuple(self.ids), )) # get progress stage_ids = [r[0] for r in cr.fetchall()] for stage in self.env["automation.task.stage"].browse(stage_ids): res[stage.task_id.id] = stage.complete_progress # assign for r in self: r.progress = res[r.id] @api.one def _res_ref(self): if self.res_model and self.res_id: res = self.env[self.res_model].search_count([("id", "=", self.res_id)]) if res: self.res_ref = "%s,%s" % (self.res_model, self.res_id) else: self.res_ref = None else: self.res_ref = None @api.multi def _total_logs(self): res = dict.fromkeys(self.ids, 0) cr = self._cr cr.execute( "SELECT task_id, COUNT(*) FROM automation_task_log WHERE task_id IN %s GROUP BY 1", (tuple(self.ids), )) for task_id, log_count in cr.fetchall(): res[task_id] = log_count for r in self: r.total_logs = res[r.id] @api.multi def _total_warnings(self): res = dict.fromkeys(self.ids, 0) cr = self._cr cr.execute( "SELECT task_id, COUNT(*) FROM automation_task_log WHERE pri IN ('a','e','w','x') AND task_id IN %s GROUP BY 1", (tuple(self.ids), )) for task_id, log_count in cr.fetchall(): res[task_id] = log_count for r in self: r.total_warnings = res[r.id] @api.multi def _total_stages(self): res = dict.fromkeys(self.ids, 0) cr = self._cr cr.execute( "SELECT task_id, COUNT(*) FROM automation_task_stage WHERE task_id IN %s GROUP BY 1", (tuple(self.ids), )) for task_id, stage_count in cr.fetchall(): res[task_id] = stage_count for r in self: r.total_stages = res[r.id] @api.one def _run(self, taskc): """" Test Task """ for stage in range(1, 10): taskc.stage("Stage %s" % stage) for proc in range(1, 100, 10): taskc.log("Processing %s" % stage) taskc.progress("Processing %s" % stage, proc) time.sleep(1) taskc.done() @api.multi def _stage_count(self): self.ensure_one() return 10 def _check_execution_rights(self): # check rights if self.owner_id.id != self._uid and not self.user_has_groups( "automation.group_automation_manager,base.group_system"): raise Warning( _("Not allowed to start task. You be the owner or an automation manager" )) @api.multi def action_cancel(self): for task in self: # check rights task._check_execution_rights() if task.state == "queued": task.state = "cancel" return True @api.multi def action_refresh(self): return True @api.multi def action_reset(self): return True @api.multi def _get_cron_values(self): self.ensure_one() # new cron entry return { "name": "Task: %s" % self.name, "user_id": SUPERUSER_ID, "interval_type": "minutes", "interval_number": 1, "nextcall": util.currentDateTime(), "numbercall": 1, "model": self._name, "function": "_process_task", "args": "(%s,)" % self.id, "active": True, "priority": 1000 + self.id, "task_id": self.id } @api.multi def action_queue(self): for task in self: # check rights task._check_execution_rights() if task.state in ("draft", "cancel", "failed", "done"): # sudo task sudo_task = task.sudo() # add cron entry sudo_cron = sudo_task.cron_id if not sudo_cron: sudo_cron = self.env["ir.cron"].sudo().create( sudo_task._get_cron_values()) else: sudo_cron.write(sudo_task._get_cron_values()) # set stages inactive self._cr.execute( "DELETE FROM automation_task_stage WHERE task_id=%s", (sudo_task.id, )) # set queued sudo_task.state = "queued" sudo_task.error = None sudo_task.cron_id = sudo_cron # create secret sudo_secret = self.env["automation.task.secret"].sudo() if not sudo_secret.search([("task_id", "=", sudo_task.id)]): sudo_secret.create({"task_id": sudo_task.id}) return True @api.model def _cleanup_tasks(self): # clean up cron tasks self._cr.execute( "DELETE FROM ir_cron WHERE task_id IS NOT NULL AND NOT active") return True @api.model def _process_task(self, task_id): task = self.browse(task_id) if task and task.state == "queued": try: # get options if task.res_model and task.res_id: model_obj = self.env[task.res_model] resource = model_obj.browse(task.res_id) else: resource = task # options options = {"stages": 1, "resource": resource} # get custom options if hasattr(resource, "_run_options"): res_options = getattr(resource, "_run_options") if callable(res_options): res_options = resource._run_options() options.update(res_options) stage_count = options["stages"] # check if it is a singleton task # if already another task run, requeue # don't process this task if options.get("singleton"): # cleanup self._cr.execute( "DELETE FROM ir_cron WHERE task_id=%s AND id!=%s AND NOT active", (task.id, task.cron_id.id)) # check concurrent self._cr.execute( "SELECT MIN(id) FROM automation_task WHERE res_model=%s AND state IN ('queued','run')", (resource._model._name, )) active_task_id = self._cr.fetchone()[0] if active_task_id and active_task_id < task_id: # requeue task.cron_id = self.env["ir.cron"].create( task._get_cron_values()) return True task_after_once = task.after_once_task_id # change task state # and commit task.write({ "state_change": util.currentDateTime(), "state": "run", "error": None }) # commit after start self._cr.commit() # run task taskc = TaskStatus(task, stage_count) resource._run(taskc) # check fail on errors if options.get("fail_on_errors"): if taskc.errors: raise Warning("Task finished with errors") # close taskc.close() # update status task.write({ "state_change": util.currentDateTime(), "state": "done", "error": None, "after_once_task_id": None }) # commit after finish self._cr.commit() # queue task after if task_after_once: task_after_ref = task_after_once.res_ref if task_after_ref: task_after_ref.action_queue() except Exception as e: # rollback on error self._cr.rollback() _logger.exception("Task execution failed") error = str(e) if not error and hasattr(e, "message"): error = e.message if not error: error = "Unexpected error, see logs" # write error task.write({ "state_change": util.currentDateTime(), "state": "failed", "error": error }) self._cr.commit() return True
class BudgetBreakdownLine(ChartField, models.Model): _name = 'budget.breakdown.line' _description = 'Budget Breakdown Lines' breakdown_id = fields.Many2one( 'budget.breakdown', string='Budget Breakdown', index=True, ondelete='cascade', ) chart_view = fields.Selection( CHART_VIEW_LIST, related='breakdown_id.chart_view', string='Budget View', store=True, readonly=True, ) # References budget_plan_id = fields.Reference( [ ('budget.plan.unit', 'Budget Plan - Unit Based'), ('budget.plan.invest.asset', 'Budget Plan - Investment Asset'), ], string='Budget Plan', readonly=True, ondelete='set null', ) budget_id = fields.Many2one('account.budget', string='Budget Control', readonly=True, ondelete='set null') budget_state = fields.Selection( [('draft', 'Draft'), ('done', 'Controlled')], related='budget_id.state', string='Budget Status', store=True, readnly=True, ) # -- past_consumed = fields.Float( string='Consumed', compute='_compute_amount', store=True, readonly=True, ) future_plan = fields.Float( string='Future', compute='_compute_amount', store=True, readonly=True, ) rolling = fields.Float( string='Rolling', compute='_compute_amount', store=True, readonly=True, ) released_amount = fields.Float( string='Released', compute='_compute_amount', store=True, readonly=True, ) planned_amount = fields.Float( string='Planned Amount', compute='_compute_amount', store=True, readonly=True, ) latest_policy_amount = fields.Float( string='Latest Policy Amount', compute='_compute_amount', store=True, readonly=True, ) policy_amount = fields.Float(string='Policy Amount', ) @api.model def _get_planned_expense_hook(self, breakdown, budget_plan): planned_amount = budget_plan and budget_plan.planned_expense or 0.0 return planned_amount @api.multi @api.depends('budget_plan_id', 'budget_id') def _compute_amount(self): for line in self: # From Budget Plan budget_plan = line.budget_plan_id line.planned_amount = \ self._get_planned_expense_hook(line.breakdown_id, budget_plan) line.latest_policy_amount = line.budget_id and \ line.budget_id.policy_amount or 0.0 # From Budget Control line.future_plan = line.budget_id.future_plan line.past_consumed = line.budget_id.past_consumed line.rolling = line.budget_id.rolling line.released_amount = line.budget_id.released_amount @api.model def _change_amount_content(self, breakdown, new_amount): BREAKDOWN_LEVEL = { 'unit_base': 'section_id', # only 2 types 'invest_asset': 'org_id', 'personnel': False, } title = _('Policy amount change(s)') message = '<h3>%s</h3><ul>' % title for rec in self: field = BREAKDOWN_LEVEL[breakdown.chart_view] code = 'NSTDA' if field: obj = rec[field] code = obj.code or obj.name_short or obj.name message += _('<li><b>%s</b>: %s → %s</li>') % ( code, '{:,.2f}'.format(rec.policy_amount), '{:,.2f}'.format(new_amount), ) message += '</ul>' return message @api.multi def write(self, vals): # Grouping by Policy if 'policy_amount' in vals: for breakdown in self.mapped('breakdown_id'): lines = self.filtered(lambda l: l.breakdown_id == breakdown) new_amount = vals.get('policy_amount') message = lines._change_amount_content(breakdown, new_amount) if message: breakdown.message_post(body=message) return super(BudgetBreakdownLine, self).write(vals)
class NeedSyncConnectionRecordException(models.Model): _name = "need.sync.connection.record.exception" _description = "Need Sync Connection Records Not synced" def _select_models(self): return self.env['need.sync.model']._select_models() name = fields.Char(string="Sync", compute="_get_name", store=True) need_sync_connection = fields.Many2one(comodel_name="need.sync.connection", string="Connection", index=True) model = fields.Selection(selection=_select_models, string="Model", required=True, index=True) res_id = fields.Integer(string='Record ID', index=True, required=True, help="ID of the target record in the database") record = fields.Reference(selection=_select_models, string="Record", compute="_get_record", store=True) @api.one @api.depends('res_id', 'model') def _get_record(self): if self.res_id and self.model: self.record = self.env[str(self.model)].browse(self.res_id) @api.one @api.depends('res_id', 'model') def _get_name(self): object = self.env[self.model].browse(self.res_id) if object and 'name' in object._fields: object_name = object.name else: object_name = "No object name defined" self.name = '%s' % (object_name) def unlink(self): """ Recreate related need sync line :return: """ res_ids = [] for rec in self: res_ids.append(rec.res_id) need_sync_lines = self.get_need_sync_lines( res_ids, self[0].model, self[0].need_sync_connection.id) if need_sync_lines: need_sync_lines.write({'published': True}) return super(NeedSyncConnectionRecordException, self).unlink() def create(self, values): """ Remove related need sync lines :return: """ if values.get('res_id') and values.get('model') and values.get( 'need_sync_connection'): need_sync_lines = self.get_need_sync_lines( values.get('res_id'), values.get('model'), values.get('need_sync_connection')) if need_sync_lines: need_sync_lines.write({'published': False}) return super(NeedSyncConnectionRecordException, self).create(values) @api.model def get_need_sync_lines(self, res_ids, model, connection_id): if isinstance(res_ids, (long, int)): res_ids = [res_ids] need_sync_lines = self.env['need.sync.line'].search([ ('res_id', 'in', res_ids), ('model', '=', model), ('need_sync_connection', '=', connection_id) ]) return need_sync_lines
class AccountAnalyticLine(ChartFieldAction, models.Model): _inherit = 'account.analytic.line' # ChartfieldAction changed account_id = account.account, must change back account_id = fields.Many2one('account.analytic.account') # Following fields is not mature yet, so we need it to be store=False docline_seq = fields.Integer( string='Docline Seq', compute='_compute_docline_seq', ) document_date = fields.Date( string='Document Date', compute='_compute_document_date', ) request_emp_id = fields.Many2one( 'hr.employee', string='Requester', compute='_compute_document_employee_partner', ) prepare_emp_id = fields.Many2one( 'hr.employee', string='Requester', compute='_compute_document_employee_partner', ) approve_emp_id = fields.Many2one( 'hr.employee', string='Requester', compute='_compute_document_employee_partner', ) partner_id = fields.Many2one( 'res.partner', string='Partner', compute='_compute_document_employee_partner', ) chartfield_id = fields.Reference( [ ('res.section', 'Section'), ('res.project', 'Project'), ('res.invest.asset', 'Invest Asset'), ('res.invest.construction.phase', 'Construction Phase'), ('res.personnel.costcenter', 'Personnel'), ], string='Budget', compute='_compute_chartfield', ) @api.multi def _compute_docline_seq(self): """ Only for PR/PO/SO/EX that we can do at this moment """ for rec in self: if rec.doctype not in ('sale_order', 'purchase_order', 'purchase_request', 'employee_expense'): continue rec.docline_seq = \ rec.purchase_line_id.docline_seq or \ rec.sale_line_id.docline_seq or \ rec.expense_line_id.docline_seq or \ rec.purchase_request_line_id.docline_seq return True @api.multi def _compute_document_date(self): for rec in self: res_model = rec.document_id and rec.document_id._name or False if res_model in ['hr.expense.expense']: rec.document_date = rec.document_id.create_date if res_model in ['sale.order', 'purchase.order']: rec.document_date = rec.document_id.date_order if res_model in ['purchase.request']: create_date = datetime.strptime(rec.document_id.create_date, '%Y-%m-%d %H:%M:%S') rec.document_date = create_date.strftime('%Y-%m-%d') if res_model in ['account.invoice']: rec.document_date = rec.document_id.date_document if res_model in ['stock.picking']: rec.document_date = rec.document_id.date return True @api.multi def _compute_document_employee_partner(self): """ Only for PR/EX that will have request/prepare/approver user """ for rec in self: # Employee if rec.doctype == 'employee_expense': rec.request_emp_id = rec.document_id.employee_id rec.prepare_emp_id = \ rec.document_id.user_id.partner_id.employee_id rec.approve_emp_id = \ rec.document_id.approver_id.partner_id.employee_id if rec.doctype == 'purchase_request': rec.request_emp_id = \ rec.document_id.requested_by.partner_id.employee_id rec.prepare_emp_id = \ rec.document_id.responsible_uid.partner_id.employee_id rec.approve_emp_id = \ rec.document_id.assigned_to.partner_id.employee_id # Partner res_model = rec.document_id and rec.document_id._name or False if res_model in [ 'hr.expense.expense', 'sale.order', 'purchase.order', 'account.invoice', 'stock.picking' ]: rec.partner_id = rec.document_id.partner_id return True @api.multi def _compute_chartfield(self): for rec in self: model, res_id = False, False if rec.section_id: model, res_id = ('res.section', rec.section_id.id) if rec.project_id: model, res_id = ('res.project', rec.project_id.id) if rec.invest_asset_id: model, res_id = ('res.invest.asset', rec.invest_asset_id.id) if rec.invest_construction_phase_id: model, res_id = ('res.invest.construction.phase', rec.invest_construction_phase_id.id) if rec.personnel_costcenter_id: model, res_id = ('res.personnel.costcenter', rec.personnel_costcenter_id.id) rec.chartfield_id = '%s,%s' % (model, res_id) return True
class AccountMove(models.Model): _inherit = 'account.move' document = fields.Char( string='Document', compute='_compute_document', store=True, readonly=True, ) document_id = fields.Reference( REFERENCE_SELECT, string='Document', compute='_compute_document', store=True, readonly=True, ) doctype = fields.Selection( DOCTYPE_SELECT, string='Doctype', compute='_compute_document', store=True, index=True, help="Use selection as refer_type in res_doctype", ) date_value = fields.Date( string='Value Date', compute='_compute_document', store=True, help="If origin document have value date. Otherwise, use move date", ) invoice_ids = fields.One2many( 'account.invoice', 'move_id', string='Invoice', readonly=True, ) invoice_cancel_ids = fields.One2many( 'account.invoice', 'cancel_move_id', string='Invoice Cancel', readonly=True, ) invoice_clear_prepaid_ids = fields.One2many( 'account.invoice', 'clear_prepaid_move_id', string='Invoice Clear Prepaid', readonly=True, ) voucher_ids = fields.One2many( 'account.voucher', 'move_id', string='Payment', readonly=True, ) voucher_cancel_ids = fields.One2many( 'account.voucher', 'cancel_move_id', string='Payment Cancel', readonly=True, ) voucher_recognize_vat_ids = fields.One2many( 'account.voucher', 'recognize_vat_move_id', string='Payment Recognize VAT', readonly=True, ) bank_receipt_ids = fields.One2many( 'account.bank.receipt', 'move_id', string='Bank Receipt', readonly=True, ) bank_receipt_cancel_ids = fields.One2many( 'account.bank.receipt', 'cancel_move_id', string='Bank Receipt Cancel', readonly=True, ) salary_expense_ids = fields.One2many( 'hr.salary.expense', 'move_id', string='Salary Expense', readonly=True, ) salary_expense_cancel_ids = fields.One2many( 'hr.salary.expense', 'cancel_move_id', string='Salary Expense Cancel', readonly=True, ) expense_rev_ic_ids = fields.One2many( 'hr.expense.expense', 'rev_ic_move_id', string='IC Revenue', readonly=True, ) expense_exp_ic_ids = fields.One2many( 'hr.expense.expense', 'exp_ic_move_id', string='IC Expense', readonly=True, ) account_interface_ids = fields.One2many( 'interface.account.entry', 'move_id', string='Account Interface', readonly=True, ) @api.multi @api.depends('invoice_ids.internal_number', 'invoice_cancel_ids.internal_number', 'invoice_clear_prepaid_ids.internal_number', 'voucher_ids.number', 'voucher_cancel_ids.number', 'voucher_recognize_vat_ids.number', 'bank_receipt_ids.name', 'bank_receipt_cancel_ids.name', 'salary_expense_ids.name', 'salary_expense_cancel_ids.name', 'expense_rev_ic_ids.number', 'expense_exp_ic_ids.number', 'account_interface_ids.number', 'ref', # check for stock.picking case, as it has no move_id ) def _compute_document(self): for rec in self: document = False # Invoice if rec.invoice_ids: document = rec.invoice_ids[0] elif rec.invoice_cancel_ids: document = rec.invoice_cancel_ids[0] elif rec.invoice_clear_prepaid_ids: document = rec.invoice_clear_prepaid_ids[0] # Voucher elif rec.voucher_ids: document = rec.voucher_ids[0] elif rec.voucher_cancel_ids: document = rec.voucher_cancel_ids[0] elif rec.voucher_recognize_vat_ids: document = rec.voucher_recognize_vat_ids[0] # Bank Receipt elif rec.bank_receipt_ids: document = rec.bank_receipt_ids[0] elif rec.bank_receipt_cancel_ids: document = rec.bank_receipt_cancel_ids[0] # Salary Expense elif rec.salary_expense_ids: document = rec.salary_expense_ids[0] elif rec.salary_expense_cancel_ids: document = rec.salary_expense_cancel_ids[0] # Expense IC elif rec.expense_rev_ic_ids: document = rec.expense_rev_ic_ids[0] elif rec.expense_exp_ic_ids: document = rec.expense_exp_ic_ids[0] # Account Interface elif rec.account_interface_ids: document = rec.account_interface_ids[0] elif rec.ref: # Last chance for picking, as it not have move_id Picking = self.env['stock.picking'] picking = Picking.search([('name', '=', rec.ref)]) document = picking and picking[0] or False # Assign reference if document: rec.document_id = '%s,%s' % (document._name, document.id) if document._name in ('stock.picking', 'account.bank.receipt'): rec.document = document.name elif document._name == 'account.invoice': rec.document = document.internal_number else: rec.document = document.number rec.doctype = self._get_doctype(document._name, document) if 'date_value' in document._fields: rec.date_value = document.date_value else: rec.doctype = 'adjustment' # <-- Not related to any doc if not rec.date_value: rec.date_value = rec.date # No Value Date, same as date @api.model def _get_doctype(self, model, document): if model == 'account.invoice': return INVOICE_DOCTYPE[document.journal_id.type] if model == 'account.voucher': return VOUCHER_DOCTYPE[document.type] if model == 'account.bank.receipt': return 'bank_receipt' if model == 'hr.expense.expense': return 'employee_expense' if model == 'hr.salary.expense': return 'salary_expense' if model == 'stock.picking': return PICKING_DOCTYPE[document.picking_type_id.code] if model == 'interface.account.entry': return 'interface_account'
class ExchangeProvider(models.Model): """ Base Model for Transaction engines or external DB's Exchange Provider Model. Each specific Exchange Provider can extend the model by adding its own fields, using the Exchange Provider_name as a prefix for the new fields. Using the required_if_provider='<name>' attribute on fields it is possible to have required fields that depend on a specific Exchange Provider. Methods that should be added in an Exchange Provider-specific implementation: - ``<name>_form_generate_values(self, values) reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None)``: method that generates the values used to render the form button template. - ``<name>_get_form_action_url(self,):``: method that returns the url of the button form. It is used to post some data to the Exchange Provider. - ``<name>_compute_fees(self, amount, currency_id, country_id)``: computed the fees of the Exchange Provider, using generic fields defined on the Exchange Provider model (see fields definition). Each Exchange Provider should also define controllers to handle communication between Odoo and the Exchange Provider. It generally consists in return urls given to the payment form and that the Exchange Provider uses to send the customer back after the transaction, with transaction details given as a POST request. """ _name = 'exchange.provider' _description = 'Exchange Provider' _order = 'sequence' @api.model # collects selection items from provider_xxx modules def _get_providers(self): return [] # indirection to ease inheritance _provider_selection = lambda self, *args, **kwargs: self._get_providers( *args, **kwargs) @api.model def _compute_external(self): if self.environment == "internal": return False else: return True name = fields.Char('Name', size=64, required=True) sequence = fields.Integer('Sequence', help="Determine the display order") provider = fields.Selection(_provider_selection, string='Provider', required=True) # TODO provider_model = fields.Many2one('exchange.provider.model', string='Provider Model', required=False) ref_provider = fields.Reference( [('exchange.account.provider.internal', 'Internal'), ('exchange.account.provider.dumy', 'Dumy')], 'Accounts PR') # balance = fields.Float( # 'Balance Pr', related='ref_provider.balance', readonly=True) account_conf_ids = fields.One2many('exchange.config.accounts', 'exchange_provider_id', string='Account Templates', required=False) connection = fields.Selection( [('none', 'No connection'), ('single', 'Singlepoint'), ('multiuser', 'Multiple Users'), ('multisys', 'Multiple Accounts')], string='Connection Type', required=True, help="Defines how the provider connected to the Exchange framework." "- Single-point connection. Eg. a Clearing account" "- Multiple Users connection -> Eg. normal usecase with ext. transaction engine" "- Multiple Accounts connection -> One Admin can manage all account") singlepoint = fields.Boolean( string='Singlepoint Provider', readonly=True, # TODO help="if checked the provider is serving only a single" " point connection. Eg. a Clearing account") environment = fields.Selection([('internal', 'Internal'), ('test', 'External Test'), ('prod', 'External Production')], string='Environment', required=True) is_external = fields.Boolean(compute='_compute_external', string='External Account') test_url = fields.Char('Test URL', required=False) test_login = fields.Char('Test Login', size=64, required=False) test_secret = fields.Char('Test secret', size=128, required=False) asset_class = fields.Char('Asset Class', size=64, required=False) active = fields.Boolean('Active?', default=False) partner_id = fields.Many2one('res.partner', string='Related Partner') currency_ids = fields.One2many('exchange.provider.currency', 'provider_id', readonly=True, string='Provided Currencies') currency_id = fields.Many2one( 'exchange.provider.currency', 'Currency', required=False, help="Currency used for this Provider Configuration" "(only by the module provided currencies are available!)") view_template_id = fields.Many2one('ir.ui.view', 'Form Button Template', required=False) """ registration_view_template_id = fields.Many2one('ir.ui.view', 'Form Template', domain=[('type', '=', 'qweb')], help="Template for method registration") """ description = fields.Text('Description') image = fields.Binary( "Image", attachment=True, help= "This field holds the image used for this Exchange Provider, limited to 1024x1024px" ) image_medium = fields.Binary("Medium-sized image", compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True, help="Medium-sized image of this Exchange Provider. It is automatically " \ "resized as a 128x128px image, with aspect ratio preserved. " \ "Use this field in form views or some kanban views.") image_small = fields.Binary("Small-sized image", compute='_compute_images', inverse='_inverse_image_small', store=True, attachment=True, help="Small-sized image of this Exchange Provider. It is automatically " \ "resized as a 64x64px image, with aspect ratio preserved. " \ "Use this field anywhere a small image is required.") pre_msg = fields.Html( 'Help Message', translate=True, help='Message displayed to explain and help the payment process.') post_msg = fields.Html( 'Thanks Message', help='Message displayed after having done the payment process.') pending_msg = fields.Html( 'Pending Message', translate=True, help= 'Message displayed, if order is in pending state after having done the payment process.' ) done_msg = fields.Html( 'Done Message', translate=True, help= 'Message displayed, if order is done successfully after having done the payment process.' ) cancel_msg = fields.Html( 'Cancel Message', translate=True, help='Message displayed, if order is cancel during the payment process.' ) error_msg = fields.Html( 'Error Message', translate=True, help='Message displayed, if error is occur during the payment process.' ) balance_test = fields.Float( 'Balance', help='Balance of the account that is connected to the test credentials' ) # Fields that are related from exchange.config.settings model exch_code = fields.Char('Exchange Code', required=False, size=7, help="Unique Exchange Code (EC)" "First part of the 20 digits Account Code CC BBBB" "CC country code -> DE Germany" "BBBB Exchange code") display_balance = fields.Boolean('Everyone can see balances?', default=True) journal_id = fields.Many2one('account.journal', 'Community Journal', required=False) use_account_numbers = fields.Boolean( 'Use of Account Numbering System', default=True, help= "Use of the 20 digits Account Numbering Code 'CC BBBB DDDDDDDD XXXX-KK'" ) email_sysadmin = fields.Char('Sysadmin mail address') # Field that is related to exchange.config.settings model _sql_constraints = [('exch_code_name_unique', 'UNIQUE (exch_code, active)', 'Exchange code must be unique!')] @api.depends('image') def _compute_images(self): for rec in self: rec.image_medium = openerp.tools.image_resize_image_medium( rec.image) rec.image_small = openerp.tools.image_resize_image_small(rec.image) @api.one # Action connection test via the provider models def act_provider_test(self): sub_function = "_act_provider_test_" + str(self.provider) call_test = getattr(self, sub_function) result = call_test() @api.one # get provider_balance from the provider models def act_provider_get_balance(self): sub_function = "_get_provider_balance_" + str(self.provider) call_balance = getattr(self, sub_function) result = call_balance() self.balance_test = result
class TodoTask(models.Model): _inherit = 'todo.task' # Relational fields stage_id = fields.Many2one('todo.task.stage', 'Stage') tag_ids = fields.Many2many( 'todo.task.tag', 'todo_task_tag_rel', 'task_id', 'tag_id', string='Tags', # Relational field attributes: auto_join=False, context="{}", domain="[]", ondelete='cascade', ) # Dynamic Reference fields: refers_to = fields.Reference( # Set a selection list, such as: # [('res.user', 'User'), ('res.partner', 'Partner')], # Or use standard "Referencable Models": referencable_models, 'Refers to', # string= (title) ) # Related fields: stage_state = fields.Selection( related='stage_id.state', string='Stage State', store=True, # optional ) # Calculated fields: stage_fold = fields.Boolean( string='Stage Folded?', compute='_compute_stage_fold', search='_search_stage_fold', inverse='_write_stage_fold', store=False, # the default ) @api.one @api.depends('stage_id.fold') def _compute_stage_fold(self): self.stage_fold = self.stage_id.fold def _search_stage_fold(self, operator, value): return [('stage_id.fold', operator, value)] def _write_stage_fold(self): self.stage_id.fold = self.stage_fold # Constraints _sql_constraints = [ ('todo_task_name_unique', 'UNIQUE (name, user_id, active)', 'Task title must be unique!') ] @api.one @api.constrains('name') def _check_name_size(self): if len(self.name) < 5: raise ValidationError('Title must have 5 chars!') @api.one def compute_user_todo_count(self): self.user_todo_count = self.search_count([('user_id', '=', self.user_id.id)]) user_todo_count = fields.Interger('User To-Do Count', compute='compute_user_todo_count') effort_estimate = fields.Integer('Effort Estimate')
class TaxExemptionlView(models.Model): _name = 'tax.exemption.view' _auto = False id = fields.Integer( string='ID', readonly=True, ) move_id = fields.Many2one( 'account.move', string='Move', readonly=True, ) taxbranch_id = fields.Many2one( 'res.taxbranch', string='Tax Branch', readonly=True, ) date_invoice = fields.Date( string='Posting Date', readonly=True, ) number_preprint = fields.Char( string='Preprint Number', readonly=True, ) partner_id = fields.Many2one( 'res.partner', string='Partner', readonly=True, ) amount_untaxed = fields.Float( string='Subtotal', readonly=True, ) amount_tax = fields.Float( string='Tax', readonly=True, ) source_document_id = fields.Reference( [('purchase.order', 'Purchase'), ('sale.order', 'Sales'), ('hr.expense.expense', 'HR Expense')], string='Source Document Ref.', readonly=True, ) number = fields.Char( string='Document Number', readonly=True, ) document_origin = fields.Char( string='Document Origin', readonly=True, ) validate_user_id = fields.Many2one( 'res.users', string='Validated By', readonly=True, ) def _get_sql_view(self): sql_view = """ SELECT ROW_NUMBER() OVER(ORDER BY invoice.move_id) AS id, * FROM ((SELECT move_id, taxbranch_id, date_invoice, number_preprint, partner_id, amount_untaxed, amount_tax, source_document_id, number, NULL AS document_origin, validate_user_id FROM account_invoice WHERE type IN ('out_invoice', 'out_refund') AND state NOT IN ('draft', 'cancel') AND id NOT IN (SELECT DISTINCT invoice_id FROM account_invoice_tax)) UNION ALL (SELECT iae.move_id, iael.taxbranch_id, iael.date AS date_invoice, iae.preprint_number AS number_preprint, iael.partner_id, SUM(iael.debit) AS amount_untaxed, (SELECT ABS(SUM(credit) - SUM(debit)) FROM interface_account_entry_line WHERE tax_id IS NOT NULL AND interface_id = iae.id GROUP BY interface_id) AS amount_tax, NULL AS source_document_id, iae.number, iae.name AS document_origin, iae.validate_user_id FROM interface_account_entry iae LEFT JOIN interface_account_entry_line iael ON iae.id = iael.interface_id WHERE iae.type = 'invoice' AND iae.state = 'done' AND iae.id NOT IN (SELECT DISTINCT interface_id FROM interface_account_entry_line WHERE tax_id IS NOT NULL) GROUP BY iae.id, iael.taxbranch_id, iael.date, iael.partner_id)) invoice """ return sql_view def init(self, cr): tools.drop_view_if_exists(cr, self._table) cr.execute("""CREATE OR REPLACE VIEW %s AS (%s)""" % (self._table, self._get_sql_view()))
class BudgetCarryOverLineView(models.Model): _name = 'budget.carry.over.line.view' _auto = False _order = 'name' carry_over_id = fields.Many2one( 'budget.carry.over', string='Carry Over', readonly=True, ) budget_id = fields.Reference( [('res.section', 'Section'), ('res.project', 'Project'), ('res.invest.asset', 'Asset'), ('res.invest.construction.phase', 'Construction'), ('res.personnel.costcenter', 'Personnel')], string='Document Line', compute='_compute_budget_id', readonly=True, ) doctype = fields.Selection( [('purchase_request', 'Purchase Request'), ('sale_order', 'Sales Order'), ('purchase_order', 'Purchase Order'), ('employee_expense', 'Expense'), ], string='Document Type', readonly=True, ) name = fields.Char( string='Name', readonly=True, ) description = fields.Char( string='Description', readonly=True, ) chartfield_id = fields.Many2one( 'chartfield.view', string='Budget', readonly=True, ) chartfield_type = fields.Selection( [('sc:', 'Section'), ('pj:', 'Project'), ('cp:', 'Construction Phase'), ('ia:', 'Invest Asset'), ('pc:', 'Personnel'), ], string='Type', related='chartfield_id.type', ) commit_amount = fields.Float( string='Commitment', readonly=True, ) @api.multi def _compute_budget_id(self): for rec in self: rec.budget_id = '%s,%s' % (rec.chartfield_id.model, rec.chartfield_id.res_id) def _get_sql_view(self): sql_view = """ SELECT id, doctype, carry_over_id, commit_amount, name, description, chartfield_id FROM budget_carry_over_line """ return sql_view def init(self, cr): tools.drop_view_if_exists(cr, self._table) cr.execute("""CREATE or REPLACE VIEW %s as (%s)""" % (self._table, self._get_sql_view(), ))
class TestModel(models.Model): _name = 'test.model' _columns = {} # deprecated columns _defaults = {} # deprecated defaults length = fields.Integer() # Deprecated length by js errors name = fields.Char( _(u"Näme"), # Don't need translate help=u"My hëlp", required=False, compute='_compute_name', # good compute method name search='_search_name', # good search method name inverse='_inverse_name', # good inverse method name ) # Imported openerp.fields use Char (Upper case) other_field = fields.char( name=_("Other field"), copy=True, compute='my_method_compute', # bad compute method name search='my_method_search', # bad search method name inverse='my_method_inverse', # bad inverse method name ) compute_none = fields.Char(compute=None) other_field2 = fields.char( 'Other Field2', copy=True, ) # This is a inherit overwrite field then don't should show errors related # with creation of fields. def method_date(self): date = fields.Date.to_string( fields.Datetime.context_timestamp(self, timestamp=fields.Datetime.now()) ) return date my_ok_field = fields.Float( "My correctly named field", digits=(6, 6), # OK: Valid field parameter index=True, # OK: Valid field parameter help="My ok field", ) my_ko_field = fields.Float( digits_compute=lambda cr: (6, 6), # Deprecated field parameter select=True, # Deprecated field parameter help="My ko field", string="My Ko Field", # String parameter equal to name of variable ) """The name of the variable is equal to the string parameter Tested all fields.*""" boolean_variable_1 = fields.Boolean(string='Boolean Variable 1', help="Help") boolean_variable_2 = fields.Boolean("Boolean Variable 2", help="Help") char_variable_1 = fields.Char(string='Char Variable 1', help="Help") char_variable_2 = fields.Char("Char Variable 2", help="Help") text_variable_1 = fields.Text(string='Text Variable 1', help="Help") text_variable_2 = fields.Text("Text Variable 2", help="Help") html_variable_1 = fields.Html(string='Html Variable 1', help="Help") html_variable_2 = fields.Html("Html Variable 2", help="Help") integer_variable_1 = fields.Integer(string='Integer Variable 1', help="Help") integer_variable_2 = fields.Integer("Integer Variable 2", help="Help") float_variable_1 = fields.Float(string='Float Variable 1', help="Help") float_variable_2 = fields.Float("Float Variable 2", help="Help") date_variable_1 = fields.Date(string='Date Variable 1', help="Help") date_variable_2 = fields.Date("Date Variable 2", help="Help") date_time_variable_1 = fields.DateTime(string='Date Time Variable 1', help="Help") date_time_variable_2 = fields.DateTime("Date Time Variable 2", help="Help") binary_variable_1 = fields.Binary(string='Binary Variable 1', help="Help") binary_variable_2 = fields.Binary("Binary Variable 2", help="Help") selection_variable_1 = fields.Selection(selection=[('a', 'A')], string='Selection Variable 1', help="Help") selection_variable_2 = fields.Selection([('a', 'A')], "Selection Variable 2", help="Help") reference_variable_1 = fields.Reference(selection=[('res.user', 'User')], string="Reference Variable 1", help="Help") reference_variable_2 = fields.Reference([('res.user', 'User')], "Reference Variable 2", help="Help") many_2_one_variable_1 = fields.Many2one(comodel_name='res.users', string='Many 2 One Variable 1', help="Help") many_2_one_variable_2 = fields.Many2one('res.users', "Many 2 One Variable 2", help="Help") one_2_many_variable_1 = fields.One2many(comodel_name='res.users', inverse_name='rel_id', string='One 2 Many Variable 1', help="Help") one_2_many_variable_2 = fields.One2many('res.users', 'rel_id', "One 2 Many Variable 2", help="Help") many_2_many_variable_1 = fields.Many2many(comodel_name='res.users', relation='table_name', column1='col_name', column2='other_col_name', string='Many 2 Many Variable 1', help="Help") many_2_many_variable_2 = fields.Many2many('res.users', 'table_name', 'col_name', 'other_col_name', "Many 2 Many Variable 2", help="Help") field_case_sensitive = fields.Char( 'Field Case SENSITIVE', help="Field case sensitive" ) name_equal_to_string = fields.Float( "Name equal to string", help="Name Equal To String" ) many_2_one = fields.Many2one( 'res.users', "Many 2 One", help="Many 2 one" ) many_2_many = fields.Many2many( 'res.users', 'relation', 'fk_column_from', 'fk_column_to', "Many 2 many", help="Many 2 Many" ) # This is a inherit overwrite field then don't should show errors related # with creation of fields. field_state_overwrite = fields.Selection( selection_add=[('new_item', 'New Item')]) ids = ["parent_id_1", "parent_id_2"] def my_method1(self, variable1): # Shouldn't show error of field-argument-translate self.my_method2(_('hello world')) def my_method2(self, variable2): return variable2 def my_method3(self, cr): cr.commit() # Dangerous use of commit old api self.env.cr.commit() # Dangerous use of commit self._cr.commit() # Dangerous use of commit self.cr.commit() # Dangerous use of commit return cr def my_method4(self, variable2): self.env.cr2.commit() # This should not be detected return variable2 def my_method5(self, variable2): self.env.cr.commit2() # This should not be detected return variable2 def my_method6(self): user_id = 1 if user_id != 99: # Method without translation raise UserError('String without translation') def my_method7(self): user_id = 1 if user_id != 99: # Method with translation raise UserError(_('String with translation')) def my_method8(self): user_id = 1 if user_id != 99: str_error = 'String with translation 2' # Don't check raise UserError(str_error) def my_method9(self): user_id = 1 if user_id != 99: # Method without translation raise UserError("String without translation 2") def my_method10(self): # A example of built-in raise without parameters # Shouldn't show error from lint raise ZeroDivisionError raise ZeroDivisionError() def my_method11(self): # A example of built-in raise with parameters # Shouldn't show error from lint raise ZeroDivisionError("String without translation") # raise without class-exception to increase coverage raise raise "obsolete case" def my_method12(self): # Should show error raise exceptions.Warning( 'String with params format {p1}'.format(p1='v1')) raise exceptions.Warning( 'qp2w String with params format %(p1)s' % {'p1': 'v1'}) def my_method13(self): # Shouldn't show error raise exceptions.Warning(_( 'String with params format {p1}').format(p1='v1')) raise exceptions.Warning(_( 'String with params format {p1}'.format(p1='v1'))) raise exceptions.Warning(_( 'String with params format %(p1)s') % {'p1': 'v1'}) raise exceptions.Warning(_( 'String with params format %(p1)s' % {'p1': 'v1'})) def old_api_method_alias(self, cursor, user, ids, context=None): # old api pass def sql_method(self, ids, cr): # Use of query parameters: nothing wrong here self._cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) self.env.cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) self.cr.execute( 'SELECT name FROM account WHERE id IN %s', (tuple(ids),)) def sql_injection_ignored_cases(self, ids, cr2): # This cr.execute2 or cr2.execute should not be detected self._cr.execute2( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) cr2.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) # Ignore when the query is built using private attributes self._cr.execute( 'DELETE FROM %s WHERE id IN %%s' % self._table, (tuple(ids),)) # old api def sql_injection_modulo_operator(self, cr, uid, ids, context=None): # Use of % operator: risky self._cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) self.env.cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) self.cr.execute( 'SELECT name FROM account WHERE id IN %s' % (tuple(ids),)) operator = 'WHERE' self._cr.execute( 'SELECT name FROM account %s id IN %%s' % operator, ids) var = 'SELECT name FROM account WHERE id IN %s' values = ([1, 2, 3, ], ) self._cr.execute(var % values) def sql_injection_executemany(self, ids, cr, v1, v2): # Check executemany() as well self.cr.executemany( 'INSERT INTO account VALUES (%s, %s)' % (v1, v2)) def sql_injection_format(self, ids, cr): # Use of .format(): risky self.cr.execute( 'SELECT name FROM account WHERE id IN {}'.format(ids)) def sql_injection_plus_operator(self, ids, cr): # Use of +: risky self.cr.execute( 'SELECT name FROM account WHERE id IN ' + str(tuple(ids))) operator = 'WHERE' self._cr.execute( 'SELECT name FROM account ' + operator + ' id IN %s', ids) self.cr.execute( ('SELECT name FROM account ' + operator + ' id IN (1)')) self.cr.execute( 'SELECT name FROM account ' + operator + ' id IN %s' % (tuple(ids),)) self.cr.execute( ('SELECT name FROM account ' + operator + ' id IN %s') % (tuple(ids),)) def sql_injection_before(self, ids): # query built before execute: risky as well var = 'SELECT name FROM account WHERE id IN %s' % tuple(ids) self._cr.execute(var) var[1] = 'SELECT name FROM account WHERE id IN %s' % tuple(ids) self._cr.execute(var[1])
class NeedSync(models.Model): _name = "need.sync" _description = "Need Sync Base Model" def _select_models(self): return self.env['need.sync.model']._select_models() name = fields.Char(string="Sync", compute="_get_name", store=True) model = fields.Selection(selection=_select_models, string="Model", required=True, index=True) res_id = fields.Integer(string='Record ID', index=True, required=True, help="ID of the target record in the database") record = fields.Reference(selection=_select_models, string="Record", compute="_get_record", store=True, size=128) need_sync_date = fields.Datetime(string="Need Sync Datetime") sync_lines = fields.One2many(comodel_name="need.sync.line", inverse_name="need_sync", string="Sync Lines") @api.one @api.depends('res_id', 'model') def _get_record(self): if self.res_id and self.model: print self.res_id print self.model self.record = self.env[str(self.model)].browse(self.res_id) @api.one @api.depends('res_id', 'model') def _get_name(self): object = self.env[self.model].browse(self.res_id) if object and 'name' in object._fields: object_name = object.name else: object_name = "No object name defined" self.name = '%s' % (object_name) @api.multi def set_need_sync(self, model, res_ids): """ Pass need sync to model and resources :param model: need sync on wich model :param res: list of resources to set sync :return: boolean True or False """ if isinstance(res_ids, (long, int)): res_ids = [res_ids] # Get list of IDS where a record in need sync exists # and a list for creating a need sync record need_syncs = self.search([('model', '=', model), ('res_id', 'in', res_ids)]) need_syncs.write({'need_sync_date': fields.Datetime.now()}) # Need sync res_ids list need_sync_res_ids = [x.res_id for x in need_syncs] create_sync_ids = list(set(res_ids) - set(need_sync_res_ids)) if create_sync_ids: _logger.debug("Create new Need sync records") self._create_need_sync(model, create_sync_ids) @api.model def _create_need_sync(self, model, res_ids): if model and res_ids: for res_id in res_ids: create_need_sync = self.create({ 'model': model, 'res_id': res_id, 'need_sync_date': fields.Datetime.now() }) if create_need_sync: for connection_model in self.env[ 'need.sync.connection.model'].search([ ('model', '=', model) ]): self.env['need.sync.line']._auto_create_need_sync( create_need_sync, connection_model.need_sync_connection)
class MailNotification(models.Model): _inherit = 'mail.notification' record = fields.Reference( selection=lambda self: [(m.model, m.name) for m in self.env['ir.model'].search([])], compute='_compute_record') record_access_link = fields.Char(compute='_compute_record') @api.multi def _notify_email(self, message_id, force_send=False, user_signature=True): if not self.mapped('message_id.subtype_id.template_id'): return super(MailNotification, self)._notify_email(message_id, force_send=force_send, user_signature=user_signature) message_ids = [] for this in self: if not this.mapped('message_id.subtype_id.template_id'): super(MailNotification, this)._notify_email(message_id, force_send=force_send, user_signature=user_signature) continue message = this.message_id if not this.get_partners_to_email(message): continue custom_values = { 'references': message.parent_id.message_id, 'author_id': message.author_id.id } if message.res_id and hasattr(self.env[message.model], 'message_get_email_values'): message_values = self.env[message.model].browse( message.res_id).message_get_email_values(message) # message_get_email_values is guessed to @api.one if message_values and isinstance(message_values, list): message_values = message_values[0] custom_values.update(message_values) message_id = message.subtype_id.template_id.send_mail(this.id) if 'mail_message_id' in custom_values: custom_values.pop('mail_message_id') self.env['mail.mail'].browse(message_id).write(custom_values) message_ids.append(message_id) return message_ids or True @api.multi def _compute_record(self): for this in self: if not this.message_id.model or not this.message_id.res_id: continue this.record = self.env[this.message_id.model].browse( this.message_id.res_id) link_html = self.env['mail.mail']._get_partner_access_link( self.env['mail.mail'].new({ 'notification': True, 'mail_message_id': this.message_id.id, }), this.partner_id) for a in etree.HTML(link_html or '<html/>').xpath('//a[@href]'): this.record_access_link = a.get('href')
class SriDocumentoElectronico(models.Model): _name = 'l10n_ec_sri.documento.electronico' @api.multi def name_get(self): return [(documento.id, '%s %s' % (documento.claveacceso, documento.estado)) for documento in self] @api.model def create(self, vals): res = super(SriDocumentoElectronico, self).create(vals) if not res: return line = self.env['l10n_ec_sri.documento.electronico.queue.line'] line.create({ 'queue_id': self.env.ref('l10n_ec_sri_ece.documento_electronico_queue').id, 'documento_electronico_id': res.id, }) return res @api.multi def validate_xsd_schema(self, xml, xsd_path): """ :param xml: xml codificado como utf-8 :param xsd_path: /dir/archivo.xsd :return: """ xsd_path = os.path.join(__file__, "../..", xsd_path) xsd_path = os.path.abspath(xsd_path) xsd = open(xsd_path) schema = e.parse(xsd) xsd = e.XMLSchema(schema) xml = e.XML(xml) try: xsd.assertValid(xml) return True except e.DocumentInvalid: return False @api.multi def modulo11(self, clave): digitos = list(clave) nro = 6 # cantidad de digitos en cada segmento segmentos = [digitos[n:n + nro] for n in range(0, len(digitos), nro)] total = 0 while segmentos: segmento = segmentos.pop() factor = 7 # numero inicial del mod11 for s in segmento: total += int(s) * factor factor -= 1 mod = 11 - (total % 11) if mod == 11: mod = 0 elif mod == 10: mod = 1 return mod @api.multi def firma_xades_bes(self, xml, p12, clave): """ :param xml: cadena xml :param clave: clave en formato base64 :param p12: archivo p12 en formato base64 :return: """ jar_path = os.path.join(__file__, "../../src/xadesBes/firma.jar") jar_path = os.path.abspath(jar_path) cmd = ['java', '-jar', jar_path, xml, p12, clave] try: subprocess.check_output(cmd) sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) res = sp.communicate() return res[0] except subprocess.CalledProcessError as se: _logger.exception('FIRMA ELECTRONICA FALLIDA: %s' % se.returncode) raise UserError( _("Firma electrónica fallida, por favor, " "verifique el archivo y la contraseña")) @api.multi def process_de(self): if self.estado == 'NO ENVIADO': self.send_de_backend() if self.estado in ('RECIBIDA', 'EN PROCESO'): self.receive_de_offline() if self.estado in ('DEVUELTA', 'NO AUTORIZADO', 'RECHAZADA'): # TODO: NOTIFICAR AL USUARIO. pass return True @api.multi def send_de_backend(self): """ Envía el documento electrónico desde el backend para evitar demoras en caso de que el SRI se encuentre fuera de línea. """ ambiente_id = self.env.user.company_id.ambiente_id xml = base64.b64decode(self.xml_file) envio = self.send_de_offline(ambiente_id, xml) if envio: self.write({ 'estado': envio['estado'] or 'NO ENVIADO', 'mensajes': envio['comprobantes'] or '', }) return True else: return False @api.multi def send_de_offline(self, ambiente_id, xml): """ :param ambiente_id: recordset del ambiente :param xml: documento xml en base 64 :return: respuesta del SRI """ client = Client(ambiente_id.recepcioncomprobantes) with client.options(raw_response=False): response = client.service.validarComprobante(xml) return response @api.multi def receive_de_offline(self): ambiente_id = self.env.user.company_id.ambiente_id claveacceso = self.claveacceso client = Client(ambiente_id.autorizacioncomprobantes) with client.options(raw_response=False): response = client.service.autorizacionComprobante(claveacceso) try: autorizaciones = response['autorizaciones']['autorizacion'][0] except: return False autorizacion = OrderedDict([ ('autorizacion', OrderedDict([ ('estado', autorizaciones['estado']), ('numeroAutorizacion', autorizaciones['numeroAutorizacion']), ('fechaAutorizacion', { '@class': 'fechaAutorizacion', '#text': str(autorizaciones['fechaAutorizacion']) }), ('ambiente', autorizaciones['ambiente']), ('comprobante', u'<![CDATA[{}]]>'.format(autorizaciones['comprobante'])), ])) ]) comprobante = xml.sax.saxutils.unescape( xmltodict.unparse(autorizacion)) self.write({ 'estado': autorizaciones['estado'], 'mensajes': autorizaciones['mensajes'], 'xml_file': base64.b64encode(comprobante.encode('utf-8')), 'fechaautorizacion': fields.Datetime.to_string(autorizaciones['fechaAutorizacion']), }) # Enviar correo si el documento es AUTORIZADO. if autorizaciones['estado'] == 'AUTORIZADO': try: sent = self.reference.send_email_de() # Si se envía, marcamos la línea como enviada. if sent: line_obj = self.env[ 'l10n_ec_sri.documento.electronico.queue.line'] line = line_obj.search( [('documento_electronico_id', '=', self.id)], limit=1) line.sent = True except: pass return True @api.multi def get_documento_electronico_dict(self, ambiente_id, comprobante_id, documento, claveacceso, tipoemision, reference): # Generamos el xml en memoria. xml = xmltodict.unparse(documento, pretty=False) xml = xml.encode('utf8') # Validamos el esquema. xsd_path = 'src/esquemasXsd/Factura_V_1_1_0.xsd' self.validate_xsd_schema(xml, xsd_path) firma = self.env.user.company_id.firma_id clave = base64.b64encode(firma.clave) if not os.path.exists(firma.path): firma.write({ 'path': firma.save_sign(firma.p12), }) p12 = base64.b64encode(firma.path) xml = self.firma_xades_bes(xml, p12, clave) filename = ''.join([claveacceso, '.xml']) # Creamos el diccionario del documento electrónico. vals = { 'xml_file': base64.b64encode(xml), 'xml_filename': filename, 'estado': 'NO ENVIADO', 'mensajes': '', 'ambiente': ambiente_id.ambiente, 'tipoemision': tipoemision, 'claveacceso': claveacceso, 'reference': reference, 'comprobante_id': comprobante_id.id, } return vals @api.multi def get_claveacceso(self, fecha, comprobante, ruc, ambiente_id, establecimiento, puntoemision, secuencial): """ :param fecha: fields.Date :param comprobante: código del tipo de comprobante en str zfill(2) :param ruc: de la empresa en str :param ambiente_id: recordset :param comprobante: str :param puntoemision: str :param secuencial: str :return: """ fecha = datetime.strptime(fecha, '%Y-%m-%d') data = [ fecha.strftime('%d%m%Y'), str(comprobante), str(ruc), str(ambiente_id.ambiente), str(establecimiento).zfill(3), str(puntoemision).zfill(3), str(secuencial).zfill(9), str(randrange(1, 99999999)).zfill(8), '1', ] try: claveacceso = ''.join(data) claveacceso += str(self.modulo11(claveacceso)) except: raise UserError( _(u""" Falta informacion: fecha = %s, comprobante = %s, ruc = %s, ambiente = %s, establecimiento = %s, puntoemision = %s, secuencial = %s, nro aleatorio = %s, Tipo de emisión = %s, """ % tuple(data))) return claveacceso @api.multi def _get_reference_models(self): records = self.env['ir.model'].search([ '|', ('model', '=', 'account.invoice'), ('model', '=', 'stock.picking') ]) return [(record.model, record.name) for record in records] + [('', '')] reference = fields.Reference(string='Reference', selection='_get_reference_models') comprobante_id = fields.Many2one( 'l10n_ec_sri.comprobante', string='Comprobante', copy=False, ) tipoemision = fields.Selection( [ ('1', 'Emisión normal'), ('2', 'Emisión por indisponibilidad del sistema'), ], string='Tipo de emisión', ) ambiente = fields.Selection( [ ('1', 'Pruebas'), ('2', 'Producción'), ], string='Ambiente', ) @api.one def get_barcode_128(self): if self.claveacceso: file_data = StringIO.StringIO() generate('code128', u'{}'.format(self.claveacceso), writer=ImageWriter(), output=file_data) file_data.seek(0) self.barcode128 = base64.encodestring(file_data.read()) claveacceso = fields.Char('Clave de acceso', ) barcode128 = fields.Binary('Barcode', compute=get_barcode_128) fechaautorizacion = fields.Datetime('Fecha y hora de autorización', ) mensajes = fields.Text('Mensajes', ) estado = fields.Selection([ ('NO ENVIADO', 'NO ENVIADO'), # Documentos fuera de línea. ('RECIBIDA', 'RECIBIDA'), ('EN PROCESO', 'EN PROCESO'), ('DEVUELTA', 'DEVUELTA'), ('AUTORIZADO', 'AUTORIZADO'), ('NO AUTORIZADO', 'NO AUTORIZADO'), ('RECHAZADA', 'RECHAZADA'), ]) xml_file = fields.Binary( 'Archivo XML', attachment=True, readonly=True, ) xml_filename = fields.Char('Filename', )
class edi_message(models.Model): _name = 'edi.message' _inherit = ['mail.thread'] _description = 'EDI Message' name = fields.Char(string="Name", required=True) envelope_id = fields.Many2one(comodel_name='edi.envelope', required=False) consignor_id = fields.Many2one( comodel_name='res.partner', required=False, string="Consignor", help="Consignor - the party sending the goods.") consignee_id = fields.Many2one( comodel_name='res.partner', required=False, string="Consignee", help="Consignee - the party receiving the goods.") sender = fields.Many2one(comodel_name='res.partner', string='Interchange Sender') recipient = fields.Many2one(comodel_name='res.partner', string='Interchange Recipient') forwarder_id = fields.Many2one( comodel_name='res.partner', string="Forwarder", help= "Forwarder - the party planning the transport on behalf of the consignor or consignee." ) carrier_id = fields.Many2one( comodel_name='res.partner', string="Carrier", help="Carrier - the party transporting the goods between two points.") body = fields.Binary() model = fields.Char(string="Model") res_id = fields.Integer() to_import = fields.Boolean(default=False) to_export = fields.Boolean(default=False) route_id = fields.Many2one(comodel_name="edi.route") route_type = fields.Selection(selection=[('plain', 'Plain')], default='plain') edi_type = fields.Many2one(comodel_name='edi.message.type', string="Edi Type") state = fields.Selection([('progress', 'Progress'), ('sent', 'Sent'), ('received', 'Received'), ('canceled', 'Canceled')], default='progress') @api.one def draft(self): self.state = 'progress' @api.one def unpack(self): try: res = self._unpack() except ValueError as e: id = self.env['mail.message'].create({ 'body': _("Route %s type %s Error %s\n" % (self.route_id.name, self.route_type, e)), 'subject': "ValueError", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) _logger.error( 'edi.message.unpack(): EDI ValueError Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) #raise Warning('EDI ValueError in split %s (%s) %s' % (e,id,d)) self.state = 'canceled' except TypeError as e: self.env['mail.message'].create({ 'body': _("Route %s type %s Error %s\n" % (self.route_id.name, self.route_type, e)), 'subject': "TypeError", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) _logger.error( 'edi.message.unpack(): EDI TypeError Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) #raise Warning('EDI TypeError in split %s' % e) self.state = 'canceled' except IOError as e: self.env['mail.message'].create({ 'body': _("Route %s type %s Error %s\n" % (self.route_id.name, self.route_type, e)), 'subject': "IOError", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) _logger.error( 'edi.message.unpack(): EDI IOError Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) #raise Warning('EDI IOError in split %s' % e) self.state = 'canceled' except Warning as e: _logger.error( 'edi.message.unpack(): EDI Warning Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) self.state = 'canceled' else: self.env['mail.message'].create({ 'body': _("Route %s type %s %s messages unpacked\n" % (self.route_id.name, self.route_type, self.edi_type.name)), 'subject': "Success", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) self.state = 'received' @api.one def _unpack(self): pass @api.one def pack(self): try: res = self._pack() except ValueError as e: id = self.env['mail.message'].create({ 'body': _("Route %s type %s Value Error %s\n" % (self.route_id.name, self.route_type, e)), 'subject': "ValueError", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) _logger.error( 'edi.message.pack(): EDI ValueError Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) #raise Warning('EDI ValueError in split %s (%s) %s' % (e,id,d)) except TypeError as e: self.env['mail.message'].create({ 'body': _("Route %s type %s Type Error %s\n" % (self.route_id.name, self.route_type, e)), 'subject': "TypeError", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) _logger.error( 'edi.message.pack(): EDI TypeError Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) raise raise Warning('EDI TypeError in split %s' % e) except IOError as e: self.env['mail.message'].create({ 'body': _("Route %s type %s IOError %s\n" % (self.route_id.name, self.route_type, e)), 'subject': "IOError", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) _logger.error( 'edi.message.pack(): EDI IOError Route %s type %s Error %s ' % (self.route_id.name, self.route_type, e)) #raise Warning('EDI IOError in split %s' % e) else: self.env['mail.message'].create({ 'body': _("Route %s type %s %s messages packed\n" % (self.route_id.name, self.route_type, self.edi_type.name)), 'subject': "Success", 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': self.id, 'model': self._name, 'type': 'notification', }) @api.one def _pack(self): pass def _edi_message_create(self, edi_type=None, obj=None, sender=None, recipient=None, consignee=None, consignor=None, route=None, check_double=True): if consignee and obj and edi_type: #do not create message if edi type is not listed in consignee if not self.env.ref(edi_type).id in consignee.get_edi_types( consignee): return None if check_double and len(self.env['edi.message'].search( [('model', '=', obj._name), ('res_id', '=', obj.id), ('edi_type', '=', self.env.ref(edi_type).id)])) > 0: return None message = self.env['edi.message'].create({ 'name': self.env['ir.sequence'].next_by_id( self.env.ref('edi_route.sequence_edi_message').id), 'edi_type': self.env.ref(edi_type).id, 'model': obj._name, 'res_id': obj.id, 'route_id': route and route.id or self.env.ref('edi_route.main_route'). id, #routes.get(edi_type,1),# self.env.ref('edi_route.main_route').id), 'route_type': route and route.route_type or self.env.ref('edi_route.main_route').route_type, # This is a reply, switch recipient/sender unless we got excplicit parties 'sender': sender and sender.id or obj.unb_recipient.id, 'recipient': recipient and recipient.id or obj.unb_sender.id, 'consignor_id': consignor and consignor.id or self.env.ref('base.main_partner').id, 'consignee_id': consignee.id, }) message.pack() self.env['mail.message'].create({ 'body': _("{type} <a href='/web#model={model}&id={id}'>{message}</a> created\n" ).format(type=self.env.ref(edi_type).name, model=message._name, id=message.id, message=message.name), 'subject': self.env.ref(edi_type).name, 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': obj.id, 'model': obj._name, 'type': 'notification', }) self.env['mail.message'].create({ 'body': _("{type} <a href='/web#model={model}&id={id}'>{message}</a> created\n" ).format(type=self.env.ref(edi_type).name, model=obj._name, id=obj.id, message=obj.name), 'subject': self.env.ref(edi_type).name, 'author_id': self.env['res.users'].browse(self.env.uid).partner_id.id, 'res_id': message.id, 'model': message._name, 'type': 'notification', }) @api.one def _model_record(self): if self.model and self.res_id and self.env[self.model].browse( self.res_id): self.model_record = self.env[self.model].browse(self.res_id) @api.model def _reference_models(self): models = self.env['ir.model'].search([('state', '!=', 'manual')]) # return self.env[self.model].browse(self.res_id) return [(model.model, model.name) for model in models if not model.model.startswith('ir.')] model_record = fields.Reference(string="Record", selection="_reference_models", compute="_model_record")
class gdpr_object(models.Model): _name = 'gdpr.object' @api.one def _get_name(self): if self.object_id and hasattr(self.object_id, 'name'): self.name = self.object_id.name elif self.object_id: self.name = '%s, %s' % (self.object_id._name, self.object_id.id) else: self.name = 'gdpr.object, %s' % self.id name = fields.Char(string='Name', compute='_get_name') gdpr_id = fields.Many2one(string='Inventory', comodel_name='gdpr.inventory') object_id = fields.Reference(string='Object', selection='_reference_models', compute='_get_object_id', inverse='_set_object_id', search='_search_object_id') object_model = fields.Char(string='Object Model') object_res_id = fields.Integer(string='Object ID') partner_id = fields.Many2one(string='Partners', comodel_name='res.partner') restricted = fields.Boolean(string='Restricted', help="This record has been restricted.") manual = fields.Boolean(string='Manual Action Required', help="This record needs attention.") @api.one def _get_object_id(self): if self.object_model and self.object_res_id: self.object_id = self.env[self.object_model].search([ ('id', '=', self.object_res_id) ]) @api.one def _set_object_id(self): if self.object_id: self.object_res_id = self.object_id.id self.object_model = self.object_id._name else: self.object_res_id = False self.object_model = False @api.model def _search_object_id(self, operator, value): _logger.debug('_search_object_id; operator: %s, value: %s' % (operator, value)) if operator in ('in', 'not in'): if operator == 'in': op_m = '=' ao1 = '&' ao2 = '|' else: op_m = '!=' ao1 = '|' ao2 = '&' ids = {} for v in value: m, id = v.split(',') if m not in ids: ids[m] = [] ids[m].append(int(id)) res = [] for model in ids: if res: res = [ao2] + res res += [ ao1, ('object_model', op_m, model), ('object_res_id', operator, ids[model]) ] elif value: res = [ '&', ('object_model', operator, value.split(',')[0]), ('object_res_id', operator, int(value.split(',')[1])) ] else: res = [ '&', ('object_model', operator, value), ('object_res_id', operator, value) ] _logger.debug(res) return res @api.model def _reference_models(self): models = self.env['ir.model'].search([('state', '!=', 'manual')]) return [(model.model, model.name) for model in models]
class CenitFlow(models.Model): _name = "cenit.flow" _inherit = 'cenit.api' cenit_model = 'flow' cenit_models = 'flows' cenitID = fields.Char('Cenit ID') namespace = fields.Many2one('cenit.namespace', string='Namespace', ondelete='cascade') name = fields.Char('Name', size=64, required=True, unique=True) enabled = fields.Boolean('Enabled', default=True) event = fields.Many2one("cenit.event", string='Event') discard_events = fields.Boolean("Discard events", default=False) cron = fields.Many2one('ir.cron', string='Cron rules') base_action_rules = fields.Many2many( 'base.action.rule', string='Action Rule' ) format_ = fields.Selection( [ ('application/json', 'JSON'), ('application/EDI-X12', 'EDI') ], 'Format', default='application/json', required=True ) local = fields.Boolean('Bypass Cenit', default=False) cenit_translator = fields.Many2one('cenit.translator', "Translator") schema = fields.Many2one( 'cenit.schema', 'Data type', required=True ) data_type = fields.Many2one( 'cenit.data_type', string='Source data type' ) webhook = fields.Reference(string='Webhook', selection=[('cenit.webhook', 'Plain'), ('cenit.operation', 'Operation')], required=True) connection_role = fields.Many2one( 'cenit.connection.role', string='Connection role' ) @api.depends('webhook') def _compute_method(self): self.method = self.webhook.method method = fields.Char(compute="_compute_method") _sql_constraints = [ ('name_uniq', 'UNIQUE(namespace, name)', 'The name must be unique for each namespace!') ] @api.one def _get_values(self): vals = { 'namespace': self.namespace.name, 'name': self.name, 'active': self.enabled, 'discard_events': False, 'data_type_scope': 'All', } if self.cenitID: vals.update({'id': self.cenitID}) event = { "_reference": True, "id": self.event.cenitID, } vals.update({ 'event': event, 'data_type_scope': 'Event', }) if self.cenit_translator: vals.update({ 'translator': { '_reference': True, 'id': self.cenit_translator.cenitID, } }) if self.schema.cenitID: vals.update({ 'custom_data_type': { '_reference': True, 'id': self.schema.cenitID } }) if self.connection_role: vals.update({ 'connection_role': { '_reference': True, 'id': self.connection_role.cenitID } }) if self.webhook: vals.update({ 'webhook': { '_reference': True, 'id': self.webhook.cenitID } }) return vals @api.one def _calculate_update(self, values): update = {} for k, v in values.items(): if k == "%s" % (self.cenit_models,): update = { 'cenitID': v[0]['id'], } return update @api.onchange('webhook') def on_webhook_changed(self): return { 'value': { 'connection_role': "" }, "domain": { "connection_role": [ ('webhooks', 'in', self.webhook.id) ] } } @api.onchange('schema') def on_schema_changed(self): return { 'value': { 'data_type': "", 'event': "", }, "domain": { "data_type": [ ('schema', '=', self.schema.id), ('enabled', '=', True) ], 'event': [ ('schema', '=', self.schema.id) ], } } @api.onchange('schema', 'webhook') def _on_schema_or_hook_changed(self): return { 'value': { 'cenit_translator': "", }, 'domain': { 'cenit_translator': [ ('schema', 'in', (self.schema.id, False)), ('type_', '=', {'get': 'Import', }.get(self.webhook.method, 'Export')) ] } } @api.one def _get_direction(self): my_url = self.env['ir.config_parameter'].get_param( 'web.base.url', default='' ) conn = self.connection_role.connections and \ self.connection_role.connections[0] my_conn = conn.url == my_url rc = { ('get', True): 'send', ('put', False): 'send', ('post', False): 'send', ('delete', False): 'send', }.get((self.webhook.method, my_conn), 'receive') return rc @api.one def _get_data_types(self, dt_id): dt_pool = self.env['cenit.data_type'] if self.data_type: return self.data_type else: domain = [('schema', '=', self.schema.id), ('enabled', '=', True), ('id', '=', dt_id)] return dt_pool.search(domain) @api.model def create(self, vals): local = (vals.get('cenitID', False) is False) or \ (self.env.context.get('local'), False) if not isinstance(vals['namespace'], int): vals['namespace'] = vals['namespace']['id'] obj = super(CenitFlow, self).create(vals) return obj @api.model def find(self, model, purpose): rc = [] domain = [("schema.slug", "=", model)] objs = self.search(domain) if objs: rc = [x for x in objs if ((x._get_direction()[0] == purpose) and x.enabled)] return rc @api.one def set_receive_execution(self): return True @api.model def receive(self, model, data): res = False context = self.env.context.copy() or {} flows = self.find(model.lower(), 'receive') if not flows: return res data_types = set() for flow in flows: dts = flow._get_data_types() for dt in dts: data_types.add(dt) for dt in data_types: klass = self.env[dt.model.model] if flow.format_ == 'application/json': action = context.get('action', 'push') wh = self.env['cenit.handler'] context.update({'receive_object': True}) action = getattr(wh, action, False) if action: root = dt.cenit_root res = action(data, root) elif flow.format_ == 'application/EDI-X12': for edi_document in data: klass.edi_import(edi_document) res = True return res @api.one def set_send_execution(self): return True @api.model def send(self, obj, flow_id, dt_id): flow = self.browse(flow_id) if not (flow and flow.enabled): return False ws = self.env['cenit.serializer'] data_types = flow._get_data_types(dt_id) if isinstance(data_types, list) and len(data_types) == 1: data_types = data_types[0] data = None if flow.format_ == 'application/json': data = [] for dt in data_types: match = dt.ensure_object(obj) if isinstance(match, list): match = match[0] if match: data.append(ws.serialize(obj, dt)) elif flow.format_ == 'application/EDI-X12': dt = data_types[0] if dt.ensure_object(obj): data = dt.model.edi_export([obj]) rc = False if data: _logger.info("\n\nPushing: %s\n", data) rc = flow._send(data) return rc @api.model def send_all(self, id_, dt, domain=list()): flow = self.browse(id_) dt_ = flow.data_type or dt mo = self.env[dt_.model.model] _logger.info("Performing search on %s with %s", mo, domain) data = [] query = "SELECT id from %s" % dt.model.model.replace(".", "_") for entry in domain: query += " WHERE %s%s'%s'" % (entry[0], entry[1], entry[2]) self.env.cr.execute(query) rc = self.env.cr.fetchall() objs = mo.browse([x[0] for x in rc]) if flow.format_ == 'application/json': ws = self.env['cenit.serializer'] for x in objs: if dt_.ensure_object(x): data.append(ws.serialize(x, dt_)) elif flow.format_ == 'application/EDI-X12' and \ hasattr(mo, 'edi_export'): for x in objs: if dt_.ensure_object(x): data.append(mo.edi_export(x)) if data: return flow._send(data) return False @api.one def _send(self, data): method = "http_post" return getattr(self, method)(data) @api.one def http_post(self, data): path = "/%s/%s" % (self.schema.namespace.slug, self.schema.slug,) values = data[0] rc = False try: rc = self.post(path, values) except Warning as e: _logger.exception(e) return rc
class IrUiMenu(models.Model): _name = 'builder.ir.ui.menu' _rec_name = 'complete_name' @api.multi def get_user_roots(self): """ Return all root menu ids visible for the user. :return: the root menu ids :rtype: list(int) """ menu_domain = [('parent_id', '=', False), ('parent_ref', '=', False)] return self.search(menu_domain) @api.multi def load_menus_root(self): menu_roots = self.get_user_roots() return { 'id': False, 'name': 'root', 'parent_id': [-1, ''], 'children': menu_roots, 'all_menu_ids': [i.id for i in menu_roots], } def _get_full_name(self, cr, uid, ids, name=None, args=None, context=None): if context is None: context = {} res = {} for elmt in self.browse(cr, uid, ids, context=context): res[elmt.id] = self._get_one_full_name(elmt) return res def _get_one_full_name(self, elmt, level=6): if level<=0: return '...' if elmt.parent_id: parent_path = self._get_one_full_name(elmt.parent_id, level-1) + MENU_ITEM_SEPARATOR else: parent_path = '' return parent_path + elmt.name @api.onchange('parent_ref') def onchange_parent_ref(self): self.parent_menu_id = False if self.parent_ref: self.parent_menu_id = self.env['ir.model.data'].xmlid_to_res_id(self.parent_ref) @api.onchange('parent_menu_id') def onchange_parent_menu_id(self): if self.parent_menu_id: data = self.env['ir.model.data'].search([('model', '=', 'ir.ui.menu'), ('res_id', '=', self.parent_menu_id.id)]) self.parent_ref = "{module}.{id}".format(module=data.module, id=data.name) if data.id else False @api.onchange('parent_type') def onchange_parent_type(self): self.parent_ref = False self.parent_menu_id = False self.parent_id = False module_id = fields.Many2one('builder.ir.module.module', 'Module', ondelete='cascade') name = fields.Char('Menu', required=True, translate=True) xml_id = fields.Char('XML ID', required=True) complete_name = fields.Char('Complete Name', compute='_compute_complete_name') morder = fields.Integer('Order') sequence = fields.Integer('Sequence') child_ids = fields.One2many('builder.ir.ui.menu', 'parent_id', 'Child Ids', copy=True) # group_ids = fields.Many2many('builder.res.groups', 'builder_ir_ui_menu_group_rel', 'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\ # "If this field is empty, Odoo will compute visibility based on the related object's read access.") parent_menu_id = fields.Many2one('ir.ui.menu', 'System Menu', ondelete='set null') parent_ref = fields.Char('System Menu Ref', select=True) parent_id = fields.Many2one('builder.ir.ui.menu', 'Parent Menu', select=True, ondelete='cascade') parent_type = fields.Selection([('module', 'Module'), ('system', 'System')], 'Parent Type') parent_left = fields.Integer('Parent Left', select=True) parent_right = fields.Integer('Parent Left', select=True) action_type = fields.Selection([('module', 'Module'), ('system', 'System')], 'Action Type') action_system_ref = fields.Char('Action System Ref') action_system = fields.Reference([ ('ir.actions.report.xml', 'ir.actions.report.xml'), ('ir.actions.act_window', 'ir.actions.act_window'), ('ir.actions.wizard', 'ir.actions.wizard'), ('ir.actions.act_url', 'ir.actions.act_url'), ('ir.actions.server', 'ir.actions.server'), ('ir.actions.client', 'ir.actions.client'), ], 'System Action') action_module = fields.Reference([ ('builder.ir.actions.act_window', 'Window'), # ('builder.ir.actions.act_url', 'URL'), ], 'Module Action') group_ids = fields.Many2many('builder.res.groups', 'builder_ir_ui_menu_group_rel', 'menu_id', 'gid', string='Groups', help="If this field is empty, the menu applies to all users. Otherwise, the view applies to the users of those groups only.") @api.onchange('action_system') def onchange_action_system(self): if self.action_system: model, res_id = self.action_system._name, self.action_system.id data = self.env['ir.model.data'].search([('model', '=', model), ('res_id', '=', res_id)]) self.action_system_ref = "{module}.{id}".format(module=data.module, id=data.name) if data.id else False self.name = self.action_system.name self.xml_id = "menu_{action}".format(action=self.action_system_ref.replace('.', '_')) @api.onchange('action_module') def onchange_action_module(self): if self.action_module: self.name = self.action_module.name self.xml_id = "menu_{action}".format(action=self.action_module.xml_id) @api.model @api.returns('self', lambda value: value.id) def create(self, vals): if not vals.get('parent_type', False): vals['parent_id'] = False vals['parent_menu_id'] = False vals['parent_ref'] = False return super(IrUiMenu, self).create(vals) @api.multi def write(self, vals): if not vals.get('parent_type', self.parent_type): vals['parent_id'] = False vals['parent_menu_id'] = False vals['parent_ref'] = False return super(IrUiMenu, self).write(vals) @api.one def _compute_complete_name(self): self.complete_name = self._get_full_name_one() @api.multi def _get_full_name_one(self, level=6): if level <= 0: return '...' parent_path = '' if self.parent_id: parent_path = self.parent_id._get_full_name_one(level-1) + MENU_ITEM_SEPARATOR elif self.parent_ref: if self.parent_menu_id: parent_path = '[{name}]'.format(name=self.parent_menu_id.complete_name.encode('utf-8')) + MENU_ITEM_SEPARATOR else: parent_path = '[{ref}]'.format(ref=self.parent_ref) + MENU_ITEM_SEPARATOR try: return parent_path + self.name.encode('utf-8') except: return False @api.one def name_get(self): return self.id, self._get_full_name_one() def _rec_message(self, cr, uid, ids, context=None): return _('Error ! You can not create recursive Menu.') @property def real_xml_id(self): return self.xml_id if '.' in self.xml_id else '{module}.{xml_id}'.format(module=self.module_id.name, xml_id=self.xml_id) _constraints = [ (osv.osv._check_recursion, _rec_message, ['parent_id']) ] _defaults = { 'sequence': 10, } _order = "morder,id" _parent_store = True
class clv_medicament_dispensation_ext(models.Model): _name = 'clv_medicament_dispensation_ext' name = fields.Char(size=32, string='Dispensation Code', required=False, help='Type in the Code of this dispensation (ext)') authorization_code = fields.Char(size=32, string='Authorization Code', required=False) dispensation_date = fields.Date(string='Dispensation Date', required=False) insured_card_code = fields.Char(size=32, string='Insured Card Code', required=False) insured_name = fields.Char(size=256, string='Insured Name', required=False) prescriber_code = fields.Char(size=32, string='Prescriber Code', required=False) pharmacy_code = fields.Char(size=32, string='Pharmacy Code', required=False) pharmacy_name = fields.Char(size=256, string='Pharmacy Name', required=False) medicament_code = fields.Integer(string='Medicament Code') medicament_description = fields.Char(size=256, string='Medicament Description', required=False) notes = fields.Text(string='Dispensation Notes') # dispenser = fields.Many2one ('res.users', 'Dispenser') medicament_ref = fields.Reference([ ('clv_medicament', 'Medicament'), ], 'Medicament Reference') medicament = fields.Many2one('clv_medicament', string='Dispensed Medicament', required=False, help='Dispensed Medicament') # max_retail_price = fields.Float('Maximum Retail Price') pack_quantity = fields.Integer(string='Pack Quantity', help='Quantity of packs of the medicament') # refund_price = fields.Float('Refund Price') # total_refund_price = fields.Float('Refund Value', size=32, compute='_total_refund_price', store=False) sale_value = fields.Float('Sale Value') subsidy_value = fields.Float('Subsidy Value') at_sight_value = fields.Float('At Sight Value') date_inclusion = fields.Datetime( "Inclusion Date", required=False, readonly=False, default=lambda *a: datetime.now().strftime('%Y-%m-%d %H:%M:%S')) active = fields.Boolean( 'Active', help= "If unchecked, it will allow you to hide the dispensation without removing it.", default=1) _sql_constraints = [ ('uniq_name', 'unique(name)', "Error! The Dispensation (Ext) Code must be unique!"), ] _order = 'name'
class Cloud_Service_tmpl(models.Model): _inherit = 'cloud.service.tmpl' instance_de_gestion = fields.Reference( selection_add=[('cloud.service.instance.service', '')])
class DobtorTodoListCore(models.Model): _name = "dobtor.todolist.core" _inherit = ["mail.thread", 'ir.needaction_mixin'] _description = 'Dobtor Todo List Core' state = fields.Selection([(k, v) for k, v in TODO_STATES.items()], 'Status', required=True, copy=False, default='todo') name = fields.Char(required=True, string="Description") creater = fields.Many2one('res.users', 'Creater', readonly=True, default=lambda self: self.env.user) reviewer_id = fields.Many2one('res.users', 'Reviewer', default=lambda self: self.env.user) user_id = fields.Many2one('res.users', 'Assigned to', required=True) hide_button = fields.Boolean(compute='_compute_hide_button') recolor = fields.Boolean(compute='_compute_recolor') ref_model = fields.Reference(referencable_models, "Refer To", default=None) ref_id = fields.Integer(string='ref_id') ref_name = fields.Char(string='ref_name') parent_model = fields.Reference(referencable_models, "Parent", default=None) parent_id = fields.Integer(string='parent_id') parent_name = fields.Char(string='parent_name') partner_id = fields.Many2one('res.partner', default=lambda self: self.env.user.partner_id) date_assign = fields.Datetime('Assigning Date', select=True, default=fields.Datetime.now) date_complete = fields.Datetime('Complete Date', select=True) date_deadline = fields.Datetime("Deadline", select=True) planned_hours = fields.Float(string='Planned Hours', default=0) out_of_deadline = fields.Boolean("Out of deadline", default=False, compute="check_deadline") sequence = fields.Integer() @api.multi def check_deadline(self): for record in self: if record.date_deadline and record.date_deadline <= fields.Datetime.now( ): record.out_of_deadline = True else: record.out_of_deadline = False @api.multi def _compute_recolor(self): for record in self: if self.env.user == record.user_id and record.state == 'todo': record.recolor = True @api.multi def _compute_hide_button(self): for record in self: if self.env.user not in [record.reviewer_id, record.user_id]: record.hide_button = True @api.multi def _compute_reviewer_id(self): for record in self: record.reviewer_id = record.create_uid @api.model def _needaction_domain_get(self): if self._needaction: return [('state', '=', 'todo'), ('user_id', '=', self.env.uid)] return [] @api.multi def write(self, vals): if 'ref_model' in vals and vals['ref_model']: vals['ref_id'] = vals['ref_model'].split(',')[1] vals['ref_name'] = vals['ref_model'].split(',')[0] if 'parent_model' in vals and vals['parent_model']: vals['parent_id'] = vals['parent_model'].split(',')[1] vals['parent_name'] = vals['parent_model'].split(',')[0] result = super(DobtorTodoListCore, self).write(vals) return result @api.model def create(self, vals): print("todo create") if 'ref_model' in vals and vals['ref_model']: vals['ref_id'] = vals['ref_model'].split(',')[1] vals['ref_name'] = vals['ref_model'].split(',')[0] if 'parent_model' in vals and vals['parent_model']: vals['parent_id'] = vals['parent_model'].split(',')[1] vals['parent_name'] = vals['parent_model'].split(',')[0] result = super(DobtorTodoListCore, self).create(vals) vals = self._add_missing_default_values(vals) # task = self.env['project.task'].browse(vals.get('task_id')) # task.send_subtask_email(vals['name'], vals['state'], vals['reviewer_id'], vals['user_id']) return result @api.multi def change_state_done(self): for record in self: record.state = 'done' record.date_complete = fields.Datetime.now() @api.multi def change_state_todo(self): for record in self: record.state = 'todo' record.date_complete = None @api.multi def change_state_cancelled(self): for record in self: record.state = 'cancelled' record.date_complete = None @api.multi def change_state_waiting(self): for record in self: record.state = 'waiting' record.date_complete = None @api.onchange('user_id') def change_user_id(self): if self.user_id: self.date_assign = fields.Datetime.now() else: self.date_assign = None
class NeedSync(models.Model): _name = "need.sync" _description = "Need Sync Base Model" def _select_models(self): return self.env['need.sync.model']._select_models() name = fields.Char(string="Sync", compute="_get_name", store=True) model = fields.Selection(selection=_select_models, string="Model", required=True, index=True) res_id = fields.Integer(string='Record ID', index=True, required=True, help="ID of the target record in the database") record = fields.Reference(selection=_select_models, string="Record", compute="_get_record", store=True, size=128) need_sync_date = fields.Datetime(string="Need Sync Datetime") sync_lines = fields.One2many(comodel_name="need.sync.line", inverse_name="need_sync", string="Sync Lines") @api.one @api.depends('res_id', 'model') def _get_record(self): if self.res_id and self.model: self.record = self.env[str(self.model)].browse(self.res_id) @api.one @api.depends('res_id', 'model') def _get_name(self): object = self.env[self.model].browse(self.res_id) if object and 'name' in object._fields: object_name = object.name else: object_name = "No object name defined" self.name = '%s' % (object_name) @api.model def get_model_allowed_connections(self): syncmodels = self.env['need.sync.connection.model'].search([ ('model', '=', self.model), ('auto_create_lines', '=', True) ]) _logger.debug("Sync Model Connnections: %s", syncmodels) connections = syncmodels.mapped('need_sync_connection') _logger.debug("Sync Connections: %s", connections) return connections @api.model def _autocreate_syncline_connection(self, connection): lines = self.sync_lines cline = lines.filtered( lambda l: l.need_sync_connection.id == connection.id) if not cline: self.env['need.sync.line'].create({ 'need_sync_connection': connection.id, 'need_sync': self.id }) @api.one def _autocreate_sync_lines(self): if self.model: connections = self.get_model_allowed_connections() for connection in connections: _logger.debug("Autocreate for Conncetion: %s", connection) self._autocreate_syncline_connection(connection) @api.multi def set_need_sync(self, model, res_ids): """ Pass need sync to model and resources :param model: need sync on wich model :param res: list of resources to set sync :return: boolean True or False """ if isinstance(res_ids, (long, int)): res_ids = [res_ids] # Get list of IDS where a record in need sync exists # and a list for creating a need sync record need_syncs = self.search([('model', '=', model), ('res_id', 'in', res_ids)]) need_syncs.write({'need_sync_date': fields.Datetime.now()}) # Need sync res_ids list need_sync_res_ids = [x.res_id for x in need_syncs] create_sync_ids = list(set(res_ids) - set(need_sync_res_ids)) if create_sync_ids: _logger.debug("Create new Need sync records") created_need_syncs = self._create_need_sync(model, create_sync_ids) need_syncs = need_syncs | created_need_syncs # Check if all lines exist for autocreate models _logger.debug("Need Syncs Autocreate Check: %s", need_syncs) need_syncs._autocreate_sync_lines() @api.model def _create_need_sync(self, model, res_ids): return_need_syncs = self.env['need.sync'] if model and res_ids: for res_id in res_ids: create_need_sync = self.create({ 'model': model, 'res_id': res_id, 'need_sync_date': fields.Datetime.now() }) _logger.debug("Need Sync Created: %s", create_need_sync) return_need_syncs = return_need_syncs | create_need_sync return return_need_syncs @api.model def unlink_records(self, model, res_ids): ''' When calling unlink of a used model record, call this method to remove the linked need syncs. :param model: Model :param res_ids: List of ids :return: True ''' need_syncs = self.search([('model', '=', model), ('res_id', 'in', res_ids)]) if need_syncs: need_syncs.unlink() return True
class AccountAnalyticReport(models.Model): _name = 'account.analytic.report' name = fields.Char('Name', required=True) template_id = fields.Many2one('account.analytic.report.template', 'Template', required=True) calc_date = fields.Date('Calc date') ref_1 = fields.Reference(selection=[('res.company', 'Company'), ('res.partner.category', 'Farm group') ], string='Reference') from_date_1 = fields.Date('From date') to_date_1 = fields.Date('To date') milk_1 = fields.Float('Milk') total_cows_1 = fields.Integer('Total cows') employees_1 = fields.Integer('Total employees') total_heifer_1 = fields.Integer('Total heifer') ref_2 = fields.Reference(selection=[('res.company', 'Company'), ('res.partner.category', 'Farm group') ], string='Reference') from_date_2 = fields.Date('From date') to_date_2 = fields.Date('To date') milk_2 = fields.Float('Milk') total_cows_2 = fields.Integer('Total cows') employees_2 = fields.Integer('Total employees') total_heifer_2 = fields.Integer('Total heifer') line_ids = fields.One2many('account.analytic.report.line', 'report_id', 'Lines') state = fields.Selection([('draft', 'Draft'), ('calc', 'Calculating'), ('calc_done', 'Calculated'), ('done', 'Done'), ('cancel', 'Cancel')], 'State', default='draft') def _get_company(self): return self.env.user.company_id company_id = fields.Many2one('res.company', 'Company', default=_get_company) @api.multi def _get_companies(self, company_1_2=1): self.ensure_one() companies = self.env['res.company'] ref_field = 'ref_%s' % str(company_1_2) if not self[ref_field]: return companies if 'res.company' == str(self[ref_field]._model): companies = self[ref_field] elif 'res.partner.category' == str(self[ref_field]._model): partners = self.env['res.partner'].search([('category_id', '=', self[ref_field].id)]) companies = partners.filtered(lambda partner: partner.farm).mapped( 'company_id') return companies @api.multi def _set_milk_fields(self): self.ensure_one() for i in (1, 2): from_date = 'from_date_' + str(i) to_date = 'to_date_' + str(i) companies = self._get_companies(i) partner_companies = companies.mapped('partner_id') quotas = self.env['output.quota'].search([ ('farm_id', 'in', partner_companies._ids), ('date', '>=', self[from_date]), ('date', '<=', self[to_date]) ]) self['milk_' + str(i)] = sum([x.value for x in quotas]) @api.multi def _set_total_cows_fields(self): self.ensure_one() for i in (1, 2): from_date = 'from_date_' + str(i) to_date = 'to_date_' + str(i) companies = self._get_companies(i) partner_companies = companies.mapped('partner_id') total_cows = 0 for partner in partner_companies: cow_counts = self.env['cow.count'].search([ ('partner_id', '=', partner.id), ('date', '>=', self[from_date]), ('date', '<=', self[to_date]) ]) if not cow_counts: continue total_count = len(cow_counts) heifer_0_3 = sum(cow_counts.mapped('heifer_0_3')) / total_count heifer_3_12 = sum( cow_counts.mapped('heifer_3_12')) / total_count heifer_plus_12 = sum( cow_counts.mapped('heifer_plus_12')) / total_count milk_cow = sum(cow_counts.mapped('milk_cow')) / total_count dry_cow = sum(cow_counts.mapped('dry_cow')) / total_count total_cows += sum((heifer_0_3, heifer_3_12, heifer_plus_12, milk_cow, dry_cow)) self['total_cows_' + str(i)] = total_cows @api.multi def _set_employee_fields(self): self.ensure_one() for i in (1, 2): from_date = 'from_date_' + str(i) to_date = 'to_date_' + str(i) companies = self._get_companies(i) partner_companies = companies.mapped('partner_id') total_employee = 0 for partner in partner_companies: employee_count = self.env['employee.farm.count'].search([ ('partner_id', '=', partner.id), ('date', '>=', self[from_date]), ('date', '<=', self[to_date]) ]) if not employee_count: continue total_count = len(employee_count) total_employee += sum( employee_count.mapped('quantity')) / total_count self['employees_' + str(i)] = total_employee @api.multi def _set_total_heifer_fields(self): self.ensure_one() for i in (1, 2): from_date = 'from_date_' + str(i) to_date = 'to_date_' + str(i) companies = self._get_companies(i) partner_companies = companies.mapped('partner_id') total_cows = 0 for partner in partner_companies: cow_counts = self.env['cow.count'].search([ ('partner_id', '=', partner.id), ('date', '>=', self[from_date]), ('date', '<=', self[to_date]) ]) if not cow_counts: continue total_count = len(cow_counts) heifer_0_3 = sum(cow_counts.mapped('heifer_0_3')) / total_count heifer_3_12 = sum( cow_counts.mapped('heifer_3_12')) / total_count heifer_plus_12 = sum( cow_counts.mapped('heifer_plus_12')) / total_count total_cows += sum((heifer_0_3, heifer_3_12, heifer_plus_12)) self['total_heifer_' + str(i)] = total_cows @api.multi def act_button_update_fields(self): for report in self: report._set_milk_fields() report._set_total_cows_fields() report._set_employee_fields() report._set_total_heifer_fields() return True @api.one def refresh_values(self): field = 'val_%s' % str(1) for line in self.line_ids: companies = self._get_companies(1) line.value_1 = sum([line.get_value_1(x) for x in companies]) companies = self._get_companies(2) line.value_2 = sum([line.get_value_2(x) for x in companies]) @api.multi def act_cancel(self): self.write({'state': 'cancel'}) @api.multi def act_done(self): self.write({'state': 'done'}) @api.multi def calculate(self): self.write({ 'state': 'calc', 'calc_date': time.strftime('%Y-%m-%d %H:%M:%S') }) self.line_ids.unlink() for line in self.template_id.line_ids: self.env['account.analytic.report.line'].create({ 'report_id': self.id, 'code': line.code, 'sequence': line.sequence, 'name': line.name, 'notes': '', 'template_line_id': line.id, 'css_style': line.css_style }) for line in self.line_ids: if line.template_line_id.parent_id: parent_line = self.env['account.analytic.report.line'].search([ ('template_line_id', '=', line.template_line_id.parent_id.id), ('report_id', '=', self.id) ]) line.parent_id = parent_line self.refresh_values() self.state = 'calc_done'