From bafa1a677e0b7d5063e932a15ad7a448359ccbe0 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Fri, 29 Jan 2016 12:25:30 +0100 Subject: [PATCH 1/8] [FIX] stock: creation of stock inventory adjustement The system cannot create two inventory adjustements in state 'in Progess' with the same product, with the same location, same package, same lot and same owner. Example:if two adjustments(ADJ1, ADJ2) are created with the same product(P) and with the same location(L), let's say: qty_available for P is 10 in ADJ1: Theoritical Quantity=10 and Real Quantity=20 => a quant with +10 is created in ADJ2: Theoritical Quantity=10 and Real Quantity=30 => a quant with +20 is created When ADJ1 is validated then qty_available for P is now 20(that 's ok) When ADJ2 is validated then qty_available for P is now 40(that's wrong because the Real Quantity is expected which is 30) This is why this fix is required. opw:660658 --- addons/stock/i18n/stock.pot | 6 ++++++ addons/stock/stock.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/addons/stock/i18n/stock.pot b/addons/stock/i18n/stock.pot index daae3a0fc74..805485062d1 100644 --- a/addons/stock/i18n/stock.pot +++ b/addons/stock/i18n/stock.pot @@ -51,6 +51,12 @@ msgstr "" msgid " (reserved)" msgstr "" +#. module: stock +#: code:addons/stock/stock.py:2954 +#, python-format +msgid "You cannot have two inventory adjustements in state 'in Progess' with the same product(%s), same location(%s), same package, same owner and same lot. Please first validate the first inventory adjustement with this product before creating another one." +msgstr "" + #. module: stock #: code:addons/stock/stock.py:3090 #, python-format diff --git a/addons/stock/stock.py b/addons/stock/stock.py index a4deff3d161..8cef6087172 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2942,6 +2942,18 @@ class stock_inventory_line(osv.osv): 'product_uom_id': lambda self, cr, uid, ctx=None: self.pool['ir.model.data'].get_object_reference(cr, uid, 'product', 'product_uom_unit')[1] } + def create(self, cr, uid, values, context=None): + product_obj = self.pool.get('product.product') + dom = [('product_id', '=', values.get('product_id')), ('inventory_id.state', '=', 'confirm'), + ('location_id', '=', values.get('location_id')), ('partner_id', '=', values.get('partner_id')), + ('package_id', '=', values.get('package_id')), ('prod_lot_id', '=', values.get('prod_lot_id'))] + res = self.search(cr, uid, dom, context=context) + if res: + location = self.pool['stock.location'].browse(cr, uid, values.get('location_id'), context=context) + product = product_obj.browse(cr, uid, values.get('product_id'), context=context) + raise Warning(_("You cannot have two inventory adjustements in state 'in Progess' with the same product(%s), same location(%s), same package, same owner and same lot. Please first validate the first inventory adjustement with this product before creating another one.") % (product.name, location.name)) + return super(stock_inventory_line, self).create(cr, uid, values, context=context) + def _get_quants(self, cr, uid, line, context=None): quant_obj = self.pool["stock.quant"] dom = [('company_id', '=', line.company_id.id), ('location_id', '=', line.location_id.id), ('lot_id', '=', line.prod_lot_id.id), From 19a1c18f57289aaffba6e978e73fa3f6ad251df7 Mon Sep 17 00:00:00 2001 From: xmo-odoo Date: Fri, 29 Jan 2016 16:24:14 +0100 Subject: [PATCH 2/8] [FIX] make m2m checkbox labels clickable --- addons/web/static/src/xml/base.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 65185467b3f..311e3b5aeb2 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -2023,13 +2023,11 @@
- - - - - - - +
From 2083c16606db7e0c646b27737ce16c4634825118 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 1 Feb 2016 12:45:26 +0100 Subject: [PATCH 3/8] [FIX] account: bank statement lines indeterminist order The order of a bank statement lines is entirely done on the sequence: `_order = "statement_id desc, sequence"` The `create` method of `accounT.bank.statement` is overriden to handle the sequences of each line. The `write` method as well, except that the set of the sequences lines is done after the call to `super`. So, if you add several new lines to a bank statement, the order of the line you just added can be different before and after save, as the sequence of these new lines are not set before actually writting them on the bank statement. The widget `handle` serves this sequencing purpose. The fact it isn't used here is most-likely because it did not exist at the time this was designed. Besides, this gives the possibility to the user to add a new line and re-order it where he wants. For instance, when manually entering a bank statement, a user could skip unintentionally a line. If he would like to add it at the right place, before this revision, he would have to delete all the lines coming after the line he skipped. Now, he can add it at the end, and re-order it where he wants. What is done in the overriden `create` and `write` is now useless, but we left it for retro-compatibility purposes, for databases updating their sources without updating their views. opw-667541 --- addons/account/account_bank_statement.py | 1 + addons/account/account_view.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index c85f48a83f1..001085233c3 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -947,6 +947,7 @@ class account_bank_statement_line(osv.osv): _defaults = { 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line', context=context), 'date': lambda self,cr,uid,context={}: context.get('date', fields.date.context_today(self,cr,uid,context=context)), + 'sequence': 1, } class account_statement_operation_template(osv.osv): diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 576b3347b66..0ef81a94c80 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -602,7 +602,7 @@ - + From 9481ee5c2f14c3ff185fbcd5a8bf790a8042024c Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Fri, 29 Jan 2016 16:43:10 +0100 Subject: [PATCH 4/8] [FIX] sale_margin: Cost price in a SO line The margin in a SO line is the difference between the price unit and the cost price of this SO line. In function "_product_margin" in model "sale.order.line", the cost price is equal to the purchase_price or the standard_price of the product. Then the cost price in the SO line must be set with the same value when creating SO line linked to the delivery. opw:668090 --- addons/delivery/sale.py | 5 +++++ addons/sale_margin/sale_margin.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/delivery/sale.py b/addons/delivery/sale.py index 3512fb53b61..c6b89de649b 100644 --- a/addons/delivery/sale.py +++ b/addons/delivery/sale.py @@ -94,6 +94,11 @@ class sale_order(osv.Model): 'tax_id': [(6, 0, taxes_ids)], 'is_delivery': True, } + res = line_obj.product_id_change(cr, uid, ids, order.pricelist_id.id, values['product_id'], + qty=values['product_uom_qty'], uom=False, qty_uos=0, uos=False, name='', partner_id=order.partner_id.id, + lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None) + if res['value'].get('purchase_price'): + values['purchase_price'] = res['value'].get('purchase_price') if order.order_line: values['sequence'] = order.order_line[-1].sequence + 1 line_id = line_obj.create(cr, uid, values, context=context) diff --git a/addons/sale_margin/sale_margin.py b/addons/sale_margin/sale_margin.py index f1d2e7652ce..0cd3cdf14e4 100644 --- a/addons/sale_margin/sale_margin.py +++ b/addons/sale_margin/sale_margin.py @@ -87,7 +87,7 @@ class sale_order(osv.osv): _columns = { 'margin': fields.function(_product_margin, string='Margin', help="It gives profitability by calculating the difference between the Unit Price and the cost price.", store={ - 'sale.order.line': (_get_order, ['margin', 'purchase_price'], 20), + 'sale.order.line': (_get_order, ['margin', 'purchase_price', 'order_id'], 20), 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 20), }, digits_compute= dp.get_precision('Product Price')), } From a46f8bb9c502c9e82fb1392aeb6120eaeb8d98bf Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 21 Jan 2016 16:21:31 +0530 Subject: [PATCH 5/8] [FIX] tools: do not generate translations for exported records When a record is exported, an external ID, in the form of __export__._ is created on this record. When the translations are generated (e.g. "synchronise terms" wizard), the translations may be duplicated for records that have been exported. If a translation is submitted before the export (when the record had no external ID yet), a new empty translation is created as the module differs in the import. Creating a new translation may be a problem as the new term (equal to the source term) will be used as the translation value. Fixes 9480 --- openerp/tools/translate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 83710cca956..794f0d3aed7 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -671,6 +671,10 @@ def trans_generate(lang, modules, cr): query += ' WHERE module IN %s' query_models += ' AND imd.module in %s' query_param = (tuple(modules),) + else: + query += ' WHERE module != %s' + query_models += ' AND imd.module != %s' + query_param = ('__export__',) query += ' ORDER BY module, model, name' query_models += ' ORDER BY module, model' From 08b286111c0dc0227b1692d2258be3b7d7f2d733 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 21 Jan 2016 12:47:48 +0100 Subject: [PATCH 6/8] [FIX] models: `MissingError` when writing on recordset with duplicates When writing on a recordset with duplicates, the ORM raises a `MissingError` because the rowcount gives a difference with the injected ids. The fix simply eliminates duplicates from ids. --- openerp/addons/base/tests/test_orm.py | 4 ++++ openerp/models.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/tests/test_orm.py b/openerp/addons/base/tests/test_orm.py index 6a387eec325..624dee5888c 100644 --- a/openerp/addons/base/tests/test_orm.py +++ b/openerp/addons/base/tests/test_orm.py @@ -166,6 +166,10 @@ class TestORM(common.TransactionCase): ['date'], ['date:month', 'date:day'], lazy=False) self.assertEqual(len(rg), len(all_partners)) + def test_write_duplicate(self): + cr, uid, p1 = self.cr, self.uid, self.p1 + self.partner.write(cr, uid, [p1, p1], {'name': 'X'}) + class TestInherits(common.TransactionCase): """ test the behavior of the orm for models that use _inherits; diff --git a/openerp/models.py b/openerp/models.py index 7da181495a8..1fd2c7ae196 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -3896,7 +3896,7 @@ class BaseModel(object): self._table, ','.join('"%s"=%s' % u[:2] for u in updates), ) params = tuple(u[2] for u in updates if len(u) > 2) - for sub_ids in cr.split_for_in_conditions(ids): + for sub_ids in cr.split_for_in_conditions(set(ids)): cr.execute(query, params + (sub_ids,)) if cr.rowcount != len(sub_ids): raise MissingError(_('One of the records you are trying to modify has already been deleted (Document type: %s).') % self._description) From a688bcdbbd6d1df980feca17edb94d06bcb0a4a3 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Fri, 29 Jan 2016 17:39:14 +0100 Subject: [PATCH 7/8] [FIX] fields: make `copy_cache` not invalidate the cache! --- openerp/fields.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openerp/fields.py b/openerp/fields.py index ba3bc259282..fc421fc1cc5 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -64,9 +64,11 @@ def copy_cache(records, env): for record, target in zip(records, records.with_env(env)): if not target._cache: for name, value in record._cache.iteritems(): - target[name] = value if isinstance(value, BaseModel): + target._cache[name] = value.with_env(env) copy_cache(value, env) + else: + target._cache[name] = value def resolve_all_mro(cls, name, reverse=False): From 3ac46ee3d4b9775c5d18acc8ffb95188508a20af Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 2 Feb 2016 11:25:57 +0100 Subject: [PATCH 8/8] [FIX] stock: propagate UoS quantity Both UoM and UoS quantity change should be propagated. Fixes #10623 opw-667805 --- addons/stock/stock.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 8cef6087172..f60e2ce6684 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2012,6 +2012,10 @@ class stock_move(osv.osv): propagated_changes_dict['product_uom_qty'] = vals['product_uom_qty'] if vals.get('product_uom_id'): propagated_changes_dict['product_uom_id'] = vals['product_uom_id'] + if vals.get('product_uos_qty'): + propagated_changes_dict['product_uos_qty'] = vals['product_uos_qty'] + if vals.get('product_uos_id'): + propagated_changes_dict['product_uos_id'] = vals['product_uos_id'] #propagation of expected date: propagated_date_field = False if vals.get('date_expected'):