def test_sequence_concurency(self): """Computing the same name in concurent transactions is not allowed.""" with self.env.registry.cursor() as cr0,\ self.env.registry.cursor() as cr1,\ self.env.registry.cursor() as cr2: env0 = api.Environment(cr0, SUPERUSER_ID, {}) env1 = api.Environment(cr1, SUPERUSER_ID, {}) env2 = api.Environment(cr2, SUPERUSER_ID, {}) journal = env0['account.journal'].create({ 'name': 'concurency_test', 'code': 'CT', 'type': 'general', }) account = env0['account.account'].create({ 'code': 'CT', 'name': 'CT', 'user_type_id': env0.ref('account.data_account_type_fixed_assets').id, }) moves = env0['account.move'].create([{ 'journal_id': journal.id, 'date': fields.Date.from_string('2016-01-01'), 'line_ids': [(0, 0, { 'name': 'name', 'account_id': account.id })] }] * 3) moves.name = '/' moves[0].action_post() self.assertEqual(moves.mapped('name'), ['CT/2016/01/0001', '/', '/']) env0.cr.commit() # start the transactions here on cr2 to simulate concurency with cr1 env2.cr.execute('SELECT 1') move = env1['account.move'].browse(moves[1].id) move.action_post() env1.cr.commit() move = env2['account.move'].browse(moves[2].id) with self.assertRaises( psycopg2.OperationalError), env2.cr.savepoint( ), mute_logger('flectra.sql_db'): move.action_post() self.assertEqual(moves.mapped('name'), ['CT/2016/01/0001', 'CT/2016/01/0002', '/']) moves.button_draft() moves.posted_before = False moves.unlink() journal.unlink() account.unlink() env0.cr.commit()
def poll(self, dbname, channels, last, options=None, timeout=TIMEOUT): if options is None: options = {} # Dont hang ctrl-c for a poll request, we need to bypass private # attribute access because we dont know before starting the thread that # it will handle a longpolling request if not flectra.evented: current = threading.current_thread() current._daemonic = True # rename the thread to avoid tests waiting for a longpolling current.setName("openerp.longpolling.request.%s" % current.ident) registry = flectra.registry(dbname) # immediatly returns if past notifications exist with registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) notifications = env['bus.bus'].poll(channels, last, options) # immediatly returns in peek mode if options.get('peek'): return dict(notifications=notifications, channels=channels) # or wait for future ones if not notifications: if not self.started: # Lazy start of events listener self.start() event = self.Event() for channel in channels: self.channels.setdefault(hashable(channel), set()).add(event) try: event.wait(timeout=timeout) with registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) notifications = env['bus.bus'].poll( channels, last, options) except Exception: # timeout pass finally: # gc pointers to event for channel in channels: channel_events = self.channels.get(hashable(channel)) if channel_events and event in channel_events: channel_events.remove(event) return notifications
def test_02_demo_address_and_company(self): ''' This test ensure that the company_id of the address (partner) is correctly set and also, is not wrongly changed. eg: new shipping should use the company of the website and not the one from the admin, and editing a billing should not change its company. ''' self._setUp_multicompany_env() so = self._create_so(self.demo_partner.id) env = api.Environment(self.env.cr, self.demo_user.id, {}) # change also website env for `sale_get_order` to not change order partner_id with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id): # 1. Logged in user, new shipping self.WebsiteSaleController.address(**self.default_address_values) new_shipping = self._get_last_address(self.demo_partner) self.assertTrue( new_shipping.company_id != self.env.user.company_id, "Logged in user new shipping should not get the company of the sudo() neither the one from it's partner.." ) self.assertEqual(new_shipping.company_id, self.website.company_id, ".. but the one from the website.") # 2. Logged in user, edit billing self.default_address_values['partner_id'] = self.demo_partner.id self.WebsiteSaleController.address(**self.default_address_values) self.assertEqual( self.demo_partner.company_id, self.company_c, "Logged in user edited billing (the partner itself) should not get its company modified." )
def _handle_exception(cls, exception): is_frontend_request = bool(getattr(request, 'is_frontend', False)) if not is_frontend_request: # Don't touch non frontend requests exception handling return super(IrHttp, cls)._handle_exception(exception) try: response = super(IrHttp, cls)._handle_exception(exception) if isinstance(response, Exception): exception = response else: # if parent excplicitely returns a plain response, then we don't touch it return response except Exception as e: if 'werkzeug' in config['dev_mode']: raise e exception = e code, values = cls._get_exception_code_values(exception) if code is None: # Hand-crafted HTTPException likely coming from abort(), # usually for a redirect response -> return it directly return exception if not request.uid: cls._auth_method_public() # We rollback the current transaction before initializing a new # cursor to avoid potential deadlocks. # If the current (failed) transaction was holding a lock, the new # cursor might have to wait for this lock to be released further # down the line. However, this will only happen after the # request is done (and in fact it won't happen). As a result, the # current thread/worker is frozen until its timeout is reached. # So rolling back the transaction will release any potential lock # and, since we are in a case where an exception was raised, the # transaction shouldn't be committed in the first place. request.env.cr.rollback() with registry(request.env.cr.dbname).cursor() as cr: env = api.Environment(cr, request.uid, request.env.context) if code == 500: _logger.error("500 Internal Server Error:\n\n%s", values['traceback']) values = cls._get_values_500_error(env, values, exception) elif code == 403: _logger.warning("403 Forbidden:\n\n%s", values['traceback']) elif code == 400: _logger.warning("400 Bad Request:\n\n%s", values['traceback']) try: code, html = cls._get_error_html(env, code, values) except Exception: code, html = 418, env['ir.ui.view']._render_template( 'http_routing.http_error', values) return werkzeug.wrappers.Response( html, status=code, content_type='text/html;charset=utf-8')
def _serve_attachment(cls): env = api.Environment(request.cr, SUPERUSER_ID, request.context) domain = [('type', '=', 'binary'), ('url', '=', request.httprequest.path)] fields = ['__last_update', 'datas', 'name', 'mimetype', 'checksum'] attach = env['ir.attachment'].search_read(domain, fields) if attach: wdate = attach[0]['__last_update'] datas = attach[0]['datas'] or b'' name = attach[0]['name'] checksum = attach[0]['checksum'] or hashlib.sha1(datas).hexdigest() if (not datas and name != request.httprequest.path and name.startswith(('http://', 'https://', '/'))): return werkzeug.utils.redirect(name, 301) response = werkzeug.wrappers.Response() server_format = tools.DEFAULT_SERVER_DATETIME_FORMAT try: response.last_modified = datetime.datetime.strptime(wdate, server_format + '.%f') except ValueError: # just in case we have a timestamp without microseconds response.last_modified = datetime.datetime.strptime(wdate, server_format) response.set_etag(checksum) response.make_conditional(request.httprequest) if response.status_code == 304: return response response.mimetype = attach[0]['mimetype'] or 'application/octet-stream' response.data = base64.b64decode(datas) return response
def _auto_install_enterprise_dependencies(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) module_list = ['account_accountant'] module_ids = env['ir.module.module'].search([('name', 'in', module_list), ('state', '=', 'uninstalled') ]) module_ids.sudo().button_install()
def _button_immediate_function(self, function): try: # This is done because the installation/uninstallation/upgrade can modify a currently # running cron job and prevent it from finishing, and since the ir_cron table is locked # during execution, the lock won't be released until timeout. self._cr.execute("SELECT * FROM ir_cron FOR UPDATE NOWAIT") except psycopg2.OperationalError: raise UserError( _("The server is busy right now, module operations are not possible at" " this time, please try again later.")) function(self) self._cr.commit() api.Environment.reset() modules.registry.Registry.new(self._cr.dbname, update_module=True) self._cr.commit() env = api.Environment(self._cr, self._uid, self._context) # pylint: disable=next-method-called config = env['ir.module.module'].next() or {} if config.get('type') not in ('ir.actions.act_window_close', ): return config # reload the client; open the first available root menu menu = env['ir.ui.menu'].search([('parent_id', '=', False)])[:1] return { 'type': 'ir.actions.client', 'tag': 'reload', 'params': { 'menu_id': menu.id }, }
def setUp(self): super(TestAPI, self).setUp() self.db_name = get_db_name() self.phantom_env = api.Environment(self.registry.test_cr, self.uid, {}) self.demo_user = self.phantom_env.ref(USER_DEMO) self.admin_user = self.phantom_env.ref(USER_ADMIN) self.model_name = "res.partner"
def test_03_public_user_address_and_company(self): ''' Same as test_02 but with public user ''' self._setUp_multicompany_env() so = self._create_so(self.website.user_id.partner_id.id) env = api.Environment(self.env.cr, self.website.user_id.id, {}) # change also website env for `sale_get_order` to not change order partner_id with MockRequest(env, website=self.website.with_env(env), sale_order_id=so.id): # 1. Public user, new billing self.default_address_values['partner_id'] = -1 self.WebsiteSaleController.address(**self.default_address_values) new_partner = so.partner_id self.assertNotEqual( new_partner, self.website.user_id.partner_id, "New billing should have created a new partner and assign it on the SO" ) self.assertEqual( new_partner.company_id, self.website.company_id, "The new partner should get the company of the website") # 2. Public user, edit billing self.default_address_values['partner_id'] = new_partner.id self.WebsiteSaleController.address(**self.default_address_values) self.assertEqual( new_partner.company_id, self.website.company_id, "Public user edited billing (the partner itself) should not get its company modified." )
def log_xml(self, xml_string, func): self.ensure_one() if self.debug_logging: self.flush() db_name = self._cr.dbname # Use a new cursor to avoid rollback that could be caused by an upper method try: db_registry = registry(db_name) with db_registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) IrLogging = env['ir.logging'] IrLogging.sudo().create({ 'name': 'delivery.carrier', 'type': 'server', 'dbname': db_name, 'level': 'DEBUG', 'message': xml_string, 'path': self.delivery_type, 'func': func, 'line': 1 }) except psycopg2.Error: pass
def oea(self, **kw): """login user via Flectra Account provider""" dbname = kw.pop('db', None) if not dbname: dbname = db_monodb() if not dbname: return BadRequest() if not http.db_filter([dbname]): return BadRequest() registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, {}) provider = env.ref('auth_oauth.provider_openerp') except ValueError: return set_cookie_and_redirect('/web?db=%s' % dbname) assert provider._name == 'auth.oauth.provider' state = { 'd': dbname, 'p': provider.id, 'c': { 'no_user_creation': True }, } kw['state'] = json.dumps(state) return self.signin(**kw)
def _serve_attachment(cls): env = api.Environment(request.cr, SUPERUSER_ID, request.context) attach = env['ir.attachment'].get_serve_attachment( request.httprequest.path, extra_fields=['name', 'checksum']) if attach: wdate = attach[0]['__last_update'] datas = attach[0]['datas'] or b'' name = attach[0]['name'] checksum = attach[0]['checksum'] or hashlib.sha512( datas).hexdigest()[:64] # sha512/256 if (not datas and name != request.httprequest.path and name.startswith(('http://', 'https://', '/'))): return werkzeug.utils.redirect(name, 301) response = werkzeug.wrappers.Response() response.last_modified = wdate response.set_etag(checksum) response.make_conditional(request.httprequest) if response.status_code == 304: return response response.mimetype = attach[0][ 'mimetype'] or 'application/octet-stream' response.data = base64.b64decode(datas) return response
def check_tables_exist(self, cr): """ Verify that all tables are present and try to initialize those that are missing. """ # This monkey patch is meant to avoid that the _logger writes # warning and error messages, while running an update all, # in case the model is a bi-view-generated model. env = api.Environment(cr, SUPERUSER_ID, {}) table2model = { model._table: name for name, model in env.items() if not model._abstract and not _bi_view(name) # here is the patch } missing_tables = set(table2model).difference( existing_tables(cr, table2model)) if missing_tables: missing = {table2model[table] for table in missing_tables} _logger.warning("Models have no table: %s.", ", ".join(missing)) # recreate missing tables following model dependencies deps = {name: model._depends for name, model in env.items()} for name in topological_sort(deps): if name in missing: _logger.info("Recreate table of model %s.", name) env[name].init() # check again, and log errors if tables are still missing missing_tables = set(table2model).difference( existing_tables(cr, table2model)) for table in missing_tables: _logger.error("Model %s has no table.", table2model[table])
def _set_default_identification_type(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) env.cr.execute( """ UPDATE res_partner SET l10n_latam_identification_type_id = %s """, [env.ref('l10n_latam_base.it_vat').id])
def authenticate(cls, db, login, password, user_agent_env): """Verifies and returns the user ID corresponding to the given ``login`` and ``password`` combination, or False if there was no matching user. :param str db: the database on which user is trying to authenticate :param str login: username :param str password: user password :param dict user_agent_env: environment dictionary describing any relevant environment attributes """ uid = cls._login(db, login, password) if uid == SUPERUSER_ID: # Successfully logged in as admin! # Attempt to guess the web base url... if user_agent_env and user_agent_env.get('base_location'): try: with cls.pool.cursor() as cr: base = user_agent_env['base_location'] ICP = api.Environment(cr, uid, {})['ir.config_parameter'] if not ICP.get_param('web.base.url.freeze'): ICP.set_param('web.base.url', base) except Exception: _logger.exception( "Failed to update web.base.url configuration parameter" ) return uid
def _dispatch(cls): """ In case of rerouting for translate (e.g. when visiting flectrahq.com/fr_BE/), _dispatch calls reroute() that returns _dispatch with altered request properties. The second _dispatch will continue until end of process. When second _dispatch is finished, the first _dispatch call receive the new altered request and continue. At the end, 2 calls of _dispatch (and this override) are made with exact same request properties, instead of one. As the response has not been sent back to the client, the visitor cookie does not exist yet when second _dispatch call is treated in _handle_webpage_dispatch, leading to create 2 visitors with exact same properties. To avoid this, we check if, !!! before calling super !!!, we are in a rerouting request. If not, it means that we are handling the original request, in which we should create the visitor. We ignore every other rerouting requests. """ is_rerouting = hasattr(request, 'routing_iteration') if request.session.db: reg = registry(request.session.db) with reg.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) request.website_routing = env['website'].get_current_website( ).id response = super(Http, cls)._dispatch() if not is_rerouting: cls._register_website_track(response) return response
def _l10n_es_edi_post_init(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) companies = env['res.company'].search([('partner_id.country_id.code', '=', 'ES')]) all_chart_templates = companies.chart_template_id current_chart_template = all_chart_templates while current_chart_template.parent_id: all_chart_templates |= current_chart_template.parent_id current_chart_template = current_chart_template.parent_id if all_chart_templates: tax_templates = env['account.tax.template'].search([ ('chart_template_id', 'in', all_chart_templates.ids), '|', '|', ('l10n_es_type', '!=', False), ('l10n_es_exempt_reason', '!=', False), ('tax_scope', '!=', False), ]) xml_ids = tax_templates.get_external_id() for company in companies: for tax_template in tax_templates: module, xml_id = xml_ids.get(tax_template.id).split('.') tax = env.ref('%s.%s_%s' % (module, company.id, xml_id), raise_if_not_found=False) if tax: tax.write({ 'l10n_es_exempt_reason': tax_template.l10n_es_exempt_reason, 'tax_scope': tax_template.tax_scope, 'l10n_es_type': tax_template.l10n_es_type, })
def _configure_journals(cr, registry): """Setting journal and property field (if needed)""" env = api.Environment(cr, SUPERUSER_ID, {}) # if we already have a coa installed, create journal and set property field company_ids = env['res.company'].search([('chart_template_id', '!=', False) ]) for company_id in company_ids: # Check if property exists for stock account journal exists field = env['ir.model.fields']._get("product.category", "property_stock_journal") properties = env['ir.property'].sudo().search([ ('fields_id', '=', field.id), ('company_id', '=', company_id.id) ]) # If not, check if you can find a journal that is already there with the same name, otherwise create one if not properties: journal_id = env['account.journal'].search( [('name', '=', _('Inventory Valuation')), ('company_id', '=', company_id.id), ('type', '=', 'general')], limit=1).id if not journal_id: journal_id = env['account.journal'].create({ 'name': _('Inventory Valuation'), 'type': 'general', 'code': 'STJ', 'company_id': company_id.id, 'show_on_dashboard': False }).id env['ir.property']._set_default( 'property_stock_journal', 'product.category', journal_id, company_id, ) # Property Stock Accounts todo_list = [ 'property_stock_account_input_categ_id', 'property_stock_account_output_categ_id', 'property_stock_valuation_account_id', ] for name in todo_list: account = getattr(company_id, name) if account: env['ir.property']._set_default( name, 'product.category', account, company_id, )
def update_dashboard_graph_model(dbname): db_registry = flectra.modules.registry.Registry.new(dbname) with api.Environment.manage(), db_registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) if 'crm.team' in env: recs = env['crm.team'].search([]) for rec in recs: rec._onchange_team_type()
def uninstall_hook(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) env['product.template'].search([ ('service_type', '=', 'timesheet') ]).write({'service_type': 'manual'}) env['product.product'].search([ ('service_type', '=', 'timesheet') ]).write({'service_type': 'manual'})
def set_last_price_info(cr, registry): """ This post-init-hook will update last price information for all products """ env = api.Environment(cr, SUPERUSER_ID, dict()) product_obj = env['product.product'] products = product_obj.search([('purchase_ok', '=', True)]) products.set_product_last_purchase()
def environment(): """ Return an environment with a new cursor for the current database; the cursor is committed and closed after the context block. """ reg = registry(common.get_db_name()) with reg.cursor() as cr: yield api.Environment(cr, SUPERUSER_ID, {}) cr.commit()
def rem_website_id_null(dbname): db_registry = flectra.modules.registry.Registry.new(dbname) with api.Environment.manage(), db_registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) env['ir.model.fields'].search([ ('name', '=', 'website_id'), ('model', '=', 'res.config.settings'), ]).unlink()
def _disable_pec_mail_post_init(cr, registry): ''' Pec mail cannot be used in conjunction with SdiCoop, so disable the Pec fetchmail servers. ''' env = api.Environment(cr, SUPERUSER_ID, {}) env['fetchmail.server'].search([('l10n_it_is_pec', '=', True) ]).l10n_it_is_pec = False env['res.company'].search([('l10n_it_mail_pec_server_id', '!=', None) ]).l10n_it_mail_pec_server_id = None
def post_init_hook(cr, registry): """Loaded after installing the module.""" with api.Environment.manage(): env = api.Environment(cr, SUPERUSER_ID, {}) purchase_requests = env['purchase.request'].search([]) _logger.info("Adding the department to %d purchase requests", len(purchase_requests)) for purchase_request in purchase_requests: purchase_request.onchange_requested_by()
def uninstall_hook(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) code_taxes = env['account.tax'].search([('amount_type', '=', 'code')]) code_taxes.write({'amount_type': 'percent', 'active': False}) _logger.warning( "The following taxes have been archived following 'account_tax_python' module uninstallation: %s" % code_taxes.ids)
def account_edi_block_level(cr, registery): ''' The default value for blocking_level is 'error', but without this module, the behavior is the same as a blocking_level of 'warning' so we need to set all documents in error. ''' from flectra import api, SUPERUSER_ID env = api.Environment(cr, SUPERUSER_ID, {}) env['account.edi.document'].search([('error', '!=', False)]).write({'blocking_level': 'warning'})
def _create_buy_rules(cr, registry): """ This hook is used to add a default buy_pull_id on every warehouse. It is necessary if the purchase_stock module is installed after some warehouses were already created. """ env = api.Environment(cr, SUPERUSER_ID, {}) warehouse_ids = env['stock.warehouse'].search([('buy_pull_id', '=', False) ]) warehouse_ids.write({'buy_to_resupply': True})
def _create_warehouse_data(cr, registry): """ This hook is used to add a default manufacture_pull_id, manufacture picking_type on every warehouse. It is necessary if the mrp module is installed after some warehouses were already created. """ env = api.Environment(cr, SUPERUSER_ID, {}) warehouse_ids = env['stock.warehouse'].search([('manufacture_pull_id', '=', False)]) warehouse_ids.write({'manufacture_to_resupply': True})
def called_after(): db_registry = registry(dbname) with api.Environment.manage(), db_registry.cursor() as cr: env = api.Environment(cr, uid, context) try: func(self.with_env(env), *args, **kwargs) except Exception as e: _logger.warning("Could not sync record now: %s" % self) _logger.exception(e)