diff --git a/stock_request/models/stock_move.py b/stock_request/models/stock_move.py
index eec5e0312..7cef93ec5 100644
--- a/stock_request/models/stock_move.py
+++ b/stock_request/models/stock_move.py
@@ -37,3 +37,20 @@ class StockMove(models.Model):
raise ValidationError(
_('The company of the stock request must match with '
'that of the location.'))
+
+ def copy_data(self, default=None):
+ if not default:
+ default = {}
+ if 'allocation_ids' not in default:
+ default['allocation_ids'] = []
+ for alloc in self.allocation_ids:
+ default['allocation_ids'].append((0, 0, {
+ 'stock_request_id': alloc.stock_request_id.id,
+ 'requested_product_uom_qty': alloc.requested_product_uom_qty,
+ }))
+ return super(StockMove, self).copy_data(default)
+
+ def _action_cancel(self):
+ res = super()._action_cancel()
+ self.mapped('allocation_ids.stock_request_id').check_done()
+ return res
diff --git a/stock_request/models/stock_request.py b/stock_request/models/stock_request.py
index 73be05788..e68fa1df3 100644
--- a/stock_request/models/stock_request.py
+++ b/stock_request/models/stock_request.py
@@ -83,6 +83,11 @@ class StockRequest(models.Model):
readonly=True, compute='_compute_qty', store=True,
help="Quantity completed",
)
+ qty_cancelled = fields.Float(
+ 'Qty Cancelled', digits=dp.get_precision('Product Unit of Measure'),
+ readonly=True, compute='_compute_qty', store=True,
+ help="Quantity cancelled",
+ )
picking_count = fields.Integer(string='Delivery Orders',
compute='_compute_picking_ids',
readonly=True,
@@ -124,12 +129,13 @@ class StockRequest(models.Model):
'Stock Request name must be unique'),
]
- @api.depends('allocation_ids')
+ @api.depends('allocation_ids', 'allocation_ids.stock_move_id')
def _compute_move_ids(self):
for request in self:
request.move_ids = request.allocation_ids.mapped('stock_move_id')
- @api.depends('allocation_ids')
+ @api.depends('allocation_ids', 'allocation_ids.stock_move_id',
+ 'allocation_ids.stock_move_id.picking_id')
def _compute_picking_ids(self):
for request in self:
request.picking_count = 0
@@ -146,11 +152,15 @@ class StockRequest(models.Model):
done_qty = sum(request.allocation_ids.mapped(
'allocated_product_qty'))
open_qty = sum(request.allocation_ids.mapped('open_product_qty'))
- request.qty_done = request.product_id.uom_id._compute_quantity(
+ uom = request.product_id.uom_id
+ request.qty_done = uom._compute_quantity(
done_qty, request.product_uom_id)
- request.qty_in_progress = \
- request.product_id.uom_id._compute_quantity(
- open_qty, request.product_uom_id)
+ request.qty_in_progress = uom._compute_quantity(
+ open_qty, request.product_uom_id)
+ request.qty_cancelled = max(0, uom._compute_quantity(
+ request.product_qty - done_qty - open_qty,
+ request.product_uom_id
+ )) if request.allocation_ids else 0
@api.constrains('order_id', 'requested_by')
def check_order_requested_by(self):
@@ -210,7 +220,7 @@ class StockRequest(models.Model):
@api.multi
def _action_confirm(self):
self._action_launch_procurement_rule()
- self.state = 'open'
+ self.write({'state': 'open'})
@api.multi
def action_confirm(self):
@@ -223,13 +233,12 @@ class StockRequest(models.Model):
def action_cancel(self):
self.sudo().mapped('move_ids')._action_cancel()
- self.state = 'cancel'
+ self.write({'state': 'cancel'})
return True
def action_done(self):
- self.state = 'done'
- if self.order_id:
- self.order_id.check_done()
+ self.write({'state': 'done'})
+ self.mapped('order_id').check_done()
return True
def check_done(self):
@@ -243,8 +252,18 @@ class StockRequest(models.Model):
if float_compare(qty_done, request.product_uom_qty,
precision_digits=precision) >= 0:
request.action_done()
+ elif request._check_done_allocation():
+ request.action_done()
return True
+ def _check_done_allocation(self):
+ precision = self.env['decimal.precision'].precision_get(
+ 'Product Unit of Measure')
+ self.ensure_one()
+ return self.allocation_ids and float_compare(
+ self.qty_cancelled, 0, precision_digits=precision
+ ) > 0
+
def _prepare_procurement_values(self, group_id=False):
""" Prepare specific key for moves or other components that
diff --git a/stock_request/models/stock_request_allocation.py b/stock_request/models/stock_request_allocation.py
index 99b05fb7f..1e69601dd 100644
--- a/stock_request/models/stock_request_allocation.py
+++ b/stock_request/models/stock_request_allocation.py
@@ -44,6 +44,7 @@ class StockRequestAllocation(models.Model):
)
allocated_product_qty = fields.Float(
'Allocated Quantity',
+ copy=False,
help='Quantity of the stock request allocated to the stock move, '
'in the default UoM of the product',
)
@@ -62,7 +63,7 @@ class StockRequestAllocation(models.Model):
'stock_move_id', 'stock_move_id.state')
def _compute_open_product_qty(self):
for rec in self:
- if rec.stock_move_id.state == 'cancel':
+ if rec.stock_move_id.state in ['cancel', 'done']:
rec.open_product_qty = 0.0
else:
rec.open_product_qty = \
diff --git a/stock_request/models/stock_request_order.py b/stock_request/models/stock_request_order.py
index 392617a1b..8813e865c 100644
--- a/stock_request/models/stock_request_order.py
+++ b/stock_request/models/stock_request_order.py
@@ -201,30 +201,28 @@ class StockRequestOrder(models.Model):
@api.multi
def action_confirm(self):
- for line in self.stock_request_ids:
- line.action_confirm()
- self.state = 'open'
+ self.mapped('stock_request_ids').action_confirm()
+ self.write({'state': 'open'})
return True
def action_draft(self):
- for line in self.stock_request_ids:
- line.action_draft()
- self.state = 'draft'
+ self.mapped('stock_request_ids').action_draft()
+ self.write({'state': 'draft'})
return True
def action_cancel(self):
- for line in self.stock_request_ids:
- line.action_cancel()
- self.state = 'cancel'
+ self.mapped('stock_request_ids').action_cancel()
+ self.write({'state': 'cancel'})
return True
def action_done(self):
- self.state = 'done'
+ self.write({'state': 'done'})
return True
def check_done(self):
- if not self.stock_request_ids.filtered(lambda r: r.state != 'done'):
- self.action_done()
+ for rec in self:
+ if not rec.stock_request_ids.filtered(lambda r: r.state != 'done'):
+ rec.action_done()
return
@api.multi
diff --git a/stock_request/tests/test_stock_request.py b/stock_request/tests/test_stock_request.py
index 51b98fa6f..5f05df4d1 100644
--- a/stock_request/tests/test_stock_request.py
+++ b/stock_request/tests/test_stock_request.py
@@ -880,3 +880,99 @@ class TestStockRequestBase(TestStockRequest):
order.stock_request_ids.onchange_warehouse_id()
self.assertEqual(
order.stock_request_ids[0].location_id, self.virtual_loc)
+
+ def test_cancellation(self):
+ group = self.env['procurement.group'].create({
+ 'name': 'Procurement group'
+ })
+ product2 = self._create_product('SH2', 'Shoes2', False)
+ product3 = self._create_product('SH3', 'Shoes3', False)
+ self.product.type = 'consu'
+ product2.type = 'consu'
+ product3.type = 'consu'
+ vals = {
+ 'company_id': self.main_company.id,
+ 'warehouse_id': self.warehouse.id,
+ 'location_id': self.virtual_loc.id,
+ 'procurement_group_id': group.id,
+ 'stock_request_ids': [(0, 0, {
+ 'product_id': self.product.id,
+ 'product_uom_id': self.product.uom_id.id,
+ 'procurement_group_id': group.id,
+ 'product_uom_qty': 5.0,
+ 'company_id': self.main_company.id,
+ 'warehouse_id': self.warehouse.id,
+ 'location_id': self.virtual_loc.id,
+ }), (0, 0, {
+ 'product_id': product2.id,
+ 'product_uom_id': self.product.uom_id.id,
+ 'procurement_group_id': group.id,
+ 'product_uom_qty': 5.0,
+ 'company_id': self.main_company.id,
+ 'warehouse_id': self.warehouse.id,
+ 'location_id': self.virtual_loc.id,
+ }), (0, 0, {
+ 'product_id': product3.id,
+ 'product_uom_id': self.product.uom_id.id,
+ 'procurement_group_id': group.id,
+ 'product_uom_qty': 5.0,
+ 'company_id': self.main_company.id,
+ 'warehouse_id': self.warehouse.id,
+ 'location_id': self.virtual_loc.id,
+ })]
+ }
+ order = self.request_order.create(vals)
+ self.product.route_ids = [(6, 0, self.route.ids)]
+ product2.route_ids = [(6, 0, self.route.ids)]
+ product3.route_ids = [(6, 0, self.route.ids)]
+ order.action_confirm()
+ picking = order.picking_ids
+ self.assertEqual(1, len(picking))
+ picking.action_assign()
+ self.assertEqual(3, len(picking.move_lines))
+ line = picking.move_lines.filtered(
+ lambda r: r.product_id == self.product)
+ line.quantity_done = 1
+ sr1 = order.stock_request_ids.filtered(
+ lambda r: r.product_id == self.product)
+ sr2 = order.stock_request_ids.filtered(
+ lambda r: r.product_id == product2)
+ sr3 = order.stock_request_ids.filtered(
+ lambda r: r.product_id == product3)
+ self.assertNotEqual(sr1.state, 'done')
+ self.assertNotEqual(sr2.state, 'done')
+ self.assertNotEqual(sr3.state, 'done')
+ self.env['stock.backorder.confirmation'].create(
+ {'pick_ids': [(4, picking.id)]}
+ ).process()
+ sr1.refresh()
+ sr2.refresh()
+ sr3.refresh()
+ self.assertNotEqual(sr1.state, 'done')
+ self.assertNotEqual(sr2.state, 'done')
+ self.assertNotEqual(sr3.state, 'done')
+ picking = order.picking_ids.filtered(lambda r: r.state not in [
+ 'done', 'cancel'
+ ])
+ self.assertEqual(1, len(picking))
+ picking.action_assign()
+ self.assertEqual(3, len(picking.move_lines))
+ line = picking.move_lines.filtered(
+ lambda r: r.product_id == self.product)
+ line.quantity_done = 4
+ line = picking.move_lines.filtered(
+ lambda r: r.product_id == product2)
+ line.quantity_done = 1
+
+ self.env['stock.backorder.confirmation'].create(
+ {'pick_ids': [(4, picking.id)]}
+ ).process_cancel_backorder()
+ sr1.refresh()
+ sr2.refresh()
+ sr3.refresh()
+ self.assertEqual(sr1.state, 'done')
+ self.assertEqual(sr1.qty_cancelled, 0)
+ self.assertEqual(sr2.state, 'done')
+ self.assertEqual(sr2.qty_cancelled, 4)
+ self.assertEqual(sr3.state, 'done')
+ self.assertEqual(sr3.qty_cancelled, 5)
diff --git a/stock_request/views/stock_request_views.xml b/stock_request/views/stock_request_views.xml
index 80eec6f76..f18489134 100644
--- a/stock_request/views/stock_request_views.xml
+++ b/stock_request/views/stock_request_views.xml
@@ -20,6 +20,7 @@
+
@@ -109,8 +110,9 @@
options="{'no_open': True, 'no_create': True}"
groups="uom.group_uom"/>
-
-
+
+
+