From 16a23041b25b6568f98e46e5f6323dea610c50a4 Mon Sep 17 00:00:00 2001 From: Ravi Gohil Date: Fri, 17 Oct 2014 19:00:49 +0530 Subject: [PATCH 01/13] [FIX] point_of_sale: fixed rounding issue for pos order when discount added(maintenance: 615322). --- addons/point_of_sale/static/src/js/models.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index b7b36d05b4e..606ee1e78c0 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -494,7 +494,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal get_all_prices: function(){ var self = this; var currency_rounding = this.pos.get('currency').rounding; - var base = round_pr(this.get_quantity() * this.get_unit_price() * (1.0 - (this.get_discount() / 100.0)), currency_rounding); + var base = round_pr(round_pr(this.get_quantity() * this.get_unit_price(), currency_rounding) * (1.0 - (this.get_discount() / 100.0)), currency_rounding); var totalTax = base; var totalNoTax = base; From e4fdd85424b4e205024ebf6353a4780871af9907 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 6 Nov 2014 17:41:23 +0100 Subject: [PATCH 02/13] [FIX] hr,mail: correct remove of suggestions. --- addons/hr/static/src/xml/suggestions.xml | 2 +- addons/mail/static/src/xml/suggestions.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/hr/static/src/xml/suggestions.xml b/addons/hr/static/src/xml/suggestions.xml index f3095627bae..00fdb9b19cd 100644 --- a/addons/hr/static/src/xml/suggestions.xml +++ b/addons/hr/static/src/xml/suggestions.xml @@ -24,7 +24,7 @@
- X + X
diff --git a/addons/mail/static/src/xml/suggestions.xml b/addons/mail/static/src/xml/suggestions.xml index 9157dcbe32e..fbd983b767f 100644 --- a/addons/mail/static/src/xml/suggestions.xml +++ b/addons/mail/static/src/xml/suggestions.xml @@ -25,7 +25,7 @@
- X + X
From c6a5be0a195c71c7ded9cc863815d115259abfd9 Mon Sep 17 00:00:00 2001 From: Ravi Gohil Date: Tue, 4 Nov 2014 15:33:25 +0530 Subject: [PATCH 03/13] [IMP] stock: added missing 'context' parameter (opw 616952) --- addons/stock/wizard/stock_partial_move.py | 2 +- addons/stock/wizard/stock_partial_picking.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/stock/wizard/stock_partial_move.py b/addons/stock/wizard/stock_partial_move.py index e1956e202c9..baba6e7792b 100644 --- a/addons/stock/wizard/stock_partial_move.py +++ b/addons/stock/wizard/stock_partial_move.py @@ -53,7 +53,7 @@ class stock_partial_move(osv.osv_memory): return res if 'move_ids' in fields: move_ids = self.pool.get('stock.move').browse(cr, uid, move_ids, context=context) - moves = [self._partial_move_for(cr, uid, m) for m in move_ids if m.state not in ('done','cancel')] + moves = [self._partial_move_for(cr, uid, m, context=context) for m in move_ids if m.state not in ('done','cancel')] res.update(move_ids=moves) if 'date' in fields: res.update(date=time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py index 5419d2dda2a..b67c126e775 100644 --- a/addons/stock/wizard/stock_partial_picking.py +++ b/addons/stock/wizard/stock_partial_picking.py @@ -130,7 +130,7 @@ class stock_partial_picking(osv.osv_memory): res.update(picking_id=picking_id) if 'move_ids' in fields: picking = self.pool.get('stock.picking').browse(cr, uid, picking_id, context=context) - moves = [self._partial_move_for(cr, uid, m) for m in picking.move_lines if m.state not in ('done','cancel')] + moves = [self._partial_move_for(cr, uid, m, context=context) for m in picking.move_lines if m.state not in ('done','cancel')] res.update(move_ids=moves) if 'date' in fields: res.update(date=time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) @@ -154,7 +154,7 @@ class stock_partial_picking(osv.osv_memory): return {'cost': move.product_id.standard_price, 'currency': product_currency_id or picking_currency_id or False} - def _partial_move_for(self, cr, uid, move): + def _partial_move_for(self, cr, uid, move, context=None): partial_move = { 'product_id' : move.product_id.id, 'quantity' : move.product_qty if move.state == 'assigned' or move.picking_id.type == 'in' else 0, From c200ffd74e892492994fa66ac8f38b390bc2b8d9 Mon Sep 17 00:00:00 2001 From: Dhs-odoo Date: Mon, 10 Nov 2014 14:13:43 +0100 Subject: [PATCH 04/13] [FIX] project_timesheet: missing timesheet for tasks without project Timesheet activities (hr.analytic.timesheet) are generated when a work activity (project.task.work) is logged on a task. These are updated if the project of the task is modified. This patch applies the same behaviour for tasks without project, the timesheet activities are generated once a project is set on the task. To avoid redundency in the code, extract the computation in a distinct method. Fixes #701, opw 609481 --- addons/project_timesheet/project_timesheet.py | 108 +++++++++++------- 1 file changed, 68 insertions(+), 40 deletions(-) diff --git a/addons/project_timesheet/project_timesheet.py b/addons/project_timesheet/project_timesheet.py index 5945d52c5c2..b6988590acb 100644 --- a/addons/project_timesheet/project_timesheet.py +++ b/addons/project_timesheet/project_timesheet.py @@ -105,49 +105,56 @@ class project_work(osv.osv): res['product_uom_id'] = emp.product_id.uom_id.id return res - def create(self, cr, uid, vals, *args, **kwargs): - timesheet_obj = self.pool.get('hr.analytic.timesheet') - task_obj = self.pool.get('project.task') - uom_obj = self.pool.get('product.uom') + def _create_analytic_entries(self, cr, uid, vals, context): + """Create the hr analytic timesheet from project task work""" + timesheet_obj = self.pool['hr.analytic.timesheet'] + task_obj = self.pool['project.task'] vals_line = {} + timeline_id = False + acc_id = False + + task_obj = task_obj.browse(cr, uid, vals['task_id'], context=context) + result = self.get_user_related_details(cr, uid, vals.get('user_id', uid)) + vals_line['name'] = '%s: %s' % (tools.ustr(task_obj.name), tools.ustr(vals['name'] or '/')) + vals_line['user_id'] = vals['user_id'] + vals_line['product_id'] = result['product_id'] + vals_line['date'] = vals['date'][:10] + + # Calculate quantity based on employee's product's uom + vals_line['unit_amount'] = vals['hours'] + + default_uom = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.project_time_mode_id.id + if result['product_uom_id'] != default_uom: + vals_line['unit_amount'] = self.pool['product.uom']._compute_qty(cr, uid, default_uom, vals['hours'], result['product_uom_id']) + acc_id = task_obj.project_id and task_obj.project_id.analytic_account_id.id or acc_id + if acc_id: + vals_line['account_id'] = acc_id + res = timesheet_obj.on_change_account_id(cr, uid, False, acc_id) + if res.get('value'): + vals_line.update(res['value']) + vals_line['general_account_id'] = result['general_account_id'] + vals_line['journal_id'] = result['journal_id'] + vals_line['amount'] = 0.0 + vals_line['product_uom_id'] = result['product_uom_id'] + amount = vals_line['unit_amount'] + prod_id = vals_line['product_id'] + unit = False + timeline_id = timesheet_obj.create(cr, uid, vals=vals_line, context=context) + + # Compute based on pricetype + amount_unit = timesheet_obj.on_change_unit_amount(cr, uid, timeline_id, + prod_id, amount, False, unit, vals_line['journal_id'], context=context) + if amount_unit and 'amount' in amount_unit.get('value',{}): + updv = { 'amount': amount_unit['value']['amount'] } + timesheet_obj.write(cr, uid, [timeline_id], updv, context=context) + + return timeline_id + + def create(self, cr, uid, vals, *args, **kwargs): context = kwargs.get('context', {}) if not context.get('no_analytic_entry',False): - task_obj = task_obj.browse(cr, uid, vals['task_id']) - result = self.get_user_related_details(cr, uid, vals.get('user_id', uid)) - vals_line['name'] = '%s: %s' % (tools.ustr(task_obj.name), tools.ustr(vals['name'] or '/')) - vals_line['user_id'] = vals['user_id'] - vals_line['product_id'] = result['product_id'] - vals_line['date'] = vals['date'][:10] - - # Calculate quantity based on employee's product's uom - vals_line['unit_amount'] = vals['hours'] - - default_uom = self.pool.get('res.users').browse(cr, uid, uid).company_id.project_time_mode_id.id - if result['product_uom_id'] != default_uom: - vals_line['unit_amount'] = uom_obj._compute_qty(cr, uid, default_uom, vals['hours'], result['product_uom_id']) - acc_id = task_obj.project_id and task_obj.project_id.analytic_account_id.id or False - if acc_id: - vals_line['account_id'] = acc_id - res = timesheet_obj.on_change_account_id(cr, uid, False, acc_id) - if res.get('value'): - vals_line.update(res['value']) - vals_line['general_account_id'] = result['general_account_id'] - vals_line['journal_id'] = result['journal_id'] - vals_line['amount'] = 0.0 - vals_line['product_uom_id'] = result['product_uom_id'] - amount = vals_line['unit_amount'] - prod_id = vals_line['product_id'] - unit = False - timeline_id = timesheet_obj.create(cr, uid, vals=vals_line, context=context) - - # Compute based on pricetype - amount_unit = timesheet_obj.on_change_unit_amount(cr, uid, timeline_id, - prod_id, amount, False, unit, vals_line['journal_id'], context=context) - if amount_unit and 'amount' in amount_unit.get('value',{}): - updv = { 'amount': amount_unit['value']['amount'] } - timesheet_obj.write(cr, uid, [timeline_id], updv, context=context) - vals['hr_analytic_timesheet_id'] = timeline_id + vals['hr_analytic_timesheet_id'] = self._create_analytic_entries(cr, uid, vals, context=context) return super(project_work,self).create(cr, uid, vals, *args, **kwargs) def write(self, cr, uid, ids, vals, context=None): @@ -236,6 +243,10 @@ class task(osv.osv): def write(self, cr, uid, ids, vals, context=None): if context is None: context = {} + task_work_obj = self.pool['project.task.work'] + acc_id = False + missing_analytic_entries = {} + if vals.get('project_id',False) or vals.get('name',False): vals_line = {} hr_anlytic_timesheet = self.pool.get('hr.analytic.timesheet') @@ -247,6 +258,16 @@ class task(osv.osv): if len(task_obj.work_ids): for task_work in task_obj.work_ids: if not task_work.hr_analytic_timesheet_id: + if acc_id : + # missing timesheet activities to generate + missing_analytic_entries[task_work.id] = { + 'name' : task_work.name, + 'user_id' : task_work.user_id.id, + 'date' : task_work.date[:10], + 'account_id': acc_id, + 'hours' : task_work.hours, + 'task_id' : task_obj.id + } continue line_id = task_work.hr_analytic_timesheet_id.id if vals.get('project_id',False): @@ -254,7 +275,14 @@ class task(osv.osv): if vals.get('name',False): vals_line['name'] = '%s: %s' % (tools.ustr(vals['name']), tools.ustr(task_work.name) or '/') hr_anlytic_timesheet.write(cr, uid, [line_id], vals_line, {}) - return super(task,self).write(cr, uid, ids, vals, context) + + res = super(task,self).write(cr, uid, ids, vals, context) + + for task_work_id, analytic_entry in missing_analytic_entries.items(): + timeline_id = task_work_obj._create_analytic_entries(cr, uid, analytic_entry, context=context) + task_work_obj.write(cr, uid, task_work_id, {'hr_analytic_timesheet_id' : timeline_id}, context=context) + + return res task() From e27afc13cb5d95831cb9f4a0f1fb98e70129ceed Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 10 Nov 2014 15:36:40 +0100 Subject: [PATCH 05/13] [FIX] mrp: prevent suppression of bom if used in mo The field bom_id is required on a manufacturing order and deleting a mrp.bom would block the current mo. Restrict the suppression for manufacturing order in progress. Fixes #3417 --- addons/mrp/mrp.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 72226e9de60..45b2bcbc047 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -379,6 +379,13 @@ class mrp_bom(osv.osv): default.update(name=_("%s (copy)") % (bom_data['name']), bom_id=False) return super(mrp_bom, self).copy_data(cr, uid, id, default, context=context) + def unlink(self, cr, uid, ids, context=None): + if self.pool['mrp.production'].search(cr, uid, [ + ('bom_id', 'in', ids), ('state', 'not in', ['done', 'cancel']) + ], context=context): + raise osv.except_osv(_('Warning!'), _('You can not delete a Bill of Material with running manufacturing orders.\nPlease close or cancel it first.')) + return super(mrp_bom, self).unlink(cr, uid, ids, context=context) + def rounding(f, r): # TODO for trunk: log deprecation warning From ab5ecef476b82c7e00dbd1868de19832ac044f15 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 10 Nov 2014 15:59:30 +0100 Subject: [PATCH 06/13] [FIX] project_timesheet: accept work without date date field on a project.task.work is not required while it is on the hr.analytic.timesheet (with default value). Avoid error if fill a task work without date, fallback on context_today. --- addons/project_timesheet/project_timesheet.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/project_timesheet/project_timesheet.py b/addons/project_timesheet/project_timesheet.py index b6988590acb..6cbb4e8cf01 100644 --- a/addons/project_timesheet/project_timesheet.py +++ b/addons/project_timesheet/project_timesheet.py @@ -119,7 +119,8 @@ class project_work(osv.osv): vals_line['name'] = '%s: %s' % (tools.ustr(task_obj.name), tools.ustr(vals['name'] or '/')) vals_line['user_id'] = vals['user_id'] vals_line['product_id'] = result['product_id'] - vals_line['date'] = vals['date'][:10] + if vals.get('date'): + vals_line['date' ] = vals['date'][:10] # Calculate quantity based on employee's product's uom vals_line['unit_amount'] = vals['hours'] @@ -263,7 +264,7 @@ class task(osv.osv): missing_analytic_entries[task_work.id] = { 'name' : task_work.name, 'user_id' : task_work.user_id.id, - 'date' : task_work.date[:10], + 'date' : task_work.date and task_work.date[:10] or False, 'account_id': acc_id, 'hours' : task_work.hours, 'task_id' : task_obj.id From 69d60465ee67969d72210a61a9e23204d037378a Mon Sep 17 00:00:00 2001 From: Rifakat Haradwala Date: Wed, 22 Oct 2014 15:37:00 +0530 Subject: [PATCH 07/13] [FIX] web: date autocompletion should use user's locale search bar does not suggest date field format based on user's locale and always shows based on mmddyy using Date.parse, opw:615276 Note: starting in 9.0, datejs has been replaced by momentjs, so this problem should be solved in a better way. --- addons/web/static/src/js/search.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index c09661f430d..89cf5521db1 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1497,7 +1497,11 @@ instance.web.search.DateField = instance.web.search.Field.extend(/** @lends inst return instance.web.date_to_str(facetValue.get('value')); }, complete: function (needle) { - var d = Date.parse(needle); + try { + var d = instance.web.str_to_date(instance.web.parse_value(needle, {'widget': 'date'})); + } catch (e) { + return false; + } if (!d) { return $.when(null); } var date_string = instance.web.format_value(d, this.attrs); var label = _.str.sprintf(_.str.escapeHTML( From 1a826e07fe61b8e55291f207da81eddf55baf14b Mon Sep 17 00:00:00 2001 From: Samus CTO Date: Thu, 13 Nov 2014 16:23:08 +0100 Subject: [PATCH 08/13] [IMP] Speedup test account_assert_test.xml in account --- addons/account/account.py | 13 +++++++++++++ addons/account/account_assert_test.xml | 4 +--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index a12b5bd1052..c1aca3ee8ec 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1157,6 +1157,19 @@ class account_move(osv.osv): _description = "Account Entry" _order = 'id desc' + def account_assert_balanced(self, cr, uid, context=None): + cr.execute("""\ + SELECT move_id + FROM account_move_line + WHERE state = 'valid' + GROUP BY move_id + HAVING abs(sum(debit) - sum(credit)) > 0.00001 + """) + assert len(cr.fetchall()) == 0, \ + "For all Journal Items, the state is valid implies that the sum " \ + "of credits equals the sum of debits" + return True + def account_move_prepare(self, cr, uid, journal_id, date=False, ref='', company_id=False, context=None): ''' Prepares and returns a dictionary of values, ready to be passed to create() based on the parameters received. diff --git a/addons/account/account_assert_test.xml b/addons/account/account_assert_test.xml index 88025514763..32e8afb1b50 100644 --- a/addons/account/account_assert_test.xml +++ b/addons/account/account_assert_test.xml @@ -1,8 +1,6 @@ - - - + From 7f4c4a5e8a94c4cea0700a3fcc928fa11fbdc96f Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 13 Nov 2014 18:01:25 +0100 Subject: [PATCH 09/13] [IMP] purchase: error message linked to product, not company --- addons/purchase/purchase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index d1bb845e38d..e6f4989c9a3 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -471,7 +471,7 @@ class purchase_order(osv.osv): if not acc_id: acc_id = po_line.product_id.categ_id.property_account_expense_categ.id if not acc_id: - raise osv.except_osv(_('Error!'), _('Define expense account for this company: "%s" (id:%d).') % (po_line.product_id.name, po_line.product_id.id,)) + raise osv.except_osv(_('Error!'), _('Define expense account for this product: "%s" (id:%d).') % (po_line.product_id.name, po_line.product_id.id,)) else: acc_id = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context=context).id fpos = po_line.order_id.fiscal_position or False From cf488682c82a320589b1241f4b6bd9d59018bfed Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 14 Nov 2014 11:10:15 +0100 Subject: [PATCH 10/13] [FIX] stock: multicompany reception When a picking is confirmed, the generated account.move(.line) should take the company, accounts, journals and period with the same company as the picking, not the one of the current user. This was problematic if a user in a company confirm a picking linked to a purchase order done in another company. For real time valuations, the generated accounting entries were mixing both companies. Fixes #3466 --- addons/stock/stock.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 16565871de3..bd15c45e421 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2355,6 +2355,9 @@ class stock_move(osv.osv): context = {} src_company_ctx = dict(context,force_company=move.location_id.company_id.id) dest_company_ctx = dict(context,force_company=move.location_dest_id.company_id.id) + # do not take the company of the one of the user + # used to select the correct period + company_ctx = dict(context, company_id=move.company_id.id) account_moves = [] # Outgoing moves (or cross-company output part) if move.location_id.company_id \ @@ -2386,7 +2389,8 @@ class stock_move(osv.osv): { 'journal_id': j_id, 'line_id': move_lines, - 'ref': move.picking_id and move.picking_id.name}, context=context) + 'company_id': move.company_id.id, + 'ref': move.picking_id and move.picking_id.name}, context=company_ctx) def action_done(self, cr, uid, ids, context=None): """ Makes the move done and if all moves are done, it will finish the picking. From 5b2f13abdfed218db9098325061cd6b14eac0d3c Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 14 Nov 2014 13:40:02 +0100 Subject: [PATCH 11/13] [FIX] product: more accurate name_search First, name_search searches on default_code, then, if the limit is not reached, it searches on the product name The results found from the default code search must be removed from the search domain when doing the search on the product name, to avoid having results already found by the search on the default_code opw-618015 --- addons/product/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/product.py b/addons/product/product.py index b70fa030dd0..ce5b9bacddf 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -691,7 +691,7 @@ class product_product(osv.osv): ids.update(self.search(cr, user, args + [('default_code',operator,name)], limit=limit, context=context)) if not limit or len(ids) < limit: # we may underrun the limit because of dupes in the results, that's fine - ids.update(self.search(cr, user, args + [('name',operator,name)], limit=(limit and (limit-len(ids)) or False) , context=context)) + ids.update(self.search(cr, user, args + [('name',operator,name), ('id', 'not in', list(ids))], limit=(limit and (limit-len(ids)) or False) , context=context)) ids = list(ids) elif not ids and operator in expression.NEGATIVE_TERM_OPERATORS: ids = self.search(cr, user, args + ['&', ('default_code', operator, name), ('name', operator, name)], limit=limit, context=context) From 3613b74df37a5a0c7bc2479a4b18471e6036e0a9 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 14 Nov 2014 14:14:58 +0100 Subject: [PATCH 12/13] [FIX] point_of_sale: missing multi-company rule --- addons/point_of_sale/security/point_of_sale_security.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/point_of_sale/security/point_of_sale_security.xml b/addons/point_of_sale/security/point_of_sale_security.xml index 47cdf47fda4..4804dc20dc8 100644 --- a/addons/point_of_sale/security/point_of_sale_security.xml +++ b/addons/point_of_sale/security/point_of_sale_security.xml @@ -25,5 +25,11 @@ ['|',('shop_id.company_id','=',False),('shop_id.company_id','child_of',[user.company_id.id])] + + Point Of Sale Order Analysis multi-company + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + From da15c9d27b420e7643048dfab07aebcf94b92b4a Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 14 Nov 2014 15:49:39 +0100 Subject: [PATCH 13/13] [FIX] web: do not set the one2many dirty on field validation This rev. 06104ba553702b16878d52c5b8ab089355216a5e Added the dirty flag on the o2m field when the editor of the editable list was enabled (meaning that the editable list has been altered)) because the dirty flag was not set correctly by the one2many during the edition, at the time. It looks like this is now the case Besides, as now, we valid all the editable list of the form, wether or not the editable list was altered, we must not set the o2m as dirty anymore. --- addons/web/static/src/js/view_form.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 819920f89b3..be16faa309a 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3885,7 +3885,6 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ if (!this.fields_view || !this.editable()){ return true; } - this.o2m._dirty_flag = true; var r; return _.every(this.records.records, function(record){ r = record;