[MERGE] forward port branch saas-14 up to e7d174a142
This commit is contained in:
@@ -726,7 +726,7 @@ class WizardMultiChartsAccounts(models.TransientModel):
|
|||||||
if company_id:
|
if company_id:
|
||||||
company = self.env['res.company'].browse(company_id)
|
company = self.env['res.company'].browse(company_id)
|
||||||
currency_id = company.on_change_country(company.country_id.id)['value']['currency_id']
|
currency_id = company.on_change_country(company.country_id.id)['value']['currency_id']
|
||||||
res.update({'currency_id': currency_id})
|
res.update({'currency_id': currency_id.id})
|
||||||
|
|
||||||
chart_templates = account_chart_template.search([('visible', '=', True)])
|
chart_templates = account_chart_template.search([('visible', '=', True)])
|
||||||
if chart_templates:
|
if chart_templates:
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class ChangeProductionQty(models.TransientModel):
|
|||||||
cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
|
cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
|
||||||
quantity = wo.qty_production - wo.qty_produced
|
quantity = wo.qty_production - wo.qty_produced
|
||||||
if production.product_id.tracking == 'serial':
|
if production.product_id.tracking == 'serial':
|
||||||
quantity = 1.0 if float_is_zero(quantity, precision_digits=precision) else 0.0
|
quantity = 1.0 if not float_is_zero(quantity, precision_digits=precision) else 0.0
|
||||||
else:
|
else:
|
||||||
quantity = quantity if (quantity > 0) else 0
|
quantity = quantity if (quantity > 0) else 0
|
||||||
if float_is_zero(quantity, precision_digits=precision):
|
if float_is_zero(quantity, precision_digits=precision):
|
||||||
|
|||||||
@@ -1125,12 +1125,15 @@ var ClientListScreenWidget = ScreenWidget.extend({
|
|||||||
var self = this;
|
var self = this;
|
||||||
var order = this.pos.get_order();
|
var order = this.pos.get_order();
|
||||||
if( this.has_client_changed() ){
|
if( this.has_client_changed() ){
|
||||||
if ( this.new_client ) {
|
var default_fiscal_position_id = _.find(this.pos.fiscal_positions, function(fp) {
|
||||||
|
return fp.id === self.pos.config.default_fiscal_position_id[0];
|
||||||
|
});
|
||||||
|
if ( this.new_client && this.new_client.property_account_position_id ) {
|
||||||
order.fiscal_position = _.find(this.pos.fiscal_positions, function (fp) {
|
order.fiscal_position = _.find(this.pos.fiscal_positions, function (fp) {
|
||||||
return fp.id === self.new_client.property_account_position_id[0];
|
return fp.id === self.new_client.property_account_position_id[0];
|
||||||
});
|
}) || default_fiscal_position_id;
|
||||||
} else {
|
} else {
|
||||||
order.fiscal_position = undefined;
|
order.fiscal_position = default_fiscal_position_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
order.set_client(this.new_client);
|
order.set_client(this.new_client);
|
||||||
|
|||||||
@@ -32,10 +32,13 @@ class ProductCategory(models.Model):
|
|||||||
help="The number of products under this category (Does not consider the children categories)")
|
help="The number of products under this category (Does not consider the children categories)")
|
||||||
|
|
||||||
def _compute_product_count(self):
|
def _compute_product_count(self):
|
||||||
read_group_res = self.env['product.template'].read_group([('categ_id', 'in', self.ids)], ['categ_id'], ['categ_id'])
|
read_group_res = self.env['product.template'].read_group([('categ_id', 'child_of', self.ids)], ['categ_id'], ['categ_id'])
|
||||||
group_data = dict((data['categ_id'][0], data['categ_id_count']) for data in read_group_res)
|
group_data = dict((data['categ_id'][0], data['categ_id_count']) for data in read_group_res)
|
||||||
for categ in self:
|
for categ in self:
|
||||||
categ.product_count = group_data.get(categ.id, 0)
|
product_count = 0
|
||||||
|
for sub_categ_id in categ.search([('id', 'child_of', categ.id)]).ids:
|
||||||
|
product_count += group_data.get(sub_categ_id, 0)
|
||||||
|
categ.product_count = product_count
|
||||||
|
|
||||||
@api.constrains('parent_id')
|
@api.constrains('parent_id')
|
||||||
def _check_category_recursion(self):
|
def _check_category_recursion(self):
|
||||||
|
|||||||
@@ -112,7 +112,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Product">
|
<search string="Product">
|
||||||
<field name="name" string="Product" filter_domain="['|','|',('default_code','ilike',self),('name','ilike',self),('barcode','ilike',self)]"/>
|
<field name="name" string="Product" filter_domain="['|','|',('default_code','ilike',self),('name','ilike',self),('barcode','ilike',self)]"/>
|
||||||
<field name="categ_id" filter_domain="[('categ_id', 'child_of', self)]"/>
|
<field name="categ_id" filter_domain="[('categ_id', 'child_of', raw_value)]"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Services" name="services" domain="[('type','=','service')]"/>
|
<filter string="Services" name="services" domain="[('type','=','service')]"/>
|
||||||
<filter string="Products" name="consumable" domain="[('type', 'in', ['consu', 'product'])]"/>
|
<filter string="Products" name="consumable" domain="[('type', 'in', ['consu', 'product'])]"/>
|
||||||
|
|||||||
@@ -243,7 +243,8 @@ class Project(models.Model):
|
|||||||
project = super(Project, self).copy(default)
|
project = super(Project, self).copy(default)
|
||||||
for follower in self.message_follower_ids:
|
for follower in self.message_follower_ids:
|
||||||
project.message_subscribe(partner_ids=follower.partner_id.ids, subtype_ids=follower.subtype_ids.ids)
|
project.message_subscribe(partner_ids=follower.partner_id.ids, subtype_ids=follower.subtype_ids.ids)
|
||||||
self.map_tasks(project.id)
|
if 'tasks' not in default:
|
||||||
|
self.map_tasks(project.id)
|
||||||
return project
|
return project
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
@@ -264,6 +265,8 @@ class Project(models.Model):
|
|||||||
if 'active' in vals:
|
if 'active' in vals:
|
||||||
# archiving/unarchiving a project does it on its tasks, too
|
# archiving/unarchiving a project does it on its tasks, too
|
||||||
self.with_context(active_test=False).mapped('tasks').write({'active': vals['active']})
|
self.with_context(active_test=False).mapped('tasks').write({'active': vals['active']})
|
||||||
|
# archiving/unarchiving a project implies that we don't want to use the analytic account anymore
|
||||||
|
self.with_context(active_test=False).mapped('analytic_account_id').write({'active': vals['active']})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
|||||||
@@ -1250,7 +1250,7 @@ var FieldBinaryFile = FieldBinary.extend({
|
|||||||
this._super();
|
this._super();
|
||||||
if (this.get("effective_readonly")) {
|
if (this.get("effective_readonly")) {
|
||||||
this.$el.click(function(ev) {
|
this.$el.click(function(ev) {
|
||||||
if (self.get('value')) {
|
if (self.get('value') && self.view.datarecord.id) {
|
||||||
self.on_save_as(ev);
|
self.on_save_as(ev);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1268,6 +1268,11 @@ var FieldBinaryFile = FieldBinary.extend({
|
|||||||
this.do_toggle(!!this.get('value'));
|
this.do_toggle(!!this.get('value'));
|
||||||
if (this.get('value')) {
|
if (this.get('value')) {
|
||||||
this.$el.empty().append($("<span/>").addClass('fa fa-download'));
|
this.$el.empty().append($("<span/>").addClass('fa fa-download'));
|
||||||
|
if (this.view.datarecord.id) {
|
||||||
|
this.$el.css('cursor', 'pointer');
|
||||||
|
} else {
|
||||||
|
this.$el.css('cursor', 'not-allowed');
|
||||||
|
}
|
||||||
if (filename) {
|
if (filename) {
|
||||||
this.$el.append(" " + filename);
|
this.$el.append(" " + filename);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ return Widget.extend({
|
|||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
var chart = this['display_' + this.mode]();
|
var chart = this['display_' + this.mode]();
|
||||||
if (chart) {
|
if (chart && chart.tooltip.chartContainer) {
|
||||||
chart.tooltip.chartContainer(this.$el[0]);
|
chart.tooltip.chartContainer(this.$el[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ var Field = Input.extend( /** @lends instance.web.search.Field# */ {
|
|||||||
if (domain) {
|
if (domain) {
|
||||||
value_to_domain = function (facetValue) {
|
value_to_domain = function (facetValue) {
|
||||||
return new data.CompoundDomain(domain)
|
return new data.CompoundDomain(domain)
|
||||||
.set_eval_context({self: self.value_from(facetValue)});
|
.set_eval_context({self: self.value_from(facetValue), raw_value: facetValue.attributes.value});
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
value_to_domain = function (facetValue) {
|
value_to_domain = function (facetValue) {
|
||||||
|
|||||||
@@ -355,8 +355,8 @@ var RTE = Widget.extend({
|
|||||||
var $el = $(this);
|
var $el = $(this);
|
||||||
|
|
||||||
$el.find('[class]').filter(function () {
|
$el.find('[class]').filter(function () {
|
||||||
if (!this.className.match(/\S/)) {
|
if (!this.getAttribute('class').match(/\S/)) {
|
||||||
this.removeAttribute("class");
|
this.removeAttribute('class');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -415,16 +415,35 @@ animation.registry.media_video = animation.Class.extend({
|
|||||||
start: function () {
|
start: function () {
|
||||||
// TODO: this code should be refactored to make more sense and be better
|
// TODO: this code should be refactored to make more sense and be better
|
||||||
// integrated with Odoo (this refactoring should be done in master).
|
// integrated with Odoo (this refactoring should be done in master).
|
||||||
this.$target.find('iframe').remove();
|
|
||||||
|
|
||||||
if (!this.$target.has('.media_iframe_video_size').length) {
|
var def = this._super.apply(this, arguments);
|
||||||
var editor = '<div class="css_editable_mode_display"> </div>';
|
if (this.$target.children('iframe').length) {
|
||||||
var size = '<div class="media_iframe_video_size"> </div>';
|
// There already is an <iframe/>, do nothing
|
||||||
this.$target.html(editor+size);
|
return def;
|
||||||
}
|
}
|
||||||
// rebuilding the iframe, from https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
||||||
this.$target.html(this.$target.html()+'<iframe sandbox="allow-scripts allow-same-origin" src="'+_.escape(this.$target.data("oe-expression"))+'" frameborder="0" allowfullscreen="allowfullscreen"></iframe>');
|
// Bug fix / compatibility: empty the <div/> element as all information
|
||||||
return this._super.apply(this, arguments);
|
// to rebuild the iframe should have been saved on the <div/> element
|
||||||
|
this.$target.empty();
|
||||||
|
|
||||||
|
// Add extra content for size / edition
|
||||||
|
this.$target.append(
|
||||||
|
'<div class="css_editable_mode_display"> </div>' +
|
||||||
|
'<div class="media_iframe_video_size"> </div>'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Rebuild the iframe. Depending on version / compatibility / instance,
|
||||||
|
// the src is saved in the 'data-src' attribute or the
|
||||||
|
// 'data-oe-expression' one (the latter is used as a workaround in 10.0
|
||||||
|
// system but should obviously be reviewed in master).
|
||||||
|
this.$target.append($('<iframe/>', {
|
||||||
|
src: _.escape(this.$target.data('oe-expression') || this.$target.data('src')),
|
||||||
|
frameborder: '0',
|
||||||
|
allowfullscreen: 'allowfullscreen',
|
||||||
|
sandbox: 'allow-scripts allow-same-origin', // https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
||||||
|
}));
|
||||||
|
|
||||||
|
return def;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ class WebsiteSale(http.Controller):
|
|||||||
Partner = order.partner_id.with_context(show_address=1).sudo()
|
Partner = order.partner_id.with_context(show_address=1).sudo()
|
||||||
shippings = Partner.search([
|
shippings = Partner.search([
|
||||||
("id", "child_of", order.partner_id.commercial_partner_id.ids),
|
("id", "child_of", order.partner_id.commercial_partner_id.ids),
|
||||||
'|', ("type", "=", "delivery"), ("id", "=", order.partner_id.commercial_partner_id.id)
|
'|', ("type", "in", ["delivery", "other"]), ("id", "=", order.partner_id.commercial_partner_id.id)
|
||||||
], order='id desc')
|
], order='id desc')
|
||||||
if shippings:
|
if shippings:
|
||||||
if kw.get('partner_id') or 'use_billing' in kw:
|
if kw.get('partner_id') or 'use_billing' in kw:
|
||||||
|
|||||||
@@ -1106,6 +1106,7 @@
|
|||||||
<t t-foreach="shippings" t-as="ship">
|
<t t-foreach="shippings" t-as="ship">
|
||||||
<div class="col-sm-12 col-md-6 one_kanban">
|
<div class="col-sm-12 col-md-6 one_kanban">
|
||||||
<t t-call="website_sale.address_kanban">
|
<t t-call="website_sale.address_kanban">
|
||||||
|
<t t-set="actual_partner" t-value="order.partner_id" />
|
||||||
<t t-set='contact' t-value="ship"/>
|
<t t-set='contact' t-value="ship"/>
|
||||||
<t t-set='selected' t-value="order.partner_shipping_id==ship"/>
|
<t t-set='selected' t-value="order.partner_shipping_id==ship"/>
|
||||||
<t t-set='readonly' t-value="bool(len(shippings)==1)"/>
|
<t t-set='readonly' t-value="bool(len(shippings)==1)"/>
|
||||||
@@ -1139,7 +1140,7 @@
|
|||||||
</t>
|
</t>
|
||||||
<input type='submit'/>
|
<input type='submit'/>
|
||||||
</form>
|
</form>
|
||||||
<a class='btn btn-link pull-right fa fa-edit js_edit_address no-decoration' title="Edit this address"></a>
|
<a t-if="not actual_partner or (ship.id in actual_partner.ids + actual_partner.child_ids.ids)" class='btn btn-link pull-right fa fa-edit js_edit_address no-decoration' title="Edit this address"></a>
|
||||||
<div t-att-class="'panel panel-default %s' % (selected and 'border_primary' or 'js_change_shipping')">
|
<div t-att-class="'panel panel-default %s' % (selected and 'border_primary' or 'js_change_shipping')">
|
||||||
<div class='panel-body' style='min-height: 130px;'>
|
<div class='panel-body' style='min-height: 130px;'>
|
||||||
<t t-esc="contact" t-options="dict(widget='contact', fields=['name', 'address'], no_marker=True)"/>
|
<t t-esc="contact" t-options="dict(widget='contact', fields=['name', 'address'], no_marker=True)"/>
|
||||||
@@ -1175,7 +1176,9 @@
|
|||||||
<t t-if="mode == ('new', 'billing')">
|
<t t-if="mode == ('new', 'billing')">
|
||||||
<h3 class="page-header mt32 ml16">Your Address
|
<h3 class="page-header mt32 ml16">Your Address
|
||||||
<small> or </small>
|
<small> or </small>
|
||||||
<t t-set='connect' t-value="request.env['ir.config_parameter'].sudo().get_param('auth_signup.allow_uninvited') == 'True' and ('signup', 'Sign Up') or ('login', 'Log In')"/>
|
<t t-set="signup_text">Sign Up</t>
|
||||||
|
<t t-set="login_text">Log In</t>
|
||||||
|
<t t-set='connect' t-value="request.env['ir.config_parameter'].sudo().get_param('auth_signup.allow_uninvited') == 'True' and ('signup', signup_text) or ('login', login_text)"/>
|
||||||
<a t-attf-href='/web/{{connect[0]}}?redirect=/shop/checkout' class='btn btn-primary' style="margin-top: -11px"><t t-esc='connect[1]'/></a>
|
<a t-attf-href='/web/{{connect[0]}}?redirect=/shop/checkout' class='btn btn-primary' style="margin-top: -11px"><t t-esc='connect[1]'/></a>
|
||||||
</h3>
|
</h3>
|
||||||
</t>
|
</t>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
France, 2017-11-29
|
||||||
|
|
||||||
|
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||||
|
Agreement v1.0.
|
||||||
|
|
||||||
|
I declare that I am authorized and able to make this agreement and sign this
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
Signed,
|
||||||
|
|
||||||
|
Maximilien TANTIN <maximilien.tantin@gmail.com> https://github.com/MTantin
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
Germany, 2017-12-01
|
||||||
|
|
||||||
|
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||||
|
Agreement v1.0.
|
||||||
|
|
||||||
|
I declare that I am authorized and able to make this agreement and sign this
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
Signed,
|
||||||
|
|
||||||
|
Alex Vai satriani-vai@users.noreply.github.com https://github.com/satriani-vai
|
||||||
@@ -5,7 +5,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
import psycopg2
|
import psycopg2
|
||||||
import pytz
|
import pytz
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
import odoo
|
import odoo
|
||||||
@@ -15,6 +15,7 @@ from odoo.exceptions import UserError
|
|||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
BASE_VERSION = odoo.modules.load_information_from_description_file('base')['version']
|
BASE_VERSION = odoo.modules.load_information_from_description_file('base')['version']
|
||||||
|
MAX_FAIL_TIME = timedelta(hours=5) # chosen with a fair roll of the dice
|
||||||
|
|
||||||
|
|
||||||
class BadVersion(Exception):
|
class BadVersion(Exception):
|
||||||
@@ -168,7 +169,7 @@ class ir_cron(models.Model):
|
|||||||
(version,) = cr.fetchone()
|
(version,) = cr.fetchone()
|
||||||
cr.execute("SELECT COUNT(*) FROM ir_module_module WHERE state LIKE %s", ['to %'])
|
cr.execute("SELECT COUNT(*) FROM ir_module_module WHERE state LIKE %s", ['to %'])
|
||||||
(changes,) = cr.fetchone()
|
(changes,) = cr.fetchone()
|
||||||
if not version or changes:
|
if version is None:
|
||||||
raise BadModuleState()
|
raise BadModuleState()
|
||||||
elif version != BASE_VERSION:
|
elif version != BASE_VERSION:
|
||||||
raise BadVersion()
|
raise BadVersion()
|
||||||
@@ -179,6 +180,19 @@ class ir_cron(models.Model):
|
|||||||
ORDER BY priority""")
|
ORDER BY priority""")
|
||||||
jobs = cr.dictfetchall()
|
jobs = cr.dictfetchall()
|
||||||
|
|
||||||
|
if changes:
|
||||||
|
if not jobs:
|
||||||
|
raise BadModuleState()
|
||||||
|
# nextcall is never updated if the cron is not executed,
|
||||||
|
# it is used as a sentinel value to check whether cron jobs
|
||||||
|
# have been locked for a long time (stuck)
|
||||||
|
parse = fields.Datetime.from_string
|
||||||
|
oldest = min([parse(job['nextcall']) for job in jobs])
|
||||||
|
if datetime.now() - oldest > MAX_FAIL_TIME:
|
||||||
|
odoo.modules.reset_modules_state(db_name)
|
||||||
|
else:
|
||||||
|
raise BadModuleState()
|
||||||
|
|
||||||
for job in jobs:
|
for job in jobs:
|
||||||
lock_cr = db.cursor()
|
lock_cr = db.cursor()
|
||||||
try:
|
try:
|
||||||
|
|||||||
+2
-1
@@ -1647,7 +1647,8 @@ class BaseModel(object):
|
|||||||
order = '"%s" %s' % (order_field, '' if len(order_split) == 1 else order_split[1])
|
order = '"%s" %s' % (order_field, '' if len(order_split) == 1 else order_split[1])
|
||||||
orderby_terms.append(order)
|
orderby_terms.append(order)
|
||||||
elif order_field in aggregated_fields:
|
elif order_field in aggregated_fields:
|
||||||
orderby_terms.append(order_part)
|
order_split[0] = '"' + order_field + '"'
|
||||||
|
orderby_terms.append(' '.join(order_split))
|
||||||
else:
|
else:
|
||||||
# Cannot order by a field that will not appear in the results (needs to be grouped or aggregated)
|
# Cannot order by a field that will not appear in the results (needs to be grouped or aggregated)
|
||||||
_logger.warn('%s: read_group order by `%s` ignored, cannot sort on empty columns (not grouped/aggregated)',
|
_logger.warn('%s: read_group order by `%s` ignored, cannot sort on empty columns (not grouped/aggregated)',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
from . import db, graph, loading, migration, module, registry
|
from . import db, graph, loading, migration, module, registry
|
||||||
|
|
||||||
from odoo.modules.loading import load_modules
|
from odoo.modules.loading import load_modules, reset_modules_state
|
||||||
|
|
||||||
from odoo.modules.module import (
|
from odoo.modules.module import (
|
||||||
adapt_version,
|
adapt_version,
|
||||||
|
|||||||
@@ -421,3 +421,24 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||||||
|
|
||||||
finally:
|
finally:
|
||||||
cr.close()
|
cr.close()
|
||||||
|
|
||||||
|
|
||||||
|
def reset_modules_state(db_name):
|
||||||
|
"""
|
||||||
|
Resets modules flagged as "to x" to their original state
|
||||||
|
"""
|
||||||
|
# Warning, this function was introduced in response to commit 763d714
|
||||||
|
# which locks cron jobs for dbs which have modules marked as 'to %'.
|
||||||
|
# The goal of this function is to be called ONLY when module
|
||||||
|
# installation/upgrade/uninstallation fails, which is the only known case
|
||||||
|
# for which modules can stay marked as 'to %' for an indefinite amount
|
||||||
|
# of time
|
||||||
|
db = odoo.sql_db.db_connect(db_name)
|
||||||
|
with db.cursor() as cr:
|
||||||
|
cr.execute(
|
||||||
|
"UPDATE ir_module_module SET state='installed' WHERE state IN ('to remove', 'to upgrade')"
|
||||||
|
)
|
||||||
|
cr.execute(
|
||||||
|
"UPDATE ir_module_module SET state='uninstalled' WHERE state='to install'"
|
||||||
|
)
|
||||||
|
_logger.warning("Transient module states were reset")
|
||||||
|
|||||||
@@ -80,7 +80,11 @@ class Registry(Mapping):
|
|||||||
try:
|
try:
|
||||||
registry.setup_signaling()
|
registry.setup_signaling()
|
||||||
# This should be a method on Registry
|
# This should be a method on Registry
|
||||||
odoo.modules.load_modules(registry._db, force_demo, status, update_module)
|
try:
|
||||||
|
odoo.modules.load_modules(registry._db, force_demo, status, update_module)
|
||||||
|
except Exception:
|
||||||
|
odoo.modules.reset_modules_state(db_name)
|
||||||
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
_logger.exception('Failed to load registry')
|
_logger.exception('Failed to load registry')
|
||||||
del cls.registries[db_name]
|
del cls.registries[db_name]
|
||||||
|
|||||||
Reference in New Issue
Block a user