[MERGE] forward port branch 11.0 up to 22a13073f0

This commit is contained in:
Christophe Simonis
2018-10-19 12:25:17 +02:00
19 changed files with 202 additions and 17 deletions
+1 -1
View File
@@ -227,7 +227,7 @@ class AccountInvoice(models.Model):
for line in self.move_id.line_ids.filtered(lambda l: l.account_id.id == self.account_id.id):
payment_lines.update(line.mapped('matched_credit_ids.credit_move_id.id'))
payment_lines.update(line.mapped('matched_debit_ids.debit_move_id.id'))
self.payment_move_line_ids = self.env['account.move.line'].browse(list(payment_lines))
self.payment_move_line_ids = self.env['account.move.line'].browse(list(payment_lines)).sorted()
name = fields.Char(string='Reference/Description', index=True,
readonly=True, states={'draft': [('readonly', False)]}, copy=False, help='The name that will be used on account move lines')
+2
View File
@@ -115,6 +115,8 @@ class MailMail(models.Model):
ids = filtered_ids
else:
ids = list(set(filtered_ids) & set(ids))
ids.sort()
res = None
try:
# auto-commit except in testing mode
+1 -1
View File
@@ -65,7 +65,7 @@
<field name="res_model">project.task</field>
<field name="view_mode">kanban,tree,form,calendar,pivot,graph</field>
<field name="context">{
'group_by': 'stage_id',
'default_group_by': 'stage_id',
'search_default_project_id': [active_id],
'default_project_id': active_id,
}</field>
+2 -2
View File
@@ -510,6 +510,8 @@ class StockMoveLine(models.Model):
candidate.product_uom_qty = 0.0
else:
candidate.unlink()
if float_is_zero(quantity, precision_rounding=rounding):
break
else:
# split this move line and assign the new part to our extra move
quantity_split = float_round(
@@ -517,8 +519,6 @@ class StockMoveLine(models.Model):
precision_rounding=self.product_uom_id.rounding,
rounding_method='UP')
candidate.product_uom_qty = self.product_id.uom_id._compute_quantity(quantity_split, candidate.product_uom_id, rounding_method='HALF-UP')
quantity -= quantity_split
move_to_recompute_state |= candidate.move_id
if quantity == 0.0:
break
move_to_recompute_state._recompute_state()
+42
View File
@@ -2004,6 +2004,48 @@ class StockMove(TransactionCase):
self.assertAlmostEqual(move_pack_cust.reserved_availability, 1.0)
self.assertEqual(move_pack_cust.state, 'partially_available')
def test_use_reserved_move_line_1(self):
""" Test that _free_reservation work when quantity is only available on
reserved move lines.
"""
self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 10.0)
move1 = self.env['stock.move'].create({
'name': 'test_use_unreserved_move_line_1_1',
'location_id': self.stock_location.id,
'location_dest_id': self.customer_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 5.0,
})
move2 = self.env['stock.move'].create({
'name': 'test_use_unreserved_move_line_1_1',
'location_id': self.stock_location.id,
'location_dest_id': self.customer_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 5.0,
})
move1._action_confirm()
move1._action_assign()
move2._action_confirm()
move2._action_assign()
move3 = self.env['stock.move'].create({
'name': 'test_use_unreserved_move_line_1_1',
'location_id': self.stock_location.id,
'location_dest_id': self.customer_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 0.0,
'quantity_done': 1.0,
})
move3._action_confirm()
move3._action_assign()
move3._action_done()
self.assertEqual(move3.state, 'done')
quant = self.env['stock.quant']._gather(self.product1, self.stock_location)
self.assertEqual(quant.quantity, 9.0)
self.assertEqual(quant.reserved_quantity, 9.0)
def test_use_unreserved_move_line_1(self):
""" Test that validating a stock move linked to an untracked product reserved by another one
correctly unreserves the other one.
@@ -273,3 +273,35 @@ var AbstractView = Class.extend({
return AbstractView;
});
odoo.define('web.viewUtils', function () {
"use strict";
/**
* FIXME: move this module to its own file in master
*/
var utils = {
/**
* States whether or not the quick create feature is available for the given
* datapoint, depending on its groupBy field.
*
* @param {Object} list dataPoint of type list
* @returns {Boolean} true iff the kanban quick create feature is available
*/
isQuickCreateEnabled: function (list) {
var groupByField = list.groupedBy[0] && list.groupedBy[0].split(':')[0];
if (!groupByField) {
return false;
}
var availableTypes = ['char', 'boolean', 'many2one'];
if (!_.contains(availableTypes, list.fields[groupByField].type)) {
return false;
}
return true;
},
};
return utils;
});
@@ -213,7 +213,7 @@ var BasicView = AbstractView.extend({
attrs.options = attrs.options ? pyeval.py_eval(attrs.options) : {};
}
if (attrs.on_change && !field.onChange) {
if (attrs.on_change && attrs.on_change !== "0" && !field.onChange) {
field.onChange = "1";
}
@@ -12,6 +12,7 @@ var Context = require('web.Context');
var core = require('web.core');
var Domain = require('web.Domain');
var view_dialogs = require('web.view_dialogs');
var viewUtils = require('web.viewUtils');
var _t = core._t;
var qweb = core.qweb;
@@ -34,12 +35,15 @@ var KanbanController = BasicController.extend({
/**
* @override
* @param {Object} params
* @param {boolean} params.quickCreateEnabled set to false to disable the
* quick create feature
*/
init: function (parent, model, renderer, params) {
this._super.apply(this, arguments);
this.on_create = params.on_create;
this.hasButtons = params.hasButtons;
this.quickCreateEnabled = params.quickCreateEnabled;
},
//--------------------------------------------------------------------------
@@ -259,8 +263,8 @@ var KanbanController = BasicController.extend({
*/
_onButtonNew: function () {
var state = this.model.get(this.handle, {raw: true});
var hasColumns = state.groupedBy.length > 0 && state.data.length > 0;
if (hasColumns && this.on_create === 'quick_create') {
var quickCreateEnabled = this.quickCreateEnabled && viewUtils.isQuickCreateEnabled(state);
if (this.on_create === 'quick_create' && quickCreateEnabled) {
// Activate the quick create in the first column
this.renderer.addQuickCreate();
} else if (this.on_create && this.on_create !== 'quick_create') {
@@ -9,6 +9,7 @@ var ColumnQuickCreate = require('web.kanban_column_quick_create');
var QWeb = require('web.QWeb');
var session = require('web.session');
var utils = require('web.utils');
var viewUtils = require('web.viewUtils');
var qweb = core.qweb;
@@ -93,6 +94,9 @@ var KanbanRenderer = BasicRenderer.extend({
}),
/**
* @override
* @param {Object} params
* @param {boolean} params.quickCreateEnabled set to false to disable the
* quick create feature
*/
init: function (parent, state, params) {
this._super.apply(this, arguments);
@@ -111,6 +115,7 @@ var KanbanRenderer = BasicRenderer.extend({
if (this.columnOptions.hasProgressBar) {
this.columnOptions.progressBarStates = {};
}
this.quickCreateEnabled = params.quickCreateEnabled;
this._setState(state);
},
/**
@@ -423,6 +428,7 @@ var KanbanRenderer = BasicRenderer.extend({
groupedBy: groupByField,
grouped_by_m2o: this.groupedByM2O,
relation: relation,
quick_create: this.quickCreateEnabled && viewUtils.isQuickCreateEnabled(state),
});
this.createColumnEnabled = this.groupedByM2O && this.columnOptions.group_creatable;
},
@@ -62,7 +62,6 @@ var KanbanView = BasicView.extend({
editable: activeActions.group_edit,
deletable: activeActions.group_delete,
group_creatable: activeActions.group_create && !config.device.isMobile,
quick_create: params.isQuickCreateEnabled || this._isQuickCreateEnabled(),
quickCreateView: this.arch.attrs.quick_create_view || null,
hasProgressBar: !!progressBar,
};
@@ -71,6 +70,7 @@ var KanbanView = BasicView.extend({
deletable: activeActions.delete,
read_only_mode: params.readOnlyMode,
};
this.rendererParams.quickCreateEnabled = this._isQuickCreateEnabled();
var examples = this.arch.attrs.examples;
if (examples) {
this.rendererParams.examples = kanbanExamplesRegistry.get(examples);
@@ -79,6 +79,7 @@ var KanbanView = BasicView.extend({
this.controllerParams.on_create = this.arch.attrs.on_create;
this.controllerParams.readOnlyMode = false;
this.controllerParams.hasButtons = true;
this.controllerParams.quickCreateEnabled = this.rendererParams.quickCreateEnabled;
if (config.device.isMobile) {
this.jsLibs.push('/web/static/lib/jquery.touchSwipe/jquery.touchSwipe.js');
@@ -92,13 +93,10 @@ var KanbanView = BasicView.extend({
/**
* @private
* @param {Object} viewInfo
* @returns {boolean} true iff the quick create feature is not explicitely
* disabled (with create="False" or quick_create="False" in the arch)
*/
_isQuickCreateEnabled: function () {
var groupBy = this.loadParams.groupBy[0];
groupBy = groupBy !== undefined ? groupBy.split(':')[0] : undefined;
if (groupBy !== undefined && !_.contains(['char', 'boolean', 'many2one'], this.fields[groupBy].type)) {
return false;
}
if (!this.controllerParams.activeActions.create) {
return false;
}
+1 -1
View File
@@ -790,7 +790,7 @@
</t>
<t t-name="FieldMany2One">
<t t-if="widget.mode === 'readonly'">
<a t-if="!widget.nodeOptions.no_open" class="o_form_uri" href="#"/>
<a t-if="!widget.nodeOptions.no_open" t-att-tabindex="widget.attrs.tabindex" class="o_form_uri" href="#"/>
<span t-if="widget.nodeOptions.no_open"/>
</t>
<div t-if="widget.mode === 'edit'" class="o_field_widget o_field_many2one">
+76 -1
View File
@@ -1218,6 +1218,81 @@ QUnit.module('Views', {
kanban.destroy();
});
QUnit.test('quick create record in grouped on date(time) field', function (assert) {
assert.expect(6);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
'<templates><t t-name="kanban-box">' +
'<div><field name="display_name"/></div>' +
'</t></templates>' +
'</kanban>',
groupBy: ['date'],
intercepts: {
switch_view: function (ev) {
assert.deepEqual(_.pick(ev.data, 'res_id', 'view_type'), {
res_id: undefined,
view_type: 'form',
}, "should trigger an event to open the form view (twice)");
},
},
});
assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0,
"quick create should be disabled when grouped on a date field");
// clicking on CREATE in control panel should not open a quick create
kanban.$buttons.find('.o-kanban-button-new').click();
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0,
"should not have opened the quick create widget");
kanban.reload({groupBy: ['datetime']});
assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0,
"quick create should be disabled when grouped on a datetime field");
// clicking on CREATE in control panel should not open a quick create
kanban.$buttons.find('.o-kanban-button-new').click();
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0,
"should not have opened the quick create widget");
kanban.destroy();
});
QUnit.test('quick create record feature is properly enabled/disabled at reload', function (assert) {
assert.expect(3);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
'<templates><t t-name="kanban-box">' +
'<div><field name="display_name"/></div>' +
'</t></templates>' +
'</kanban>',
groupBy: ['foo'],
});
assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3,
"quick create should be enabled when grouped on a char field");
kanban.reload({groupBy: ['date']});
assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0,
"quick create should now be disabled (grouped on date field)");
kanban.reload({groupBy: ['bar']});
assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2,
"quick create should be enabled again (grouped on boolean field)");
kanban.destroy();
});
QUnit.test('many2many_tags in kanban views', function (assert) {
assert.expect(12);
@@ -3568,7 +3643,7 @@ QUnit.module('Views', {
'<div><field name="foo"/></div>' +
'</t></templates>' +
'</kanban>',
groupBy: ['int_field'],
groupBy: ['foo'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
return $.when(true);
+11
View File
@@ -0,0 +1,11 @@
Germany, 2017-11-24
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,
Andreas Raster lazor@affenbande.org https://github.com/rakete
+11
View File
@@ -0,0 +1,11 @@
FRANCE, 2018-09-26
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,
zoggy 43614933+zoggy444@users.noreply.github.com https://github.com/zoggy444
+1 -1
View File
@@ -852,7 +852,7 @@ attributes:
``quick_create``
whether it should be possible to create records without switching to the
form view. By default, ``quick_create`` is enabled when the Kanban view is
grouped, and disabled when not.
grouped by many2one, char or boolean fields, and disabled when not.
Set to ``true`` to always enable it, and to ``false`` to always disable it.
+1
View File
@@ -107,6 +107,7 @@ CREATE TABLE res_company (
name varchar NOT NULL,
partner_id integer,
currency_id integer,
sequence integer,
create_date timestamp without time zone,
primary key(id)
);
+1 -1
View File
@@ -339,7 +339,7 @@ class IrActionsServer(models.Model):
DEFAULT_PYTHON_CODE = """# Available variables:
# - env: Odoo Environment on which the action is triggered
# - model: Odoo Model of the record on which the action is triggered; is a void recordset
# - record: record on which the action is triggered; may be be void
# - record: record on which the action is triggered; may be void
# - records: recordset of all records on which the action is triggered in multi-mode; may be void
# - time, datetime, dateutil, timezone: useful Python libraries
# - log: log(message, level='info'): logging function to record debug information in ir.logging table
+1
View File
@@ -768,6 +768,7 @@ class IrModelFields(models.Model):
'index': bool(field.index),
'store': bool(field.store),
'copy': bool(field.copy),
'on_delete': getattr(field, 'ondelete', None),
'related': ".".join(field.related) if field.related else None,
'readonly': bool(field.readonly),
'required': bool(field.required),
+2
View File
@@ -135,6 +135,8 @@ class FSWatcher(object):
try:
source = open(path, 'rb').read() + b'\n'
compile(source, path, 'exec')
except FileNotFoundError:
_logger.error('autoreload: python code change detected, FileNotFound for %s', path)
except SyntaxError:
_logger.error('autoreload: python code change detected, SyntaxError in %s', path)
else: