Unify shipment assignation scheduled jobs

The order shipments are assigned is important as it determines which order
will be done or not. So we must try to assign all the shipments and
productions following a defined order.

Closes #13027
This commit is contained in:
Cédric Krier
2024-02-09 16:42:28 +01:00
parent ec5a00c82e
commit 31e3eb142c
5 changed files with 194 additions and 9 deletions
+13 -1
View File
@@ -1,6 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.pool import PoolMeta
from trytond.transaction import Transaction
class Cron(metaclass=PoolMeta):
@@ -12,5 +13,16 @@ class Cron(metaclass=PoolMeta):
cls.method.selection.extend([
('production|set_cost_from_moves', "Set Cost from Moves"),
('production|reschedule', "Reschedule Productions"),
('production|assign_cron', "Assign Productions"),
])
@classmethod
def __register__(cls, module):
table = cls.__table__()
cursor = Transaction().connection.cursor()
super().__register__(module)
# Migration from 7.0: replace assign_cron
cursor.execute(*table.update(
[table.method], ['ir.cron|stock_shipment_assign_try'],
where=table.method == 'production|assign_cron'))
+1
View File
@@ -1,3 +1,4 @@
* Unify shipment assignation scheduled jobs
* Fill shipment number only in waiting state
* Manage assignation for customer shipment with same picking and output location
* Add pblc argument to assign_try
+37 -5
View File
@@ -1,6 +1,13 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.pool import PoolMeta
from itertools import groupby
from operator import attrgetter
from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction
from .shipment import ShipmentAssignMixin
class Cron(metaclass=PoolMeta):
@@ -18,8 +25,33 @@ class Cron(metaclass=PoolMeta):
"Reschedule Supplier Return Shipments"),
('stock.shipment.internal|reschedule',
"Reschedule Internal Shipments"),
('stock.shipment.out|assign_cron',
"Assign Customer Shipments"),
('stock.shipment.internal|assign_cron',
"Assign Internal Shipments"),
('ir.cron|stock_shipment_assign_try', "Assign Shipments"),
])
@classmethod
def __register__(cls, module):
table = cls.__table__()
cursor = Transaction().connection.cursor()
super().__register__(module)
# Migration from 7.0: replace assign_cron
cursor.execute(*table.update(
[table.method], ['ir.cron|stock_shipment_assign_try'],
where=table.method.in_([
'stock.shipment.out|assign_cron',
'stock.shipment.internal|assign_cron',
])))
@classmethod
def stock_shipment_assign_try(cls):
pool = Pool()
records = []
for _, kls in pool.iterobject():
if issubclass(kls, ShipmentAssignMixin):
records.extend(kls.to_assign())
records.sort(key=attrgetter('assign_order_key'))
for kls, records in groupby(records, key=attrgetter('__class__')):
kls.assign_try(list(records))
+6 -3
View File
@@ -210,9 +210,12 @@ class ShipmentAssignMixin(ShipmentMixin):
]
@classmethod
def assign_cron(cls):
shipments = cls.search(cls._get_assign_domain())
cls.assign_try(shipments)
def to_assign(cls):
return cls.search(cls._get_assign_domain())
@property
def assign_order_key(self):
return (self.planned_date, self.create_date)
def get_partially_assigned(self, name):
return (self.state != 'assigned'
@@ -0,0 +1,137 @@
==========================
Stock Shipment Cron Assign
==========================
Imports::
>>> import datetime as dt
>>> from decimal import Decimal
>>> from proteus import Model
>>> from trytond.modules.company.tests.tools import create_company, get_company
>>> from trytond.tests.tools import activate_modules
>>> today = dt.date.today()
>>> yesterday = today - dt.timedelta(days=1)
Activate modules::
>>> config = activate_modules('stock')
>>> Cron = Model.get('ir.cron')
>>> Location = Model.get('stock.location')
>>> Move = Model.get('stock.move')
>>> Party = Model.get('party.party')
>>> ProductTemplate = Model.get('product.template')
>>> ShipmentInternal = Model.get('stock.shipment.internal')
>>> ShipmentOut = Model.get('stock.shipment.out')
>>> UoM = Model.get('product.uom')
Create company::
>>> _ = create_company()
>>> company = get_company()
Create a product::
>>> unit, = UoM.find([('name', '=', "Unit")])
>>> template = ProductTemplate()
>>> template.name = "Product"
>>> template.type = 'goods'
>>> template.default_uom = unit
>>> template.save()
>>> product, = template.products
Create customer::
>>> customer = Party(name="Customer")
>>> customer.save()
Get locations::
>>> storage_loc, = Location.find([('code', '=', "STO")])
>>> supplier_loc, = Location.find([('code', '=', "SUP")])
>>> lost_loc, = Location.find([('type', '=', 'lost_found')], limit=1)
Fill storage::
>>> move = Move()
>>> move.product = product
>>> move.quantity = 5
>>> move.from_location = supplier_loc
>>> move.to_location = storage_loc
>>> move.unit_price = Decimal('10.0000')
>>> move.currency = company.currency
>>> move.effective_date = yesterday
>>> move.click('do')
>>> move.state
'done'
Create different shipments with different planned dates::
>>> shipment_int_1 = ShipmentInternal()
>>> shipment_int_1.planned_date = today
>>> shipment_int_1.from_location = storage_loc
>>> shipment_int_1.to_location = lost_loc
>>> move = shipment_int_1.moves.new()
>>> move.from_location = shipment_int_1.from_location
>>> move.to_location = shipment_int_1.to_location
>>> move.product = product
>>> move.quantity = 2
>>> shipment_int_1.click('wait')
>>> shipment_int_1.state
'waiting'
>>> shipment_out_1 = ShipmentOut()
>>> shipment_out_1.planned_date = today
>>> shipment_out_1.customer = customer
>>> move = shipment_out_1.outgoing_moves.new()
>>> move.from_location = shipment_out_1.warehouse_output
>>> move.to_location = shipment_out_1.customer_location
>>> move.product = product
>>> move.quantity = 2
>>> move.unit_price = Decimal('10.0000')
>>> move.currency = company.currency
>>> shipment_out_1.click('wait')
>>> shipment_out_1.state
'waiting'
>>> shipment_int_2, = shipment_int_1.duplicate()
>>> shipment_int_2.click('wait')
>>> shipment_int_2.state
'waiting'
>>> shipment_out_2, = shipment_out_1.duplicate()
>>> shipment_out_2.click('wait')
>>> shipment_out_2.state
'waiting'
Run assignation cron::
>>> cron = Cron(method='ir.cron|stock_shipment_assign_try')
>>> cron.interval_number = 1
>>> cron.interval_type = 'days'
>>> cron.click('run_once')
Check assignations::
>>> shipment_int_1.reload()
>>> shipment_int_1.state
'assigned'
>>> shipment_out_1.reload()
>>> shipment_out_1.state
'assigned'
>>> shipment_int_2.reload()
>>> shipment_int_2.state
'waiting'
>>> shipment_int_2.partially_assigned
True
>>> shipment_out_2.reload()
>>> shipment_out_2.state
'waiting'
>>> shipment_out_2.partially_assigned
False