diff --git a/addons/hr/models/hr_employee.py b/addons/hr/models/hr_employee.py
index 09c7f656f6..8c678de7d5 100644
--- a/addons/hr/models/hr_employee.py
+++ b/addons/hr/models/hr_employee.py
@@ -230,7 +230,7 @@ class HrEmployeePrivate(models.Model):
vals.update(self._sync_user(user, vals.get('image_1920') == self._default_image()))
vals['name'] = vals.get('name', user.name)
employee = super(HrEmployeePrivate, self).create(vals)
- employee.message_subscribe(employee.address_home_id.ids)
+ employee._message_subscribe(employee.address_home_id.ids)
url = '/web#%s' % url_encode({
'action': 'hr.plan_wizard_action',
'active_id': employee.id,
@@ -250,7 +250,8 @@ class HrEmployeePrivate(models.Model):
if account_id:
self.env['res.partner.bank'].browse(account_id).partner_id = vals['address_home_id']
self.message_unsubscribe(self.address_home_id.ids)
- self.message_subscribe([vals['address_home_id']])
+ if vals['address_home_id']:
+ self._message_subscribe([vals['address_home_id']])
if vals.get('user_id'):
# Update the profile pictures with user, except if provided
vals.update(self._sync_user(self.env['res.users'].browse(vals['user_id']), bool(vals.get('image_1920'))))
diff --git a/addons/hr_holidays/models/hr_employee.py b/addons/hr_holidays/models/hr_employee.py
index 2400e8a112..9392d49a87 100644
--- a/addons/hr_holidays/models/hr_employee.py
+++ b/addons/hr_holidays/models/hr_employee.py
@@ -4,7 +4,8 @@
import datetime
from dateutil.relativedelta import relativedelta
-from flectra import api, fields, models
+from flectra import api, fields, models, _
+from flectra.exceptions import UserError
from flectra.tools.float_utils import float_round
@@ -118,7 +119,7 @@ class HrEmployeeBase(models.AbstractModel):
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
- ('state', 'not in', ('cancel', 'refuse'))
+ ('state', '=', 'validate'),
])
leave_data = {}
for holiday in holidays:
@@ -154,6 +155,8 @@ class HrEmployeeBase(models.AbstractModel):
employee.show_leaves = False
def _search_absent_employee(self, operator, value):
+ if operator not in ('=', '!=') or not isinstance(value, bool):
+ raise UserError(_('Operation not supported'))
# This search is only used for the 'Absent Today' filter however
# this only returns employees that are absent right now.
today_date = datetime.datetime.utcnow().date()
@@ -161,11 +164,12 @@ class HrEmployeeBase(models.AbstractModel):
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
holidays = self.env['hr.leave'].sudo().search([
('employee_id', '!=', False),
- ('state', 'not in', ['cancel', 'refuse']),
+ ('state', '=', 'validate1'),
('date_from', '<=', today_end),
('date_to', '>=', today_start),
])
- return [('id', 'in', holidays.mapped('employee_id').ids)]
+ operator = ['in', 'not in'][(operator == '=') != value]
+ return [('id', operator, holidays.mapped('employee_id').ids)]
@api.model
def create(self, values):
diff --git a/addons/hr_holidays/tests/test_leave_requests.py b/addons/hr_holidays/tests/test_leave_requests.py
index 2e650e153d..8d478d2882 100644
--- a/addons/hr_holidays/tests/test_leave_requests.py
+++ b/addons/hr_holidays/tests/test_leave_requests.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
-from datetime import datetime, date
+from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
from pytz import timezone, UTC
@@ -466,3 +466,48 @@ class TestLeaveRequests(TestHrHolidaysCommon):
'date_to': datetime(2022, 3, 11, 23, 59, 59),
})
self.assertEqual(leave.number_of_days, 1)
+
+ def test_current_leave_status(self):
+ types = ('no_validation', 'manager', 'hr', 'both')
+ employee = self.employee_emp
+
+ def run_validation_flow(leave_validation_type):
+ LeaveType = self.env['hr.leave.type'].with_user(self.user_hrmanager_id)
+ leave_type = LeaveType.with_context(tracking_disable=True).create({
+ 'name': leave_validation_type.capitalize(),
+ 'leave_validation_type': leave_validation_type,
+ 'allocation_type': 'no',
+ })
+ current_leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
+ 'name': 'Holiday Request',
+ 'holiday_type': 'employee',
+ 'employee_id': employee.id,
+ 'holiday_status_id': leave_type.id,
+ 'date_from': datetime.today() - timedelta(days=1),
+ 'date_to': datetime.today() + timedelta(days=1),
+ })
+
+ if leave_validation_type in ('manager', 'both'):
+ self.assertFalse(employee.is_absent)
+ self.assertFalse(employee.current_leave_id)
+ self.assertEqual(employee.filtered_domain([('is_absent', '=', False)]), employee)
+ self.assertFalse(employee.filtered_domain([('is_absent', '=', True)]))
+ current_leave.with_user(self.user_hruser_id).action_approve()
+
+ if leave_validation_type in ('hr', 'both'):
+ self.assertFalse(employee.is_absent)
+ self.assertFalse(employee.current_leave_id)
+ self.assertEqual(employee.filtered_domain([('is_absent', '=', False)]), employee)
+ self.assertFalse(employee.filtered_domain([('is_absent', '=', True)]))
+ current_leave.with_user(self.user_hrmanager_id).action_validate()
+
+ self.assertTrue(employee.is_absent)
+ self.assertEqual(employee.current_leave_id, current_leave.holiday_status_id)
+ self.assertFalse(employee.filtered_domain([('is_absent', '=', False)]))
+ self.assertEqual(employee.filtered_domain([('is_absent', '=', True)]), employee)
+
+ raise RuntimeError()
+
+ for leave_validation_type in types:
+ with self.assertRaises(RuntimeError), self.env.cr.savepoint():
+ run_validation_flow(leave_validation_type)
diff --git a/addons/point_of_sale/tests/test_point_of_sale_flow.py b/addons/point_of_sale/tests/test_point_of_sale_flow.py
index 368a717f2e..903a865813 100644
--- a/addons/point_of_sale/tests/test_point_of_sale_flow.py
+++ b/addons/point_of_sale/tests/test_point_of_sale_flow.py
@@ -1176,7 +1176,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon):
[0, 0, {'lot_name': '1001'}],
]
})],
- 'pricelist_id': 1,
+ 'pricelist_id': self.pos_config.pricelist_id.id,
'amount_paid': 6.0,
'amount_total': 6.0,
'amount_tax': 0.0,
diff --git a/addons/stock/static/src/js/stock_orderpoint_list_controller.js b/addons/stock/static/src/js/stock_orderpoint_list_controller.js
index 611f9b677e..81696ef6b3 100644
--- a/addons/stock/static/src/js/stock_orderpoint_list_controller.js
+++ b/addons/stock/static/src/js/stock_orderpoint_list_controller.js
@@ -46,8 +46,7 @@ var StockOrderpointListController = ListController.extend({
},
_onReplenish: function () {
- var records = this.getSelectedRecords();
- this.model.replenish(records);
+ this.getSelectedIdsWithDomain().then(ids => this.model.replenish((ids)));
},
_onSelectionChanged: function (ev) {
@@ -64,8 +63,7 @@ var StockOrderpointListController = ListController.extend({
},
_onSnooze: function () {
- var records = this.getSelectedRecords();
- this.model.snooze(records);
+ this.getSelectedIdsWithDomain().then(ids => this.model.snooze((ids)));
},
});
diff --git a/addons/stock/static/src/js/stock_orderpoint_list_model.js b/addons/stock/static/src/js/stock_orderpoint_list_model.js
index 1b71df1339..f1b1f9fdd8 100644
--- a/addons/stock/static/src/js/stock_orderpoint_list_model.js
+++ b/addons/stock/static/src/js/stock_orderpoint_list_model.js
@@ -14,23 +14,19 @@ var StockOrderpointListModel = ListModel.extend({
// -------------------------------------------------------------------------
/**
*/
- replenish: function (records) {
+ replenish: function (recordResIds) {
var self = this;
- var model = records[0].model;
- var recordResIds = _.pluck(records, 'res_id');
- var context = records[0].getContext();
return this._rpc({
- model: model,
+ model: this.loadParams.modelName,
method: 'action_replenish',
args: [recordResIds],
- context: context,
+ context: this.loadParams.context,
}).then(function () {
return self.do_action('stock.action_replenishment');
});
},
- snooze: function (records) {
- var recordResIds = _.pluck(records, 'res_id');
+ snooze: function (recordResIds) {
var self = this;
return this.do_action('stock.action_orderpoint_snooze', {
additional_context: {
diff --git a/addons/stock/static/tests/stock_orderpoint_tests.js b/addons/stock/static/tests/stock_orderpoint_tests.js
new file mode 100644
index 0000000000..54853e18e7
--- /dev/null
+++ b/addons/stock/static/tests/stock_orderpoint_tests.js
@@ -0,0 +1,96 @@
+flectra.define("stock.orderpoint_tests", function (require) {
+ "use strict";
+
+ const { createView, dom, nextTick } = require("web.test_utils");
+ const StockOrderpointListView = require("stock.StockOrderpointListView");
+
+ QUnit.module(
+ "Views",
+ {
+ beforeEach: function () {
+ this.data = {
+ person: {
+ fields: {
+ name: { string: "Name", type: "char" },
+ age: { string: "Age", type: "integer" },
+ job: { string: "Profession", type: "char" },
+ },
+ records: [
+ { id: 1, name: "Daniel Fortesque", age: 32, job: "Soldier" },
+ { id: 2, name: "Samuel Oak", age: 64, job: "Professor" },
+ { id: 3, name: "Leto II Atreides", age: 128, job: "Emperor" },
+ ],
+ },
+ };
+ },
+ },
+ () => {
+ QUnit.module("StockOrderpointListView");
+
+ QUnit.test(
+ "domain selection: order should be called on all records",
+ async function (assert) {
+ assert.expect(1);
+
+ const view = await createView({
+ View: StockOrderpointListView,
+ model: "person",
+ data: this.data,
+ arch: `
+
+
+ `,
+ mockRPC: function (route, { args, method, model }) {
+ if (method === "action_replenish") {
+ assert.deepEqual(
+ { args, model },
+ { args: [[1, 2, 3]], model: "person" }
+ );
+ return Promise.resolve({});
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ await dom.click(view.$("thead .o_list_record_selector input"));
+ await dom.click(view.$(".o_list_selection_box .o_list_select_domain"));
+ await dom.click(view.$(".o_button_order"));
+ await nextTick();
+ view.destroy();
+ }
+ );
+
+ QUnit.test(
+ "domain selection: snooze should be called on all records",
+ async function (assert) {
+ assert.expect(1);
+
+ const view = await createView({
+ View: StockOrderpointListView,
+ model: "person",
+ data: this.data,
+ arch: `
+
+
+ `,
+ intercepts: {
+ do_action: function (event) {
+ if (event.data.action === "stock.action_orderpoint_snooze") {
+ assert.deepEqual(event.data.options.additional_context, {
+ default_orderpoint_ids: [1, 2, 3],
+ });
+ }
+ },
+ },
+ });
+
+ await dom.click(view.$("thead .o_list_record_selector input"));
+ await dom.click(view.$(".o_list_selection_box .o_list_select_domain"));
+ await dom.click(view.$(".o_button_snooze"));
+ await nextTick();
+ view.destroy();
+ }
+ );
+ }
+ );
+});
diff --git a/addons/stock/views/stock_template.xml b/addons/stock/views/stock_template.xml
index f8e7528c17..aa322e22fb 100644
--- a/addons/stock/views/stock_template.xml
+++ b/addons/stock/views/stock_template.xml
@@ -31,6 +31,7 @@
+
diff --git a/addons/transifex/data/transifex_data.xml b/addons/transifex/data/transifex_data.xml
index 17941e5642..bdf4f53b58 100644
--- a/addons/transifex/data/transifex_data.xml
+++ b/addons/transifex/data/transifex_data.xml
@@ -3,7 +3,7 @@
transifex.project_url
- https://www.transifex.com/flectra
+ https://app.transifex.com/flectra
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js
index 38deb76f7b..31d494ba03 100644
--- a/addons/web_editor/static/src/js/editor/rte.summernote.js
+++ b/addons/web_editor/static/src/js/editor/rte.summernote.js
@@ -431,9 +431,9 @@ eventHandler.modules.editor.floatMe = function ($editable, sValue) {
var $target = $(getImgTarget($editable));
$editable.data('NoteHistory').recordUndo();
switch (sValue) {
- case 'center': $target.toggleClass('d-block mx-auto').removeClass('float-right float-left'); break;
- case 'left': $target.toggleClass('float-left').removeClass('float-right d-block mx-auto'); break;
- case 'right': $target.toggleClass('float-right').removeClass('float-left d-block mx-auto'); break;
+ case 'center': $target.toggleClass('d-block mx-auto').removeClass('float-right float-left ml-auto'); break;
+ case 'left': $target.toggleClass('float-left').removeClass('float-right d-block mx-auto ml-auto'); break;
+ case 'right': $target.toggleClass('ml-auto float-right').removeClass('float-left d-block mx-auto'); break;
}
};
eventHandler.modules.editor.imageShape = function ($editable, sValue) {
diff --git a/addons/web_editor/static/src/scss/web_editor.common.scss b/addons/web_editor/static/src/scss/web_editor.common.scss
index de5e912ca0..dd51747e76 100644
--- a/addons/web_editor/static/src/scss/web_editor.common.scss
+++ b/addons/web_editor/static/src/scss/web_editor.common.scss
@@ -199,6 +199,9 @@ img.ml-auto, img.mx-auto {
display: block;
text-align: center;
}
+.fa.card-img, .fa.card-img-top, .fa.card-img-bottom {
+ width: auto;
+}
div.media_iframe_video {
margin: 0 auto;