def OdooEnvironment(database, rollback=False): with Environment.manage(): registry = odoo.registry(database) try: with registry.cursor() as cr: uid = odoo.SUPERUSER_ID try: ctx = Environment(cr, uid, {})["res.users"].context_get() except Exception as e: ctx = {"lang": "en_US"} # this happens, for instance, when there are new # fields declared on res_partner which are not yet # in the database (before -u) _logger.warning( "Could not obtain a user context, continuing " "anyway with a default context. Error was: %s", e, ) env = Environment(cr, uid, ctx) cr.rollback() yield env if rollback: cr.rollback() else: cr.commit() finally: if odoo.release.version_info[0] < 10: odoo.modules.registry.RegistryManager.delete(database) else: odoo.modules.registry.Registry.delete(database) odoo.sql_db.close_db(database)
def _build_odoo_env(self, odoo_args): odoo.tools.config.parse_config(odoo_args) dbname = odoo.tools.config['db_name'] odoo.tools.config['workers'] = 0 odoo.tools.config['xmlrpc'] = False if not dbname: argparse.ArgumentParser().error( "please provide a database name though Odoo options (either " "-d or an Odoo configuration file)") logging.getLogger(odoo_logger).setLevel(logging.ERROR) odoo.service.server.start(preload=[], stop=True) # odoo.service.server.start() modifies the SIGINT signal by its own # one which in fact prevents us to stop anthem with Ctrl-c. # Restore the default one. signal.signal(signal.SIGINT, signal.default_int_handler) odoo_version = odoo.release.version_info[0] # On saas versions this will be "saas-XX" where XX is the odoo version if not isinstance(odoo_version, int): odoo_version = int(odoo_version.lstrip(string.ascii_letters + '-~')) if odoo_version > 9: registry = odoo.modules.registry.Registry(dbname) else: registry = odoo.modules.registry.RegistryManager.get(dbname) cr = registry.cursor() uid = odoo.SUPERUSER_ID Environment.reset() context = Environment(cr, uid, {})['res.users'].context_get() return Environment(cr, uid, context)
def environment(cr): old_local = Environment._local Environment._local = FakeLocal() uid = SUPERUSER_ID ctx = Environment(cr, uid, {})['res.users'].context_get() yield Environment(cr, uid, ctx) Environment._local = old_local
def test_02_remove_developer_mode_menu_elements(self): env = Environment(self.registry.test_cr, self.uid, {}) # needed because tests are run before the module is marked as # installed. In js web will only load qweb coming from modules # that are returned by the backend in module_boot. Without # this you end up with js, css but no qweb. env['ir.module.module'].search([('name', '=', 'web_debranding')], limit=1).state = 'installed' self.registry.cursor().release() url = '/web' code = """ $(document).ready( function() { setInterval(function(){ if (!$('.navbar-collapse.collapse .oe_user_menu_placeholder .dropdown-menu').length) { console.log('page is loading'); return; } if ($('li a[data-menu="debug"]').length > 0 && $('li a[data-menu="debugassets"]').length > 0) { console.log('ok'); } else { console.log('error', 'Developer mode menu elements are not displayed for admin'); } }, 1000); }) """ self.phantom_js(url, code, login="******")
def remove_menus(cr): env = Environment(cr, SUPERUSER_ID, {}) for menu_id in ('base.module_mi', 'base.menu_module_updates'): try: env.ref(menu_id).unlink() except ValueError: pass
def test_01_pos_is_loaded(self): # see more https://odoo-development.readthedocs.io/en/latest/dev/tests/js.html#phantom-js-python-tests cr = self.registry.cursor() assert cr == self.registry.test_cr env = Environment(cr, self.uid, {}) # From https://github.com/odoo/odoo/blob/48dafd5b2011cee966920f664a904de2e2715ae8/addons/point_of_sale/tests/test_frontend.py#L306-L310 # # needed because tests are run before the module is marked as # installed. In js web will only load qweb coming from modules # that are returned by the backend in module_boot. Without # this you end up with js, css but no qweb. env['res.users'].create({ 'name': "test", 'login': "******", 'password': "******", 'pos_security_pin': "0000", }) env['ir.module.module'].search([('name', '=', 'pos_logout')], limit=1).state = 'installed' self.registry.test_cr.release() self.phantom_js( '/web', "odoo.__DEBUG__.services['web_tour.tour']" ".run('pos_logout_tour')", "odoo.__DEBUG__.services['web_tour.tour']" ".tours.pos_logout_tour.ready", login="******", timeout=240, )
def uninstall_hook_update_rule(cr, registry): env = Environment(cr, SUPERUSER_ID, {}) for rule_xml_id, group_xml_id in multi_company_ir_rules.items(): rule = env.ref(rule_xml_id) group = env.ref(group_xml_id) if group in rule.groups: rule.write({'groups': [(3, group.id)]})
def test_01_pos_is_loaded(self): # see more https://odoo-development.readthedocs.io/en/latest/dev/tests/js.html#phantom-js-python-tests env = Environment(self.registry.test_cr, self.uid, {}) pos_receipt = env["pos.custom_receipt"].search( [("type", "=", "receipt")], limit=1) self.assertTrue(pos_receipt, "Receipt Not Found") pos_ticket = env["pos.custom_receipt"].search( [("type", "=", "ticket")], limit=1) self.assertTrue(pos_ticket, "Ticket Not Found") main_pos_config = env.ref("point_of_sale.pos_config_main") main_pos_config.write({ "proxy_ip": "localhost", "iface_print_via_proxy": True, "custom_xml_receipt": True, "custom_xml_receipt_id": pos_receipt.id, "iface_print_auto": False, "custom_ticket": True, "custom_ticket_id": pos_ticket.id, }) main_pos_config.open_session_cb() self.phantom_js( "/pos/web", "odoo.__DEBUG__.services['web_tour.tour']" ".run('pos_receipt_custom_template_tour')", "odoo.__DEBUG__.services['web_tour.tour']" ".tours.pos_receipt_custom_template_tour.ready", login="******", timeout=240, )
def post_init_hook(cr, registry): _logger.info("Compute discount columns") env = Environment(cr, SUPERUSER_ID, {}) query = """ update sale_order_line set price_total_no_discount = price_total where discount = 0.0 """ cr.execute(query) query = """ update sale_order set price_total_no_discount = amount_total """ cr.execute(query) query = """ select distinct order_id from sale_order_line where discount > 0.0; """ cr.execute(query) order_ids = cr.fetchall() orders = env["sale.order"].search([("id", "in", order_ids)]) orders.mapped("order_line")._update_discount_display_fields()
def create_return_picking(self): with Environment.manage(): env_thread1 = Environment(self._cr, self._uid, self._context) for picking in self.order_id.picking_ids: if picking.picking_type_code != 'outgoing': continue moves = [] move_qty = {} for line in self.amazon_refund_line_ids: if line.amazon_order_line_id: move = env_thread1['stock.move'].search([ ('sale_line_id', '=', line.amazon_order_line_id.id), ('product_id', '=', line.product_id.id), ('picking_id', '=', picking.id) ]) moves.append(move.id) move_qty.update({move.id: line.qty_canceled}) result = env_thread1['stock.return.picking'].with_context({ 'active_id': picking.id }).default_get(fields=[ 'product_return_moves', 'move_dest_exists', 'location_id' ]) move_dest_exists = [] product_return_moves = [] # if result.get('move_dest_exists',[]): # for exist_line in result.get('move_dest_exists',[]): # if exist_line.get('move_id') in moves: # move_dest_exists.append([0,0,exist_line]) if result.get('product_return_moves', []): for move_line in result.get('product_return_moves', []): if len(move_line) == 3: if move_line[2].get('move_id') in moves: if move_qty.get( move_line[2].get('move_id'), 0.0) > 0.0: move_line[2].update({ 'quantity': move_qty.get( move_line.get('move_id'), 0.0) }) product_return_moves.append(move_line) record = env_thread1['stock.return.picking'].create({ 'picking_id': picking.id, 'move_dest_exists': move_dest_exists, 'product_return_moves': product_return_moves, 'location_id': result.get('location_id') }) result = record.create_returns() return True
def setUpClass(cls): """Setup a picking to test user scanned by is correct""" super().setUpClass() # Setup user cls.test_company = cls.create_company("test_company") cls.test_user = cls.create_user( "test_user", "test_user_login", company_id=cls.test_company.id, company_ids=[(6, 0, cls.test_company.ids)], ) cls.other_user = cls.create_user( "other_user", "other_user_login", company_id=cls.test_company.id, company_ids=[(6, 0, cls.test_company.ids)], ) test_user_env = Environment(cls.env.cr, uid=cls.test_user.id, context=cls.env.context) # Setup picking cls.create_quant(cls.apple.id, cls.test_location_01.id, 10) cls.create_quant(cls.banana.id, cls.test_location_02.id, 20) picking = cls.create_picking(cls.picking_type_internal) move = cls.create_move(cls.apple, 10, picking) move = cls.create_move(cls.banana, 20, picking) picking.action_confirm() picking.action_assign() cls.picking = picking.with_env(test_user_env)
def uninstall_hook(cr, registry): """Delete the actions that were created with chained_swapper when the module is uninstalled""" env = Environment(cr, SUPERUSER_ID, {}) env['ir.actions.act_window'].search([('res_model', '=', 'chained.swapper.wizard')]).unlink() return True
def setUpClass(cls): super(TestResPartner, cls).setUpClass() # Test using the demo user to prevent bugs related with access rights. cls.env = Environment(cls.env.cr, cls.env.ref('base.user_demo').id, {}) cls.partner_1_phone = '+1 (450) 555-2671' cls.partner_1_mobile = '+1 (450) 678-4529' cls.partner_1 = cls.env['res.partner'].create({ 'name': 'Hadi', 'country_id': cls.env.ref('base.ca').id, 'phone': cls.partner_1_phone, 'mobile': cls.partner_1_mobile, }) cls.partner_2_phone_other = '450-222-3456' cls.partner_2_phone_home = '581-999-5555' cls.partner_2 = cls.env['res.partner'].create({ 'name': 'Cohen', 'country_id': cls.env.ref('base.ca').id, 'phone_other': cls.partner_2_phone_other, 'phone_home': cls.partner_2_phone_home, })
def test_01_subtask_sort_button(self): env = Environment(self.registry.test_cr, self.uid, {}) # needed because tests are run before the module is marked as # installed. In js web will only load qweb coming from modules # that are returned by the backend in module_boot. Without # this you end up with js, css but no qweb. env['ir.module.module'].search([('name', '=', 'project_task_subtask')], limit=1).state = 'installed' # find active tasks task = env['project.task'].search([('active', '=', 'true')], limit=1) url = '/web?#id=%s&view_type=form&model=project.task&/' % str(task.id) self.registry.cursor().release() code = """ $(document).ready( function() { setInterval(function(){ if ($('.o_x2m_control_panel .o_cp_buttons .btn.o_pager_sort').length > 0) { console.log('ok'); } }, 1000); setTimeout(function(){ if ($('.o_x2m_control_panel .o_cp_buttons .btn.o_pager_sort').length > 0) { console.log('ok'); } else { console.log(document.documentElement.innerHTML); console.log('error', 'Sort Button is not displayed'); } }, 20000); }); """ self.phantom_js(url, code, login="******")
def _synchronize_cron(cr, registry): env = Environment(cr, SUPERUSER_ID, {'active_test': False}) cron = env.ref('crm_iap_lead_enrich.ir_cron_lead_enrichment') if cron: config = env['ir.config_parameter'].get_param( 'crm.iap.lead.enrich.setting', 'manual') cron.active = config != 'manual'
def test_01_pos_is_loaded(self): # see more https://odoo-development.readthedocs.io/en/latest/dev/tests/js.html#phantom-js-python-tests env = Environment(self.registry.test_cr, self.uid, {}) main_pos_config = env.ref("point_of_sale.pos_config_main") main_pos_config.write({"iface_discount": True}) main_pos_config.discount_product_id = env.ref( "point_of_sale.boni_orange") main_pos_config.open_session_cb() env["ir.module.module"].search( [("name", "=", "pos_product_category_discount")], limit=1).state = "installed" self.phantom_js( "/pos/web", "odoo.__DEBUG__.services['web_tour.tour']" ".run('pos_product_category_discount_tour')", "odoo.__DEBUG__.services['web_tour.tour']" ".tours.pos_product_category_discount_tour.ready", login="******", timeout=240, )
def migrate(cr, version): """Propagate the user_logged/not_logged fields to dupplicate menu entries. In Odoo 12.0, multiple website is enabled. However, one website is defined as main website. Every menu entry in the main website is dupplicated: | Website | URL | |-----------------------------| | Your Company | / | | Your Company | /aboutus | | Your Company | /contact | | <empty> | / | | <empty> | /aboutus | | <empty> | /contact | |--------------|--------------| When website is migrated, the dupplicate are created without the fields user_logged and user_not_logged. Therefore, they must be propagated from the original to the new menu entries. """ env = Environment(cr, SUPERUSER_ID, {}) menus_with_user_logged = env['website.menu'].search([('user_logged', '=', True)]) for menu in menus_with_user_logged: dupplicate_menus = env['website.menu'].search([('url', '=', menu.url)]) dupplicate_menus.write({'user_logged': True}) menus_with_user_not_logged = env['website.menu'].search([ ('user_not_logged', '=', True) ]) for menu in menus_with_user_not_logged: dupplicate_menus = env['website.menu'].search([('url', '=', menu.url)]) dupplicate_menus.write({'user_not_logged': True})
def set_multi_sales_price(cr, registry): env = Environment(cr, SUPERUSER_ID, {}) conf_page = env['res.config.settings'].create({}) conf_page.group_uom = True conf_page.multi_sales_price = True conf_page.multi_sales_price_method = "formula" conf_page.execute()
def view(self, db, token, action, id, view='calendar'): registry = registry_get(db) with registry.cursor() as cr: # Since we are in auth=none, create an env with SUPERUSER_ID env = Environment(cr, SUPERUSER_ID, {}) attendee = env['calendar.attendee'].search([('access_token', '=', token)]) timezone = attendee.partner_id.tz event = env['calendar.event'].with_context(tz=timezone).browse( int(id)) # If user is logged, redirect to form view of event # otherwise, display the simplifyed web page with event informations if request.session.uid: return werkzeug.utils.redirect( '/web?db=%s#id=%s&view_type=form&model=calendar.event' % (db, id)) # NOTE : calling render return a lazy response. The rendering result will be done when the # cursor will be closed. So it is requried to call `flatten` to make the redering before # existing the `with` clause response = request.render('calendar.invitation_page_anonymous', { 'event': event, 'attendee': attendee, }) response.flatten() return response
def view(self, db, token, action, id, view='calendar'): registry = registry_get(db) with registry.cursor() as cr: # Since we are in auth=none, create an env with SUPERUSER_ID env = Environment(cr, SUPERUSER_ID, {}) attendee = env['calendar.attendee'].search([('access_token', '=', token), ('event_id', '=', int(id))]) if not attendee: return request.not_found() timezone = attendee.partner_id.tz lang = attendee.partner_id.lang or get_lang(request.env).code event = env['calendar.event'].with_context(tz=timezone, lang=lang).browse(int(id)) # If user is internal and logged, redirect to form view of event # otherwise, display the simplifyed web page with event informations if request.session.uid and request.env['res.users'].browse(request.session.uid).user_has_groups('base.group_user'): return werkzeug.utils.redirect('/web?db=%s#id=%s&view_type=form&model=calendar.event' % (db, id)) # NOTE : we don't use request.render() since: # - we need a template rendering which is not lazy, to render before cursor closing # - we need to display the template in the language of the user (not possible with # request.render()) response_content = env['ir.ui.view'].with_context(lang=lang).render_template( 'calendar.invitation_page_anonymous', { 'event': event, 'attendee': attendee, }) return request.make_response(response_content, headers=[('Content-Type', 'text/html')])
def post_init_hook(cr, pool): """ Fetches all invoice and resets the sequence of their invoice line """ env = Environment(cr, SUPERUSER_ID, {}) invoice = env['account.invoice'].search([]) invoice._reset_sequence()
def post_init_hook(cr, pool): """ Fetches all invoice and resets the sequence of their invoice line """ env = Environment(cr, SUPERUSER_ID, {}) sale_order = env['sale.order'].search([]) sale_order._reset_sequence()
def post_init_hook(cr, pool): """ Fetches all the pickings and resets the sequence of the move lines """ env = Environment(cr, SUPERUSER_ID, {}) stock = env['stock.picking'].search([]) stock.with_context(skip_update_line_ids=True)._reset_sequence()
def create_invoice(self, partner): env = Environment(self.env.cr, SUPERUSER_ID, {}) currency = env['res.currency'].search([('name', '=', 'EUR')]) product = env['product.product'].create({ 'name': 'Product', }) account_1 = env['account.account'].create({ 'code': random.randint(100, 999), 'name': 'Payable Account', 'reconcile': True, 'user_type_id': env.ref('account.data_account_type_payable').id, }) account_2 = env['account.account'].create({ 'code': random.randint(100, 999), 'name': 'Expenses Account', 'user_type_id': env.ref('account.data_account_type_expenses').id, }) partner.write({ 'property_account_payable_id': account_2.id, }) journal = env['account.journal'].create({ 'name': 'Journal', 'type': 'bank', 'code': str(random.randint(100, 999)), }) account_invoice_line = env['account.invoice.line'].create({ 'name': 'My line 1', 'product_id': product.id, 'account_id': account_2.id, 'price_unit': '20', }) account_invoice = env['account.invoice'].create({ 'partner_id': partner.id, 'account_id': account_1.id, 'journal_id': journal.id, 'currency_id': currency.id, 'invoice_line_ids': [(4, account_invoice_line.id)], 'type': 'in_invoice', }) return account_invoice
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True): res = super(stock_history, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy) if 'parallel_inventory_value' in fields and 'inventory_value' in fields: context['date'] = context.get('history_date') for line in res: with Environment.manage(): # class function env = Environment(cr, uid, context) line[ 'parallel_inventory_value'] = env.user.company_id.currency_id.compute( line['inventory_value'], env.user.company_id.parallel_currency_id) return res
def test_01_pos_postponed_invoice(self): self.phantom_js( "/pos/web?m=1", "odoo.__DEBUG__.services['web_tour.tour'].run('pos_invoice_postponed_tour', 1000)", "odoo.__DEBUG__.services['web_tour.tour'].tours.pos_invoice_postponed_tour.ready", login="******", timeout=240, ) cr = self.registry.cursor() cr.execute('select "id" from "pos_order" order by "id" desc limit 1') res = cr.fetchall() env = Environment(cr, self.uid, {}) order = env["pos.order"].browse(res[0]) self.assertEqual( len(order.statement_ids), 0, "Number of statements are {} expected {}".format( len(order.statement_ids), 0), ) self.assertEqual( order.amount_paid, 0, "Amount paid is {} expected {}".format(order.amount_paid, 0), ) cr.release()
def get_journal(self, data): env = Environment(self.cr, SUPERUSER_ID, {}) journals = env['account.journal'] journal_ids = [] for journal in journals.browse(data['form'][0]['journal_ids']): journal_ids.append(journal) return journal_ids
def view(self, db, token, action, id, view='calendar'): registry = registry_get(db) with registry.cursor() as cr: # Since we are in auth=none, create an env with SUPERUSER_ID env = Environment(cr, SUPERUSER_ID, {}) attendee = env['calendar.attendee'].search([('access_token', '=', token)]) timezone = attendee.partner_id.tz lang = attendee.partner_id.lang or 'en_US' event = env['calendar.event'].with_context(tz=timezone, lang=lang).browse( int(id)) # If user is logged, redirect to form view of event # otherwise, display the simplifyed web page with event informations if request.session.uid: return werkzeug.utils.redirect( '/web?db=%s#id=%s&view_type=form&model=calendar.event' % (db, id)) # NOTE : we don't use request.render() since: # - we need a template rendering which is not lazy, to render before cursor closing # - we need to display the template in the language of the user (not possible with # request.render()) return env['ir.ui.view'].with_context(lang=lang).render_template( 'calendar.invitation_page_anonymous', { 'event': event, 'attendee': attendee, })
def post_init_hook(cr, registry): env = Environment(cr, SUPERUSER_ID, {}) res_ids = env['ir.model.data'].search([ ('model', '=', 'ir.ui.menu'), ('module', '=', 'sale'), ]).mapped('res_id') env['ir.ui.menu'].browse(res_ids).update({'active': True})
def test_01_remove_developer_mode_menu_elements(self): env = Environment(self.registry.test_cr, self.uid, {}) # needed because tests are run before the module is marked as # installed. In js web will only load qweb coming from modules # that are returned by the backend in module_boot. Without # this you end up with js, css but no qweb. env['ir.module.module'].search([('name', '=', 'web_debranding')], limit=1).state = 'installed' self.registry.cursor().release() url = '/web' code = """ $(document).ready( function() { setInterval(function(){ if (!$('.navbar-collapse.collapse .oe_user_menu_placeholder .dropdown-menu').length) { console.log('page is loading'); return; } setTimeout(function(){ // request ..../res.users/is_admin may take some time // TODO: add a way to check that it's a time to check result (variable on loading in web_debranding/static/src/js/user_menu.js ?) if ($('li a[data-menu="debug"]').length > 0 || $('li a[data-menu="debugassets"]').length > 0) { console.log('error', 'Developer mode menu elements are displayed for non-admin user'); } else { console.log('ok'); } }, 1000); }, 1000); }) """ self.phantom_js(url, code, login="******")