Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a9daf1b
[REF] shopfloor_reception_mobile: relocate date-picker-input for bett…
nicolas-delbovier-acsone Jan 28, 2026
a8fdb26
[REF] shopfloor_reception: better lot handling.
nicolas-delbovier-acsone Feb 3, 2026
2685314
[REF] shopfloor_reception: adapt test suite to "set_lot" refactoring
nicolas-delbovier-acsone Feb 3, 2026
a2d4f1d
[IMP] shopfloor_reception: pass product.use_expiration_date value to …
nicolas-delbovier-acsone Feb 6, 2026
8b39c07
[REF] shopfloor_reception_mobile: buffer lot inputs in UI
nicolas-delbovier-acsone Feb 3, 2026
2757b3e
[FIX] shopfloor: decouple unit tests from product serialization
nicolas-delbovier-acsone Feb 11, 2026
5666555
[IMP] shopfloor_reception: add scan_lot_name endpoint.
nicolas-delbovier-acsone Feb 11, 2026
5718c48
[IMP] shopfloor_reception_mobile: call "scan_lot_name" endpoint on lo…
nicolas-delbovier-acsone Feb 9, 2026
cc8a356
[IMP] shopfloor_reception: extract expiration date from barcode on lo…
nicolas-delbovier-acsone Feb 12, 2026
7bb5cb9
[FIX] shopfloor_reception: persist lot_name on validation error
nicolas-delbovier-acsone Feb 11, 2026
8898384
[IMP] shopfloor_reception: add missing unit test
nicolas-delbovier-acsone Feb 12, 2026
6c7d5d3
[FIX] shopfloor_reception_mobile: normalize lot expiration dates to UTC
nicolas-delbovier-acsone Feb 12, 2026
11c7554
[IMP] shopfloor_reception_mobile: hide time from lot expiration date …
nicolas-delbovier-acsone Feb 12, 2026
80ac0c0
[IMP] shopfloor_reception_mobile: add red color for past lot expirati…
nicolas-delbovier-acsone Feb 12, 2026
326d52e
[REF] shopfloor_reception_mobile: use refactored/improved date-picker…
nicolas-delbovier-acsone Apr 9, 2026
9cc9c19
[FIX] shopfloor_reception: align component method naming and fix docs…
nicolas-delbovier-acsone Feb 18, 2026
742bf10
[IMP] shopfloor_reception: use ISO format for lot expiration date
nicolas-delbovier-acsone Feb 23, 2026
f572a05
[IMP] shopfloor_reception_mobile: use ISO format for lot expiration date
nicolas-delbovier-acsone Feb 23, 2026
4ad6044
[IMP] shopfloor_reception: prevent user from changing an existing exp…
nicolas-delbovier-acsone Feb 23, 2026
517a9e4
[FIX] shopfloor_reception: fix Python 3.10 compatibility
nicolas-delbovier-acsone Feb 24, 2026
dc9f223
[FIX] shopfloor_reception: enforce lot creation restriction
nicolas-delbovier-acsone Feb 24, 2026
3cbc611
[FIX] shopfloor_reception_mobile: bind cancel event in 'set quantity'…
nicolas-delbovier-acsone Feb 24, 2026
0e3219d
[IMP] shopfloor_reception: clear lot when canceling in "set_quantity"
nicolas-delbovier-acsone Feb 24, 2026
7f7d846
[IMP] shopfloor_reception: prioritize lot_id over lot_name for state …
nicolas-delbovier-acsone Feb 24, 2026
e6ed38a
[IMP] shopfloor_reception: resolve lot record from name for UI pre-fill
nicolas-delbovier-acsone Feb 24, 2026
055f42f
[IMP] shopfloor_reception: auto-confirm lot when data is found in scan
nicolas-delbovier-acsone Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 1 addition & 17 deletions shopfloor/tests/test_actions_data_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,23 +120,7 @@ def _expected_location(self, record, **kw):
return data

def _expected_product(self, record, **kw):
data = {
"id": record.id,
"name": record.name,
"display_name": record.display_name,
"default_code": record.default_code,
"barcode": record.barcode,
"packaging": [
self._expected_packaging(x) for x in record.packaging_ids if x.qty
],
"uom": {
"factor": record.uom_id.factor,
"id": record.uom_id.id,
"name": record.uom_id.name,
"rounding": record.uom_id.rounding,
},
"supplier_code": self._expected_supplier_code(record),
}
data = self.data._jsonify(record, self.data._product_parser)
data.update(kw)
return data

Expand Down
2 changes: 1 addition & 1 deletion shopfloor_reception/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from . import services, models
from . import services, models, actions
from .hooks import post_init_hook, uninstall_hook
4 changes: 4 additions & 0 deletions shopfloor_reception/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import data
from . import schema
from . import message
from . import stock
51 changes: 51 additions & 0 deletions shopfloor_reception/actions/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2026 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo.addons.component.core import Component
from odoo.addons.shopfloor_base.utils import ensure_model


class DataAction(Component):
_inherit = "shopfloor.data.action"

@property
def _product_parser(self):
"""
The jsonifier engine passes (record, field_name) when calling
parser functions. We use *args to capture them.
"""
res = super(DataAction, self)._product_parser
return res + ["use_expiration_date"]

@property
def _lot_parser_reception(self):
return self._simple_record_parser() + [
"ref",
(
"expiration_date",
lambda rec, fname:
# Odoo Datetime fields are stored as naive UTC in the DB.
rec.expiration_date.isoformat() + "+00:00"
if rec.expiration_date
else None,
),
]

@ensure_model("stock.move.line")
def move_line(self, record, with_picking=False, **kw):
data = super().move_line(record, with_picking, **kw)

lot_data = {}
if lot := kw.get("lot"):
lot_data = self._jsonify(lot, self._lot_parser_reception)
else:
if lot_name := kw.get("lot_name"):
lot_data["name"] = lot_name
if lot_expiration_date := kw.get("lot_expiration_date"):
lot_data["expiration_date"] = lot_expiration_date.isoformat()

if lot_data:
data["lot"] = data.get("lot") or {}
data["lot"].update(lot_data)

return data
41 changes: 41 additions & 0 deletions shopfloor_reception/actions/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2025 ACSONE SA/NV (https://www.acsone.eu)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging

from odoo import _

from odoo.addons.component.core import Component

_logger = logging.getLogger(__name__)


class MessageAction(Component):
_inherit = "shopfloor.message.action"

def lot_already_exists_different_expiration_date(self, lot, expiration_date):
formatted_lot_expiration_date = self.work.env[
"ir.qweb.field.date"
].value_to_html(lot.expiration_date, {})
formatted_provided_expiration_date = self.work.env[
"ir.qweb.field.date"
].value_to_html(expiration_date, {})
return {
"message_type": "warning",
"body": _(
"A lot already exists with a different expiration date.\n\n"
"Lot '%(lot_name)s' expiration date: %(current)s "
"!= provided expiration date: %(provided)s",
lot_name=lot.name,
current=formatted_lot_expiration_date,
provided=formatted_provided_expiration_date,
),
}

def lot_creation_disabled(self, picking_type):
return {
"message_type": "error",
"body": _(
"The operation type '%(picking_type)s' does not allow to create new lots.",
picking_type=picking_type.display_name,
),
}
32 changes: 32 additions & 0 deletions shopfloor_reception/actions/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2026 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.addons.component.core import Component


class ShopfloorSchemaAction(Component):
_inherit = "shopfloor.schema.action"

def product(self):
res = super().product()
res.update(
{
"use_expiration_date": {
"type": "boolean",
"nullable": True,
"required": False,
},
}
)
return res

def lot(self):
res = super().lot()

# We need to be able to send lot name and expiration date info
# for "virtual lot" not yet created -> not yet an id
res.update(
{
"id": {"required": False, "type": "integer"},
}
)
return res
12 changes: 12 additions & 0 deletions shopfloor_reception/actions/stock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from odoo.addons.component.core import Component


class StockAction(Component):
"""Provide methods to work with stock operations."""

_inherit = "shopfloor.stock.action"

def unmark_move_line_as_picked(self, move_lines):
res = super().unmark_move_line_as_picked(move_lines)
move_lines.write({"lot_id": False})
return res
Loading
Loading