[MERGE] forward port branch saas-11 up to 4c2b536
This commit is contained in:
@@ -688,7 +688,18 @@ class AccountTax(models.Model):
|
|||||||
# the 'Account' decimal precision + 5), and that way it's like
|
# the 'Account' decimal precision + 5), and that way it's like
|
||||||
# rounding after the sum of the tax amounts of each line
|
# rounding after the sum of the tax amounts of each line
|
||||||
prec = currency.decimal_places
|
prec = currency.decimal_places
|
||||||
if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)):
|
|
||||||
|
# In some cases, it is necessary to force/prevent the rounding of the tax and the total
|
||||||
|
# amounts. For example, in SO/PO line, we don't want to round the price unit at the
|
||||||
|
# precision of the currency.
|
||||||
|
# The context key 'round' allows to force the standard behavior.
|
||||||
|
round_tax = False if company_id.tax_calculation_rounding_method == 'round_globally' else True
|
||||||
|
round_total = True
|
||||||
|
if 'round' in self.env.context:
|
||||||
|
round_tax = bool(self.env.context['round'])
|
||||||
|
round_total = bool(self.env.context['round'])
|
||||||
|
|
||||||
|
if not round_tax:
|
||||||
prec += 5
|
prec += 5
|
||||||
total_excluded = total_included = base = round(price_unit * quantity, prec)
|
total_excluded = total_included = base = round(price_unit * quantity, prec)
|
||||||
|
|
||||||
@@ -707,7 +718,7 @@ class AccountTax(models.Model):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner)
|
tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner)
|
||||||
if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)):
|
if not round_tax:
|
||||||
tax_amount = round(tax_amount, prec)
|
tax_amount = round(tax_amount, prec)
|
||||||
else:
|
else:
|
||||||
tax_amount = currency.round(tax_amount)
|
tax_amount = currency.round(tax_amount)
|
||||||
@@ -733,8 +744,8 @@ class AccountTax(models.Model):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
'taxes': sorted(taxes, key=lambda k: k['sequence']),
|
'taxes': sorted(taxes, key=lambda k: k['sequence']),
|
||||||
'total_excluded': currency.round(total_excluded) if bool(self.env.context.get("round", True)) else total_excluded,
|
'total_excluded': currency.round(total_excluded) if round_total else total_excluded,
|
||||||
'total_included': currency.round(total_included) if bool(self.env.context.get("round", True)) else total_included,
|
'total_included': currency.round(total_included) if round_total else total_included,
|
||||||
'base': base,
|
'base': base,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1097,7 +1097,7 @@ class AccountMoveLine(models.Model):
|
|||||||
taxes = self.env['account.tax'].browse(tax_ids)
|
taxes = self.env['account.tax'].browse(tax_ids)
|
||||||
currency = self.env['res.currency'].browse(vals.get('currency_id'))
|
currency = self.env['res.currency'].browse(vals.get('currency_id'))
|
||||||
partner = self.env['res.partner'].browse(vals.get('partner_id'))
|
partner = self.env['res.partner'].browse(vals.get('partner_id'))
|
||||||
res = taxes.compute_all(amount,
|
res = taxes.with_context(round=True).compute_all(amount,
|
||||||
currency, 1, vals.get('product_id'), partner)
|
currency, 1, vals.get('product_id'), partner)
|
||||||
# Adjust line amount if any tax is price_include
|
# Adjust line amount if any tax is price_include
|
||||||
if abs(res['total_excluded']) < abs(amount):
|
if abs(res['total_excluded']) < abs(amount):
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ var pyeval = require('web.pyeval');
|
|||||||
var web_client = require('web.web_client');
|
var web_client = require('web.web_client');
|
||||||
var parse_value = require('web.web_client');
|
var parse_value = require('web.web_client');
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
|
var session = require('web.session');
|
||||||
|
|
||||||
var FieldMany2One = core.form_widget_registry.get('many2one');
|
var FieldMany2One = core.form_widget_registry.get('many2one');
|
||||||
var FieldChar = core.form_widget_registry.get('char');
|
var FieldChar = core.form_widget_registry.get('char');
|
||||||
@@ -73,8 +74,6 @@ var abstractReconciliation = Widget.extend(ControlPanelMixin, {
|
|||||||
|
|
||||||
this.action_manager = this.findAncestor(function(ancestor){ return ancestor instanceof ActionManager });
|
this.action_manager = this.findAncestor(function(ancestor){ return ancestor instanceof ActionManager });
|
||||||
this.crash_manager = new CrashManager();
|
this.crash_manager = new CrashManager();
|
||||||
// Method that tests if a monetary amount == 0, we use 4 digits because no currency uses more
|
|
||||||
this.monetaryIsZero = _.partial(utils.float_is_zero, _, 4);
|
|
||||||
this.formatCurrencies; // Method that formats the currency ; loaded from the server
|
this.formatCurrencies; // Method that formats the currency ; loaded from the server
|
||||||
this.model_res_users = new Model("res.users");
|
this.model_res_users = new Model("res.users");
|
||||||
this.model_tax = new Model("account.tax");
|
this.model_tax = new Model("account.tax");
|
||||||
@@ -367,6 +366,11 @@ var abstractReconciliation = Widget.extend(ControlPanelMixin, {
|
|||||||
if (line.ref && line.ref !== line.name)
|
if (line.ref && line.ref !== line.name)
|
||||||
line.q_label = line.q_label + " : " + line.ref;
|
line.q_label = line.q_label + " : " + line.ref;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Method that tests if a monetary amount == 0, we use 4 digits because no currency uses more
|
||||||
|
monetaryIsZero: function(amount, digits) {
|
||||||
|
return utils.float_is_zero(amount, digits === undefined ? 4 : digits);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var abstractReconciliationLine = Widget.extend({
|
var abstractReconciliationLine = Widget.extend({
|
||||||
@@ -1870,7 +1874,11 @@ var bankStatementReconciliationLine = abstractReconciliationLine.extend({
|
|||||||
|
|
||||||
// Find out if the counterpart is lower than, equal or greater than the transaction being reconciled
|
// Find out if the counterpart is lower than, equal or greater than the transaction being reconciled
|
||||||
var balance_type = undefined;
|
var balance_type = undefined;
|
||||||
if (self.monetaryIsZero(self.get("balance"))) balance_type = "equal";
|
var digits = 4;
|
||||||
|
if (this.get("currency_id") && session.get_currency(this.get("currency_id"))) {
|
||||||
|
digits = session.get_currency(this.get("currency_id")).digits[1];
|
||||||
|
}
|
||||||
|
if (self.monetaryIsZero(self.get("balance"), digits)) balance_type = "equal";
|
||||||
else if (self.get("balance") * self.st_line.amount > 0) balance_type = "greater";
|
else if (self.get("balance") * self.st_line.amount > 0) balance_type = "greater";
|
||||||
else if (self.get("balance") * self.st_line.amount < 0) balance_type = "lower";
|
else if (self.get("balance") * self.st_line.amount < 0) balance_type = "lower";
|
||||||
|
|
||||||
@@ -2065,7 +2073,11 @@ var bankStatementReconciliationLine = abstractReconciliationLine.extend({
|
|||||||
var payment_aml = _.filter(this.get("mv_lines_selected"), function(line) { return line.already_paid });
|
var payment_aml = _.filter(this.get("mv_lines_selected"), function(line) { return line.already_paid });
|
||||||
var payment_aml_ids = _.collect(payment_aml, function(line) { return line.id });
|
var payment_aml_ids = _.collect(payment_aml, function(line) { return line.id });
|
||||||
var new_aml_dicts = this.prepareCreatedMoveLinesForPersisting(this.getCreatedLines());
|
var new_aml_dicts = this.prepareCreatedMoveLinesForPersisting(this.getCreatedLines());
|
||||||
if (! self.monetaryIsZero(this.get("balance"))) new_aml_dicts.push(this.prepareOpenBalanceForPersisting());
|
var digits = 4;
|
||||||
|
if (this.get("currency_id") && session.get_currency(this.get("currency_id"))) {
|
||||||
|
digits = session.get_currency(this.get("currency_id")).digits[1];
|
||||||
|
}
|
||||||
|
if (! self.monetaryIsZero(this.get("balance"), digits)) new_aml_dicts.push(this.prepareOpenBalanceForPersisting());
|
||||||
return {
|
return {
|
||||||
'counterpart_aml_dicts': counterpart_aml_dicts,
|
'counterpart_aml_dicts': counterpart_aml_dicts,
|
||||||
'payment_aml_ids': payment_aml_ids,
|
'payment_aml_ids': payment_aml_ids,
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.stop_listening();
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
_display_no_edit_mode_warning: function() {
|
_display_no_edit_mode_warning: function() {
|
||||||
this.do_warn(_t('Error : Document not editable'), _t('To modify this document, please first start edition.'));
|
this.do_warn(_t('Error : Document not editable'), _t('To modify this document, please first start edition.'));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -164,8 +164,9 @@ class PackOperation(models.Model):
|
|||||||
def split_quantities(self):
|
def split_quantities(self):
|
||||||
for operation in self:
|
for operation in self:
|
||||||
if float_compare(operation.product_qty, operation.qty_done, precision_rounding=operation.product_uom_id.rounding) == 1:
|
if float_compare(operation.product_qty, operation.qty_done, precision_rounding=operation.product_uom_id.rounding) == 1:
|
||||||
operation.copy(default={'qty_done': 0.0, 'product_qty': operation.product_qty - operation.qty_done})
|
cpy = operation.copy(default={'qty_done': 0.0, 'product_qty': operation.product_qty - operation.qty_done})
|
||||||
operation.write({'product_qty': operation.qty_done})
|
operation.write({'product_qty': operation.qty_done})
|
||||||
|
operation._copy_remaining_pack_lot_ids(cpy)
|
||||||
else:
|
else:
|
||||||
raise UserError(_('The quantity to split should be smaller than the quantity To Do. '))
|
raise UserError(_('The quantity to split should be smaller than the quantity To Do. '))
|
||||||
return True
|
return True
|
||||||
@@ -238,6 +239,19 @@ class PackOperation(models.Model):
|
|||||||
raise UserError(_('You should provide a different serial number for each piece'))
|
raise UserError(_('You should provide a different serial number for each piece'))
|
||||||
check_tracking = _check_serial_number
|
check_tracking = _check_serial_number
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _copy_remaining_pack_lot_ids(self, new_operation):
|
||||||
|
for op in self:
|
||||||
|
for lot in op.pack_lot_ids:
|
||||||
|
new_qty_todo = lot.qty_todo - lot.qty
|
||||||
|
|
||||||
|
if float_compare(new_qty_todo, 0, precision_rounding=op.product_uom_id.rounding) > 0:
|
||||||
|
lot.copy({
|
||||||
|
'operation_id': new_operation.id,
|
||||||
|
'qty_todo': new_qty_todo,
|
||||||
|
'qty': 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class PackOperationLot(models.Model):
|
class PackOperationLot(models.Model):
|
||||||
_name = "stock.pack.operation.lot"
|
_name = "stock.pack.operation.lot"
|
||||||
|
|||||||
@@ -999,6 +999,10 @@ class Picking(models.Model):
|
|||||||
packlots_transfer = [(4, x.id) for x in operation.pack_lot_ids]
|
packlots_transfer = [(4, x.id) for x in operation.pack_lot_ids]
|
||||||
new_operation.write({'pack_lot_ids': packlots_transfer})
|
new_operation.write({'pack_lot_ids': packlots_transfer})
|
||||||
|
|
||||||
|
# the stock.pack.operation.lot records now belong to the new, packaged stock.pack.operation
|
||||||
|
# we have to create new ones with new quantities for our original, unfinished stock.pack.operation
|
||||||
|
new_operation._copy_remaining_pack_lot_ids(operation)
|
||||||
|
|
||||||
op = new_operation
|
op = new_operation
|
||||||
pack_operation_ids |= op
|
pack_operation_ids |= op
|
||||||
if operations:
|
if operations:
|
||||||
|
|||||||
@@ -808,7 +808,7 @@ class Orderpoint(models.Model):
|
|||||||
|
|
||||||
def _get_date_planned(self, start_date):
|
def _get_date_planned(self, start_date):
|
||||||
days = self.lead_days or 0.0
|
days = self.lead_days or 0.0
|
||||||
if self.lead_type == 'purchase':
|
if self.lead_type == 'supplier':
|
||||||
# These days will be substracted when creating the PO
|
# These days will be substracted when creating the PO
|
||||||
days += self.product_id._select_seller(self.product_id).delay or 0.0
|
days += self.product_id._select_seller(self.product_id).delay or 0.0
|
||||||
date_planned = start_date + relativedelta.relativedelta(days=days)
|
date_planned = start_date + relativedelta.relativedelta(days=days)
|
||||||
|
|||||||
@@ -237,6 +237,7 @@
|
|||||||
<field name="model">survey.survey</field>
|
<field name="model">survey.survey</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Survey">
|
<search string="Survey">
|
||||||
|
<field string="Title" name="title"/>
|
||||||
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
|
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -1092,8 +1092,8 @@ ListView.List = Class.extend({
|
|||||||
_(names).pluck(1).join(', '));
|
_(names).pluck(1).join(', '));
|
||||||
record.set(column.id, ids);
|
record.set(column.id, ids);
|
||||||
});
|
});
|
||||||
// temp empty value
|
// temporary empty display name
|
||||||
record.set(column.id, false);
|
record.set(column.id + '__display', false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return column.format(record.toForm().data, {
|
return column.format(record.toForm().data, {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ var TreeView = View.extend({
|
|||||||
},
|
},
|
||||||
willStart: function () {
|
willStart: function () {
|
||||||
_(this.fields_view.arch.children).each(function (field) {
|
_(this.fields_view.arch.children).each(function (field) {
|
||||||
if (field.attrs.modifiers) {
|
if (field.attrs.modifiers && typeof field.attrs.modifiers === "string") {
|
||||||
field.attrs.modifiers = JSON.parse(field.attrs.modifiers);
|
field.attrs.modifiers = JSON.parse(field.attrs.modifiers);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -321,6 +321,9 @@ data.Class = Widget.extend({
|
|||||||
|
|
||||||
self.make_snippet_draggable(self.$snippets);
|
self.make_snippet_draggable(self.$snippets);
|
||||||
this.associate_snippet_names(this.$snippets);
|
this.associate_snippet_names(this.$snippets);
|
||||||
|
|
||||||
|
this.show_blocks();
|
||||||
|
this.$el.on("snippet-dropped snippet-removed", this.show_blocks.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
associate_snippet_names: function ($snippets) {
|
associate_snippet_names: function ($snippets) {
|
||||||
@@ -1087,6 +1090,8 @@ data.Editor = Class.extend({
|
|||||||
$(".note-control-selection").hide();
|
$(".note-control-selection").hide();
|
||||||
$('.o_table_handler').remove();
|
$('.o_table_handler').remove();
|
||||||
|
|
||||||
|
this.buildingBlock.$el.trigger("snippet-removed");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
<!-- t-field options -->
|
<!-- t-field options -->
|
||||||
<t t-name="web_editor.many2one.button">
|
<t t-name="web_editor.many2one.button">
|
||||||
<div class="dropdown">
|
<div class="btn-group">
|
||||||
<a href="#" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="Search Contact"><i class="fa fa-search"></i></a>
|
<a href="#" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="Search Contact"><i class="fa fa-search"></i></a>
|
||||||
<ul class="dropdown-menu contact_menu" role="menu">
|
<ul class="dropdown-menu contact_menu" role="menu">
|
||||||
<li><a><input href="#" type="email" placeholder="Search"/></a></li>
|
<li><a><input href="#" type="email" placeholder="Search"/></a></li>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class sale_quote(http.Controller):
|
|||||||
if order and request.session.get('view_quote', False) != now:
|
if order and request.session.get('view_quote', False) != now:
|
||||||
request.session['view_quote'] = now
|
request.session['view_quote'] = now
|
||||||
body = _('Quotation viewed by customer')
|
body = _('Quotation viewed by customer')
|
||||||
_message_post_helper(res_model='sale.order', res_id=order.id, message=body, token=token, token_field="access_token", message_type='notification')
|
_message_post_helper(res_model='sale.order', res_id=order.id, message=body, token=token, token_field="access_token", message_type='notification', subtype="mail.mt_note", partner_ids=order.user_id.partner_id.ids)
|
||||||
else:
|
else:
|
||||||
order = request.env['sale.order'].search([('id', '=', order_id)])
|
order = request.env['sale.order'].search([('id', '=', order_id)])
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ class WebsiteSale(http.Controller):
|
|||||||
(variant id, [visible attribute ids], variant price, variant sale price)
|
(variant id, [visible attribute ids], variant price, variant sale price)
|
||||||
"""
|
"""
|
||||||
# product attributes with at least two choices
|
# product attributes with at least two choices
|
||||||
visible_attrs_ids = product.mapped('attribute_line_ids.attribute_id').filtered(lambda attr: len(attr.value_ids) > 1).ids
|
visible_attrs_ids = product.attribute_line_ids.filtered(lambda l: len(l.value_ids) > 1).mapped('attribute_id').ids
|
||||||
pl = request.website.get_current_pricelist()
|
pl = request.website.get_current_pricelist()
|
||||||
to_currency = pl.currency_id
|
to_currency = pl.currency_id
|
||||||
attribute_value_ids = []
|
attribute_value_ids = []
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
from odoo import api, fields, models, tools, _
|
from odoo import api, fields, models, tools, _
|
||||||
|
from odoo.tools.translate import html_translate
|
||||||
|
|
||||||
|
|
||||||
class ProductStyle(models.Model):
|
class ProductStyle(models.Model):
|
||||||
@@ -80,7 +81,7 @@ class ProductTemplate(models.Model):
|
|||||||
domain=lambda self: ['&', ('model', '=', self._name), ('message_type', '=', 'comment')],
|
domain=lambda self: ['&', ('model', '=', self._name), ('message_type', '=', 'comment')],
|
||||||
string='Website Comments',
|
string='Website Comments',
|
||||||
)
|
)
|
||||||
website_description = fields.Html('Description for the website', sanitize=False, translate=True)
|
website_description = fields.Html('Description for the website', sanitize=False, translate=html_translate)
|
||||||
alternative_product_ids = fields.Many2many('product.template', 'product_alternative_rel', 'src_id', 'dest_id',
|
alternative_product_ids = fields.Many2many('product.template', 'product_alternative_rel', 'src_id', 'dest_id',
|
||||||
string='Suggested Products', help='Appear on the product page')
|
string='Suggested Products', help='Appear on the product page')
|
||||||
accessory_product_ids = fields.Many2many('product.product', 'product_accessory_rel', 'src_id', 'dest_id',
|
accessory_product_ids = fields.Many2many('product.product', 'product_accessory_rel', 'src_id', 'dest_id',
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ class IrHttp(models.AbstractModel):
|
|||||||
|
|
||||||
# cache
|
# cache
|
||||||
etag = hasattr(request, 'httprequest') and request.httprequest.headers.get('If-None-Match')
|
etag = hasattr(request, 'httprequest') and request.httprequest.headers.get('If-None-Match')
|
||||||
retag = hashlib.md5(last_update).hexdigest()
|
retag = '"%s"' % hashlib.md5(last_update).hexdigest()
|
||||||
status = status or (304 if etag == retag else 200)
|
status = status or (304 if etag == retag else 200)
|
||||||
headers.append(('ETag', retag))
|
headers.append(('ETag', retag))
|
||||||
headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0)))
|
headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0)))
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ class Category(models.Model):
|
|||||||
name = fields.Char(required=True)
|
name = fields.Char(required=True)
|
||||||
color = fields.Integer('Color Index')
|
color = fields.Integer('Color Index')
|
||||||
parent = fields.Many2one('test_new_api.category')
|
parent = fields.Many2one('test_new_api.category')
|
||||||
|
root_categ = fields.Many2one(_name, compute='_compute_root_categ')
|
||||||
display_name = fields.Char(compute='_compute_display_name', inverse='_inverse_display_name')
|
display_name = fields.Char(compute='_compute_display_name', inverse='_inverse_display_name')
|
||||||
dummy = fields.Char(store=False)
|
dummy = fields.Char(store=False)
|
||||||
discussions = fields.Many2many('test_new_api.discussion', 'test_new_api_discussion_category',
|
discussions = fields.Many2many('test_new_api.discussion', 'test_new_api_discussion_category',
|
||||||
@@ -95,6 +96,14 @@ class Category(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.display_name = self.name
|
self.display_name = self.name
|
||||||
|
|
||||||
|
@api.depends('parent')
|
||||||
|
def _compute_root_categ(self):
|
||||||
|
for cat in self:
|
||||||
|
current = cat
|
||||||
|
while current.parent:
|
||||||
|
current = current.parent
|
||||||
|
cat.root_categ = current
|
||||||
|
|
||||||
@api.one
|
@api.one
|
||||||
def _inverse_display_name(self):
|
def _inverse_display_name(self):
|
||||||
names = self.display_name.split('/')
|
names = self.display_name.split('/')
|
||||||
|
|||||||
@@ -75,6 +75,33 @@ class TestOnChange(common.TransactionCase):
|
|||||||
result = self.Message.onchange(values, 'body', field_onchange)
|
result = self.Message.onchange(values, 'body', field_onchange)
|
||||||
self.assertNotIn('name', result['value'])
|
self.assertNotIn('name', result['value'])
|
||||||
|
|
||||||
|
def test_onchange_many2one(self):
|
||||||
|
Category = self.env['test_new_api.category']
|
||||||
|
|
||||||
|
field_onchange = Category._onchange_spec()
|
||||||
|
self.assertEqual(field_onchange.get('parent'), '1')
|
||||||
|
|
||||||
|
root = Category.create(dict(name='root'))
|
||||||
|
|
||||||
|
values = {
|
||||||
|
'name': 'test',
|
||||||
|
'parent': root.id,
|
||||||
|
'root_categ': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.env.invalidate_all()
|
||||||
|
result = Category.onchange(values, 'parent', field_onchange).get('value', {})
|
||||||
|
self.assertIn('root_categ', result)
|
||||||
|
self.assertEqual(result['root_categ'], root.name_get()[0])
|
||||||
|
|
||||||
|
values.update(result)
|
||||||
|
values['parent'] = False
|
||||||
|
|
||||||
|
self.env.invalidate_all()
|
||||||
|
result = Category.onchange(values, 'parent', field_onchange).get('value', {})
|
||||||
|
self.assertIn('root_categ', result)
|
||||||
|
self.assertIs(result['root_categ'], False)
|
||||||
|
|
||||||
def test_onchange_one2many(self):
|
def test_onchange_one2many(self):
|
||||||
""" test the effect of onchange() on one2many fields """
|
""" test the effect of onchange() on one2many fields """
|
||||||
BODY = "What a beautiful day!"
|
BODY = "What a beautiful day!"
|
||||||
|
|||||||
@@ -207,6 +207,7 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="parent"/>
|
<field name="parent"/>
|
||||||
|
<field name="root_categ"/>
|
||||||
<field name="dummy"/>
|
<field name="dummy"/>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
|||||||
+7
-3
@@ -1748,6 +1748,10 @@ class Many2one(_Relational):
|
|||||||
def convert_to_display_name(self, value, record):
|
def convert_to_display_name(self, value, record):
|
||||||
return ustr(value.display_name)
|
return ustr(value.display_name)
|
||||||
|
|
||||||
|
def convert_to_onchange(self, value, record, fnames=()):
|
||||||
|
if not value.id:
|
||||||
|
return False
|
||||||
|
return super(Many2one, self).convert_to_onchange(value, record, fnames)
|
||||||
|
|
||||||
class UnionUpdate(SpecialValue):
|
class UnionUpdate(SpecialValue):
|
||||||
""" Placeholder for a value update; when this value is taken from the cache,
|
""" Placeholder for a value update; when this value is taken from the cache,
|
||||||
@@ -1773,10 +1777,10 @@ class _RelationalMulti(_Relational):
|
|||||||
""" Update the cached value of ``self`` for ``records`` with ``value``. """
|
""" Update the cached value of ``self`` for ``records`` with ``value``. """
|
||||||
for record in records:
|
for record in records:
|
||||||
if self in record._cache:
|
if self in record._cache:
|
||||||
value = self.convert_to_cache(record[self.name] | value, record, validate=False)
|
val = self.convert_to_cache(record[self.name] | value, record, validate=False)
|
||||||
else:
|
else:
|
||||||
value = UnionUpdate(self, record, value)
|
val = UnionUpdate(self, record, value)
|
||||||
record._cache[self] = value
|
record._cache[self] = val
|
||||||
|
|
||||||
def convert_to_cache(self, value, record, validate=True):
|
def convert_to_cache(self, value, record, validate=True):
|
||||||
# cache format: tuple(ids)
|
# cache format: tuple(ids)
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ def get_module_path(module, downloaded=False, display_warning=True):
|
|||||||
"""
|
"""
|
||||||
initialize_sys_path()
|
initialize_sys_path()
|
||||||
for adp in ad_paths:
|
for adp in ad_paths:
|
||||||
if os.path.exists(opj(adp, module)) or os.path.exists(opj(adp, '%s.zip' % module)):
|
if os.path.exists(opj(adp, module, MANIFEST)) or os.path.exists(opj(adp, '%s.zip' % module)):
|
||||||
return opj(adp, module)
|
return opj(adp, module)
|
||||||
|
|
||||||
if downloaded:
|
if downloaded:
|
||||||
|
|||||||
@@ -740,7 +740,8 @@ form: module.record_id""" % (xml_id,)
|
|||||||
record.append(Field(name, name='name'))
|
record.append(Field(name, name='name'))
|
||||||
record.append(Field(full_tpl_id, name='key'))
|
record.append(Field(full_tpl_id, name='key'))
|
||||||
record.append(Field("qweb", name='type'))
|
record.append(Field("qweb", name='type'))
|
||||||
record.append(Field(el.get('priority', "16"), name='priority'))
|
if 'priority' in el.attrib:
|
||||||
|
record.append(Field(el.get('priority'), name='priority'))
|
||||||
if 'inherit_id' in el.attrib:
|
if 'inherit_id' in el.attrib:
|
||||||
record.append(Field(name='inherit_id', ref=el.get('inherit_id')))
|
record.append(Field(name='inherit_id', ref=el.get('inherit_id')))
|
||||||
if 'website_id' in el.attrib:
|
if 'website_id' in el.attrib:
|
||||||
|
|||||||
Reference in New Issue
Block a user