mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] stock_move_auto_assign_auto_release: Release release_ready pickings instead of moves
Instead of just releasing the release ready moves of a give product it now releases the whole transfer This ensures that a transfer with a release_policy=one gets not split
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record
|
||||
id="job_function_product_product_moves_auto_release"
|
||||
id="job_function_product_product_pickings_auto_release"
|
||||
model="queue.job.function"
|
||||
>
|
||||
<field name="model_id" ref="product.model_product_product" />
|
||||
<field name="method">moves_auto_release</field>
|
||||
<field name="method">pickings_auto_release</field>
|
||||
<field name="channel_id" ref="channel_stock_auto_release" />
|
||||
</record>
|
||||
|
||||
<record id="job_function_stock_picking_auto_release" model="queue.job.function">
|
||||
<field name="model_id" ref="stock.model_stock_picking" />
|
||||
<field name="method">auto_release_available_to_promise</field>
|
||||
<field name="channel_id" ref="channel_stock_auto_release" />
|
||||
<field name="retry_pattern" eval="{1: 1, 5: 5, 10: 10, 15: 30}" />
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copyright 2022 ACSONE SA/NV
|
||||
# Copyright 2024 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models
|
||||
@@ -14,16 +15,15 @@ class ProductProduct(models.Model):
|
||||
("is_auto_release_allowed", "=", True),
|
||||
]
|
||||
|
||||
def moves_auto_release(self):
|
||||
"""Job trying to auto release moves based on product
|
||||
def pickings_auto_release(self):
|
||||
"""Job trying to auto release pickings based on product
|
||||
|
||||
It searches all* the moves auto releasable and trigger the release
|
||||
available to promise process.
|
||||
It searches all* the moves auto releasable
|
||||
and triggers a delayed release available to promise for their pickings.
|
||||
"""
|
||||
self.ensure_one()
|
||||
moves = self.env["stock.move"].search(self._moves_auto_release_domain())
|
||||
pickings = moves.picking_id
|
||||
if not pickings:
|
||||
return
|
||||
self._lock_pickings_or_retry(pickings)
|
||||
moves.release_available_to_promise()
|
||||
pickings._delay_auto_release_available_to_promise()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copyright 2022 ACSONE SA/NV
|
||||
# Copyright 2024 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
@@ -69,6 +70,6 @@ class StockMove(models.Model):
|
||||
)
|
||||
job_options.setdefault("identity_key", identity_exact)
|
||||
delayable = product.delayable(**job_options)
|
||||
release_job = delayable.moves_auto_release()
|
||||
release_job = delayable.pickings_auto_release()
|
||||
job.on_done(release_job)
|
||||
return job
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# Copyright 2022 ACSONE SA/NV
|
||||
# Copyright 2024 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.osv.expression import NEGATIVE_TERM_OPERATORS
|
||||
|
||||
from odoo.addons.queue_job.job import identity_exact
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
|
||||
@@ -47,3 +50,17 @@ class StockPicking(models.Model):
|
||||
if not is_auto_release_allowed:
|
||||
domain = [("id", "not in", self.search(domain).ids)]
|
||||
return domain
|
||||
|
||||
def _delay_auto_release_available_to_promise(self):
|
||||
for picking in self:
|
||||
picking.with_delay(
|
||||
identity_key=identity_exact,
|
||||
description=_(
|
||||
"Auto release available to promise %(name)s", name=picking.name
|
||||
),
|
||||
).auto_release_available_to_promise()
|
||||
|
||||
def auto_release_available_to_promise(self):
|
||||
to_release = self.filtered("is_auto_release_allowed")
|
||||
to_release.release_available_to_promise()
|
||||
return to_release
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
* Laurent Mignon <laurent.mignon@acsone.eu>
|
||||
* Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copyright 2022 ACSONE SA/NV
|
||||
# Copyright 2024 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
from datetime import datetime
|
||||
|
||||
@@ -82,7 +83,7 @@ class TestAssignAutoRelease(PromiseReleaseCommonCase):
|
||||
move.move_line_ids.location_dest_id = self.loc_bin1.id
|
||||
move._action_done()
|
||||
|
||||
def test_product_moves_auto_release(self):
|
||||
def test_product_pickings_auto_release(self):
|
||||
"""Test job method, update qty available and launch auto release on
|
||||
the product"""
|
||||
self.assertEqual(1, len(self.unreleased_move))
|
||||
@@ -90,7 +91,13 @@ class TestAssignAutoRelease(PromiseReleaseCommonCase):
|
||||
self.assertEqual(5, self.picking.move_ids.product_qty)
|
||||
# put stock in Stock/Shelf 1, the move has a source location in Stock
|
||||
self._update_qty_in_location(self.loc_bin1, self.product1, 100)
|
||||
self.product1.moves_auto_release()
|
||||
with trap_jobs() as trap:
|
||||
self.product1.pickings_auto_release()
|
||||
job = self._get_job_for_method(
|
||||
trap.enqueued_jobs,
|
||||
self.unreleased_move.picking_id.auto_release_available_to_promise,
|
||||
)
|
||||
job.perform()
|
||||
self.assertFalse(self.unreleased_move.need_release)
|
||||
self.assertEqual(1, len(self.picking.move_ids))
|
||||
self.assertEqual(10, self.picking.move_ids.product_qty)
|
||||
@@ -114,7 +121,7 @@ class TestAssignAutoRelease(PromiseReleaseCommonCase):
|
||||
)
|
||||
# and a second one to auto release
|
||||
trap.assert_enqueued_job(
|
||||
self.product1.moves_auto_release,
|
||||
self.product1.pickings_auto_release,
|
||||
args=(),
|
||||
kwargs={},
|
||||
properties=dict(
|
||||
@@ -126,7 +133,7 @@ class TestAssignAutoRelease(PromiseReleaseCommonCase):
|
||||
trap.enqueued_jobs, self.product1.moves_auto_assign
|
||||
)
|
||||
job2 = self._get_job_for_method(
|
||||
trap.enqueued_jobs, self.product1.moves_auto_release
|
||||
trap.enqueued_jobs, self.product1.pickings_auto_release
|
||||
)
|
||||
self.assertIn(job1, job2.depends_on)
|
||||
|
||||
@@ -165,3 +172,48 @@ class TestAssignAutoRelease(PromiseReleaseCommonCase):
|
||||
for domain in NOT_RELEASABLE_DOMAINS:
|
||||
self.assertIn(move_released, self.env["stock.move"].search(domain))
|
||||
self.assertNotIn(move_not_released, self.env["stock.move"].search(domain))
|
||||
|
||||
def test_picking_policy_one_async_receive(self):
|
||||
self.shipping.action_cancel()
|
||||
self.picking.action_cancel()
|
||||
shipping = self._out_picking(
|
||||
self._create_picking_chain(
|
||||
self.wh,
|
||||
[(self.product1, 10), (self.product2, 10)],
|
||||
date=datetime(2019, 9, 2, 16, 0),
|
||||
)
|
||||
)
|
||||
shipping.release_policy = "one"
|
||||
shipping.move_type = "one"
|
||||
self.assertTrue(
|
||||
all(
|
||||
move.need_release and not move.release_ready
|
||||
for move in shipping.move_lines
|
||||
)
|
||||
)
|
||||
with trap_jobs() as trap:
|
||||
self._receive_product(self.product1, 100)
|
||||
shipping.invalidate_cache()
|
||||
shipping.move_lines.invalidate_cache()
|
||||
trap.perform_enqueued_jobs()
|
||||
job = self._get_job_for_method(
|
||||
trap.enqueued_jobs, shipping.auto_release_available_to_promise
|
||||
)
|
||||
self.assertFalse(job)
|
||||
with trap_jobs() as trap:
|
||||
self._receive_product(self.product2, 100)
|
||||
shipping.invalidate_cache()
|
||||
shipping.move_lines.invalidate_cache()
|
||||
trap.perform_enqueued_jobs()
|
||||
job = self._get_job_for_method(
|
||||
trap.enqueued_jobs, shipping.auto_release_available_to_promise
|
||||
)
|
||||
job.perform()
|
||||
move_product1 = shipping.move_lines.filtered(
|
||||
lambda m: m.product_id == self.product1
|
||||
)
|
||||
move_product2 = shipping.move_lines - move_product1
|
||||
self.assertFalse(move_product2.release_ready)
|
||||
self.assertFalse(move_product2.need_release)
|
||||
self.assertFalse(move_product1.need_release)
|
||||
self.assertFalse(move_product1.release_ready)
|
||||
|
||||
Reference in New Issue
Block a user