From 5fdc41b610729851c8aebe2c262df64d6ffbd117 Mon Sep 17 00:00:00 2001 From: FactorLibre Date: Thu, 9 Jan 2025 12:28:31 +0100 Subject: [PATCH] [UPD] stock_picking_mass_action Added reservation logic for moves defined in odoo base and added test for "by_date" resevation method --- .../models/stock_picking.py | 33 ++--- .../tests/test_mass_action.py | 135 +++++------------- 2 files changed, 49 insertions(+), 119 deletions(-) diff --git a/stock_picking_mass_action/models/stock_picking.py b/stock_picking_mass_action/models/stock_picking.py index 24467c67e46..abddfb94a8b 100644 --- a/stock_picking_mass_action/models/stock_picking.py +++ b/stock_picking_mass_action/models/stock_picking.py @@ -3,9 +3,8 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import _, api, fields +from odoo import _, api from odoo.models import Model -from odoo.tools.misc import split_every class StockPicking(Model): @@ -13,25 +12,23 @@ class StockPicking(Model): @api.model def check_assign_all(self, domain=None, batch_size=False): + """Try to assign confirmed pickings""" if not batch_size: batch_size = 1000 - """Try to assign confirmed pickings""" - search_domain = [("state", "=", "confirmed")] + domains = self.env["procurement.group"]._get_moves_to_assign_domain( + self.company_id.id + ) if domain: - search_domain += domain - else: - search_domain += [("picking_type_code", "=", "outgoing")] - records = self.search(search_domain, order="scheduled_date") - - filtered_records = [] - for picking in records: - if all([m.state in ["confirmed", "partially_available"] and m.product_uom_qty != 0 and m.reservation_date != False and m.reservation_date <= fields.Date.today() for m in picking.move_ids]): - filtered_records.append(picking) - for i in range(0, len(filtered_records), batch_size): - batch = filtered_records[i:i + batch_size] - for picking in batch: - picking.sudo().action_assign() - + domains.append(domain) + moves_to_assign = self.env["stock.move"].search( + domains, + limit=None, + order="reservation_date, priority desc, date asc, id asc", + ) + total_items = len(moves_to_assign) + for i in range(0, total_items, batch_size): + batch = moves_to_assign[i : i + batch_size] + self.env["stock.move"].browse(batch.ids).sudo()._action_assign() def action_immediate_transfer_wizard(self): view = self.env.ref("stock.view_immediate_transfer") diff --git a/stock_picking_mass_action/tests/test_mass_action.py b/stock_picking_mass_action/tests/test_mass_action.py index c1da0588f28..790549edc44 100644 --- a/stock_picking_mass_action/tests/test_mass_action.py +++ b/stock_picking_mass_action/tests/test_mass_action.py @@ -1,10 +1,11 @@ # Copyright 2018 Tecnativa - Vicent Cubells # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo.tests import common -from odoo import fields from datetime import timedelta +from odoo import fields +from odoo.tests import common + class TestMassAction(common.TransactionCase): @classmethod @@ -52,8 +53,6 @@ def setUpClass(cls): } ) - - def test_mass_action(self): self.assertEqual(self.picking.state, "draft") wiz = self.env["stock.picking.mass.action"] @@ -103,6 +102,37 @@ def test_mass_action(self): self.assertEqual(pick1.state, "assigned") self.assertEqual(pick2.state, "assigned") + def test_mass_action_by_date(self): + # Set by date method + self.env.ref("stock.picking_type_out").write( + {"reservation_method": "by_date", "reservation_days_before": 4} + ) + self.assertEqual(self.picking.state, "draft") + wiz = self.env["stock.picking.mass.action"] + # We test checking assign all with "by date" method + pickings = self.env["stock.picking"] + pickOutDate = self.picking.copy() + # Set scheduled date out of the range of 4 days + pickOutDate.scheduled_date = fields.Date.today() + timedelta(days=15) + pickings |= pickOutDate + pickInDate = self.picking.copy() + pickings |= pickInDate + self.assertEqual(pickOutDate.state, "draft") + self.assertEqual(pickInDate.state, "draft") + wiz_confirm = wiz.create( + {"picking_ids": [(6, 0, [pickOutDate.id, pickInDate.id])]} + ) + wiz_confirm.confirm = True + wiz_confirm.mass_action() + self.assertEqual(pickOutDate.state, "confirmed") + self.assertEqual(pickInDate.state, "assigned") + pickings.check_assign_all() + self.assertEqual(pickOutDate.state, "confirmed") + # Change scheduled date in the range of 4 days + pickOutDate.scheduled_date = fields.Date.today() + timedelta(days=1) + pickings.check_assign_all() + self.assertEqual(pickOutDate.state, "assigned") + def test_mass_action_inmediate_transfer(self): wiz_tranfer = self.env["stock.picking.mass.action"].create( {"picking_ids": [(4, self.picking.id)], "confirm": True, "transfer": True} @@ -118,100 +148,3 @@ def test_mass_action_backorder(self): self.picking.move_ids[0].quantity_done = 30 res = wiz_tranfer.mass_action() self.assertEqual(res["res_model"], "stock.backorder.confirmation") - - def test_mass_action_reservation_by_date(self): - picking_type_out = self.env.ref("stock.picking_type_out") - picking_type_out.reservation_method = "by_date" - picking_type_out.reservation_days_before = 2 - - product = self.env["product.product"].create( - {"name": "Product Test Date", "type": "product"} - ) - stock_location = self.env.ref("stock.stock_location_stock") - customer_location = self.env.ref("stock.stock_location_customers") - - self.env["stock.quant"].create( - { - "product_id": product.id, - "location_id": stock_location.id, - "quantity": 100.0, - } - ) - - # Creamos dos pickings: uno con fecha válida y otro fuera del rango permitido - picking_valid_date = self.env["stock.picking"].create( - { - "partner_id": self.env["res.partner"].create({"name": "Partner 1"}).id, - "picking_type_id": picking_type_out.id, - "location_id": stock_location.id, - "location_dest_id": customer_location.id, - "scheduled_date": fields.Date.today() + timedelta(days=1), - "move_ids": [ - ( - 0, - 0, - { - "name": product.name, - "product_id": product.id, - "product_uom_qty": 50, - "product_uom": product.uom_id.id, - "location_id": stock_location.id, - "location_dest_id": customer_location.id, - }, - ) - ], - } - ) - - picking_out_of_range = self.env["stock.picking"].create( - { - "partner_id": self.env["res.partner"].create({"name": "Partner 2"}).id, - "picking_type_id": picking_type_out.id, - "location_id": stock_location.id, - "location_dest_id": customer_location.id, - "scheduled_date": fields.Date.today() + timedelta(days=6), - "move_ids": [ - ( - 0, - 0, - { - "name": product.name, - "product_id": product.id, - "product_uom_qty": 50, - "product_uom": product.uom_id.id, - "location_id": stock_location.id, - "location_dest_id": customer_location.id, - }, - ) - ], - } - ) - self.assertEqual(picking_valid_date.state, "draft") - self.assertEqual(picking_out_of_range.state, "draft") - wiz = self.env["stock.picking.mass.action"] - wiz_confirm = wiz.create({"picking_ids": [(4, picking_valid_date.id), (4, picking_out_of_range.id)]}) - wiz_confirm.confirm = True - wiz_confirm.mass_action() - # Confirmamos los pickings - # picking_valid_date.action_confirm() - # picking_out_of_range.action_confirm() - self.assertEqual(picking_valid_date.state, "confirmed") - self.assertEqual(picking_out_of_range.state, "confirmed") - self.env["stock.picking"].check_assign_all() - self.assertEqual( - picking_valid_date.state, "assigned", - "El picking con fecha dentro del rango no fue asignado." - ) - self.assertEqual( - picking_out_of_range.state, "confirmed", - "El picking con fecha fuera del rango no debería haberse asignado." - ) - self.env["stock.picking"].check_assign_all() - self.assertEqual( - picking_valid_date.state, "assigned", - "El picking con fecha válida no fue asignado." - ) - self.assertEqual( - picking_out_of_range.state, "confirmed", - "El picking con fecha futura no debería haberse asignado." - )