mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] add a proxy to communicate with the kardex server
This commit is contained in:
committed by
Hai Lang
parent
cf5848c2c3
commit
68e10cd503
@@ -1 +1,2 @@
|
||||
from . import models
|
||||
from . import controllers
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
'views/stock_vertical_lift_templates.xml',
|
||||
'views/shuttle_screen_templates.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/ir_sequence.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'development_status': 'Alpha',
|
||||
|
||||
1
stock_vertical_lift/controllers/__init__.py
Normal file
1
stock_vertical_lift/controllers/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import main
|
||||
20
stock_vertical_lift/controllers/main.py
Normal file
20
stock_vertical_lift/controllers/main.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VerticalLiftController(http.Controller):
|
||||
@http.route(['/vertical-lift'], type='http', auth='public', csrf=False)
|
||||
def vertical_lift(self, answer, secret):
|
||||
if secret == os.environ.get('VERTICAL_LIFT_SECRET', ''):
|
||||
rec = request.env['vertical.lift.command'].sudo().record_answer(
|
||||
answer
|
||||
)
|
||||
return str(rec.id)
|
||||
else:
|
||||
_logger.error('secret mismatch: %r != %r', secret, os.environ.get('VERTICAL_LIFT_SECRET', ''))
|
||||
raise http.AuthenticationError()
|
||||
12
stock_vertical_lift/data/ir_sequence.xml
Normal file
12
stock_vertical_lift/data/ir_sequence.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record model="ir.sequence" id="sequence_kardex_command">
|
||||
<field name="name">Vertical Lift Commands</field>
|
||||
<field name="code">vertical.lift.command</field>
|
||||
<field name="prefix">L</field>
|
||||
<field name="padding">6</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -8,3 +8,4 @@ from . import stock_location
|
||||
from . import stock_move
|
||||
from . import stock_move_line
|
||||
from . import stock_quant
|
||||
from . import vertical_lift_command
|
||||
|
||||
@@ -127,7 +127,7 @@ class StockLocation(models.Model):
|
||||
)
|
||||
return message
|
||||
else:
|
||||
return super()._hardware_vertical_lift_tray_payload(cell_location)
|
||||
raise NotImplemented()
|
||||
|
||||
def fetch_vertical_lift_tray(self, cell_location=None):
|
||||
"""Send instructions to the vertical lift hardware
|
||||
|
||||
50
stock_vertical_lift/models/vertical_lift_command.py
Normal file
50
stock_vertical_lift/models/vertical_lift_command.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright 2019 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
|
||||
from odoo import api, exceptions, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VerticalLiftCommand(models.Model):
|
||||
_name = 'vertical.lift.command'
|
||||
_order = 'shuttle_id, name desc'
|
||||
_description = "commands sent to the shuttle"
|
||||
|
||||
@api.model
|
||||
def _default_name(self):
|
||||
return self.env['ir.sequence'].next_by_code('vertical.lift.command')
|
||||
|
||||
name = fields.Char(
|
||||
'Name', default=_default_name, required=True, index=True
|
||||
)
|
||||
command = fields.Char(required=True)
|
||||
answer = fields.Char()
|
||||
error = fields.Char()
|
||||
shuttle_id = fields.Many2one('vertical.lift.shuttle', required=True)
|
||||
|
||||
@api.model
|
||||
def record_answer(self, answer):
|
||||
name = self._get_key(answer)
|
||||
record = self.search([('name', '=', name)], limit=1)
|
||||
if not record:
|
||||
_logger.error('unable to match answer to a command: %r', answer)
|
||||
raise exceptions.UserError('Unknown record %s' % name)
|
||||
record.answer = answer
|
||||
record.shuttle_id._hardware_response_callback(record)
|
||||
return record
|
||||
|
||||
def _get_key(self, answer):
|
||||
key = answer.split('|')[1]
|
||||
return key
|
||||
|
||||
@api.model_create_multi
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def create(self, vals_list):
|
||||
for values in vals_list:
|
||||
if "name" not in values:
|
||||
name = self._get_key(values.get('command'))
|
||||
if name:
|
||||
values["name"] = name
|
||||
return super().create(vals_list)
|
||||
@@ -38,7 +38,10 @@ class VerticalLiftShuttle(models.Model):
|
||||
use_tls = fields.Boolean(
|
||||
help="set this if the server expects TLS wrapped communication"
|
||||
)
|
||||
|
||||
command_ids = fields.One2many(
|
||||
'vertical.lift.command', 'shuttle_id',
|
||||
string="Hardware commands"
|
||||
)
|
||||
_sql_constraints = [
|
||||
(
|
||||
"location_id_unique",
|
||||
@@ -81,14 +84,21 @@ class VerticalLiftShuttle(models.Model):
|
||||
|
||||
If in hardware is 'simulation' then display a simple message.
|
||||
Otherwise defaults to connecting to server:port using a TCP socket
|
||||
(optionnally wrapped with TLS) and sending the payload, then waiting
|
||||
for a response and disconnecting.
|
||||
(optionnally wrapped with TLS) and sending the payload.
|
||||
|
||||
:param payload: a bytes object containing the payload
|
||||
|
||||
"""
|
||||
self.ensure_one()
|
||||
_logger.info('send %r', payload)
|
||||
command_values = {
|
||||
'shuttle_id': self.id,
|
||||
'command': payload.decode(),
|
||||
}
|
||||
|
||||
self.env['vertical.lift.command'].sudo().create(
|
||||
command_values
|
||||
)
|
||||
if self.hardware == "simulation":
|
||||
self.env.user.notify_info(message=payload,
|
||||
title=_("Lift Simulation"))
|
||||
@@ -102,28 +112,18 @@ class VerticalLiftShuttle(models.Model):
|
||||
offset += size
|
||||
if offset >= len(payload) or not size:
|
||||
break
|
||||
response = self._hardware_recv_response(conn)
|
||||
_logger.info('recv %r', response)
|
||||
return self._check_server_response(payload, response)
|
||||
finally:
|
||||
self._hardware_release_server_connection(conn)
|
||||
|
||||
def _hardware_recv_response(self, conn):
|
||||
"""Default implementation expects the remote server to close()
|
||||
the socket after sending the reponse.
|
||||
Override to match the protocol implemented by the hardware.
|
||||
def _hardware_response_callback(self, command):
|
||||
"""should be called when a response is received from the hardware
|
||||
|
||||
:param conn: a socket connected to the server
|
||||
:return: the response sent by the server, as a bytes object
|
||||
:param response: a string
|
||||
"""
|
||||
response = b''
|
||||
chunk = True
|
||||
while chunk:
|
||||
chunk = conn.recv(1024)
|
||||
response += chunk
|
||||
return response
|
||||
success = self._check_server_response(command)
|
||||
self._send_notification_refresh(success)
|
||||
|
||||
def _check_server_response(self, payload, response):
|
||||
def _check_server_response(self, command):
|
||||
"""Use this to check if the response is a success or a failure
|
||||
|
||||
:param payload: the payload sent
|
||||
@@ -214,7 +214,7 @@ class VerticalLiftShuttle(models.Model):
|
||||
self.mode = "inventory"
|
||||
return self.action_open_screen()
|
||||
|
||||
def _send_notification_refresh(self):
|
||||
def _send_notification_refresh(self, success):
|
||||
"""Send a refresh notification to the current opened screen
|
||||
|
||||
The form controller on the front-end side will instantaneously
|
||||
@@ -226,7 +226,8 @@ class VerticalLiftShuttle(models.Model):
|
||||
The method is private only to prevent xml/rpc calls to
|
||||
interact with the screen.
|
||||
"""
|
||||
self._operation_for_mode._send_notification_refresh()
|
||||
# XXX do we want to do something special in the notification?
|
||||
self._operation_for_mode()._send_notification_refresh()
|
||||
|
||||
|
||||
class VerticalLiftShuttleManualBarcode(models.TransientModel):
|
||||
|
||||
@@ -5,3 +5,4 @@ access_vertical_lift_operation_pick_stock_user,access_vertical_lift_operation_pi
|
||||
access_vertical_lift_operation_put_stock_user,access_vertical_lift_operation_put stock user,model_vertical_lift_operation_put,stock.group_stock_user,1,1,1,1
|
||||
access_vertical_lift_operation_put_line_stock_user,access_vertical_lift_operation_put_line stock user,model_vertical_lift_operation_put_line,stock.group_stock_user,1,1,1,1
|
||||
access_vertical_lift_operation_inventory_stock_user,access_vertical_lift_operation_inventory stock user,model_vertical_lift_operation_inventory,stock.group_stock_user,1,1,1,1
|
||||
access_vertical_lift_command,vertical_lift_command,model_vertical_lift_command,base.group_user,1,0,0,0
|
||||
|
||||
|
@@ -71,6 +71,18 @@
|
||||
<field name="use_tls"/>
|
||||
</group>
|
||||
</group>
|
||||
<group groups="base.group_no_one">
|
||||
<label for="command_ids"/>
|
||||
<field name="command_ids">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="command"/>
|
||||
<field name="answer"/>
|
||||
<field name="error"/>
|
||||
<field name="create_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user