diff --git a/ddmrp/models/stock_buffer.py b/ddmrp/models/stock_buffer.py
index b3fcb319c..35efc345f 100644
--- a/ddmrp/models/stock_buffer.py
+++ b/ddmrp/models/stock_buffer.py
@@ -1362,17 +1362,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
@@ -1821,72 +1810,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 5b8966758..98d3252bd 100644
--- a/ddmrp/views/stock_buffer_view.xml
+++ b/ddmrp/views/stock_buffer_view.xml
@@ -38,24 +38,19 @@
type="object"
/>
-
@@ -71,13 +66,22 @@
/>
+
+