[MERGE] forward port branch 11.0 up to bfe88c50e2
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="delivery_comp_rule" model="ir.rule">
|
||||
<field name="name">Delivery multi-company</field>
|
||||
<field name="model_id" ref="model_delivery_carrier"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force"> ['|',('product_id.company_id','=',user.company_id.id),('product_id.company_id','=',False)]</field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -416,7 +416,8 @@ class HrExpense(models.Model):
|
||||
product = default_product
|
||||
else:
|
||||
expense_description = expense_description.replace(product_code.group(), '')
|
||||
product = self.env['product.product'].search([('default_code', 'ilike', product_code.group(1))]) or default_product
|
||||
products = self.env['product.product'].search([('default_code', 'ilike', product_code.group(1))]) or default_product
|
||||
product = products.filtered(lambda p: p.default_code == product_code.group(1)) or products[0]
|
||||
|
||||
pattern = '[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?'
|
||||
# Match the last occurence of a float in the string
|
||||
|
||||
@@ -35,6 +35,7 @@ class HrPayslipEmployees(models.TransientModel):
|
||||
'date_from': from_date,
|
||||
'date_to': to_date,
|
||||
'credit_note': run_data.get('credit_note'),
|
||||
'company_id': employee.company_id.id,
|
||||
}
|
||||
payslips += self.env['hr.payslip'].create(res)
|
||||
payslips.compute_sheet()
|
||||
|
||||
@@ -2,7 +2,7 @@ odoo.define('mail.Activity', function (require) {
|
||||
"use strict";
|
||||
|
||||
var AbstractField = require('web.AbstractField');
|
||||
var concurrency = require('web.concurrency');
|
||||
var BasicModel = require('web.BasicModel');
|
||||
var core = require('web.core');
|
||||
var field_registry = require('web.field_registry');
|
||||
var time = require('web.time');
|
||||
@@ -11,6 +11,63 @@ var utils = require('mail.utils');
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
/**
|
||||
* Fetches activities and postprocesses them.
|
||||
*
|
||||
* This standalone function performs an RPC, but to do so, it needs an instance
|
||||
* of a widget that implements the _rpc() function.
|
||||
*
|
||||
* @todo i'm not very proud of the widget instance given in arguments, we should
|
||||
* probably try to do it a better way in the future.
|
||||
*
|
||||
* @param {Widget} self a widget instance that can perform RPCs
|
||||
* @param {Array} ids the ids of activities to read
|
||||
* @return {Deferred<Array>} resolved with the activities
|
||||
*/
|
||||
function _readActivities(self, ids) {
|
||||
if (!ids.length) {
|
||||
return $.when([]);
|
||||
}
|
||||
return self._rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'read',
|
||||
args: [ids],
|
||||
}).then(function (activities) {
|
||||
// convert create_date and date_deadline to moments
|
||||
_.each(activities, function (activity) {
|
||||
activity.create_date = moment(time.auto_str_to_date(activity.create_date));
|
||||
activity.date_deadline = moment(time.auto_str_to_date(activity.date_deadline));
|
||||
});
|
||||
|
||||
// sort activities by due date
|
||||
activities = _.sortBy(activities, 'date_deadline');
|
||||
|
||||
return activities;
|
||||
});
|
||||
}
|
||||
|
||||
BasicModel.include({
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetches the activities displayed by the activity field widget in form
|
||||
* views.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} record - an element from the localData
|
||||
* @param {string} fieldName
|
||||
* @return {Deferred<Array>} resolved with the activities
|
||||
*/
|
||||
_fetchSpecialActivity: function (record, fieldName) {
|
||||
var localID = (record._changes && fieldName in record._changes) ?
|
||||
record._changes[fieldName] :
|
||||
record.data[fieldName];
|
||||
return _readActivities(this, this.localData[localID].res_ids);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Set the 'label_delay' entry in activity data according to the deadline date
|
||||
* @param {Array} activities list of activity Object
|
||||
@@ -44,12 +101,6 @@ var setDelayLabel = function(activities){
|
||||
};
|
||||
|
||||
var AbstractActivityField = AbstractField.extend({
|
||||
// inherited
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.activities = [];
|
||||
},
|
||||
|
||||
// private
|
||||
_markActivityDone: function (id, feedback) {
|
||||
return this._rpc({
|
||||
@@ -59,33 +110,6 @@ var AbstractActivityField = AbstractField.extend({
|
||||
kwargs: {feedback: feedback},
|
||||
});
|
||||
},
|
||||
_readActivities: function () {
|
||||
var self = this;
|
||||
var missing_ids = _.difference(this.value.res_ids, _.pluck(this.activities, 'id'));
|
||||
var fetch_def;
|
||||
if (missing_ids.length) {
|
||||
fetch_def = this._rpc({
|
||||
model: 'mail.activity',
|
||||
method: 'read',
|
||||
args: [missing_ids],
|
||||
});
|
||||
}
|
||||
return $.when(fetch_def).then(function (results) {
|
||||
// convert create_date and date_deadline to moments
|
||||
_.each(results, function (activity) {
|
||||
activity.create_date = moment(time.auto_str_to_date(activity.create_date));
|
||||
activity.date_deadline = moment(time.auto_str_to_date(activity.date_deadline));
|
||||
});
|
||||
|
||||
// filter out activities that are no longer linked to this record
|
||||
self.activities = _.filter(self.activities.concat(results || []), function (activity) {
|
||||
return _.contains(self.value.res_ids, activity.id);
|
||||
});
|
||||
|
||||
// sort activities by due date
|
||||
self.activities = _.sortBy(self.activities, 'date_deadline');
|
||||
});
|
||||
},
|
||||
_scheduleActivity: function (id, previous_activity_type_id, callback) {
|
||||
var action = {
|
||||
type: 'ir.actions.act_window',
|
||||
@@ -116,41 +140,37 @@ var Activity = AbstractActivityField.extend({
|
||||
'click .o_activity_unlink': '_onUnlinkActivity',
|
||||
'click .o_activity_done': '_onMarkActivityDone',
|
||||
},
|
||||
specialData: '_fetchSpecialActivity',
|
||||
|
||||
// inherited
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.dp = new concurrency.DropPrevious();
|
||||
this.activities = this.record.specialData[this.name];
|
||||
},
|
||||
_render: function () {
|
||||
// note: the rendering of this widget is asynchronous as it needs to
|
||||
// fetch the details of the linked activities
|
||||
var self = this;
|
||||
var fetch_def = this.dp.add(this._readActivities());
|
||||
return fetch_def.then(function () {
|
||||
_.each(self.activities, function (activity) {
|
||||
if (activity.note) {
|
||||
activity.note = utils.parse_and_transform(activity.note, utils.add_link);
|
||||
}
|
||||
});
|
||||
var activities = setDelayLabel(self.activities);
|
||||
if (activities.length) {
|
||||
var nbActivities = _.countBy(activities, 'state');
|
||||
self.$el.html(QWeb.render('mail.activity_items', {
|
||||
activities: activities,
|
||||
nbPlannedActivities: nbActivities.planned,
|
||||
nbTodayActivities: nbActivities.today,
|
||||
nbOverdueActivities: nbActivities.overdue,
|
||||
date_format: time.getLangDateFormat(),
|
||||
datetime_format: time.getLangDatetimeFormat(),
|
||||
}));
|
||||
} else {
|
||||
self.$el.empty();
|
||||
_.each(this.activities, function (activity) {
|
||||
if (activity.note) {
|
||||
activity.note = utils.parse_and_transform(activity.note, utils.add_link);
|
||||
}
|
||||
});
|
||||
var activities = setDelayLabel(this.activities);
|
||||
if (activities.length) {
|
||||
var nbActivities = _.countBy(activities, 'state');
|
||||
this.$el.html(QWeb.render('mail.activity_items', {
|
||||
activities: activities,
|
||||
nbPlannedActivities: nbActivities.planned,
|
||||
nbTodayActivities: nbActivities.today,
|
||||
nbOverdueActivities: nbActivities.overdue,
|
||||
date_format: time.getLangDateFormat(),
|
||||
datetime_format: time.getLangDatetimeFormat(),
|
||||
}));
|
||||
} else {
|
||||
this.$el.empty();
|
||||
}
|
||||
},
|
||||
_reset: function (record) {
|
||||
this._super.apply(this, arguments);
|
||||
this.activities = this.record.specialData[this.name];
|
||||
// the mail widgets being persistent, one need to update the res_id on reset
|
||||
this.res_id = record.res_id;
|
||||
},
|
||||
@@ -196,9 +216,6 @@ var Activity = AbstractActivityField.extend({
|
||||
});
|
||||
return this.do_action(action, {
|
||||
on_close: function () {
|
||||
// remove the edited activity from the array of fetched activities to
|
||||
// force a reload of that activity
|
||||
self.activities = _.reject(self.activities, {id: activity_id});
|
||||
self._reload({activity: true, thread: true});
|
||||
},
|
||||
});
|
||||
@@ -312,10 +329,10 @@ var KanbanActivity = AbstractActivityField.extend({
|
||||
_renderDropdown: function () {
|
||||
var self = this;
|
||||
this.$('.o_activity').html(QWeb.render("mail.KanbanActivityLoading"));
|
||||
return this._readActivities().then(function () {
|
||||
return _readActivities(this, this.value.res_ids).then(function (activities) {
|
||||
self.$('.o_activity').html(QWeb.render("mail.KanbanActivityDropdown", {
|
||||
selection: self.selection,
|
||||
records: _.groupBy(setDelayLabel(self.activities), 'state'),
|
||||
records: _.groupBy(setDelayLabel(activities), 'state'),
|
||||
uid: self.getSession().uid,
|
||||
}));
|
||||
});
|
||||
@@ -328,7 +345,9 @@ var KanbanActivity = AbstractActivityField.extend({
|
||||
// handlers
|
||||
_onButtonClicked: function (event) {
|
||||
event.preventDefault();
|
||||
this._renderDropdown();
|
||||
if (!this.$el.hasClass('open')) {
|
||||
this._renderDropdown();
|
||||
}
|
||||
},
|
||||
_onMarkActivityDone: function (event) {
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -351,12 +351,12 @@ QUnit.test('kanban activity widget with an activity', function (assert) {
|
||||
|
||||
// click on the activity button to re-open dropdown
|
||||
$record.find('.o_activity_btn').click();
|
||||
assert.strictEqual(rpcCount, 2, 'no RPC should be done as the activities are now in cache');
|
||||
assert.strictEqual(rpcCount, 3, 'should have reloaded the activities');
|
||||
|
||||
// mark activity as done
|
||||
$record.find('.o_mark_as_done').click();
|
||||
$record = kanban.$('.o_kanban_record').first(); // the record widget has been reset
|
||||
assert.strictEqual(rpcCount, 4, 'should have done an RPC to mark activity as done, and a read');
|
||||
assert.strictEqual(rpcCount, 5, 'should have done an RPC to mark activity as done, and a read');
|
||||
assert.ok($record.find('.o_mail_activity .o_activity_color_default:not(.o_activity_color_today)').length,
|
||||
"activity widget should have been updated correctly");
|
||||
assert.strictEqual($record.find('.o_mail_activity.open').length, 1,
|
||||
@@ -707,6 +707,125 @@ QUnit.test('chatter: Attachment viewer', function (assert) {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('form activity widget: read RPCs', function (assert) {
|
||||
// Records of model 'mail.activity' may be updated in business flows (e.g.
|
||||
// the date of a 'Meeting' activity is updated when the associated meeting
|
||||
// is dragged&dropped in the Calendar view). Because of that, the activities
|
||||
// must be reloaded when the form is reloaded (the widget can't keep an
|
||||
// internal cache).
|
||||
assert.expect(6);
|
||||
this.data.partner.records[0].activity_ids = [1];
|
||||
this.data.partner.records[0].activity_state = 'today';
|
||||
this.data['mail.activity'].records = [{
|
||||
id: 1,
|
||||
display_name: "An activity",
|
||||
date_deadline: moment().format("YYYY-MM-DD"), // now
|
||||
state: "today",
|
||||
user_id: 2,
|
||||
activity_type_id: 2,
|
||||
}];
|
||||
|
||||
var nbReads = 0;
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<div class="oe_chatter">' +
|
||||
'<field name="activity_ids" widget="mail_activity"/>' +
|
||||
'</div>' +
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'read' && args.model === 'mail.activity') {
|
||||
nbReads++;
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(nbReads, 1, "should have read the activities");
|
||||
assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1,
|
||||
"should display an activity");
|
||||
assert.strictEqual(form.$('.o_mail_activity .o_thread_message .o_activity_date').text(),
|
||||
'Today', "the activity should be today");
|
||||
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
|
||||
assert.strictEqual(nbReads, 1, "should not have re-read the activities");
|
||||
|
||||
// simulate a date change, and a reload of the form view
|
||||
var tomorrow = moment().add(1, 'day').format("YYYY-MM-DD");
|
||||
this.data['mail.activity'].records[0].date_deadline = tomorrow;
|
||||
form.reload();
|
||||
|
||||
assert.strictEqual(nbReads, 2, "should have re-read the activities");
|
||||
assert.strictEqual(form.$('.o_mail_activity .o_thread_message .o_activity_date').text(),
|
||||
'Tomorrow', "the activity should be tomorrow");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('form activity widget on a new record', function (assert) {
|
||||
assert.expect(0);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<div class="oe_chatter">' +
|
||||
'<field name="activity_ids" widget="mail_activity"/>' +
|
||||
'</div>' +
|
||||
'</form>',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'read' && args.model === 'mail.activity') {
|
||||
throw new Error("should not do a read on mail.activity");
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('form activity widget with another x2many field in view', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
this.data.partner.fields.m2m = {string: "M2M", type: 'many2many', relation: 'partner'};
|
||||
|
||||
this.data.partner.records[0].m2m = [2];
|
||||
this.data.partner.records[0].activity_ids = [1];
|
||||
this.data.partner.records[0].activity_state = 'today';
|
||||
this.data['mail.activity'].records = [{
|
||||
id: 1,
|
||||
display_name: "An activity",
|
||||
date_deadline: moment().format("YYYY-MM-DD"), // now
|
||||
state: "today",
|
||||
user_id: 2,
|
||||
activity_type_id: 2,
|
||||
}];
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<field name="m2m" widget="many2many_tags"/>' +
|
||||
'<div class="oe_chatter">' +
|
||||
'<field name="activity_ids" widget="mail_activity"/>' +
|
||||
'</div>' +
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
});
|
||||
|
||||
assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1,
|
||||
"should display an activity");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('form activity widget: schedule next activity', function (assert) {
|
||||
assert.expect(5);
|
||||
this.data.partner.records[0].activity_ids = [1];
|
||||
@@ -746,7 +865,7 @@ QUnit.test('form activity widget: schedule next activity', function (assert) {
|
||||
"the feedback should be sent correctly");
|
||||
return $.when();
|
||||
}
|
||||
if (args.method === 'read' && checkReadArgs) {
|
||||
if (args.method === 'read' && args.model === 'partner' && checkReadArgs) {
|
||||
assert.deepEqual(args.args[1], ['activity_ids', 'message_ids', 'display_name'],
|
||||
"should only read the mail fields");
|
||||
}
|
||||
|
||||
@@ -793,7 +793,7 @@ class PosOrder(models.Model):
|
||||
'location_dest_id': move.location_dest_id.id,
|
||||
'lot_id': lot_id,
|
||||
})
|
||||
if not pack_lots:
|
||||
if not pack_lots and not float_is_zero(qty_done, precision_rounding=move.product_uom.rounding):
|
||||
move.quantity_done = qty_done
|
||||
return has_wrong_lots
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ class TestFifoPrice(TestPurchase):
|
||||
self._load('stock_account', 'test', 'stock_valuation_account.xml')
|
||||
|
||||
# Set the company currency as EURO for the sake of repeatibility
|
||||
self.env.ref('base.main_company').currency_id = self.env.ref('base.EUR')
|
||||
self.env.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s",
|
||||
[self.env.ref("base.EUR").id, self.env.ref('base.main_company')])
|
||||
|
||||
# Set a product as using fifo price
|
||||
product_icecream = self.env['product.product'].create({
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<field name="inherit_id" ref="stock.view_inventory_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='date']" position="after">
|
||||
<field name="accounting_date"/>
|
||||
<field name="accounting_date" attrs="{'readonly':[('state','!=', 'draft')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -18,7 +18,8 @@ class TestLifoPrice(common.TransactionCase):
|
||||
self._load('stock_account', 'test', 'stock_valuation_account.xml')
|
||||
|
||||
# Set the company currency as EURO for the sake of repeatibility
|
||||
self.env.ref('base.main_company').write({'currency_id': self.env.ref('base.EUR').id})
|
||||
self.env.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s",
|
||||
[self.env.ref("base.EUR").id, self.env.ref('base.main_company')])
|
||||
|
||||
# Set product category removal strategy as LIFO
|
||||
product_category_001 = self.env['product.category'].create({
|
||||
|
||||
@@ -3048,7 +3048,7 @@ var BasicModel = AbstractModel.extend({
|
||||
if (field.type === 'one2many' || field.type === 'many2many') {
|
||||
var ids;
|
||||
if (!context[fieldName] || _.isArray(context[fieldName])) { // no dataPoint created yet
|
||||
ids = context[fieldName] || [];
|
||||
ids = context[fieldName] ? context[fieldName].slice(0) : [];
|
||||
} else {
|
||||
relDataPoint = this._applyX2ManyOperations(this.localData[context[fieldName]]);
|
||||
ids = relDataPoint.res_ids.slice(0);
|
||||
|
||||
@@ -119,6 +119,10 @@ class Website(models.Model):
|
||||
'arch': template_record.arch.replace(template, key),
|
||||
'name': name,
|
||||
})
|
||||
|
||||
if view.arch_fs:
|
||||
view.arch_fs = False
|
||||
|
||||
if ispage:
|
||||
page = self.env['website.page'].create({
|
||||
'url': page_url,
|
||||
|
||||
@@ -14,7 +14,7 @@ class Website(models.Model):
|
||||
_inherit = 'website'
|
||||
|
||||
pricelist_id = fields.Many2one('product.pricelist', compute='_compute_pricelist_id', string='Default Pricelist')
|
||||
currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', string='Default Currency')
|
||||
currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', related_sudo=False, string='Default Currency')
|
||||
salesperson_id = fields.Many2one('res.users', string='Salesperson')
|
||||
salesteam_id = fields.Many2one('crm.team', string='Sales Channel')
|
||||
pricelist_ids = fields.One2many('product.pricelist', compute="_compute_pricelist_ids",
|
||||
|
||||
@@ -115,33 +115,31 @@ def _hasclass(context, *cls):
|
||||
|
||||
def get_view_arch_from_file(filename, xmlid):
|
||||
doc = etree.parse(filename)
|
||||
node = None
|
||||
for n in doc.xpath('//*[@id="%s"]' % (xmlid)):
|
||||
if n.tag in ('template', 'record'):
|
||||
node = n
|
||||
break
|
||||
if node is None:
|
||||
# fallback search on template with implicit module name
|
||||
for n in doc.xpath('//*[@id="%s"]' % (xmlid.split('.')[1])):
|
||||
if n.tag in ('template', 'record'):
|
||||
node = n
|
||||
break
|
||||
if node is not None:
|
||||
if node.tag == 'record':
|
||||
field = node.find('field[@name="arch"]')
|
||||
_fix_multiple_roots(field)
|
||||
inner = u''.join([etree.tostring(child, encoding='unicode') for child in field.iterchildren()])
|
||||
return field.text + inner
|
||||
elif node.tag == 'template':
|
||||
# The following dom operations has been copied from convert.py's _tag_template()
|
||||
if not node.get('inherit_id'):
|
||||
node.set('t-name', xmlid)
|
||||
node.tag = 't'
|
||||
else:
|
||||
node.tag = 'data'
|
||||
node.attrib.pop('id', None)
|
||||
return etree.tostring(node, encoding='unicode')
|
||||
_logger.warning("Could not find view arch definition in file '%s' for xmlid '%s'", filename, xmlid)
|
||||
|
||||
xmlid_search = (xmlid, xmlid.split('.')[1])
|
||||
|
||||
# when view is created from model with inheritS of ir_ui_view, the xml id has been suffixed by '_ir_ui_view'
|
||||
suffix = '_ir_ui_view'
|
||||
if xmlid.endswith(suffix):
|
||||
xmlid_search += (xmlid.rsplit(suffix, 1)[0], xmlid.split('.')[1].rsplit(suffix, 1)[0])
|
||||
|
||||
for node in doc.xpath('//*[%s]' % ' or '.join(["@id='%s'" % _id for _id in xmlid_search])):
|
||||
if node.tag in ('template', 'record'):
|
||||
if node.tag == 'record':
|
||||
field = node.find('field[@name="arch"]')
|
||||
_fix_multiple_roots(field)
|
||||
inner = u''.join([etree.tostring(child, encoding='unicode') for child in field.iterchildren()])
|
||||
return field.text + inner
|
||||
elif node.tag == 'template':
|
||||
# The following dom operations has been copied from convert.py's _tag_template()
|
||||
if not node.get('inherit_id'):
|
||||
node.set('t-name', xmlid)
|
||||
node.tag = 't'
|
||||
else:
|
||||
node.tag = 'data'
|
||||
node.attrib.pop('id', None)
|
||||
return etree.tostring(node, encoding='unicode')
|
||||
_logger.warning("Could not find view arch definition in file '%s' for xmlid '%s'", filename, xmlid_search)
|
||||
return None
|
||||
|
||||
def add_text_before(node, text):
|
||||
@@ -258,14 +256,12 @@ actual arch.
|
||||
data = dict(arch_db=view.arch)
|
||||
if 'install_mode_data' in self._context:
|
||||
imd = self._context['install_mode_data']
|
||||
if '.' not in imd['xml_id']:
|
||||
imd['xml_id'] = '%s.%s' % (imd['module'], imd['xml_id'])
|
||||
if self._name == imd['model'] and (not view.xml_id or view.xml_id == imd['xml_id']):
|
||||
# we store the relative path to the resource instead of the absolute path, if found
|
||||
# (it will be missing e.g. when importing data-only modules using base_import_module)
|
||||
path_info = get_resource_from_path(imd['xml_file'])
|
||||
if path_info:
|
||||
data['arch_fs'] = '/'.join(path_info[0:2])
|
||||
|
||||
# we store the relative path to the resource instead of the absolute path, if found
|
||||
# (it will be missing e.g. when importing data-only modules using base_import_module)
|
||||
path_info = get_resource_from_path(imd['xml_file'])
|
||||
if path_info:
|
||||
data['arch_fs'] = '/'.join(path_info[0:2])
|
||||
view.write(data)
|
||||
|
||||
@api.depends('arch')
|
||||
|
||||
@@ -751,7 +751,11 @@ class GroupsView(models.Model):
|
||||
xml = E.field(E.group(*(xml1), col="2"), E.group(*(xml2), col="4"), name="groups_id", position="replace")
|
||||
xml.addprevious(etree.Comment("GENERATED AUTOMATICALLY BY GROUPS"))
|
||||
xml_content = etree.tostring(xml, pretty_print=True, encoding="unicode")
|
||||
view.with_context(lang=None).write({'arch': xml_content, 'arch_fs': False})
|
||||
|
||||
new_context = dict(view._context)
|
||||
new_context.pop('install_mode_data', None) # don't set arch_fs for this computed view
|
||||
new_context['lang'] = None
|
||||
view.with_context(new_context).write({'arch': xml_content})
|
||||
|
||||
def get_application_groups(self, domain):
|
||||
""" Return the non-share groups that satisfy ``domain``. """
|
||||
|
||||
Reference in New Issue
Block a user