[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
This commit is contained in:
William Henrotin
2018-09-20 14:47:06 +02:00
parent 7dee76b962
commit ff7df19bd3
8 changed files with 171 additions and 8 deletions
+9 -2
View File
@@ -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):
@@ -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
+1
View File
@@ -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',
+23 -2
View File
@@ -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):
+73
View File
@@ -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')
+1
View File
@@ -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
@@ -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()
@@ -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>