diff --git a/addons/sale/data/sale_demo.xml b/addons/sale/data/sale_demo.xml index a81e797d6825c748a910c18c918856861876de4e..b203cab9bf533190a55965e2dcbe3a61f256f105 100644 --- a/addons/sale/data/sale_demo.xml +++ b/addons/sale/data/sale_demo.xml @@ -198,7 +198,6 @@ <field name="user_id" ref="base.user_root"/> <field name="pricelist_id" ref="product.list0"/> <field name="team_id" ref="sales_team.team_sales_department"/> - <field name="state">sale</field> </record> <record id="sale_order_line_16" model="sale.order.line"> diff --git a/addons/web_settings_dashboard/controllers/main.py b/addons/web_settings_dashboard/controllers/main.py index 21423ec902d36968382bab7b265916529183d2de..d2a23fc7c65a4bf7ce8cc7a0701b9d04fd1eb501 100644 --- a/addons/web_settings_dashboard/controllers/main.py +++ b/addons/web_settings_dashboard/controllers/main.py @@ -53,6 +53,12 @@ class WebSettingsDashboard(http.Controller): enterprise_users = request.env['res.users'].search_count([("login_date", ">=", fields.Datetime.to_string(limit_date)), ('share', '=', False)]) expiration_date = request.env['ir.config_parameter'].sudo().get_param('database.expiration_date') + + # We assume that if there's at least one module with demo data active, then the db was + # initialized with demo=True or it has been force-activated by the `Load demo data` button + # in the settings dashboard. + demo_active = bool(request.env['ir.module.module'].search_count([('demo', '=', True)])) + return { 'apps': { 'installed_apps': installed_apps, @@ -68,6 +74,7 @@ class WebSettingsDashboard(http.Controller): 'server_version': release.version, 'expiration_date': expiration_date, 'debug': request.debug, + 'demo_active': demo_active, }, 'company': { 'company_id': request.env.user.company_id.id, diff --git a/addons/web_settings_dashboard/static/src/js/dashboard.js b/addons/web_settings_dashboard/static/src/js/dashboard.js index 9f0ed3d75523532193932bf9e51508b53f405463..4d58da38041477c4e0c29c32920b883340b97e26 100644 --- a/addons/web_settings_dashboard/static/src/js/dashboard.js +++ b/addons/web_settings_dashboard/static/src/js/dashboard.js @@ -2,6 +2,7 @@ odoo.define('web_settings_dashboard', function (require) { "use strict"; var AbstractAction = require('web.AbstractAction'); +var config = require('web.config'); var core = require('web.core'); var framework = require('web.framework'); var Widget = require('web.Widget'); @@ -279,6 +280,7 @@ var DashboardShare = Widget.extend({ 'click .tw_share': 'share_twitter', 'click .fb_share': 'share_facebook', 'click .li_share': 'share_linkedin', + 'click .o_web_settings_dashboard_force_demo': '_onClickForceDemo', }, init: function (parent, data) { @@ -286,6 +288,7 @@ var DashboardShare = Widget.extend({ this.parent = parent; this.share_url = 'https://www.odoo.com'; this.share_text = encodeURIComponent("I am using #Odoo - Awesome open source business apps."); + return this._super.apply(this, arguments); }, /** @@ -319,7 +322,23 @@ var DashboardShare = Widget.extend({ popup_url, 'Share Dialog', 'width=600,height=400'); // We have to add a size otherwise the window pops in a new tab - } + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Forces demo data to be installed in a database without demo data installed. + * + * @private + * @param {MouseEvent} ev + */ + _onClickForceDemo: function (ev) { + ev.preventDefault(); + this.do_action('base.demo_force_install_action'); + config.debug = false; + }, }); var DashboardTranslations = Widget.extend({ diff --git a/addons/web_settings_dashboard/static/src/xml/dashboard.xml b/addons/web_settings_dashboard/static/src/xml/dashboard.xml index 5a505bb02e463c372ab4ffcfd71fbc9f3e303e98..a98a557d66d3b6604d3729b6f45170661e3e3146 100644 --- a/addons/web_settings_dashboard/static/src/xml/dashboard.xml +++ b/addons/web_settings_dashboard/static/src/xml/dashboard.xml @@ -109,6 +109,7 @@ <hr/> <t t-set="server_version" t-value="widget.data.server_version"/> <t t-set="debug" t-value="widget.data.debug"/> + <t t-set="demo_active" t-value="widget.data.demo_active"/> <div class="row"> <div class="text-center"> <div class="user-heading"> @@ -134,6 +135,8 @@ <a t-if="debug != 'assets'" class="oe_activate_debug_mode pull-right" href="?debug=assets" >Activate the developer mode (with assets)</a> <br t-if="debug != 'assets'"/> <a t-if="debug != false" class="oe_activate_debug_mode pull-right" href="/web" >Deactivate the developer mode</a> + <br t-if="debug != false"/> + <a t-if="(debug) and !(demo_active)" class="oe_activate_debug_mode pull-right o_web_settings_dashboard_force_demo" href="#">Load demo data</a> </div> </div> </div> diff --git a/odoo/addons/base/__manifest__.py b/odoo/addons/base/__manifest__.py index 9caa89917c1846545a605b6acc9d44710b181a55..99f634350e2ac45bd748eb8788a4e6158f150162 100644 --- a/odoo/addons/base/__manifest__.py +++ b/odoo/addons/base/__manifest__.py @@ -20,6 +20,7 @@ The kernel of Odoo, needed for all installation. 'data/report_paperformat_data.xml', 'data/res_currency_data.xml', 'data/res_country_data.xml', + 'data/ir_demo_data.xml', 'security/base_groups.xml', 'security/base_security.xml', 'views/base_menus.xml', diff --git a/odoo/addons/base/data/ir_demo_data.xml b/odoo/addons/base/data/ir_demo_data.xml new file mode 100644 index 0000000000000000000000000000000000000000..e108590147a581a1657d36cb0a26152a0a86552e --- /dev/null +++ b/odoo/addons/base/data/ir_demo_data.xml @@ -0,0 +1,23 @@ +<odoo> + <record model="ir.actions.act_window" id="demo_force_install_action"> + <field name="name">Load demo data</field> + <field name="res_model">ir.demo</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> + + <record model="ir.ui.view" id="demo_force_install_form"> + <field name="name">ir.demo.form</field> + <field name="model">ir.demo</field> + <field name="arch" type="xml"> + <form> + <p>Demo data should only be used on test databases. Once they are loaded, they cannot be removed.</p> + <p>Are you sure you want to load demo data?</p> + <footer> + <button name="install_demo" string="Load demo data" type="object" class="btn-primary"/> + <button special="cancel" string="Discard" class="btn-default"/> + </footer> + </form> + </field> + </record> +</odoo> diff --git a/odoo/addons/base/models/__init__.py b/odoo/addons/base/models/__init__.py index 59d125ab30e8834eb6dd2e6c5966d9bc7b028f67..4506929a5c5654922873f14bb47a29559842ee9a 100644 --- a/odoo/addons/base/models/__init__.py +++ b/odoo/addons/base/models/__init__.py @@ -27,6 +27,7 @@ from . import ir_http from . import ir_logging from . import ir_property from . import ir_module +from . import ir_demo from . import report_paperformat from . import res_country from . import res_lang @@ -35,4 +36,4 @@ from . import res_bank from . import res_config from . import res_currency from . import res_company -from . import res_users \ No newline at end of file +from . import res_users diff --git a/odoo/addons/base/models/ir_demo.py b/odoo/addons/base/models/ir_demo.py new file mode 100644 index 0000000000000000000000000000000000000000..34e4292be28437cf75205a22567b9edc5d128326 --- /dev/null +++ b/odoo/addons/base/models/ir_demo.py @@ -0,0 +1,15 @@ +from odoo import models +from odoo.modules.loading import force_demo + + +class IrDemo(models.TransientModel): + + _name = 'ir.demo' + + def install_demo(self): + force_demo(self.env.cr) + return { + 'type': 'ir.actions.act_url', + 'target': 'self', + 'url': '/web', + } diff --git a/odoo/modules/loading.py b/odoo/modules/loading.py index 6e123324635f185feefe0c43fe0f3854c434a86f..d8ff08128661cd602b73b71058b9e58f636c3676 100644 --- a/odoo/modules/loading.py +++ b/odoo/modules/loading.py @@ -25,30 +25,15 @@ _logger = logging.getLogger(__name__) _test_logger = logging.getLogger('odoo.tests') -def load_module_graph(cr, graph, status=None, perform_checks=True, - skip_modules=None, report=None, models_to_check=None): - """Migrates+Updates or Installs all module nodes from ``graph`` - :param graph: graph of module nodes to load - :param status: deprecated parameter, unused, left to avoid changing signature in 8.0 - :param perform_checks: whether module descriptors should be checked for validity (prints warnings - for same cases) - :param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped - :return: list of modules that were installed or updated +def load_data(cr, idref, mode, kind, package, report): """ - def load_test(module_name, idref, mode): - cr.commit() - try: - _load_data(cr, module_name, idref, mode, 'test') - return True - except Exception: - _test_logger.exception( - 'module %s: an exception occurred in a test', module_name) - return False - finally: - cr.rollback() - # avoid keeping stale xml_id, etc. in cache - odoo.registry(cr.dbname).clear_caches() + kind: data, demo, test, init_xml, update_xml, demo_xml. + + noupdate is False, unless it is demo data or it is csv data in + init mode. + + """ def _get_files_of_kind(kind): if kind == 'demo': @@ -72,27 +57,74 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, ) return files - def _load_data(cr, module_name, idref, mode, kind): - """ + try: + if kind in ('demo', 'test'): + threading.currentThread().testing = True + for filename in _get_files_of_kind(kind): + _logger.info("loading %s/%s", package.name, filename) + noupdate = False + if kind in ('demo', 'demo_xml') or (filename.endswith('.csv') and kind in ('init', 'init_xml')): + noupdate = True + tools.convert_file(cr, package.name, filename, idref, mode, noupdate, kind, report) + finally: + if kind in ('demo', 'test'): + threading.currentThread().testing = False + - kind: data, demo, test, init_xml, update_xml, demo_xml. +def load_demo(cr, package, idref, mode, report=None): + """ + Loads demo data for the specified package. + """ + has_demo = hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed') + if has_demo: + load_data(cr, idref, mode, kind='demo', package=package, report=report) + return has_demo + + +def force_demo(cr): + """ + Forces the `demo` flag on all modules, and installs demo data for all installed modules. + """ + graph = odoo.modules.graph.Graph() + cr.execute( + "SELECT name FROM ir_module_module WHERE state IN ('installed', 'to upgrade', 'to remove')" + ) + module_list = [name for (name,) in cr.fetchall()] + graph.add_modules(cr, module_list, ['demo']) + + for package in graph: + load_demo(cr, package, {}, 'init') + + cr.execute('update ir_module_module set demo=%s', (True,)) + env = api.Environment(cr, SUPERUSER_ID, {}) + env['ir.module.module'].invalidate_cache(['demo']) + cr.commit() - noupdate is False, unless it is demo data or it is csv data in - init mode. - """ +def load_module_graph(cr, graph, status=None, perform_checks=True, + skip_modules=None, report=None, models_to_check=None): + """Migrates+Updates or Installs all module nodes from ``graph`` + :param graph: graph of module nodes to load + :param status: deprecated parameter, unused, left to avoid changing signature in 8.0 + :param perform_checks: whether module descriptors should be checked for validity (prints warnings + for same cases) + :param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped + :return: list of modules that were installed or updated + """ + def load_test(idref, mode): + nonlocal package + cr.commit() try: - if kind in ('demo', 'test'): - threading.currentThread().testing = True - for filename in _get_files_of_kind(kind): - _logger.info("loading %s/%s", module_name, filename) - noupdate = False - if kind in ('demo', 'demo_xml') or (filename.endswith('.csv') and kind in ('init', 'init_xml')): - noupdate = True - tools.convert_file(cr, module_name, filename, idref, mode, noupdate, kind, report) + load_data(cr, idref, mode, 'test', package, report) + return True + except Exception: + _test_logger.exception( + 'module %s: an exception occurred in a test', package.name) + return False finally: - if kind in ('demo', 'test'): - threading.currentThread().testing = False + cr.rollback() + # avoid keeping stale xml_id, etc. in cache + odoo.registry(cr.dbname).clear_caches() if models_to_check is None: models_to_check = set() @@ -172,13 +204,12 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, if perform_checks: module._check() - if package.state=='to upgrade': + if package.state == 'to upgrade': # upgrading the module information module.write(module.get_values_from_terp(package.data)) - _load_data(cr, module_name, idref, mode, kind='data') - has_demo = hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed') - if has_demo: - _load_data(cr, module_name, idref, mode, kind='demo') + load_data(cr, idref, mode, kind='data', package=package, report=report) + demo_loaded = load_demo(cr, package, idref, mode, report) + if demo_loaded: cr.execute('update ir_module_module set demo=%s where id=%s', (True, module_id)) module.invalidate_cache(['demo']) @@ -199,11 +230,11 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, # validate all the views at a whole env['ir.ui.view']._validate_module_views(module_name) - if has_demo: + if demo_loaded: # launch tests only in demo mode, allowing tests to use demo data. if tools.config.options['test_enable']: # Yamel test - report.record_result(load_test(module_name, idref, mode)) + report.record_result(load_test(idref, mode)) # Python tests env['ir.http']._clear_routing_map() # force routing map to be rebuilt report.record_result(odoo.modules.module.run_unit_tests(module_name, cr.dbname))