From b76cabdc87e0a46b8768700fb2fd0d2c82e2c851 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 21 Jul 2020 09:26:12 +0200 Subject: [PATCH] Add release (close) of vertical lift trays * Rename methods that fetch a tray to prevent confusion * Add methods to release a tray * The Kardex method to fetch a tray has to send "0" in the carrier and carrierNext field * The pick and inventory screens release the tray only when there is no next line, because the release is implicit when we fetch the next line, the put screen releases everytime because the operator may take time to start the next line and we don't know if they are going to scan a next line or not. * Exiting the screen or switching screen between put/pick/put-away has to release the tray as well. --- .../models/stock_location.py | 32 +++------- .../models/vertical_lift_shuttle.py | 64 +++++++++++++++++++ 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/stock_vertical_lift_kardex/models/stock_location.py b/stock_vertical_lift_kardex/models/stock_location.py index ef7379f7c..3b089845b 100644 --- a/stock_vertical_lift_kardex/models/stock_location.py +++ b/stock_vertical_lift_kardex/models/stock_location.py @@ -11,25 +11,13 @@ _logger = logging.getLogger(__name__) class StockLocation(models.Model): _inherit = "stock.location" - def _hardware_kardex_prepare_payload(self, cell_location=None): + def _hardware_kardex_prepare_fetch_payload(self, cell_location=None): if self.level is False: raise exceptions.UserError( _("Shuttle tray %s has no level. " "Please fix the configuration") % self.display_name ) - message_template = ( - "{code}|{hostId}|{addr}|{carrier}|{carrierNext}|" - "{x}|{y}|{boxType}|{Q}|{order}|{part}|{desc}|\r\n" - ) shuttle = self.vertical_lift_shuttle_id - if shuttle.mode == "pick": - code = "1" - elif shuttle.mode == "put": - code = "2" - elif shuttle.mode == "inventory": - code = "5" - else: - code = "61" # ping if cell_location: x, y = cell_location.tray_cell_center_position() if x == 0 and y == 0: @@ -45,7 +33,7 @@ class StockLocation(models.Model): else: x, y = "", "" subst = { - "code": code, + "code": shuttle._kardex_shuttle_code(), "hostId": self.env["ir.sequence"].next_by_code("vertical.lift.command"), # hard code the gate for now. # TODO proper handling of multiple gates for 1 lift. @@ -60,11 +48,10 @@ class StockLocation(models.Model): "part": "", "desc": "", } - payload = message_template.format(**subst) - return payload.encode("iso-8859-1", "replace") + return shuttle._hardware_kardex_format_template(subst) - def _hardware_vertical_lift_tray_payload(self, cell_location=None): - """Prepare the message to be sent to the vertical lift hardware + def _hardware_vertical_lift_fetch_tray_payload(self, cell_location=None): + """Prepare "fetch" message to be sent to the vertical lift hardware Private method, this is where the implementation actually happens. Addons can add their instructions based on the hardware used for @@ -100,11 +87,12 @@ class StockLocation(models.Model): highlighting the cell using a laser pointer. """ if self.vertical_lift_shuttle_id.hardware == "kardex": - payload = self._hardware_kardex_prepare_payload(cell_location=cell_location) - _logger.debug("Sending to kardex: {}", payload) - # TODO implement the communication with kardex + payload = self._hardware_kardex_prepare_fetch_payload( + cell_location=cell_location + ) + _logger.debug("Sending to kardex (fetch): {}", payload) else: - payload = super()._hardware_vertical_lift_tray_payload( + payload = super()._hardware_vertical_lift_fetch_tray_payload( cell_location=cell_location ) return payload diff --git a/stock_vertical_lift_kardex/models/vertical_lift_shuttle.py b/stock_vertical_lift_kardex/models/vertical_lift_shuttle.py index 7d0d81fd5..305e1eeeb 100644 --- a/stock_vertical_lift_kardex/models/vertical_lift_shuttle.py +++ b/stock_vertical_lift_kardex/models/vertical_lift_shuttle.py @@ -1,8 +1,13 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + from odoo import models +_logger = logging.getLogger(__name__) + + JMIF_STATUS = { 0: "success", 101: "common error", @@ -29,6 +34,65 @@ class VerticalLiftShuttle(models.Model): values += [("kardex", "Kardex")] return values + _kardex_message_template = ( + "{code}|{hostId}|{addr}|{carrier}|{carrierNext}|" + "{x}|{y}|{boxType}|{Q}|{order}|{part}|{desc}|\r\n" + ) + + def _hardware_kardex_format_template(self, values): + payload = self._kardex_message_template.format(**values) + return payload.encode("iso-8859-1", "replace") + + def _kardex_shuttle_code(self): + mapping = {"pick": "1", "put": "2", "inventory": "5"} + ping = "61" + return mapping.get(self.mode, ping) + + def _hardware_kardex_prepare_release_payload(self): + subst = { + "code": self._kardex_shuttle_code(), + "hostId": self.env["ir.sequence"].next_by_code("vertical.lift.command"), + # hard code the gate for now. + "addr": self.name + "-1", + "carrier": "0", + "carrierNext": "0", + "x": "0", + "y": "0", + "boxType": "", + "Q": "", + "order": "", + "part": "", + "desc": "", + } + return self._hardware_kardex_format_template(subst) + + def _hardware_vertical_lift_release_tray_payload(self): + """Prepare "release" message to be sent to the vertical lift hardware + + Private method, this is where the implementation actually happens. + Addons can add their instructions based on the hardware used for + this location. + + The hardware used for a location can be found in: + + ``self.vertical_lift_shuttle_id.hardware`` + + Each addon can implement its own mechanism depending of this value + and must call ``super``. + + The method must send the command to the vertical lift to release (close) + the tray. + + Returns a message in bytes, that will be sent through + ``VerticalLiftShuttle._hardware_send_message()``. + """ + if self.hardware == "kardex": + payload = self._hardware_kardex_prepare_release_payload() + _logger.debug("Sending to kardex (release): {}", payload) + else: + payload = super()._hardware_vertical_lift_release_tray_payload() + return payload + def _check_server_response(self, command): response = command.answer code, sep, remaining = response.partition("|")