Migrate stock_cubiscan to 13.0

This commit is contained in:
Guewen Baconnier
2020-01-09 14:34:27 +01:00
parent 4d1dd4a65f
commit fe4e921e4d
7 changed files with 92 additions and 93 deletions

View File

@@ -3,9 +3,9 @@
{
"name": "Stock Cubiscan",
"summary": "Implement inteface with Cubiscan devices for packaging",
"version": "12.0.1.0.0",
"category": "Stock",
"author": "Camptocamp",
"version": "13.0.1.0.0",
"category": "Warehouse",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",
"depends": [
"barcodes",
@@ -14,7 +14,8 @@
"product_packaging_dimension",
"product_packaging_type_required",
],
"website": "http://www.camptocamp.com",
"external_dependencies": {"python": ["cubiscan"]},
"website": "https://github.com/OCA/stock-logistics-warehouse",
"data": [
"views/assets.xml",
"views/cubiscan_view.xml",

View File

@@ -25,23 +25,15 @@ class CubiscanDevice(models.Model):
[("not_ready", "Not Ready"), ("ready", "Ready")],
default="not_ready",
readonly=True,
copy=False,
)
@api.multi
@api.constrains("device_address", "port")
def _check_connection_infos(self):
self.ensure_one()
if not 1 <= self.port <= 65535:
raise ValidationError("Port must be in range 1-65535")
raise ValidationError(_("Port must be in range 1-65535"))
@api.multi
def copy(self, default=None):
if not default:
default = dict()
default["state"] = "not_ready"
return super().copy(default)
@api.multi
def open_wizard(self):
self.ensure_one()
return {
@@ -50,18 +42,20 @@ class CubiscanDevice(models.Model):
"type": "ir.actions.act_window",
"view_id": False,
"view_mode": "form",
"view_type": "form",
"context": {"default_device_id": self.id},
"target": "fullscreen",
"flags": {
"headless": True,
"withControlPanel": False,
"form_view_initial_mode": "edit",
"no_breadcrumbs": True,
},
}
@api.multi
def _get_interface(self):
"""Return the CubiScan client
Can be overrided to customize the way it is instanciated
"""
self.ensure_one()
ctx = SSL.create_default_context()
ctx.load_cert_chain("/usr/lib/ssl/certs/camptocamp.pem")
@@ -69,8 +63,8 @@ class CubiscanDevice(models.Model):
ctx.verify_mode = SSL.CERT_NONE
return CubiScan(self.device_address, self.port, self.timeout, ssl=ctx)
@api.multi
def test_device(self):
"""Check connection with the Cubiscan device"""
for device in self:
res = device._get_interface().test()
if res and "error" not in res and device.state == "not_ready":
@@ -78,12 +72,14 @@ class CubiscanDevice(models.Model):
elif res and "error" in res and device.state == "ready":
device.state = "not_ready"
@api.multi
def get_measure(self):
"""Return a measure from the Cubiscan device"""
self.ensure_one()
if self.state != "ready":
raise UserError(
"Device is not ready. Please use the 'Test'"
" button before using the device."
_(
"Device is not ready. Please use the 'Test'"
" button before using the device."
)
)
return self._get_interface().measure()

View File

@@ -14,7 +14,8 @@ class StockWarehouse(models.Model):
class ProductPackaging(models.Model):
_inherit = "product.packaging"
# FIXME: Not sure this is still the best place for this constraint
# FIXME: move this constraint in product_packaging_type
# https://github.com/OCA/product-attribute/tree/13.0/product_packaging_type
_sql_constraints = [
(
"product_packaging_type_unique",

View File

@@ -1,7 +1,8 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# from cubiscan.cubiscan import CubiScan
# from mock import patch
from cubiscan.cubiscan import CubiScan
from mock import patch
from odoo.tests.common import SavepointCase
@@ -66,63 +67,56 @@ class TestCubiscanWizard(SavepointCase):
PackType.cron_check_create_required_packaging()
def test_product_onchange(self):
return
# self.wizard.product_id = self.product_1.id
self.wizard.product_id = self.product_1.id
# self.assertEqual(len(self.wizard.line_ids), 0)
# self.wizard.onchange_product_id()
# self.assertEqual(len(self.wizard.line_ids), 5)
self.assertEqual(len(self.wizard.line_ids), 0)
self.wizard.onchange_product_id()
self.assertEqual(len(self.wizard.line_ids), 6)
def test_product_onchange_barcode(self):
return
# self.assertFalse(self.wizard.product_id)
# self.assertFalse(self.wizard.line_ids)
self.assertFalse(self.wizard.product_id)
self.assertFalse(self.wizard.line_ids)
# self.wizard.on_barcode_scanned('424242')
self.wizard.on_barcode_scanned("424242")
# self.assertEqual(self.wizard.product_id, self.product_1)
# self.assertEqual(len(self.wizard.line_ids), 5)
self.assertEqual(self.wizard.product_id, self.product_1)
self.assertEqual(len(self.wizard.line_ids), 6)
def test_cubiscan_measures(self):
return
# self.wizard.product_id = self.product_1.id
# self.wizard.onchange_product_id()
self.wizard.product_id = self.product_1.id
self.wizard.onchange_product_id()
# with patch.object(CubiScan, '_make_request') as request:
# for idx, line in enumerate(self.wizard.line_ids):
# request.return_value = TestCubiscanWizard.get_measure_result(
# 2 ** idx, 1, 1, 2 ** idx
# )
# line.cubiscan_measure()
# self.assertEqual(
# line.read(
# ['length', 'width', 'height', 'max_weight', 'volume']
# )[0],
# {
# 'id': line.id,
# 'length': (2 ** idx) * 1000,
# 'width': 1000,
# 'height': 1000,
# 'max_weight': 2.0 ** idx,
# 'volume': 2.0 ** idx,
# },
# )
with patch.object(CubiScan, "_make_request") as request:
for idx, line in enumerate(self.wizard.line_ids):
request.return_value = TestCubiscanWizard.get_measure_result(
2 ** idx, 1, 1, 2 ** idx
)
line.cubiscan_measure()
self.assertEqual(
line.read(["lngth", "width", "height", "max_weight", "volume"])[0],
{
"id": line.id,
"lngth": (2 ** idx) * 1000,
"width": 1000,
"height": 1000,
"max_weight": 2.0 ** idx,
"volume": 2.0 ** idx,
},
)
# self.wizard.action_save()
self.wizard.action_save()
# packagings = self.product_1.packaging_ids
# self.assertEqual(len(packagings), 5)
# for idx, packaging in enumerate(packagings):
# self.assertEqual(
# packaging.read(
# ['length', 'width', 'height', 'max_weight', 'volume']
# )[0],
# {
# 'id': packaging.id,
# 'length': (2 ** idx) * 1000,
# 'width': 1000,
# 'height': 1000,
# 'max_weight': 2.0 ** idx,
# 'volume': 2.0 ** idx,
# },
# )
packagings = self.product_1.packaging_ids.sorted()
self.assertEqual(len(packagings), 6)
for idx, packaging in enumerate(packagings):
self.assertEqual(
packaging.read(["lngth", "width", "height", "max_weight", "volume"])[0],
{
"id": packaging.id,
"lngth": (2 ** idx) * 1000,
"width": 1000,
"height": 1000,
"max_weight": 2.0 ** idx,
"volume": 2.0 ** idx,
},
)

View File

@@ -46,7 +46,6 @@
<record id="action_cubiscan_device_form" model="ir.actions.act_window">
<field name="name">CubiScan Devices</field>
<field name="res_model">cubiscan.device</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>

View File

@@ -5,6 +5,11 @@ from odoo import _, api, fields, models
class CubiscanWizard(models.TransientModel):
"""This wizard is used to show a screen showing Cubiscan information
It is opened in a headless view (no breadcrumb, no menus, fullscreen).
"""
_name = "cubiscan.wizard"
_inherit = "barcodes.barcode_events_mixin"
_description = "Cubiscan Wizard"
@@ -33,7 +38,7 @@ class CubiscanWizard(models.TransientModel):
"name": pack_type.name,
"qty": 0,
"max_weight": 0,
"length": 0,
"lngth": 0,
"width": 0,
"height": 0,
"barcode": False,
@@ -44,7 +49,7 @@ class CubiscanWizard(models.TransientModel):
{
"qty": pack.qty,
"max_weight": pack.max_weight,
"length": pack.length,
"lngth": pack.lngth,
"width": pack.width,
"height": pack.height,
"barcode": pack.barcode,
@@ -58,7 +63,6 @@ class CubiscanWizard(models.TransientModel):
else:
self.line_ids = [(5, 0, 0)]
@api.multi
def action_reopen_fullscreen(self):
# Action to reopen wizard in fullscreen (e.g. after page refresh)
self.ensure_one()
@@ -75,14 +79,12 @@ class CubiscanWizard(models.TransientModel):
"target": "new",
}
@api.multi
def on_barcode_scanned(self, barcode):
self.ensure_one()
prod = self.env["product.product"].search([("barcode", "=", barcode)])
self.product_id = prod
self.onchange_product_id()
@api.multi
def action_save(self):
self.ensure_one()
actions = []
@@ -91,7 +93,7 @@ class CubiscanWizard(models.TransientModel):
"name": line.name,
"qty": line.qty,
"max_weight": line.max_weight,
"length": line.length,
"lngth": line.lngth,
"width": line.width,
"height": line.height,
"barcode": line.barcode,
@@ -103,8 +105,9 @@ class CubiscanWizard(models.TransientModel):
else:
actions.append((0, 0, vals))
self.product_id.packaging_ids = actions
# reload lines
self.onchange_product_id()
@api.multi
def action_close(self):
self.ensure_one()
action = self.env.ref("stock_cubiscan.action_cubiscan_device_form").read()[0]
@@ -134,7 +137,9 @@ class CubiscanWizardLine(models.TransientModel):
name = fields.Char("Packaging", readonly=True)
qty = fields.Float("Quantity")
max_weight = fields.Float("Weight (kg)", readonly=True)
length = fields.Integer("Length (mm)", readonly=True)
# this is not a typo:
# https://github.com/odoo/odoo/issues/41353#issuecomment-568037415
lngth = fields.Integer("Length (mm)", readonly=True)
width = fields.Integer("Width (mm)", readonly=True)
height = fields.Integer("Height (mm)", readonly=True)
volume = fields.Float(
@@ -151,20 +156,20 @@ class CubiscanWizardLine(models.TransientModel):
)
required = fields.Boolean(related="packaging_type_id.required", readonly=True)
@api.depends("length", "width", "height")
@api.depends("lngth", "width", "height")
def _compute_volume(self):
for line in self:
line.volume = (line.length * line.width * line.height) / 1000.0 ** 3
line.volume = (line.lngth * line.width * line.height) / 1000.0 ** 3
@api.multi
def cubiscan_measure(self):
self.ensure_one()
measures = self.wizard_id.device_id.get_measure()
# measures are a tuple of 2 slots (measure, precision error),
# we only care about the measure for now
measures = {
k: (v[0] if k in ["length", "width", "height", "weight"] else False)
for k, v in measures.items()
"lngth": int(measures["length"][0] * 1000),
"width": int(measures["width"][0] * 1000),
"height": int(measures["height"][0] * 1000),
"max_weight": measures["weight"][0],
}
weight = measures.pop("weight")
measures = {k: int(v * 1000) for k, v in measures.items()}
measures["max_weight"] = weight
self.write(measures)

View File

@@ -10,7 +10,10 @@
</header>
<group>
<group>
<field name="product_id" nolabel="1" options="{'no_open': True, 'create': False, 'create_edit': False}" />
<label for="device_id" />
<field name="device_id" nolabel="1" options="{'no_open': True, 'no_create_edit': True}" />
<label for="product_id" />
<field name="product_id" nolabel="1" options="{'no_open': True, 'no_create_edit': True}" />
<field name="_barcode_scanned" widget="barcode_handler" invisible="1" />
</group>
<group/>
@@ -23,7 +26,7 @@
<field name="name" />
<field name="qty" />
<field name="max_weight" options="{'bg_color': 'lightcoral: max_weight == 0.0 and required'}" />
<field name="length" options="{'bg_color': 'lightcoral: length == 0.0 and required'}" />
<field name="lngth" options="{'bg_color': 'lightcoral: lngth == 0.0 and required'}" />
<field name="width" options="{'bg_color': 'lightcoral: width == 0.0 and required'}" />
<field name="height" options="{'bg_color': 'lightcoral: height == 0.0 and required'}" />
<field name="volume" options="{'bg_color': 'lightcoral: volume == 0.0 and required'}" />