mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-11-03 20:56:39 -06:00
Merge branch 'master' of gitlab.com:flectra-hq/flectra
This commit is contained in:
commit
166f242fbf
26 files changed
+248
-36
No files matched your search
@@ -151,7 +151,7 @@ class AccountMove(models.Model):
|
||||
('in_refund', 'Vendor Credit Note'),
|
||||
('out_receipt', 'Sales Receipt'),
|
||||
('in_receipt', 'Purchase Receipt'),
|
||||
], string='Type', required=True, store=True, index=True, readonly=True, tracking=True,
|
||||
], string='Move Type', required=True, store=True, index=True, readonly=True, tracking=True,
|
||||
default="entry", change_default=True)
|
||||
type_name = fields.Char('Type Name', compute='_compute_type_name')
|
||||
to_check = fields.Boolean(string='To Check', default=False,
|
||||
|
||||
@@ -90,11 +90,11 @@ class AccountInvoiceLine(models.Model):
|
||||
elif self.move_id.move_type == 'in_invoice' and self.asset_category_id:
|
||||
self.account_id = self.asset_category_id.account_asset_id.id
|
||||
|
||||
@api.onchange('uom_id')
|
||||
def _onchange_uom_id(self):
|
||||
result = super(AccountInvoiceLine, self)._onchange_uom_id()
|
||||
self.onchange_asset_category_id()
|
||||
return result
|
||||
# @api.onchange('uom_id')
|
||||
# def _onchange_uom_id(self):
|
||||
# result = super(AccountInvoiceLine, self)._onchange_uom_id()
|
||||
# self.onchange_asset_category_id()
|
||||
# return result
|
||||
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id(self):
|
||||
|
||||
@@ -14,7 +14,7 @@ class AccountBankStatementLine(models.Model):
|
||||
help="This technical field can be used at the statement line creation/import time in order to avoid the reconciliation"
|
||||
" process on it later on. The statement line will simply create a counterpart on this account")
|
||||
note = fields.Text(string='Notes')
|
||||
journal_entry_ids = fields.One2many('account.move.line', 'statement_line_id', 'Journal Items', copy=False,
|
||||
journal_entry_ids = fields.One2many('account.move.line', 'statement_line_id', 'Journals', copy=False,
|
||||
readonly=True)
|
||||
move_name = fields.Char(string='Journal Entry Name', readonly=True,
|
||||
default=False, copy=False,
|
||||
|
||||
@@ -26,7 +26,7 @@ class AccountMove(models.Model):
|
||||
('not_paid', 'Not Paid'),
|
||||
('in_payment', 'In Payment'),
|
||||
('paid', 'Paid')],
|
||||
string='Payment', store=True, readonly=True, copy=False, tracking=True,
|
||||
string='Status of Payment', store=True, readonly=True, copy=False, tracking=True,
|
||||
compute='_compute_amount')
|
||||
|
||||
def action_open_reconcile(self):
|
||||
|
||||
@@ -8,7 +8,7 @@ from flectra.exceptions import UserError, ValidationError
|
||||
class AccountPayment(models.Model):
|
||||
_inherit = "account.payment"
|
||||
|
||||
payment_date = fields.Date(string='Date', default=fields.Date.context_today, required=True, readonly=True,
|
||||
payment_date = fields.Date(string='Payment Date', default=fields.Date.context_today, required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]}, copy=False, tracking=True)
|
||||
communication = fields.Char(string='Memo', readonly=True, states={'draft': [('readonly', False)]})
|
||||
move_line_ids = fields.One2many('account.move.line', 'payment_id', readonly=True, copy=False)
|
||||
|
||||
@@ -20,8 +20,8 @@ class AccountingReport(models.TransientModel):
|
||||
account_report_id = fields.Many2one('account.financial.report', string='Account Reports', required=True, default=_get_account_report)
|
||||
label_filter = fields.Char(string='Column Label', help="This label will be displayed on report to show the balance computed for the given comparison filter.")
|
||||
filter_cmp = fields.Selection([('filter_no', 'No Filters'), ('filter_date', 'Date')], string='Filter by', required=True, default='filter_no')
|
||||
date_from_cmp = fields.Date(string='Start Date')
|
||||
date_to_cmp = fields.Date(string='End Date')
|
||||
date_from_cmp = fields.Date(string='From Date')
|
||||
date_to_cmp = fields.Date(string='To Date')
|
||||
debit_credit = fields.Boolean(string='Display Debit/Credit Columns', help="This option allows you to get more details about the way your balances are computed. Because it is space consuming, we do not allow to use it while doing a comparison.")
|
||||
|
||||
def _build_comparison_context(self, data):
|
||||
|
||||
@@ -13,6 +13,6 @@ class ResUsers(models.Model):
|
||||
default_digest_emails = self.env['ir.config_parameter'].sudo().get_param('digest.default_digest_emails')
|
||||
default_digest_id = self.env['ir.config_parameter'].sudo().get_param('digest.default_digest_id')
|
||||
if default_digest_emails and default_digest_id:
|
||||
digest = self.env['digest.digest'].sudo().browse(int(default_digest_id))
|
||||
digest = self.env['digest.digest'].sudo().browse(int(default_digest_id)).exists()
|
||||
digest.user_ids |= users.filtered_domain([('share', '=', False)])
|
||||
return users
|
||||
@@ -6,7 +6,7 @@ import flectra.tests
|
||||
@flectra.tests.tagged("post_install", "-at_install")
|
||||
class TestDmsPortal(flectra.tests.HttpCase):
|
||||
def test_tour(self):
|
||||
self.phantom_js(
|
||||
self.start_tour(
|
||||
"/",
|
||||
"flectra.__DEBUG__.services['web_tour.tour'].run('dms_portal_tour')",
|
||||
"flectra.__DEBUG__.services['web_tour.tour'].tours.dms_portal_tour.ready",
|
||||
|
||||
@@ -47,6 +47,10 @@ class SaleOrder(models.Model):
|
||||
for sale_order in self:
|
||||
sale_order.attendee_count = attendee_count_data.get(sale_order.id, 0)
|
||||
|
||||
def unlink(self):
|
||||
self.order_line._unlink_associated_registrations()
|
||||
return super(SaleOrder, self).unlink()
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
|
||||
@@ -120,6 +124,13 @@ class SaleOrderLine(models.Model):
|
||||
# we call this to force update the default name
|
||||
self.product_id_change()
|
||||
|
||||
def unlink(self):
|
||||
self._unlink_associated_registrations()
|
||||
return super(SaleOrderLine, self).unlink()
|
||||
|
||||
def _unlink_associated_registrations(self):
|
||||
self.env['event.registration'].search([('sale_order_line_id', 'in', self.ids)]).unlink()
|
||||
|
||||
def get_sale_order_line_multiline_description_sale(self, product):
|
||||
""" We override this method because we decided that:
|
||||
The default description of a sales order line containing a ticket must be different than the default description when no ticket is present.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra.addons.event_sale.tests.common import TestEventSaleCommon
|
||||
from flectra.addons.mail.tests.common import mail_new_test_user
|
||||
|
||||
from flectra.tests import tagged
|
||||
from flectra.tests.common import users
|
||||
|
||||
@@ -13,20 +15,59 @@ class TestEventSale(TestEventSaleCommon):
|
||||
def setUpClass(cls):
|
||||
super(TestEventSale, cls).setUpClass()
|
||||
|
||||
product = cls.env['product.product'].create({
|
||||
'name': 'Event',
|
||||
'type': 'service',
|
||||
'event_ok': True,
|
||||
})
|
||||
|
||||
cls.user_salesperson = mail_new_test_user(cls.env, login='user_salesman', groups='sales_team.group_sale_salesman')
|
||||
|
||||
cls.ticket = cls.env['event.event.ticket'].create({
|
||||
'name': 'First Ticket',
|
||||
'product_id': cls.event_product.id,
|
||||
'seats_max': 30,
|
||||
'event_id': cls.event_0.id,
|
||||
})
|
||||
|
||||
cls.event_0.write({
|
||||
'event_ticket_ids': [
|
||||
(5, 0),
|
||||
(6, 0, cls.ticket.ids),
|
||||
(0, 0, {
|
||||
'name': 'First Ticket',
|
||||
'product_id': cls.event_product.id,
|
||||
'seats_max': 30,
|
||||
}), (0, 0, {
|
||||
'name': 'Second Ticket',
|
||||
'product_id': cls.event_product.id,
|
||||
})
|
||||
],
|
||||
})
|
||||
|
||||
cls.sale_order = cls.env['sale.order'].create({
|
||||
'partner_id': cls.env.ref('base.res_partner_2').id,
|
||||
'note': 'Invoice after delivery',
|
||||
'payment_term_id': cls.env.ref('account.account_payment_term_end_following_month').id
|
||||
})
|
||||
|
||||
# In the sales order I add some sales order lines. i choose event product
|
||||
cls.env['sale.order.line'].create({
|
||||
'product_id': product.id,
|
||||
'price_unit': 190.50,
|
||||
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
||||
'product_uom_qty': 1.0,
|
||||
'order_id': cls.sale_order.id,
|
||||
'name': 'sales order line',
|
||||
'event_id': cls.event_0.id,
|
||||
'event_ticket_id': cls.ticket.id,
|
||||
})
|
||||
|
||||
cls.register_person = cls.env['registration.editor'].create({
|
||||
'sale_order_id': cls.sale_order.id,
|
||||
'event_registration_ids': [(0, 0, {
|
||||
'event_id': cls.event_0.id,
|
||||
'name': 'Administrator',
|
||||
'email': 'abc@example.com',
|
||||
'sale_order_line_id': cls.sale_order.order_line.id,
|
||||
})],
|
||||
})
|
||||
|
||||
# make a SO for a customer, selling some tickets
|
||||
cls.customer_so = cls.env['sale.order'].with_user(cls.user_sales_salesman).create({
|
||||
'partner_id': cls.event_customer.id,
|
||||
@@ -209,3 +250,23 @@ class TestEventSale(TestEventSaleCommon):
|
||||
})
|
||||
sol.product_id_change()
|
||||
self.assertEqual(so.amount_total, 660.0, "Ticket is $1000 but the event product is on a pricelist 10 -> 6. So, $600 + a 10% tax.")
|
||||
|
||||
@users('user_salesman')
|
||||
def test_unlink_so(self):
|
||||
""" This test ensures that when deleting a sale order, if the latter is linked to an event registration,
|
||||
the number of expected seats will be correctly updated """
|
||||
event = self.env['event.event'].browse(self.event_0.ids)
|
||||
self.register_person.action_make_registration()
|
||||
self.assertEqual(event.seats_expected, 1)
|
||||
self.sale_order.unlink()
|
||||
self.assertEqual(event.seats_expected, 0)
|
||||
|
||||
@users('user_salesman')
|
||||
def test_unlink_soline(self):
|
||||
""" This test ensures that when deleting a sale order line, if the latter is linked to an event registration,
|
||||
the number of expected seats will be correctly updated """
|
||||
event = self.env['event.event'].browse(self.event_0.ids)
|
||||
self.register_person.action_make_registration()
|
||||
self.assertEqual(event.seats_expected, 1)
|
||||
self.sale_order.order_line.unlink()
|
||||
self.assertEqual(event.seats_expected, 0)
|
||||
@@ -7,7 +7,7 @@ class RegistrationEditor(models.TransientModel):
|
||||
_name = "registration.editor"
|
||||
_description = 'Edit Attendee Details on Sales Confirmation'
|
||||
|
||||
sale_order_id = fields.Many2one('sale.order', 'Sales Order', required=True)
|
||||
sale_order_id = fields.Many2one('sale.order', 'Sales Order', required=True, ondelete='cascade')
|
||||
event_registration_ids = fields.One2many('registration.editor.line', 'editor_id', string='Registrations to Edit')
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.exceptions import Warning
|
||||
from flectra.exceptions import UserError, Warning
|
||||
|
||||
|
||||
class l10n_eu_service(models.TransientModel):
|
||||
@@ -70,6 +70,12 @@ class l10n_eu_service(models.TransientModel):
|
||||
'res.country', 'l10n_eu_service_country_rel_todo', default=_default_todo_country_ids,
|
||||
string='EU Customers From', required=True)
|
||||
|
||||
@api.model
|
||||
def load_views(self, views, options=None):
|
||||
# This wizard is outdated; it shouldn't be used anymore. Users might still be able to open it using the
|
||||
# link in the settings if they didn't update the module. If they try, we tell them.
|
||||
raise UserError(_("Starting July 1st 2021, OSS regulation has replaced MOSS. Please first upgrade 'l10n_eu_service' module in the Apps menu, then go back to this setting and click on 'Refresh tax mapping'."))
|
||||
|
||||
def _get_repartition_line_copy_values(self, original_rep_lines):
|
||||
return [(0, 0, {
|
||||
'factor_percent': line.factor_percent,
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
</div>
|
||||
<p>Published on <t t-esc="rating.publisher_datetime"/></p>
|
||||
</div>
|
||||
<t t-raw="rating.publisher_comment"/>
|
||||
<t t-esc="rating.publisher_comment"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -507,6 +507,7 @@ class PricelistItem(models.Model):
|
||||
self.percent_price = 0.0
|
||||
if self.compute_price != 'formula':
|
||||
self.update({
|
||||
'base': 'list_price',
|
||||
'price_discount': 0.0,
|
||||
'price_surcharge': 0.0,
|
||||
'price_round': 0.0,
|
||||
|
||||
@@ -142,11 +142,12 @@ class Project(models.Model):
|
||||
'time': data_timesheet_invoice_type}
|
||||
|
||||
for key, value in res['repartition_employee'].items():
|
||||
res['repartition_employee'][key].update({
|
||||
emp_data[key]['type']: emp_data[key]['time']})
|
||||
if emp_data:
|
||||
res['repartition_employee'][key].update({
|
||||
emp_data[key]['type']: emp_data[key]['time']})
|
||||
|
||||
res['repartition_employee'][key]['total'] = sum(
|
||||
[value[inv_type] for inv_type in [*billable_types, 'canceled']])
|
||||
res['repartition_employee'][key]['total'] = sum(
|
||||
[value[inv_type] for inv_type in [*billable_types, 'canceled']])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@@ -696,7 +696,7 @@ Reason(s) of this behavior could be:
|
||||
invoiceable_lines = order._get_invoiceable_lines(final)
|
||||
|
||||
if not any(not line.display_type for line in invoiceable_lines):
|
||||
raise self._nothing_to_invoice_error()
|
||||
continue
|
||||
|
||||
invoice_line_vals = []
|
||||
down_payment_section_added = False
|
||||
|
||||
@@ -372,12 +372,12 @@
|
||||
</div>
|
||||
<div class="row" id="so_date">
|
||||
<div class="mb-3 col-6">
|
||||
<t t-if="sale_order.state == 'draft'">
|
||||
<strong>Quotation Date:</strong>
|
||||
</t>
|
||||
<t t-if="sale_order.state in ['sale', 'done', 'cancel']">
|
||||
<strong>Order Date:</strong>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<strong>Quotation Date:</strong>
|
||||
</t>
|
||||
<span t-field="sale_order.date_order" t-options='{"widget": "date"}'/>
|
||||
</div>
|
||||
<div class="mb-3 col-6" t-if="sale_order.validity_date">
|
||||
|
||||
@@ -619,16 +619,17 @@ class StockMoveLine(models.Model):
|
||||
# As the move's state is not computed over the move lines, we'll have to manually
|
||||
# recompute the moves which we adapted their lines.
|
||||
move_to_recompute_state = self.env['stock.move']
|
||||
to_unlink_candidates = set()
|
||||
|
||||
rounding = self.product_uom_id.rounding
|
||||
for candidate in outdated_candidates:
|
||||
if float_compare(candidate.product_qty, quantity, precision_rounding=rounding) <= 0:
|
||||
quantity -= candidate.product_qty
|
||||
move_to_recompute_state |= candidate.move_id
|
||||
if candidate.qty_done:
|
||||
move_to_recompute_state |= candidate.move_id
|
||||
candidate.product_uom_qty = 0.0
|
||||
else:
|
||||
candidate.unlink()
|
||||
to_unlink_candidates.add(candidate.id)
|
||||
if float_is_zero(quantity, precision_rounding=rounding):
|
||||
break
|
||||
else:
|
||||
@@ -640,6 +641,7 @@ class StockMoveLine(models.Model):
|
||||
candidate.product_uom_qty = self.product_id.uom_id._compute_quantity(quantity_split, candidate.product_uom_id, rounding_method='HALF-UP')
|
||||
move_to_recompute_state |= candidate.move_id
|
||||
break
|
||||
self.env['stock.move.line'].browse(to_unlink_candidates).unlink()
|
||||
move_to_recompute_state._recompute_state()
|
||||
|
||||
def _should_bypass_reservation(self, location):
|
||||
|
||||
@@ -26,7 +26,7 @@ const ReplenishReport = clientAction.extend({
|
||||
if (this.context.warehouse) {
|
||||
this.active_warehouse = {id: this.context.warehouse};
|
||||
}
|
||||
this.report_url += `?context=${JSON.stringify(this.context)}`;
|
||||
this.report_url += `?context=${JSON.stringify(this.context)}&force_context_lang=1`;
|
||||
this._title = action.name;
|
||||
},
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class AccountMove(models.Model):
|
||||
for copy_vals in res:
|
||||
if 'line_ids' in copy_vals:
|
||||
copy_vals['line_ids'] = [line_vals for line_vals in copy_vals['line_ids']
|
||||
if line_vals[0] != 0 or not line_vals[2]['is_anglo_saxon_line']]
|
||||
if line_vals[0] != 0 or not line_vals[2].get('is_anglo_saxon_line')]
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@@ -2046,7 +2046,7 @@ class ReportController(http.Controller):
|
||||
# Ignore 'lang' here, because the context in data is the one from the webclient *but* if
|
||||
# the user explicitely wants to change the lang, this mechanism overwrites it.
|
||||
data['context'] = json.loads(data['context'])
|
||||
if data['context'].get('lang'):
|
||||
if data['context'].get('lang') and not data.get('force_context_lang'):
|
||||
del data['context']['lang']
|
||||
context.update(data['context'])
|
||||
if converter == 'html':
|
||||
|
||||
@@ -647,6 +647,31 @@ var FieldDateRange = InputField.extend({
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Field widget is valid if value entered can convered to date/dateime value
|
||||
* while parsing input value to date/datetime throws error then widget considered
|
||||
* invalid
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
isValid: function () {
|
||||
const value = this.mode === "readonly" ? this.value : this.$input.val();
|
||||
try {
|
||||
return field_utils.parse[this.formatType](value, this.field, { timezone: true }) || true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the date written in the input, in UTC.
|
||||
*
|
||||
@@ -654,7 +679,14 @@ var FieldDateRange = InputField.extend({
|
||||
* @returns {Moment|false}
|
||||
*/
|
||||
_getValue: function () {
|
||||
return field_utils.parse[this.formatType](this.$input.val(), this.field, { timezone: true });
|
||||
try {
|
||||
// user may enter manual value in input and it may not be parsed as date/datetime value
|
||||
this.removeInvalidClass();
|
||||
return field_utils.parse[this.formatType](this.$input.val(), this.field, { timezone: true });
|
||||
} catch (error) {
|
||||
this.setInvalidClass();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -1837,6 +1837,12 @@ ListRenderer.include({
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore click if search facet is removed as it will re-render whole
|
||||
// listview again
|
||||
if ($(event.target).hasClass('o_facet_remove')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.unselectRow();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -261,7 +261,9 @@
|
||||
|
||||
.o_data_row.o_selected_row > .o_data_cell:not(.o_readonly_modifier):not(.o_invisible_modifier) {
|
||||
position: relative; // for o_field_translate
|
||||
background-color: white;
|
||||
&:not(.o_handle_cell) {
|
||||
background-color: white;
|
||||
}
|
||||
.o_input {
|
||||
border: none;
|
||||
padding: 0;
|
||||
|
||||
@@ -3531,6 +3531,49 @@ QUnit.module('basic_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Daterange field manually input wrong value should show toaster', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.data.partner.fields.date_end = { string: 'Date End', type: 'date' };
|
||||
this.data.partner.records[0].date_end = '2017-02-08';
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="date" widget="daterange" options="{'related_end_date': 'date_end'}"/>
|
||||
<field name="date_end" widget="daterange" options="{'related_start_date': 'date'}"/>
|
||||
</form>`,
|
||||
interceptsPropagate: {
|
||||
call_service: function (ev) {
|
||||
if (ev.data.service === 'notification') {
|
||||
assert.strictEqual(ev.data.method, 'notify');
|
||||
assert.strictEqual(ev.data.args[0].title, 'Invalid fields:');
|
||||
assert.strictEqual(ev.data.args[0].message, '<ul><li>A date</li></ul>');
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await testUtils.fields.editInput(form.$('.o_field_date_range:first'), 'blabla');
|
||||
// click outside daterange field
|
||||
await testUtils.dom.click(form.$el);
|
||||
assert.hasClass(form.$('input[name=date]'), 'o_field_invalid',
|
||||
"date field should be displayed as invalid");
|
||||
// update input date with right value
|
||||
await testUtils.fields.editInput(form.$('.o_field_date_range:first'), '02/08/2017');
|
||||
assert.doesNotHaveClass(form.$('input[name=date]'), 'o_field_invalid',
|
||||
"date field should not be displayed as invalid now");
|
||||
|
||||
// again enter wrong value and try to save should raise invalid fields value
|
||||
await testUtils.fields.editInput(form.$('.o_field_date_range:first'), 'blabla');
|
||||
await testUtils.form.clickSave(form);
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.module('FieldDate');
|
||||
|
||||
QUnit.test('date field: toggle datepicker [REQUIRE FOCUS]', async function (assert) {
|
||||
|
||||
@@ -9931,6 +9931,53 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('removing a groupby while adding a line from list', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
let checkUnselectRow = false;
|
||||
testUtils.mock.patch(ListRenderer, {
|
||||
unselectRow(options = {}) {
|
||||
if (checkUnselectRow) {
|
||||
assert.step('unselectRow');
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
const list = await createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: `
|
||||
<tree multi_edit="1" editable="bottom">
|
||||
<field name="display_name"/>
|
||||
<field name="foo"/>
|
||||
</tree>
|
||||
`,
|
||||
archs: {
|
||||
'foo,false,search': `
|
||||
<search>
|
||||
<field name="foo"/>
|
||||
<group expand="1" string="Group By">
|
||||
<filter name="groupby_foo" context="{'group_by': 'foo'}"/>
|
||||
</group>
|
||||
</search>
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
await cpHelpers.toggleGroupByMenu(list);
|
||||
await cpHelpers.toggleMenuItem(list, 0);
|
||||
// expand group
|
||||
await testUtils.dom.click(list.el.querySelector('th.o_group_name'));
|
||||
await testUtils.dom.click(list.el.querySelector('td.o_group_field_row_add a'));
|
||||
checkUnselectRow = true;
|
||||
await testUtils.dom.click($('.o_searchview_facet .o_facet_remove'));
|
||||
assert.verifySteps([]);
|
||||
testUtils.mock.unpatch(ListRenderer);
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('cell-level keyboard navigation in editable grouped list', async function (assert) {
|
||||
assert.expect(56);
|
||||
|
||||
|
||||
Reference in new issue
Block a user