summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorWilliam Henrotin <whe@odoo.com>2018-09-18 09:32:37 +0200
committerWilliam Henrotin <whe@odoo.com>2018-09-20 14:47:06 +0200
commitff7df19bd3bb80470a8a3b58b061b89405ffc2c2 (patch)
tree56da6d12e26503c985916b206c2961c338554c49 /addons
parent7dee76b962795844ec87f248994e65fddf4a388a (diff)
[IMP] stock: choose destination wizard
Purpose : during a transfer, if some move lines have different destination locations and the user click on 'put in pack' button, an warning is triggered. This message, saying : 'You cannot put in the same pack move lines having different destination location', is replaced by a wizard allowing the user to choose a unique destination location. This location will be set as location_dest_id on all transfer's stock move lines. After that, the wizard calls again the _put_in_pack() method where all the logic remains the same. Task : 1872345
Diffstat (limited to 'addons')
-rw-r--r--addons/delivery/models/stock_picking.py11
-rw-r--r--addons/delivery/wizard/choose_delivery_package.py4
-rw-r--r--addons/stock/__manifest__.py1
-rw-r--r--addons/stock/models/stock_picking.py25
-rw-r--r--addons/stock/tests/test_packing.py73
-rw-r--r--addons/stock/wizard/__init__.py1
-rw-r--r--addons/stock/wizard/stock_package_destination.py29
-rw-r--r--addons/stock/wizard/stock_package_destination_views.xml35
8 files changed, 171 insertions, 8 deletions
diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py
index e3cc5f55ed9..a9afc258004 100644
--- a/addons/delivery/models/stock_picking.py
+++ b/addons/delivery/models/stock_picking.py
@@ -113,6 +113,9 @@ class StockPicking(models.Model):
@api.multi
def put_in_pack(self):
+ res = super(StockPicking, self).put_in_pack()
+ if isinstance(res, dict) and res.get('type'):
+ return res
if self.carrier_id and self.carrier_id.delivery_type not in ['base_on_rule', 'fixed']:
view_id = self.env.ref('delivery.choose_delivery_package_view_form').id
return {
@@ -123,10 +126,14 @@ class StockPicking(models.Model):
'view_id': view_id,
'views': [(view_id, 'form')],
'target': 'new',
- 'context': dict(self.env.context, current_package_carrier_type=self.carrier_id.delivery_type),
+ 'context': dict(
+ self.env.context,
+ current_package_carrier_type=self.carrier_id.delivery_type,
+ default_stock_quant_package_id=res.id
+ ),
}
else:
- return self._put_in_pack()
+ return res
@api.multi
def action_send_confirmation_email(self):
diff --git a/addons/delivery/wizard/choose_delivery_package.py b/addons/delivery/wizard/choose_delivery_package.py
index ed10e8727aa..70c06f06dac 100644
--- a/addons/delivery/wizard/choose_delivery_package.py
+++ b/addons/delivery/wizard/choose_delivery_package.py
@@ -55,10 +55,6 @@ class ChooseDeliveryPackage(models.TransientModel):
return {'warning': warning_mess}
def put_in_pack(self):
- picking_id = self.env['stock.picking'].browse(self.env.context['active_id'])
- if not self.stock_quant_package_id:
- stock_quant_package = picking_id._put_in_pack()
- self.stock_quant_package_id = stock_quant_package
# write shipping weight and product_packaging on 'stock_quant_package' if needed
if self.delivery_packaging_id:
self.stock_quant_package_id.packaging_id = self.delivery_packaging_id
diff --git a/addons/stock/__manifest__.py b/addons/stock/__manifest__.py
index a9010b63ac2..a6c42ce4111 100644
--- a/addons/stock/__manifest__.py
+++ b/addons/stock/__manifest__.py
@@ -47,6 +47,7 @@
'wizard/stock_warn_insufficient_qty_views.xml',
'wizard/product_replenish_views.xml',
'wizard/stock_track_confirmation_views.xml',
+ 'wizard/stock_package_destination_views.xml',
'views/res_partner_views.xml',
'views/product_strategy_views.xml',
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index a798926bfdb..888d2637830 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -986,6 +986,26 @@ class Picking(models.Model):
return _explore(self.env['stock.picking'], self.env['stock.move'], moves)
+ def check_destinations(self):
+ if len(self.move_line_ids.filtered(lambda l: l.qty_done > 0 and not l.result_package_id).mapped('location_dest_id')) > 1:
+ view_id = self.env.ref('stock.stock_package_destination_form_view').id
+ wiz = self.env['stock.package.destination'].create({
+ 'picking_id': self.id,
+ 'location_dest_id': self.move_line_ids[0].location_dest_id.id,
+ })
+ return {
+ 'name': _('Choose destination location'),
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'stock.package.destination',
+ 'view_id': view_id,
+ 'views': [(view_id, 'form')],
+ 'type': 'ir.actions.act_window',
+ 'res_id': wiz.id,
+ 'target': 'new'
+ }
+ else:
+ return {}
def _put_in_pack(self):
package = False
@@ -994,8 +1014,6 @@ class Picking(models.Model):
if move_line_ids:
move_lines_to_pack = self.env['stock.move.line']
package = self.env['stock.quant.package'].create({})
- if len(move_line_ids.mapped('location_dest_id')) > 1:
- raise UserError('You cannot put in the same pack move lines having different destination locations')
for ml in move_line_ids:
if float_compare(ml.qty_done, ml.product_uom_qty,
precision_rounding=ml.product_uom_id.rounding) >= 0:
@@ -1027,6 +1045,9 @@ class Picking(models.Model):
return package
def put_in_pack(self):
+ res = self.check_destinations()
+ if res.get('type'):
+ return res
return self._put_in_pack()
def button_scrap(self):
diff --git a/addons/stock/tests/test_packing.py b/addons/stock/tests/test_packing.py
index c119bd18d10..c67d001247b 100644
--- a/addons/stock/tests/test_packing.py
+++ b/addons/stock/tests/test_packing.py
@@ -180,3 +180,76 @@ class TestPacking(TransactionCase):
self.assertEqual(package_level_reserved.location_id.id, shelf1_location.id, 'The reserved package level must be reserved in shelf1')
self.assertEqual(package_level_confirmed.location_id.id, self.stock_location.id, 'The not reserved package should keep its location')
self.assertEqual(picking.package_level_ids.mapped('is_done'), [True, True], 'Both package should still done')
+
+ def test_put_in_pack_to_different_location(self):
+ """ Hitting 'Put in pack' button while some move lines go to different
+ location should trigger a wizard. This wizard applies the same destination
+ location to all the move lines
+ """
+ shelf1_location = self.env['stock.location'].create({
+ 'name': 'shelf1',
+ 'usage': 'internal',
+ 'location_id': self.stock_location.id,
+ })
+ shelf2_location = self.env['stock.location'].create({
+ 'name': 'shelf2',
+ 'usage': 'internal',
+ 'location_id': self.stock_location.id,
+ })
+ picking = self.env['stock.picking'].create({
+ 'picking_type_id': self.warehouse.in_type_id.id,
+ 'location_id': self.stock_location.id,
+ 'location_dest_id': self.stock_location.id,
+ 'state': 'draft',
+ })
+ ship_move_a = self.env['stock.move'].create({
+ 'name': 'move 1',
+ 'product_id': self.productA.id,
+ 'product_uom_qty': 5.0,
+ 'product_uom': self.productA.uom_id.id,
+ 'location_id': self.customer_location.id,
+ 'location_dest_id': shelf1_location.id,
+ 'picking_id': picking.id,
+ 'state': 'draft',
+ })
+ picking.action_confirm()
+ picking.action_assign()
+ picking.move_line_ids.filtered(lambda ml: ml.product_id == self.productA).qty_done = 5.0
+ picking.put_in_pack()
+ pack1 = self.env['stock.quant.package'].search([])[-1]
+ picking.write({
+ 'move_line_ids': [(0, 0, {
+ 'product_id': self.productB.id,
+ 'product_uom_qty': 7.0,
+ 'qty_done': 7.0,
+ 'product_uom_id': self.productB.uom_id.id,
+ 'location_id': self.customer_location.id,
+ 'location_dest_id': shelf2_location.id,
+ 'picking_id': picking.id,
+ 'state': 'confirmed',
+ })]
+ })
+ picking.write({
+ 'move_line_ids': [(0, 0, {
+ 'product_id': self.productA.id,
+ 'product_uom_qty': 5.0,
+ 'qty_done': 5.0,
+ 'product_uom_id': self.productA.uom_id.id,
+ 'location_id': self.customer_location.id,
+ 'location_dest_id': shelf1_location.id,
+ 'picking_id': picking.id,
+ 'state': 'confirmed',
+ })]
+ })
+ wizard_values = picking.put_in_pack()
+ wizard = self.env[(wizard_values.get('res_model'))].browse(wizard_values.get('res_id'))
+ wizard.location_dest_id = shelf2_location.id
+ wizard.action_done()
+ picking.action_done()
+ pack2 = self.env['stock.quant.package'].search([])[-1]
+ self.assertEqual(pack2.location_id.id, shelf2_location.id, 'The package must be stored in shelf2')
+ self.assertEqual(pack1.location_id.id, shelf1_location.id, 'The package must be stored in shelf1')
+ qp1 = pack2.quant_ids[0]
+ qp2 = pack2.quant_ids[1]
+ self.assertEqual(qp1.quantity, 5, 'The quant has not the good quantity')
+ self.assertEqual(qp2.quantity, 7, 'The quant has not the good quantity')
diff --git a/addons/stock/wizard/__init__.py b/addons/stock/wizard/__init__.py
index 34ec326e15a..fd4115a1bfc 100644
--- a/addons/stock/wizard/__init__.py
+++ b/addons/stock/wizard/__init__.py
@@ -12,3 +12,4 @@ from . import stock_rules_report
from . import stock_warn_insufficient_qty
from . import product_replenish
from . import stock_track_confirmation
+from . import stock_package_destination
diff --git a/addons/stock/wizard/stock_package_destination.py b/addons/stock/wizard/stock_package_destination.py
new file mode 100644
index 00000000000..9dbab24c6b5
--- /dev/null
+++ b/addons/stock/wizard/stock_package_destination.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class ChooseDestinationLocation(models.TransientModel):
+ _name = 'stock.package.destination'
+
+ picking_id = fields.Many2one('stock.picking', required=True)
+ move_line_ids = fields.Many2many('stock.move.line', 'Products', compute='_compute_move_line_ids', required=True)
+ location_dest_id = fields.Many2one('stock.location', 'Destination location', required=True)
+ filtered_location = fields.One2many(comodel_name='stock.location', compute='_filter_location')
+
+ @api.one
+ @api.depends('picking_id')
+ def _compute_move_line_ids(self):
+ self.move_line_ids = self.picking_id.move_line_ids.filtered(lambda l: l.qty_done > 0 and not l.result_package_id)
+
+ @api.one
+ @api.depends('move_line_ids')
+ def _filter_location(self):
+ self.filtered_location = self.move_line_ids.mapped('location_dest_id')
+
+ def action_done(self):
+ # set the same location on each move line and pass again in _put_in_pack
+ for line in self.move_line_ids:
+ line.location_dest_id = self.location_dest_id
+ return self.picking_id.put_in_pack()
diff --git a/addons/stock/wizard/stock_package_destination_views.xml b/addons/stock/wizard/stock_package_destination_views.xml
new file mode 100644
index 00000000000..783468d9988
--- /dev/null
+++ b/addons/stock/wizard/stock_package_destination_views.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="stock_package_destination_form_view" model="ir.ui.view">
+ <field name="name">stock.package.destination.view</field>
+ <field name="model">stock.package.destination</field>
+ <field name="arch" type="xml">
+ <form>
+ <div>
+ You are trying to put products going to different locations into the same package
+ </div>
+ <div>
+ <field name="move_line_ids" style="margin-top:10px;">
+ <tree>
+ <field name="product_id"/>
+ <field name="location_dest_id"/>
+ <field name="qty_done" String="quantity"/>
+ <field name="lot_id" groups="stock.group_production_lot"/>
+ </tree>
+ </field>
+ </div>
+ <div>
+ <strong>Where do you want to send the products ?</strong>
+ </div>
+ <div>
+ <field name="filtered_location" invisible="1"/>
+ <field name="location_dest_id" domain="[('id', 'in', filtered_location)]" options="{'no_create': True, 'no_open': True}"/>
+ </div>
+ <footer>
+ <button string="Confirm" name="action_done" type="object" class="btn-primary"/>
+ <button string="Discard" name="cancel_button" class="btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+</odoo>