Skip to content

Commit

Permalink
Merge pull request OCA#27 from sebalix/13.0-shopfloor-location-conten…
Browse files Browse the repository at this point in the history
…t-transfer

[13.0][IMP] shopfloor: location content transfer
  • Loading branch information
simahawk authored Jul 16, 2020
2 parents 74342ea + 4956baf commit b803cde
Show file tree
Hide file tree
Showing 22 changed files with 2,883 additions and 49 deletions.
1 change: 1 addition & 0 deletions shopfloor/actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from . import data
from . import data_detail
from . import completion_info
from . import location_content_transfer_sorter
from . import message
from . import search
from . import inventory
29 changes: 29 additions & 0 deletions shopfloor/actions/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,35 @@ def _move_line_parser(self):
("location_dest_id:location_dest", self._location_parser),
]

def package_level(self, record, **kw):
return self._jsonify(record, self._package_level_parser)

def package_levels(self, records, **kw):
return [self.package_level(rec, **kw) for rec in records]

@property
def _package_level_parser(self):
return [
"id",
"is_done",
("package_id:package_src", self._package_parser),
("location_dest_id:location_dest", self._location_parser),
(
"location_id:location_src",
lambda rec, fname: self.location(rec.picking_id.location_id),
),
# tnx to stock_quant_package_product_packaging
(
"package_id:product",
lambda rec, fname: self.product(rec.package_id.single_product_id),
),
# TODO: allow to pass mapped path to base_jsonify
(
"package_id:quantity",
lambda rec, fname: rec.package_id.single_product_qty,
),
]

def product(self, record, **kw):
return self._jsonify(record, self._product_parser, **kw)

Expand Down
60 changes: 60 additions & 0 deletions shopfloor/actions/location_content_transfer_sorter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from odoo.addons.component.core import Component


class LocationContentTransferSorter(Component):

_name = "shopfloor.location.content.transfer.sorter"
_inherit = "shopfloor.process.action"
_usage = "location_content_transfer.sorter"

def __init__(self, work_context):
super().__init__(work_context)
self._pickings = self.env["stock.picking"].browse()
self._content = None

def feed_pickings(self, pickings):
self._pickings |= pickings

def move_lines(self):
return self._pickings.move_line_ids.filtered(
# lines without package level only (raw products)
lambda line: not line.package_level_id
and line.state not in ("cancel", "done")
)

def package_levels(self):
return self._pickings.package_level_ids.filtered(
lambda level: level.state not in ("cancel", "done")
)

@staticmethod
def _sort_key(content):
# content can be either a move line, either a package
# level
return (
# postponed content after other contents
int(content.shopfloor_postponed),
# sort by shopfloor picking sequence
content.location_dest_id.shopfloor_picking_sequence,
# sort by similar destination
content.location_dest_id.complete_name,
# lines before packages (if we have raw products and packages, raw
# will be on top? wild guess)
0 if content._name == "stock.move.line" else 1,
# to have a deterministic sort
content.id,
)

def sort(self):
content = [line for line in self.move_lines()] + [
level for level in self.package_levels()
]
self._content = sorted(content, key=self._sort_key)

def __iter__(self):
if self._content is None:
self.sort()
return iter(self._content)

def __next__(self):
return next(iter(self))
32 changes: 32 additions & 0 deletions shopfloor/actions/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,20 @@ def transfer_complete(self, picking):
"body": _("Transfer {} complete").format(picking.name),
}

def location_content_transfer_item_complete(self, location_dest):
return {
"message_type": "success",
"body": _("Content transfer to {} completed").format(location_dest.name),
}

def location_content_transfer_complete(self, location):
return {
"message_type": "success",
"body": _("Location Content Transfer from {} complete").format(
location.name
),
}

def transfer_confirm_done(self):
return {
"message_type": "warning",
Expand All @@ -315,3 +329,21 @@ def transfer_no_qty_done(self):
"No quantity has been processed, unable to complete the transfer."
),
}

def recovered_previous_session(self):
return {
"message_type": "info",
"body": _("Recovered previous session."),
}

def no_lines_to_process(self):
return {
"message_type": "info",
"body": _("No lines to process."),
}

def location_empty(self, location):
return {
"message_type": "info",
"body": _("Location {} empty").format(location.name),
}
10 changes: 10 additions & 0 deletions shopfloor/demo/shopfloor_menu_demo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@
eval="[(4, ref('shopfloor.picking_type_delivery_demo'))]"
/>
</record>
<record id="shopfloor_menu_location_content_transfer" model="shopfloor.menu">
<field name="name">Location Content Transfer</field>
<field name="sequence">60</field>
<field name="allow_move_create" eval="1" />
<field name="scenario">location_content_transfer</field>
<field
name="picking_type_ids"
eval="[(4, ref('shopfloor.picking_type_location_content_transfer_demo'))]"
/>
</record>
</odoo>
15 changes: 15 additions & 0 deletions shopfloor/demo/stock_picking_type_demo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,19 @@
<field name="show_operations" eval="1" />
<field name="display_completion_info" eval="1" />
</record>
<record id="picking_type_location_content_transfer_demo" model="stock.picking.type">
<field name="name">Location Content Transfer</field>
<field name="sequence_code">LCT</field>
<field name="sequence" eval="10" />
<field name="warehouse_id" ref="stock.warehouse0" />
<field name="default_location_src_id" ref="stock.stock_location_stock" />
<field name="default_location_dest_id" ref="stock.stock_location_stock" />
<field name="show_entire_packs" eval="1" />
<field name="use_create_lots" eval="0" />
<field name="use_existing_lots" eval="1" />
<field name="color" eval="5" />
<field name="code">internal</field>
<field name="show_operations" eval="1" />
<field name="display_completion_info" eval="1" />
</record>
</odoo>
6 changes: 5 additions & 1 deletion shopfloor/models/shopfloor_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ class ShopfloorMenu(models.Model):
_description = "Menu displayed in the scanner application"
_order = "sequence"

_scenario_allowing_create_moves = ("single_pack_transfer",)
_scenario_allowing_create_moves = (
"single_pack_transfer",
"location_content_transfer",
)

name = fields.Char(translate=True)
sequence = fields.Integer()
Expand Down Expand Up @@ -37,6 +40,7 @@ def _selection_scenario(self):
("cluster_picking", "Cluster Picking"),
("checkout", "Checkout/Packing"),
("delivery", "Delivery"),
("location_content_transfer", "Location Content Transfer"),
]

@api.depends("scenario", "picking_type_ids")
Expand Down
9 changes: 8 additions & 1 deletion shopfloor/models/stock_package_level.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
from odoo import models
from odoo import fields, models


class StockPackageLevel(models.Model):
_inherit = "stock.package_level"

shopfloor_postponed = fields.Boolean(
default=False,
copy=False,
help="Technical field. "
"Indicates if a the package level has been postponed in a barcode scenario.",
)

def replace_package(self, new_package):
"""Replace a package on an assigned package level and related records
Expand Down
6 changes: 6 additions & 0 deletions shopfloor/models/stock_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ def _calc_weight(self):
for move_line in self.mapped("move_line_ids"):
weight += move_line.product_qty * move_line.product_id.weight
return weight

def _create_backorder(self):
if self.env.context.get("_sf_no_backorder"):
return self.browse()
else:
return super()._create_backorder()
1 change: 1 addition & 0 deletions shopfloor/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
from . import checkout
from . import cluster_picking
from . import delivery
from . import location_content_transfer
from . import single_pack_transfer
58 changes: 43 additions & 15 deletions shopfloor/services/checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ def scan_line(self, picking_id, barcode):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

search = self.actions_for("search")

Expand Down Expand Up @@ -457,7 +459,9 @@ def select_line(self, picking_id, package_id=None, move_line_id=None):

picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

selection_lines = self._lines_to_pack(picking)
if not selection_lines:
Expand All @@ -475,7 +479,9 @@ def _change_line_qty(
):
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

move_lines = self.env["stock.move.line"].browse(move_line_ids).exists()

Expand Down Expand Up @@ -669,7 +675,9 @@ def scan_package_action(self, picking_id, selected_line_ids, barcode):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
search = self.actions_for("search")

selected_lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
Expand Down Expand Up @@ -718,7 +726,9 @@ def new_package(self, picking_id, selected_line_ids):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
selected_lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
return self._create_and_assign_new_packaging(picking, selected_lines)

Expand All @@ -734,7 +744,9 @@ def no_package(self, picking_id, selected_line_ids):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
selected_lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
selected_lines.write(
{"shopfloor_checkout_done": True, "result_package_id": False}
Expand All @@ -759,7 +771,9 @@ def list_dest_package(self, picking_id, selected_line_ids):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
return self._response_for_select_dest_package(picking, lines)
Expand Down Expand Up @@ -797,7 +811,9 @@ def scan_dest_package(self, picking_id, selected_line_ids, barcode):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
search = self.actions_for("search")
package = search.package_from_scan(barcode)
Expand All @@ -817,7 +833,9 @@ def set_dest_package(self, picking_id, selected_line_ids, package_id):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
package = self.env["stock.quant.package"].browse(package_id).exists()
return self._set_dest_package_from_selection(picking, lines, package)
Expand All @@ -830,7 +848,9 @@ def summary(self, picking_id):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
return self._response_for_summary(picking)

def _get_allowed_packaging(self):
Expand All @@ -848,7 +868,9 @@ def list_packaging(self, picking_id, package_id):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

package = self.env["stock.quant.package"].browse(package_id).exists()
packaging_list = self._get_allowed_packaging()
Expand All @@ -863,7 +885,9 @@ def set_packaging(self, picking_id, package_id, packaging_id):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

package = self.env["stock.quant.package"].browse(package_id).exists()
packaging = self.env["product.packaging"].browse(packaging_id).exists()
Expand Down Expand Up @@ -898,7 +922,9 @@ def cancel_line(self, picking_id, package_id=None, line_id=None):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)

package = self.env["stock.quant.package"].browse(package_id).exists()
line = self.env["stock.move.line"].browse(line_id).exists()
Expand Down Expand Up @@ -941,7 +967,9 @@ def done(self, picking_id, confirmation=False):
"""
picking = self.env["stock.picking"].browse(picking_id)
if not picking.exists():
return self._response_stock_picking_does_not_exist()
return self._response_for_select_document(
message=self.msg_store.stock_picking_not_found()
)
lines = picking.move_line_ids
if not confirmation:
if not all(line.qty_done == line.product_uom_qty for line in lines):
Expand Down Expand Up @@ -1167,7 +1195,7 @@ def _schema_stock_picking(self, lines_with_packaging=False):
{
"move_lines": self.schemas._schema_list_of(
self.schemas.move_line(with_packaging=lines_with_packaging)
),
)
}
)
return {"picking": self.schemas._schema_dict_of(schema, required=True)}
Expand Down
Loading

0 comments on commit b803cde

Please sign in to comment.