Skip to content

Commit

Permalink
[IMP] stock_barcodes: Add pending move with difference between demand…
Browse files Browse the repository at this point in the history
… and reserved
  • Loading branch information
carlosdauden committed Sep 29, 2024
1 parent 336497b commit cb20f75
Show file tree
Hide file tree
Showing 11 changed files with 379 additions and 202 deletions.
1 change: 1 addition & 0 deletions stock_barcodes/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from . import stock_barcodes_action
from . import stock_barcodes_option
from . import stock_move
from . import stock_move_line
from . import stock_picking
from . import stock_picking_type
Expand Down
37 changes: 37 additions & 0 deletions stock_barcodes/models/stock_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2024 Tecnativa - Sergio Teruel
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class StockMove(models.Model):
_inherit = "stock.move"

barcode_backorder_action = fields.Selection(
[
("pending", "Pending"),
("create_backorder", "Create Backorder"),
("skip_backorder", "No Backorder"),
],
string="Backorder action",
default="pending",
)

def _action_done(self, cancel_backorder=False):
moves_cancel_backorder = self.browse()
if not cancel_backorder:
moves_cancel_backorder = self.filtered(
lambda sm: sm.barcode_backorder_action == "skip_backorder"
)
super(StockMove, moves_cancel_backorder)._action_done(cancel_backorder=True)
moves_backorder = self - moves_cancel_backorder
moves_backorder.barcode_backorder_action = "pending"
return super(StockMove, moves_backorder)._action_done(
cancel_backorder=cancel_backorder
)

def copy_data(self, default=None):
vals_list = super().copy_data(default=default)
for vals in vals_list:
vals.pop("barcode_backorder_action", None)
return vals_list
18 changes: 6 additions & 12 deletions stock_barcodes/models/stock_move_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,13 @@ def _barcodes_process_line_to_unlink(self):

def action_barcode_detailed_operation_unlink(self):
for sml in self:
if sml.reserved_uom_qty:
sml._barcodes_process_line_to_unlink()
else:
sml.unlink()
stock_move = sml.move_id
stock_move.barcode_backorder_action = "pending"
sml.unlink()
# HACK: To force refresh wizard values
wiz_barcode = self.env["wiz.stock.barcodes.read.picking"].browse(
self.env.context.get("wiz_barcode_id", False)
)
if wiz_barcode.option_group_id.barcode_guided_mode == "guided":
wiz_barcode.todo_line_id.line_ids = wiz_barcode.todo_line_id.line_ids
if not any(wiz_barcode.todo_line_id.line_ids.mapped("qty_done")):
wiz_barcode.fill_todo_records()
wiz_barcode.determine_todo_action()
else:
wiz_barcode.fill_todo_records()
wiz_barcode.todo_line_id.line_ids = wiz_barcode.todo_line_id.line_ids
stock_move._action_assign()
wiz_barcode.fill_todo_records()
wiz_barcode.determine_todo_action()
42 changes: 8 additions & 34 deletions stock_barcodes/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Copyright 2019 Sergio Teruel <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models
from odoo.tools.float_utils import float_compare


class StockPicking(models.Model):
Expand Down Expand Up @@ -33,50 +32,25 @@ def action_barcode_scan(self, option_group=False):
wiz = self.env["wiz.stock.barcodes.read.picking"].create(
self._prepare_barcode_wiz_vals(option_group)
)
wiz.determine_todo_action()
wiz.fill_pending_moves()
wiz.determine_todo_action()
action = self.env["ir.actions.actions"]._for_xml_id(
"stock_barcodes.action_stock_barcodes_read_picking"
)
action["res_id"] = wiz.id
return action

def button_validate(self):
if (
self.picking_type_id.barcode_option_group_id.auto_put_in_pack
and not self.move_line_ids.mapped("result_package_id")
):
self.action_put_in_pack()
create_backorder = False
put_in_pack_picks = self.filtered(
lambda p: p.picking_type_id.barcode_option_group_id.auto_put_in_pack
and not p.move_line_ids.result_package_id
)
if put_in_pack_picks:
put_in_pack_picks.action_put_in_pack()
# Variable initialized as True to optimize break loop
skip_backorder = True
if self.env.context.get("stock_barcodes_validate_picking", False):
# Avoid backorder when all move lines are processed (done or done_forced)
prec = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
for move in self.move_ids.filtered(lambda sm: sm.state != "cancel"):
if (
float_compare(
move.quantity_done, move.product_uom_qty, precision_digits=prec
)
< 0
):
# In normal conditions backorder will be created
create_backorder = True
if not move.move_line_ids or any(
sml.barcode_scan_state in ["pending"]
for sml in move.move_line_ids
):
# If any move are not processed we can not skip backorder
skip_backorder = False
break
if create_backorder and skip_backorder:
res = super(
StockPicking,
self.with_context(
picking_ids_not_to_backorder=self.ids, skip_backorder=True
),
StockPicking, self.with_context(skip_backorder=True)
).button_validate()
else:
res = super().button_validate()
Expand Down
2 changes: 1 addition & 1 deletion stock_barcodes/models/stock_picking_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def action_barcode_scan(self):
):
vals["location_dest_id"] = self.default_location_dest_id.id
wiz = self.env["wiz.stock.barcodes.read.picking"].create(vals)
wiz.determine_todo_action()
wiz.fill_pending_moves()
wiz.determine_todo_action()
action = self.env["ir.actions.actions"]._for_xml_id(
"stock_barcodes.action_stock_barcodes_read_picking"
)
Expand Down
8 changes: 8 additions & 0 deletions stock_barcodes/tests/test_stock_barcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ def test_wizard_scan_package(self):
self.assertEqual(self.wiz_scan.product_qty, 15.0)
self.wiz_scan.manual_entry = False

# Force more than one package with the same lot
self.product_wo_tracking.packaging_ids.barcode = "5420008510489"
self.action_barcode_scanned(self.wiz_scan, "5420008510489")
self.assertEqual(
self.wiz_scan.message,
"5420008510489 (More than one package found)",
)

def test_wizard_scan_lot(self):
self.wiz_scan.location_id = self.location_1.id
self.wiz_scan.action_show_step()
Expand Down
57 changes: 37 additions & 20 deletions stock_barcodes/wizard/stock_barcodes_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging

from odoo import _, api, fields, models
from odoo.tools import float_round

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -64,9 +65,7 @@ class WizStockBarcodesRead(models.AbstractModel):
comodel_name="stock.barcodes.action", compute="_compute_action_ids"
)
option_group_id = fields.Many2one(comodel_name="stock.barcodes.option.group")
visible_force_done = fields.Boolean(
compute="_compute_visible_force_done", store=True, readonly=False
)
visible_force_done = fields.Boolean()
step = fields.Integer()
is_manual_qty = fields.Boolean(compute="_compute_is_manual_qty")
is_manual_confirm = fields.Boolean(compute="_compute_is_manual_qty")
Expand Down Expand Up @@ -134,6 +133,22 @@ def _compute_qty_available(self):
domain_quant, ["quantity"], [], orderby="id"
)
self.qty_available = groups[0]["quantity"]
# Unexpected done quantities must reduce qty_available
if self.lot_id:
done_move_lines = self.move_line_ids.filtered(
lambda m: m.product_id == self.product_id and m.lot_id == self.lot_id
)
else:
done_move_lines = self.move_line_ids.filtered(
lambda m: m.product_id == self.product_id
)
for sml in done_move_lines:
over_done_qty = float_round(
sml.qty_done - sml.reserved_uom_qty,
precision_rounding=sml.product_uom_id.rounding,
)
if over_done_qty > 0.0:
self.qty_available -= over_done_qty

@api.depends("product_id")
def _compute_display_assign_serial(self):
Expand All @@ -150,15 +165,15 @@ def onchange_packaging_qty(self):
if self.packaging_id:
self.product_qty = self.packaging_qty * self.packaging_id.qty

@api.depends(
@api.onchange(
"product_id",
"lot_id",
"package_id",
"result_package_id",
"packaging_qty",
"product_qty",
)
def _compute_visible_force_done(self):
def onchange_visible_force_done(self):
self.visible_force_done = False

def _set_messagge_info(self, message_type, message):
Expand Down Expand Up @@ -253,6 +268,8 @@ def process_barcode_lot_id(self):
"more_match",
_("No stock available for this lot with screen values"),
)
self.lot_id = False
self.lot_name = False
return False
if quants:
self.set_info_from_quants(quants)
Expand Down Expand Up @@ -366,8 +383,15 @@ def set_info_from_quants(self, quants):
def process_barcode_packaging_id(self):
domain = self._barcode_domain(self.barcode)
if self.env.user.has_group("product.group_stock_packaging"):
domain.append(("product_id", "!=", False))
packaging = self.env["product.packaging"].search(domain)
if packaging:
if len(packaging) > 1:
self._set_messagge_info(
"more_match", _("More than one package found")
)
self.packaging_id = False
return False
self.action_packaging_scaned_post(packaging)
return True
return False
Expand All @@ -389,14 +413,15 @@ def process_barcode(self, barcode):
option_func = getattr(self, "process_barcode_%s" % option.field_name, False)
if option_func:
res = option_func()
if option.required:
self.play_sounds(res)
if res:
barcode_found = True
self.play_sounds(barcode_found)
break
elif self.message_type != "success":
self.play_sounds(False)
return False
if not barcode_found:
self.play_sounds(barcode_found)
if self.option_group_id.ignore_filled_fields:
self._set_messagge_info(
"info", _("Barcode not found or field already filled")
Expand All @@ -405,12 +430,6 @@ def process_barcode(self, barcode):
self._set_messagge_info(
"not_found", _("Barcode not found with this screen values")
)
self.display_notification(
self.barcode,
message_type="danger",
title=_("Barcode not found"),
sticky=False,
)
return False
if not self.check_option_required():
return False
Expand Down Expand Up @@ -721,10 +740,13 @@ def onchange_package_id(self):

def action_confirm(self):
if not self.check_option_required():
self.play_sounds(False)
return False
record = self.browse(self.ids)
record.write(self._convert_to_write(self._cache))
self = record
res = self.action_done()
# self.invalidate_recordset()
self.refresh_data()
self.refresh()
self.play_sounds(res)
self._set_focus_on_qty_input()
return res
Expand Down Expand Up @@ -829,8 +851,3 @@ def display_notification(
"stock_barcodes_notify-{}".format(self.ids[0]),
message,
)

def refresh_data(self):
self.env["bus.bus"]._sendone(
"barcode_reload", "stock_barcodes_refresh_data", {}
)
Loading

0 comments on commit cb20f75

Please sign in to comment.