summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2014-12-03 19:24:57 +0100
committerChristophe Simonis <chs@odoo.com>2014-12-03 19:24:57 +0100
commit5ca7fa18fcd300a29c71bb3cc236a03ca424f33f (patch)
tree4defa9add3c74eaf35a740b4084eb0a01e3b8fda
parent31a01ea772eca493ede292c9390b0526d06ea836 (diff)
parent7c49c6d79d2029023caad3394a791957f4637c85 (diff)
[MERGE] forward port of branch 8.0 up to 31a01ea
-rw-r--r--addons/account/wizard/account_chart.py2
-rw-r--r--addons/mrp/procurement.py70
-rw-r--r--addons/product/product.py5
-rw-r--r--addons/purchase/tests/__init__.py26
-rw-r--r--addons/purchase/tests/test_average_price.py175
-rw-r--r--addons/web/static/src/js/view_list.js4
6 files changed, 245 insertions, 37 deletions
diff --git a/addons/account/wizard/account_chart.py b/addons/account/wizard/account_chart.py
index 73be9040d22..3d92b211938 100644
--- a/addons/account/wizard/account_chart.py
+++ b/addons/account/wizard/account_chart.py
@@ -51,7 +51,7 @@ class account_chart(osv.osv_memory):
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
- ORDER BY p.date_start ASC
+ ORDER BY p.date_start ASC, p.special DESC
LIMIT 1) AS period_start
UNION ALL
SELECT * FROM (SELECT p.id
diff --git a/addons/mrp/procurement.py b/addons/mrp/procurement.py
index 58727d9c160..71aae2be711 100644
--- a/addons/mrp/procurement.py
+++ b/addons/mrp/procurement.py
@@ -23,6 +23,7 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
from openerp.osv import osv, fields
from openerp.tools.translate import _
+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
from openerp import SUPERUSER_ID
class procurement_rule(osv.osv):
@@ -68,47 +69,54 @@ class procurement_order(osv.osv):
return False
return True
+ def _get_date_planned(self, cr, uid, procurement, context=None):
+ format_date_planned = datetime.strptime(procurement.date_planned,
+ DEFAULT_SERVER_DATETIME_FORMAT)
+ date_planned = format_date_planned - relativedelta(days=procurement.product_id.produce_delay or 0.0)
+ date_planned = date_planned - relativedelta(days=procurement.company_id.manufacturing_lead)
+ return date_planned
+
+ def _prepare_mo_vals(self, cr, uid, procurement, context=None):
+ res_id = procurement.move_dest_id and procurement.move_dest_id.id or False
+ newdate = self._get_date_planned(cr, uid, procurement, context=context)
+ bom_obj = self.pool.get('mrp.bom')
+ if procurement.bom_id:
+ bom_id = procurement.bom_id.id
+ routing_id = procurement.bom_id.routing_id.id
+ else:
+ properties = [x.id for x in procurement.property_ids]
+ bom_id = bom_obj._bom_find(cr, uid, product_id=procurement.product_id.id,
+ properties=properties, context=context)
+ bom = bom_obj.browse(cr, uid, bom_id, context=context)
+ routing_id = bom.routing_id.id
+ return {
+ 'origin': procurement.origin,
+ 'product_id': procurement.product_id.id,
+ 'product_qty': procurement.product_qty,
+ 'product_uom': procurement.product_uom.id,
+ 'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
+ 'product_uos': procurement.product_uos and procurement.product_uos.id or False,
+ 'location_src_id': procurement.location_id.id,
+ 'location_dest_id': procurement.location_id.id,
+ 'bom_id': bom_id,
+ 'routing_id': routing_id,
+ 'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
+ 'move_prod_id': res_id,
+ 'company_id': procurement.company_id.id,
+ }
+
def make_mo(self, cr, uid, ids, context=None):
""" Make Manufacturing(production) order from procurement
@return: New created Production Orders procurement wise
"""
res = {}
- company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
production_obj = self.pool.get('mrp.production')
- bom_obj = self.pool.get('mrp.bom')
procurement_obj = self.pool.get('procurement.order')
for procurement in procurement_obj.browse(cr, uid, ids, context=context):
if self.check_bom_exists(cr, uid, [procurement.id], context=context):
- if procurement.bom_id:
- bom_id = procurement.bom_id.id
- routing_id = procurement.bom_id.routing_id.id
- else:
- properties = [x.id for x in procurement.property_ids]
- bom_id = bom_obj._bom_find(cr, uid, product_id=procurement.product_id.id,
- properties=properties, context=context)
- bom = bom_obj.browse(cr, uid, bom_id, context=context)
- routing_id = bom.routing_id.id
-
- res_id = procurement.move_dest_id and procurement.move_dest_id.id or False
- newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.product_id.produce_delay or 0.0)
- newdate = newdate - relativedelta(days=company.manufacturing_lead)
#create the MO as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
- produce_id = production_obj.create(cr, SUPERUSER_ID, {
- 'origin': procurement.origin,
- 'product_id': procurement.product_id.id,
- 'product_qty': procurement.product_qty,
- 'product_uom': procurement.product_uom.id,
- 'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
- 'product_uos': procurement.product_uos and procurement.product_uos.id or False,
- 'location_src_id': procurement.location_id.id,
- 'location_dest_id': procurement.location_id.id,
- 'bom_id': bom_id,
- 'routing_id': routing_id,
- 'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
- 'move_prod_id': res_id,
- 'company_id': procurement.company_id.id,
- })
-
+ vals = self._prepare_mo_vals(cr, uid, procurement, context=context)
+ produce_id = production_obj.create(cr, SUPERUSER_ID, vals, context=context)
res[procurement.id] = produce_id
self.write(cr, uid, [procurement.id], {'production_id': produce_id})
self.production_order_create_note(cr, uid, procurement, context=context)
diff --git a/addons/product/product.py b/addons/product/product.py
index e5afb4ef38d..253bae7a3ee 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -898,11 +898,8 @@ class product_product(osv.osv):
return dict.fromkeys(ids, True)
def _get_name_template_ids(self, cr, uid, ids, context=None):
- result = set()
template_ids = self.pool.get('product.product').search(cr, uid, [('product_tmpl_id', 'in', ids)])
- for el in template_ids:
- result.add(el)
- return list(result)
+ return list(set(template_ids))
def _get_image_variant(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)
diff --git a/addons/purchase/tests/__init__.py b/addons/purchase/tests/__init__.py
new file mode 100644
index 00000000000..295471b9aa3
--- /dev/null
+++ b/addons/purchase/tests/__init__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import test_average_price
+
+checks = [
+ test_average_price,
+]
diff --git a/addons/purchase/tests/test_average_price.py b/addons/purchase/tests/test_average_price.py
new file mode 100644
index 00000000000..79d299a9080
--- /dev/null
+++ b/addons/purchase/tests/test_average_price.py
@@ -0,0 +1,175 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+#from openerp.test.common import TransactionCase
+from datetime import date
+from openerp.tests import common
+from openerp import workflow
+
+
+class TestAveragePrice(common.TransactionCase):
+ def setUp(self):
+ super(TestAveragePrice, self).setUp()
+ cr, uid, context = self.cr, self.uid, {}
+ self.ir_model_data = self.registry('ir.model.data')
+ self.product_product = self.registry('product.product')
+ self.purchase_order = self.registry('purchase.order')
+ self.purchase_order_line = self.registry('purchase.order.line')
+ self.pricelist = self.registry('product.pricelist')
+ self.stock_location = self.registry('stock.location')
+ self.stock_picking = self.registry('stock.picking')
+ self.stock_move = self.registry('stock.move')
+ self.stock_partial_move = self.registry('stock.partial.move')
+ self.stock_partial_move_line = self.registry('stock.partial.move.line')
+ self.partial_picking = self.registry('stock.partial.picking')
+ self.partial_picking_line = self.registry('stock.partial.picking.line')
+ change_product_qty = self.registry('stock.change.product.qty')
+
+ _, partner_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'res_partner_1')
+ _, pricelist_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'product', 'list0')
+ _, self.location_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
+ _, self.supplier_location_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_suppliers')
+ _, input_account_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'account', 'xfa')
+ _, output_account_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'account', 'xfa')
+
+ self.standard_price = 10
+ self.order_price_unit = 20
+ self.available_qty = 1
+ self.order_qty = 1
+ self.picking_qty = 1
+
+ self.product_id = self.product_product.create(cr, uid, {
+ 'name': 'Average product',
+ 'cost_method': 'average',
+ 'valuation': 'real_time',
+ 'property_stock_account_input': input_account_id,
+ 'property_stock_account_output': output_account_id,
+ }, context=context)
+
+ self.product_product.do_change_standard_price(
+ cr, uid, [self.product_id], {
+ 'new_price': self.standard_price,
+ 'stock_input_account': input_account_id,
+ 'stock_output_account': output_account_id})
+
+ change_product_qty_id = change_product_qty.create(
+ cr, uid, {
+ 'location_id': self.location_id,
+ 'new_quantity': self.available_qty,
+ 'product_id': self.product_id})
+ change_product_qty.change_product_qty(
+ cr, uid, [change_product_qty_id], {
+ 'active_model': 'product.product',
+ 'active_id': self.product_id,
+ 'active_ids': [self.product_id]})
+
+ self.po_01_id = self.purchase_order.create(cr, uid, {
+ 'partner_id': partner_id,
+ 'location_id': self.location_id,
+ 'pricelist_id': pricelist_id,
+ }, context=context)
+
+ self.order_line_10 = self.purchase_order_line.create(cr, uid, {
+ 'order_id': self.po_01_id,
+ 'product_id': self.product_id,
+ 'name': 'description',
+ 'date_planned': date.today(),
+ 'product_qty': self.order_qty,
+ 'price_unit': self.order_price_unit
+ }, context=context)
+
+ workflow.trg_validate(uid, 'purchase.order', self.po_01_id, 'purchase_confirm', cr)
+
+ def test_10_stock_move_action_done(self):
+ cr, uid, context = self.cr, self.uid, {}
+ picking_id = self.purchase_order.read(cr, uid, [self.po_01_id], ['picking_ids'])[0]['picking_ids']
+ move_lines_ids = self.stock_picking.read(cr, uid, picking_id, ['move_lines'])[0]['move_lines']
+ for move in self.stock_move.browse(cr, uid, move_lines_ids, context=context):
+ move.action_done()
+
+ new_price = self.product_product.read(cr, uid, self.product_id, ['standard_price'], context=context)['standard_price']
+ self.assertAlmostEqual(
+ new_price,
+ (self.available_qty * self.standard_price + self.order_qty * self.order_price_unit)
+ /(self.available_qty + self.order_qty))
+
+ def test_20_partial_stock_move(self):
+ cr, uid, context = self.cr, self.uid, {}
+ picking_ids = self.purchase_order.read(cr, uid, [self.po_01_id], ['picking_ids'])[0]['picking_ids']
+ product = self.product_product.browse(cr, uid, self.product_id, context=context)
+
+ partial_move_id = self.stock_partial_move.create(cr, uid, {
+ 'date': date.today(),
+ 'picking_id': picking_ids[0]
+ }, context=context)
+
+ move_lines_ids = self.stock_picking.read(cr, uid, picking_ids, ['move_lines'])[0]['move_lines']
+ for move in self.stock_move.browse(cr, uid, move_lines_ids, context=context):
+ self.stock_partial_move_line.create(cr, uid, {
+ 'product_id': self.product_id,
+ 'quantity': self.picking_qty,
+ 'product_uom': product.uom_id.id,
+ 'location_dest_id': self.location_id,
+ 'location_id': self.supplier_location_id,
+ 'move_id': move.id,
+ 'cost': self.order_price_unit,
+ 'wizard_id': partial_move_id,
+ }, context=context)
+
+ self.stock_partial_move.do_partial(cr, uid, [partial_move_id], context=context)
+
+ new_price = self.product_product.read(cr, uid, self.product_id, ['standard_price'], context=context)['standard_price']
+ self.assertAlmostEqual(
+ new_price,
+ (self.available_qty * self.standard_price + self.order_qty * self.order_price_unit)
+ /(self.available_qty + self.order_qty))
+
+ def test_30_partial_stock_picking(self):
+ cr, uid, context = self.cr, self.uid, {}
+ picking_ids = self.purchase_order.read(cr, uid, [self.po_01_id], ['picking_ids'])[0]['picking_ids']
+ product = self.product_product.browse(cr, uid, self.product_id, context=context)
+
+ partial_picking_id = self.partial_picking.create(cr, uid, {
+ 'date': date.today(),
+ 'picking_id': picking_ids[0],
+ }, context=context)
+
+ move_lines_ids = self.stock_picking.read(cr, uid, picking_ids, ['move_lines'])[0]['move_lines']
+ for move in self.stock_move.browse(cr, uid, move_lines_ids, context=context):
+ self.partial_picking_line.create(cr, uid, {
+ 'product_id': self.product_id,
+ 'quantity': self.picking_qty,
+ 'product_uom': product.uom_id.id,
+ 'location_dest_id': self.location_id,
+ 'location_id': self.supplier_location_id,
+ 'move_id': move.id,
+ 'cost': self.order_price_unit,
+ 'wizard_id': partial_picking_id,
+ }, context=context)
+
+ self.partial_picking.do_partial(cr, uid, [partial_picking_id], context=context)
+
+ new_price = self.product_product.read(cr, uid, self.product_id, ['standard_price'], context=context)['standard_price']
+ self.assertAlmostEqual(
+ new_price,
+ (self.available_qty * self.standard_price + self.order_qty * self.order_price_unit)
+ /(self.available_qty + self.order_qty))
+
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 1de4e58ab09..3779e5cd219 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -1613,7 +1613,9 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
.filter(function (column) { return column.tag === 'field';})
.pluck('name').value(),
function (groups) {
- self.view.$pager.hide();
+ // page count is irrelevant on grouped page, replace by limit
+ self.view.$pager.find('.oe_pager_group').hide();
+ self.view.$pager.find('.oe_list_pager_state').text(self.view._limit ? self.view._limit : '∞');
$el[0].appendChild(
self.render_groups(groups));
if (post_render) { post_render(); }