Extend carrier configuration to control loaded uls and/or loaded cases.

This commit refs #25499
This commit is contained in:
ramon.vidal 2023-01-18 09:09:54 +01:00 committed by Sergio Morillo
parent 6698047ab0
commit e7e8b8ecec
5 changed files with 141 additions and 12 deletions

102
load.py
View File

@ -3,12 +3,11 @@
from functools import partial
from itertools import groupby
from decimal import Decimal
from trytond.rpc import RPC
from sql import Null
from sql.operators import Concat
from trytond.model import fields, ModelView, Model, ModelSQL, Unique, Workflow
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Bool, Id
from trytond.pyson import Eval, Bool, Id, If, In
from trytond.tools import reduce_ids
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateTransition, StateView, Button, \
@ -17,6 +16,7 @@ from trytond.exceptions import UserError, UserWarning
from trytond.i18n import gettext
from .exceptions import (AddUnitLoadError, AddUnitLoadWarning,
AddUnitLoadOverloadError, AddUnitLoadOriginError, AddUnitLoadOriginWarning)
from trytond.modules.stock_unit_load import cases_digits
try:
import phonenumbers
from phonenumbers import PhoneNumberFormat, NumberParseException
@ -29,11 +29,19 @@ class Configuration(metaclass=PoolMeta):
ul_origin_restrict = fields.Boolean('Restrict UL origin',
help='Restricts origin of UL when loading in a Load order.')
quantity_check = fields.MultiSelection([
('uls', 'ULs'),
('cases', 'Cases'),
], "Quantity Check", sort=False)
@classmethod
def default_ul_origin_restrict(cls):
return True
@classmethod
def default_quantity_check(cls):
return ['uls']
class Load(metaclass=PoolMeta):
__name__ = 'carrier.load'
@ -91,6 +99,12 @@ class LoadOrder(metaclass=PoolMeta):
'get_ul_quantity')
loaded_uls = fields.Function(fields.Float('Loaded ULs', digits=(16, 0)),
'get_loaded_uls')
loaded_cases = fields.Function(
fields.Float('Loaded Cases', digits=cases_digits),
'get_loaded_cases')
cases_quantity = fields.Function(
fields.Float('Cases', digits=cases_digits),
'get_cases_quantity')
@classmethod
def __setup__(cls):
@ -145,6 +159,16 @@ class LoadOrder(metaclass=PoolMeta):
return 0
return len(self.unit_loads)
def get_loaded_cases(self, name=None):
if not self.unit_loads:
return 0
return sum(ul.cases_quantity for ul in self.unit_loads)
def get_cases_quantity(self, name=None):
if not self.lines:
return 0
return sum(l.cases_quantity for l in self.lines)
@classmethod
def set_unit_loads(cls, records, name, value):
pass
@ -414,19 +438,30 @@ class LoadOrder(metaclass=PoolMeta):
def _check_loaded_quantity(cls, records):
pool = Pool()
Warning = pool.get('res.user.warning')
Configuration = pool.get('carrier.configuration')
conf = Configuration(1)
for record in records:
if not record.unit_loads:
raise UserError(gettext(
'carrier_load_ul.msg_carrier_load_order_no_uls',
order=record.rec_name))
if record.ul_quantity > len(record.unit_loads):
if ('uls' in conf.quantity_check
and record.ul_quantity > record.loaded_uls):
warning_name = 'pending_uls_%s' % record.id
if Warning.check(warning_name):
raise UserWarning(warning_name, gettext(
'carrier_load_ul.msg_carrier_load_order_pending_uls',
uls=len(record.unit_loads),
uls=record.loaded_uls,
ul_quantity=int(record.ul_quantity)))
if ('cases' in conf.quantity_check
and record.cases_quantity > record.loaded_cases):
warning_name = 'pending_cases_%s' % record.id
if Warning.check(warning_name):
raise UserWarning(warning_name, gettext(
'carrier_load_ul.msg_carrier_load_order_pending_cases',
loaded_cases=record.loaded_cases,
cases_quantity=record.cases_quantity))
@classmethod
def _set_loaded_unit_loads(cls, records, revert=False):
@ -583,14 +618,26 @@ class LoadOrder(metaclass=PoolMeta):
order=self.rec_name))
def _choose_matched_line(self, lines, values, unit_load):
pool = Pool()
Configuration = pool.get('carrier.configuration')
configuration = Configuration(1)
line = None
for _line in lines:
if _line.id not in values:
values.setdefault(_line.id, set(
ul for ul in _line.unit_loads))
if _line.ul_quantity - len(values[_line.id]) > 0:
line = _line
break
if 'uls' in configuration.quantity_check:
if _line.ul_quantity - len(values[_line.id]) <= 0:
continue
if ('cases' in configuration.quantity_check
and _line.cases_quantity):
cases = sum(ul.cases_quantity for ul in values[_line.id])
if round(_line.cases_quantity - cases, cases_digits[1]) <= 0:
continue
line = _line
break
if line:
values[line.id].add(unit_load)
return line
@ -670,9 +717,14 @@ class LoadOrder(metaclass=PoolMeta):
class LoadOrderLine(metaclass=PoolMeta):
__name__ = 'carrier.load.order.line'
quantity_check = fields.Function(
fields.MultiSelection('_quantity_check_selection', "Quantity Check"),
'get_quantity_check')
ul_quantity = fields.Float('ULs', digits=(16, 0),
domain=[('ul_quantity', '>=', Eval('loaded_uls'))],
depends=['loaded_uls'])
domain=[If(Eval('quantity_check', []).contains('uls'),
('ul_quantity', '>=', Eval('loaded_uls')),
())],
depends=['loaded_uls', 'quantity_check'])
quantity_per_ul = fields.Function(
fields.Float('Quantity per UL', digits=(16, Eval('unit_digits', 0)),
depends=['unit_digits']),
@ -682,13 +734,19 @@ class LoadOrderLine(metaclass=PoolMeta):
'invisible': Eval('order_state') == 'done'
}, depends=['order_state'])
loaded_uls = fields.Function(fields.Float('Loaded ULs', digits=(16, 0)),
'get_loaded_uls')
'get_loaded_uls')
loaded_unit_loads = fields.Many2Many(
'carrier.load.order.line-stock.unit_load', 'load_line', 'unit_load',
'Loaded unit loads', readonly=True,
states={
'invisible': Eval('order_state') != 'done'
}, depends=['order_state'])
loaded_cases = fields.Function(
fields.Float("Loaded Cases", digits=cases_digits),
'get_loaded_cases')
cases_quantity = fields.Function(
fields.Float("Cases", digits=cases_digits),
'get_cases_quantity')
@fields.depends('quantity', 'ul_quantity', 'uom')
def on_change_with_quantity_per_ul(self, name=None):
@ -704,6 +762,30 @@ class LoadOrderLine(metaclass=PoolMeta):
def default_loaded_uls(cls):
return 0
@classmethod
def _quantity_check_selection(cls):
Configuration = Pool().get('carrier.configuration')
return Configuration.quantity_check.selection
def get_quantity_check(self, name=None):
pool = Pool()
Configuration = pool.get('carrier.configuration')
configuration = Configuration(1)
return configuration.quantity_check
def get_loaded_cases(self, name=None):
if self.order_state == 'done':
return sum([ul.cases_quantity for ul in self.loaded_unit_loads])
else:
return sum([ul.cases_quantity for ul in self.unit_loads])
def get_cases_quantity(self, name=None):
ul_cases = self.origin and getattr(
self.origin, 'ul_cases_quantity', 0) or 0
# we use origin.ul_cases_quantity instead origin.cases_quantity
# because we can define less ULs in load than origin
return round(ul_cases * self.ul_quantity, cases_digits[1])
def get_loaded_uls(self, name=None):
if self.order_state == 'done':
return len(self.loaded_unit_loads or [])

View File

@ -83,6 +83,10 @@ msgctxt "model:ir.message,text:msg_carrier_load_order_pending_uls"
msgid "You have loaded less ULs (%(uls)s) than expected (%(ul_quantity)s)."
msgstr "Ha cargado menos UdCs (%(uls)s) de las esperadas (%(ul_quantity)s)."
msgctxt "model:ir.message,text:msg_carrier_load_order_pending_cases"
msgid "You have loaded less Cases (%(loaded_cases)s) than expected (%(cases_quantity)s)."
msgstr "Ha cargado menos bultos (%(loaded_cases)s) de los esperados (%(cases_quantity)s)."
msgctxt "model:ir.message,text:msg_carrier_load_order_many_ul_locations"
msgid ""
"Cannot set \"From location\" in Internal shipment of Load Order \"%(order)s\" because Unit loads are in different locations."
@ -149,6 +153,10 @@ msgctxt "field:carrier.configuration,ul_origin_restrict:"
msgid "Restrict UL origin"
msgstr "Restringir origen UdC"
msgctxt "field:carrier.configuration,quantity_check:"
msgid "Quantity Check"
msgstr "Control de cantidad"
msgctxt "field:carrier.load,unit_loads:"
msgid "Unit loads"
msgstr "Unidades de carga"
@ -249,6 +257,14 @@ msgctxt "field:carrier.load.order.line,loaded_uls:"
msgid "Loaded ULs"
msgstr "UdCs cargadas"
msgctxt "field:carrier.load.order.line,quantity_check:"
msgid "Quantity Check"
msgstr "Control de cantidad"
msgctxt "field:carrier.load.order.line,loaded_cases:"
msgid "Loaded Cases"
msgstr "Bultos cargados"
msgctxt "field:carrier.load.order.line,quantity_per_ul:"
msgid "Quantity per UL"
msgstr "Cantidad por UdC"
@ -676,4 +692,12 @@ msgstr "Ordenes de carga"
msgctxt "model:ir.action,name:wizard_load_order_do_open"
msgid "Do Load Order and Open form"
msgstr "Finalizar Orden de cargay abrir formulario"
msgstr "Finalizar Orden de cargay abrir formulario"
msgctxt "selection:carrier.configuration,quantity_check:"
msgid "Cases"
msgstr "Bultos"
msgctxt "selection:carrier.configuration,quantity_check:"
msgid "ULs"
msgstr "UdCs"

View File

@ -64,6 +64,9 @@
<record model="ir.message" id="msg_carrier_load_order_pending_uls">
<field name="text">You have loaded less ULs (%(uls)s) than expected (%(ul_quantity)s).</field>
</record>
<record model="ir.message" id="msg_carrier_load_order_pending_cases">
<field name="text">You have loaded less Cases (%(loaded_cases)s) than expected (%(cases_quantity)s).</field>
</record>
<!-- carrier.load.order.line-stock.unit_load -->
<record model="ir.message" id="msg_carrier_load_order_line-stock_unit_load_load_line_ul_uniq">

View File

@ -70,6 +70,15 @@ Create payment term::
>>> payment_term = create_payment_term()
>>> payment_term.save()
Carrier Configuration::
>>> Configuration = Model.get('carrier.configuration')
>>> configuration = Configuration(1)
>>> configuration.quantity_check
['uls']
>>> configuration.quantity_check = ['uls', 'cases']
>>> configuration.save()
Create carrier::
>>> Carrier = Model.get('carrier')
@ -177,7 +186,6 @@ Create sale::
>>> sale_line.ul_quantity = 4.0
>>> sale_line.cases_quantity = 20
>>> sale.click('quote')
>>> import logging
>>> sale.click('confirm')
>>> sale.click('process')
Traceback (most recent call last):
@ -339,9 +347,19 @@ Finish loading::
...
trytond.exceptions.UserError: Cannot Process Sale "1" with ULs and undone loads. -
>>> start_load = Wizard('carrier.load_uls', [load_order])
>>> start_load.execute('pre_do')
Traceback (most recent call last):
...
trytond.exceptions.UserWarning: You have loaded less ULs (3) than expected (4). -
>>> Model.get('res.user.warning')(user=config.user,
... name='pending_uls_1', always=True).save()
>>> start_load.execute('pre_do')
Traceback (most recent call last):
...
trytond.exceptions.UserWarning: You have loaded less Cases (15.0) than expected (20.0). -
>>> Model.get('res.user.warning')(user=config.user,
... name='pending_cases_1', always=True).save()
>>> start_load.execute('pre_do')
>>> load_order.reload()
>>> len(load_order.unit_loads)
3

View File

@ -5,5 +5,7 @@ this repository contains the full copyright notices and license terms. -->
<xpath expr="/form/notebook/page[@id='general']" position="inside">
<label name="ul_origin_restrict"/>
<field name="ul_origin_restrict"/>
<label name="quantity_check"/>
<field name="quantity_check"/>
</xpath>
</data>