diff --git a/addons/mrp/views/stock_picking_views.xml b/addons/mrp/views/stock_picking_views.xml
index b00d5bde610..b1e4ab388f8 100644
--- a/addons/mrp/views/stock_picking_views.xml
+++ b/addons/mrp/views/stock_picking_views.xml
@@ -137,6 +137,9 @@
+
+
+
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 5574a30baa0..24941da3527 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -74,7 +74,7 @@ class PickingType(models.Model):
reservation_days_before_priority = fields.Integer('Days when starred', help="Maximum number of days before scheduled date that priority picking products should be reserved.")
auto_show_reception_report = fields.Boolean(
"Show Reception Report at Validation",
- help="If this checkbox is ticked, Odoo will automatically show the reception report (if there are moves to allocate to) when validating a picking.")
+ help="If this checkbox is ticked, Odoo will automatically show the reception report (if there are moves to allocate to) when validating.")
count_picking_draft = fields.Integer(compute='_compute_picking_count')
count_picking_ready = fields.Integer(compute='_compute_picking_count')
diff --git a/addons/stock/report/report_stock_reception.py b/addons/stock/report/report_stock_reception.py
index facd8166d71..e5bb901c87b 100644
--- a/addons/stock/report/report_stock_reception.py
+++ b/addons/stock/report/report_stock_reception.py
@@ -15,16 +15,16 @@ class ReceptionReport(models.AbstractModel):
def _get_report_values(self, docids, data=None):
''' This report is flexibly designed to work with both individual and batch pickings.
'''
- docids = self.env.context.get('default_picking_ids', docids)
- pickings = self.env['stock.picking'].search([('id', 'in', docids), ('picking_type_code', '!=', 'outgoing'), ('state', '!=', 'cancel')])
- picking_states = pickings.mapped('state')
+ docs = self._get_docs(docids)
+ doc_states = docs.mapped('state')
# unsupported cases
- if not pickings:
- msg = _("No transfers selected or a delivery order selected")
- elif 'done' in picking_states and len(set(picking_states)) > 1:
- pickings = False
- msg = _("This report cannot be used for done and not done transfers at the same time")
- if not pickings:
+ doc_types = self._get_doc_types()
+ if not docs:
+ msg = _("No %s selected or a delivery order selected", doc_types)
+ elif 'done' in doc_states and len(set(doc_states)) > 1:
+ docs = False
+ msg = _("This report cannot be used for done and not done %s at the same time", doc_types)
+ if not docs:
return {'pickings': False, 'reason': msg}
# incoming move qtys
@@ -33,7 +33,7 @@ class ReceptionReport(models.AbstractModel):
product_to_total_assigned = defaultdict(lambda: [0.0, []])
# to support batch pickings we need to track the total already assigned
- move_ids = pickings.move_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel')
+ move_ids = self._get_moves(docs)
assigned_moves = move_ids.mapped('move_dest_ids')
product_to_assigned_qty = defaultdict(float)
for assigned in assigned_moves:
@@ -58,11 +58,11 @@ class ReceptionReport(models.AbstractModel):
product_to_qty_to_assign[move.product_id].append((quantity_to_assign - qty_already_assigned, move))
# only match for non-mto moves in same warehouse
- warehouse = pickings[0].picking_type_id.warehouse_id
+ warehouse = docs[0].picking_type_id.warehouse_id
wh_location_ids = self.env['stock.location']._search([('id', 'child_of', warehouse.view_location_id.id), ('usage', '!=', 'supplier')])
allowed_states = ['confirmed', 'partially_available', 'waiting']
- if 'done' in picking_states:
+ if 'done' in doc_states:
# only done moves are allowed to be assigned to already reserved moves
allowed_states += ['assigned']
@@ -72,10 +72,9 @@ class ReceptionReport(models.AbstractModel):
('product_qty', '>', 0),
('location_id', 'in', wh_location_ids),
('move_orig_ids', '=', False),
- ('picking_id', 'not in', pickings.ids),
('product_id', 'in',
[p.id for p in list(product_to_qty_to_assign.keys()) + list(product_to_qty_draft.keys())]),
- ],
+ ] + self._get_extra_domain(docs),
order='reservation_date, priority desc, date, id')
products_to_outs = defaultdict(list)
@@ -95,7 +94,7 @@ class ReceptionReport(models.AbstractModel):
qty_to_reserve = out.product_qty
product_uom = out.product_id.uom_id
- if 'done' not in picking_states and out.state == 'partially_available':
+ if 'done' not in doc_states and out.state == 'partially_available':
qty_to_reserve -= out.product_uom._compute_quantity(out.reserved_availability, product_uom)
moves_in_ids = []
qty_done = 0
@@ -154,10 +153,10 @@ class ReceptionReport(models.AbstractModel):
return {
'data': data,
'doc_ids': docids,
- 'doc_model': 'stock.picking',
+ 'doc_model': self._get_doc_model(),
'sources_to_lines': sources_to_lines,
'precision': self.env['decimal.precision'].precision_get('Product Unit of Measure'),
- 'pickings': pickings,
+ 'docs': docs,
'sources_to_formatted_scheduled_date': sources_to_formatted_scheduled_date,
}
@@ -176,6 +175,22 @@ class ReceptionReport(models.AbstractModel):
'move_ins': move_ins and move_ins.ids or False,
}
+ def _get_docs(self, docids):
+ docids = self.env.context.get('default_picking_ids', docids)
+ return self.env['stock.picking'].search([('id', 'in', docids), ('picking_type_code', '!=', 'outgoing'), ('state', '!=', 'cancel')])
+
+ def _get_doc_model(self):
+ return 'stock.picking'
+
+ def _get_doc_types(self):
+ return "transfers"
+
+ def _get_moves(self, docs):
+ return docs.move_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel')
+
+ def _get_extra_domain(self, docs):
+ return [('picking_id', 'not in', docs.ids)]
+
def _get_formatted_scheduled_date(self, source):
""" Unfortunately different source record types have different field names for their "Scheduled Date"
Therefore an extendable method is needed.
@@ -238,6 +253,7 @@ class ReceptionReport(models.AbstractModel):
linked_qty = min(in_move.product_qty, qty_to_link)
in_move.move_dest_ids |= out
+ self._action_assign(in_move, out)
out.procure_method = 'make_to_order'
quantity_remaining -= linked_qty
qty_to_link -= linked_qty
@@ -263,6 +279,7 @@ class ReceptionReport(models.AbstractModel):
if out.id not in in_move.move_dest_ids.ids:
continue
in_move.move_dest_ids -= out
+ self._action_unassign(in_move, out)
amount_unassigned += min(qty, in_move.product_qty)
if float_compare(qty, amount_unassigned, precision_rounding=out.product_id.uom_id.rounding) <= 0:
break
@@ -296,3 +313,11 @@ class ReceptionReport(models.AbstractModel):
new_out._recompute_state()
out.procure_method = 'make_to_stock'
out._recompute_state()
+
+ def _action_assign(self, in_move, out_move):
+ """ For extension purposes only """
+ return
+
+ def _action_unassign(self, in_move, out_move):
+ """ For extension purposes only """
+ return
diff --git a/addons/stock/report/report_stock_reception.xml b/addons/stock/report/report_stock_reception.xml
index 7000b459dbe..e9d62a5761e 100644
--- a/addons/stock/report/report_stock_reception.xml
+++ b/addons/stock/report/report_stock_reception.xml
@@ -44,13 +44,13 @@
diff --git a/addons/stock/tests/test_report.py b/addons/stock/tests/test_report.py
index 8ae7a67d287..fde4efc6e8f 100644
--- a/addons/stock/tests/test_report.py
+++ b/addons/stock/tests/test_report.py
@@ -1384,7 +1384,7 @@ class TestReports(TestReportsCommon):
# check that report correctly merges not draft incoming quantities
report = self.env['report.stock.report_reception']
report_values = report._get_report_values(docids=[receipt1.id, receipt2.id])
- self.assertEqual(len(report_values['pickings']), 2, "There should be 2 receipts to assign from in this report")
+ self.assertEqual(len(report_values['docs']), 2, "There should be 2 receipts to assign from in this report")
sources_to_lines = report_values['sources_to_lines']
self.assertEqual(len(sources_to_lines), 1, "The report has wrong number of outgoing pickings.")
all_lines = list(sources_to_lines.values())[0]
@@ -1410,7 +1410,7 @@ class TestReports(TestReportsCommon):
# check that report doesn't allow done and non-done moves at same time
receipt1.button_validate()
reason = report._get_report_values(docids=[receipt1.id, receipt2.id])['reason']
- self.assertEqual(reason, "This report cannot be used for done and not done transfers at the same time", "empty report reason not shown")
+ self.assertEqual(reason, "This report cannot be used for done and not done %s at the same time" % report._get_doc_types(), "empty report reason not shown")
def test_report_reception_3_multiwarehouse(self):
""" Check that reception report respects same warehouse for