diff --git a/ddmrp/models/stock_buffer.py b/ddmrp/models/stock_buffer.py index 4bb4ffe9a..13e3fc8c4 100644 --- a/ddmrp/models/stock_buffer.py +++ b/ddmrp/models/stock_buffer.py @@ -1383,17 +1383,6 @@ def _stock_move_tree_view(self, lines): "domain": str([("id", "in", lines.ids)]), } - def open_moves(self): - self.ensure_one() - # Utility method used to add an "Open Moves" button in the buffer - # planning view - domain = self._search_open_stock_moves_domain() - moves = self.env["stock.move"].search(domain) - moves = moves.filtered( - lambda move: move.location_dest_id.is_sublocation_of(self.location_id) - ) - return self._stock_move_tree_view(moves) - def _get_horizon_adu_past_demand(self): return self.adu_calculation_method.horizon_past or 0 @@ -1839,72 +1828,72 @@ def do_auto_procure(self): wizard.make_procurement() return True - def _search_purchase_order_lines_incoming(self, outside_dlt=False): + def action_view_supply_moves(self): + result = self.env["ir.actions.actions"]._for_xml_id("stock.stock_move_action") + result["context"] = {} + moves = self._search_stock_moves_incoming() + self._search_stock_moves_incoming( + outside_dlt=True + ) + result["domain"] = [("id", "in", moves.ids)] + return result + + def _get_rfq_dlt(self, outside_dlt=False): + self.ensure_one() cut_date = self._get_incoming_supply_date_limit() if not outside_dlt: pols = self.purchase_line_ids.filtered( lambda l: l.date_planned <= fields.Datetime.to_datetime(cut_date) - and l.order_id.state in ("draft", "sent") + and l.state in ("draft", "sent") ) else: pols = self.purchase_line_ids.filtered( lambda l: l.date_planned > fields.Datetime.to_datetime(cut_date) - and l.order_id.state in ("draft", "sent") + and l.state in ("draft", "sent") ) return pols - def action_view_supply(self, outside_dlt=False): - if self.item_type == "purchased": - pols = self._search_purchase_order_lines_incoming(outside_dlt) - moves = self._search_stock_moves_incoming(outside_dlt) - while moves.mapped("move_orig_ids"): - moves = moves.mapped("move_orig_ids") - pos = pols.mapped("order_id") + moves.mapped("purchase_line_id.order_id") - result = self.env["ir.actions.actions"]._for_xml_id("purchase.purchase_rfq") - # Remove the context since the action display RFQ and not PO. - result["context"] = {} - result["domain"] = [("id", "in", pos.ids)] - elif self.item_type == "manufactured": - moves = self._search_stock_moves_incoming(outside_dlt) - mos = moves.mapped("production_id") - result = self.env["ir.actions.actions"]._for_xml_id( - "mrp.mrp_production_action" - ) - result["context"] = {} - result["domain"] = [("id", "in", mos.ids)] - else: - moves = self._search_stock_moves_incoming(outside_dlt) - picks = moves.mapped("picking_id") - result = self.env["ir.actions.actions"]._for_xml_id( - "stock.action_picking_tree_all" - ) - result["context"] = {} - result["domain"] = [("id", "in", picks.ids)] + def action_view_supply_moves_inside_dlt_window(self): + result = self.env["ir.actions.actions"]._for_xml_id("stock.stock_move_action") + moves = self._search_stock_moves_incoming() + result["context"] = {} + result["domain"] = [("id", "in", moves.ids)] return result - def action_view_supply_inside_dlt_window(self): - return self.action_view_supply() + def action_view_supply_moves_outside_dlt_window(self): + result = self.env["ir.actions.actions"]._for_xml_id("stock.stock_move_action") + moves = self._search_stock_moves_incoming(outside_dlt=True) + result["context"] = {} + result["domain"] = [("id", "in", moves.ids)] + return result - def action_view_supply_outside_dlt_window(self): - return self.action_view_supply(outside_dlt=True) + def action_view_supply_rfq_inside_dlt_window(self): + result = self.env["ir.actions.actions"]._for_xml_id("purchase.purchase_rfq") + pols = self._get_rfq_dlt() + pos = pols.mapped("order_id") + result["context"] = {} + result["domain"] = [("id", "in", pos.ids)] + return result - def action_view_qualified_demand_pickings(self): - moves = self.qualified_demand_stock_move_ids - picks = moves.mapped("picking_id") - result = self.env["ir.actions.actions"]._for_xml_id( - "stock.action_picking_tree_all" - ) + def action_view_supply_rfq_outside_dlt_window(self): + result = self.env["ir.actions.actions"]._for_xml_id("purchase.purchase_rfq") + pols = self._get_rfq_dlt(outside_dlt=True) + pos = pols.mapped("order_id") result["context"] = {} - result["domain"] = [("id", "in", picks.ids)] + result["domain"] = [("id", "in", pos.ids)] + return result + + def action_view_qualified_demand_moves(self): + result = self.env["ir.actions.actions"]._for_xml_id("stock.stock_move_action") + result["context"] = {} + result["domain"] = [("id", "in", self.qualified_demand_stock_move_ids.ids)] return result def action_view_qualified_demand_mrp(self): - mrp_moves = self.qualified_demand_mrp_move_ids result = self.env["ir.actions.actions"]._for_xml_id( "mrp_multi_level.mrp_move_action" ) result["context"] = {} - result["domain"] = [("id", "in", mrp_moves.ids)] + result["domain"] = [("id", "in", self.qualified_demand_mrp_move_ids.ids)] return result def action_view_past_adu_direct_demand(self): diff --git a/ddmrp/models/stock_move.py b/ddmrp/models/stock_move.py index 29106999a..5ef08b600 100644 --- a/ddmrp/models/stock_move.py +++ b/ddmrp/models/stock_move.py @@ -1,7 +1,7 @@ # Copyright 2019-20 ForgeFlow S.L. (http://www.forgeflow.com) # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). -from odoo import api, fields, models +from odoo import _, api, fields, models class StockMove(models.Model): @@ -84,3 +84,69 @@ def _update_ddmrp_nfp(self): buffer.cron_actions(only_nfp="out") for buffer in in_buffers.with_context(no_ddmrp_history=True): buffer.cron_actions(only_nfp="in") + + def _get_all_linked_moves(self): + """Retrieve all linked moves both origin and destination recursively.""" + + def get_moves(move_set, attr): + new_moves = move_set.mapped(attr) + while new_moves: + move_set |= new_moves + new_moves = new_moves.mapped(attr) + return move_set + + all_moves = ( + self | get_moves(self, "move_orig_ids") | get_moves(self, "move_dest_ids") + ) + return all_moves + + def _get_source_field_candidates(self): + """Extend for more source field candidates.""" + return [ + "sale_line_id.order_id", + "purchase_line_id.order_id", + "production_id", + "raw_material_production_id", + "unbuild_id", + "repair_id", + "rma_line_id", + "picking_id", + ] + + def _has_nested_field(self, field): + """Check if an object has a nested chain of fields.""" + current_object = self + try: + for field in field.split("."): + current_object = getattr(current_object, field) + return True + except AttributeError: + return False + + def _get_source_record(self): + """Find the first source record in the field candidates linked with the moves, + prioritizing the order of field candidates.""" + moves = self._get_all_linked_moves() + field_candidates = self._get_source_field_candidates() + # Iterate over the prioritized list of candidate fields + for field in field_candidates: + if self._has_nested_field(field): + for move in moves: + record = move.mapped(field) + if record: + return record + return False + + def action_open_stock_move_source(self): + """Open the source record of the stock move, if it exists.""" + self.ensure_one() + record = self._get_source_record() + if record: + return { + "name": getattr(record, "name", _("Stock Move Source")), + "view_mode": "form", + "res_model": record._name, + "type": "ir.actions.act_window", + "res_id": record.id, + } + return False diff --git a/ddmrp/views/stock_buffer_view.xml b/ddmrp/views/stock_buffer_view.xml index c07e7fcd3..5993f6792 100644 --- a/ddmrp/views/stock_buffer_view.xml +++ b/ddmrp/views/stock_buffer_view.xml @@ -47,24 +47,19 @@ type="object" /> - @@ -80,13 +75,22 @@ /> + + + + + + + + + @@ -432,7 +460,7 @@ /> - - stock.move.tree stock.move - - + +