[IMP] stock_cubiscan: black, isort

This commit is contained in:
Guewen Baconnier
2020-01-09 14:20:44 +01:00
parent a3850e0009
commit 4d1dd4a65f
6 changed files with 161 additions and 174 deletions

View File

@@ -1,25 +1,25 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Stock Cubiscan',
'summary': 'Implement inteface with Cubiscan devices for packaging',
'version': '12.0.1.0.0',
'category': 'Stock',
'author': 'Camptocamp',
'license': 'AGPL-3',
'depends': [
'barcodes',
'stock',
'web_tree_dynamic_colored_field',
'product_packaging_dimension',
'product_packaging_type_required',
"name": "Stock Cubiscan",
"summary": "Implement inteface with Cubiscan devices for packaging",
"version": "12.0.1.0.0",
"category": "Stock",
"author": "Camptocamp",
"license": "AGPL-3",
"depends": [
"barcodes",
"stock",
"web_tree_dynamic_colored_field",
"product_packaging_dimension",
"product_packaging_type_required",
],
'website': 'http://www.camptocamp.com',
'data': [
'views/assets.xml',
'views/cubiscan_view.xml',
'wizard/cubiscan_wizard.xml',
'security/ir.model.access.csv',
"website": "http://www.camptocamp.com",
"data": [
"views/assets.xml",
"views/cubiscan_view.xml",
"wizard/cubiscan_wizard.xml",
"security/ir.model.access.csv",
],
'installable': True,
"installable": True,
}

View File

@@ -4,58 +4,59 @@
import ssl as SSL
from cubiscan.cubiscan import CubiScan
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
class CubiscanDevice(models.Model):
_name = 'cubiscan.device'
_description = 'Cubiscan Device'
_order = 'warehouse_id, name'
_name = "cubiscan.device"
_description = "Cubiscan Device"
_order = "warehouse_id, name"
name = fields.Char('Name', required=True)
device_address = fields.Char('Device IP Address', required=True)
port = fields.Integer('Port', required=True)
name = fields.Char("Name", required=True)
device_address = fields.Char("Device IP Address", required=True)
port = fields.Integer("Port", required=True)
timeout = fields.Integer(
'Timeout', help="Timeout in seconds", required=True, default=30
"Timeout", help="Timeout in seconds", required=True, default=30
)
warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse')
warehouse_id = fields.Many2one("stock.warehouse", "Warehouse")
state = fields.Selection(
[('not_ready', 'Not Ready'), ('ready', 'Ready')],
default='not_ready',
[("not_ready", "Not Ready"), ("ready", "Ready")],
default="not_ready",
readonly=True,
)
@api.multi
@api.constrains('device_address', 'port')
@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'
default["state"] = "not_ready"
return super().copy(default)
@api.multi
def open_wizard(self):
self.ensure_one()
return {
'name': _('CubiScan Wizard'),
'res_model': 'cubiscan.wizard',
'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,
'form_view_initial_mode': 'edit',
'no_breadcrumbs': True,
"name": _("CubiScan Wizard"),
"res_model": "cubiscan.wizard",
"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,
"form_view_initial_mode": "edit",
"no_breadcrumbs": True,
},
}
@@ -63,7 +64,7 @@ class CubiscanDevice(models.Model):
def _get_interface(self):
self.ensure_one()
ctx = SSL.create_default_context()
ctx.load_cert_chain('/usr/lib/ssl/certs/camptocamp.pem')
ctx.load_cert_chain("/usr/lib/ssl/certs/camptocamp.pem")
ctx.check_hostname = False
ctx.verify_mode = SSL.CERT_NONE
return CubiScan(self.device_address, self.port, self.timeout, ssl=ctx)
@@ -72,16 +73,17 @@ class CubiscanDevice(models.Model):
def test_device(self):
for device in self:
res = device._get_interface().test()
if res and 'error' not in res and device.state == 'not_ready':
device.state = 'ready'
elif res and 'error' in res and device.state == 'ready':
device.state = 'not_ready'
if res and "error" not in res and device.state == "not_ready":
device.state = "ready"
elif res and "error" in res and device.state == "ready":
device.state = "not_ready"
@api.multi
def get_measure(self):
self.ensure_one()
if self.state != 'ready':
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

@@ -5,10 +5,10 @@ from odoo import fields, models
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
_inherit = "stock.warehouse"
cubiscan_device_ids = fields.One2many(
'cubiscan.device', 'warehouse_id', string="Cubiscan Devices"
"cubiscan.device", "warehouse_id", string="Cubiscan Devices"
)
@@ -17,9 +17,9 @@ class ProductPackaging(models.Model):
# FIXME: Not sure this is still the best place for this constraint
_sql_constraints = [
(
'product_packaging_type_unique',
'unique (product_id, packaging_type_id)',
'It is forbidden to have different packagings '
'with the same type for a given product.',
"product_packaging_type_unique",
"unique (product_id, packaging_type_id)",
"It is forbidden to have different packagings "
"with the same type for a given product.",
)
]

View File

@@ -2,6 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from cubiscan.cubiscan import CubiScan
from mock import patch
from odoo.exceptions import ValidationError
from odoo.tests.common import SavepointCase
@@ -10,27 +11,23 @@ class TestCubiscan(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.device_obj = cls.env['cubiscan.device']
cls.device_obj = cls.env["cubiscan.device"]
def test_constraints(self):
vals = {'name': 'Test Device'}
vals = {"name": "Test Device"}
# Wrong port
vals.update({'device_address': '10.10.0.42', 'port': -42})
vals.update({"device_address": "10.10.0.42", "port": -42})
with self.assertRaises(ValidationError):
self.device_obj.create(vals)
def test_device_test(self):
vals = {
'name': 'Test Device',
'device_address': '10.10.0.42',
'port': 5982,
}
vals = {"name": "Test Device", "device_address": "10.10.0.42", "port": 5982}
device = self.device_obj.create(vals)
self.assertEquals(device.state, 'not_ready')
self.assertEquals(device.state, "not_ready")
with patch.object(CubiScan, '_make_request') as mocked:
mocked.return_value = {'identifier': 42}
with patch.object(CubiScan, "_make_request") as mocked:
mocked.return_value = {"identifier": 42}
device.test_device()
self.assertEquals(device.state, 'ready')
self.assertEquals(device.state, "ready")

View File

@@ -9,17 +9,17 @@ class TestCubiscanWizard(SavepointCase):
@staticmethod
def get_measure_result(length, width, height, weight):
return {
'origin': '1',
'location': 'dev001',
'length': (length, None),
'width': (width, None),
'height': (height, None),
'space_metric': True,
'weight': (weight, None),
'dim_weight': (weight, None),
'weight_metric': True,
'factor': 1,
'intl_unit': True,
"origin": "1",
"location": "dev001",
"length": (length, None),
"width": (width, None),
"height": (height, None),
"space_metric": True,
"weight": (weight, None),
"dim_weight": (weight, None),
"weight_metric": True,
"factor": 1,
"intl_unit": True,
}
@classmethod
@@ -27,42 +27,42 @@ class TestCubiscanWizard(SavepointCase):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.device_obj = cls.env['cubiscan.device']
cls.cs_wizard = cls.env['cubiscan.wizard']
PackType = cls.env['product.packaging.type']
cls.device_obj = cls.env["cubiscan.device"]
cls.cs_wizard = cls.env["cubiscan.wizard"]
PackType = cls.env["product.packaging.type"]
pack_type_data = [
('unit', 1, 0, 0),
('internal', 2, 1, 0),
('retail', 10, 1, 1),
('transport', 20, 1, 1),
('pallet', 30, 1, 1),
("unit", 1, 0, 0),
("internal", 2, 1, 0),
("retail", 10, 1, 1),
("transport", 20, 1, 1),
("pallet", 30, 1, 1),
]
for name, seq, gtin, req in pack_type_data:
PackType.create(
{
'name': name,
'code': name.upper(),
'sequence': seq,
'has_gtin': gtin,
'required': req,
"name": name,
"code": name.upper(),
"sequence": seq,
"has_gtin": gtin,
"required": req,
}
)
cls.device = cls.device_obj.create(
{
'name': 'Test Device',
'device_address': '192.168.21.42',
'port': 4242,
'state': 'ready',
"name": "Test Device",
"device_address": "192.168.21.42",
"port": 4242,
"state": "ready",
}
)
cls.wizard = cls.cs_wizard.create({'device_id': cls.device.id})
cls.wizard = cls.cs_wizard.create({"device_id": cls.device.id})
cls.product_1 = cls.env.ref('product.product_product_6')
cls.product_2 = cls.env.ref('product.product_product_7')
cls.product_1 = cls.env.ref("product.product_product_6")
cls.product_2 = cls.env.ref("product.product_product_7")
cls.product_1.barcode = '424242'
cls.product_1.barcode = "424242"
PackType.cron_check_create_required_packaging()
def test_product_onchange(self):

View File

@@ -5,57 +5,55 @@ from odoo import _, api, fields, models
class CubiscanWizard(models.TransientModel):
_name = 'cubiscan.wizard'
_inherit = 'barcodes.barcode_events_mixin'
_description = 'Cubiscan Wizard'
_rec_name = 'device_id'
_name = "cubiscan.wizard"
_inherit = "barcodes.barcode_events_mixin"
_description = "Cubiscan Wizard"
_rec_name = "device_id"
device_id = fields.Many2one('cubiscan.device', readonly=True)
product_id = fields.Many2one(
'product.product', domain=[('type', '=', 'product')]
)
line_ids = fields.One2many('cubiscan.wizard.line', 'wizard_id')
device_id = fields.Many2one("cubiscan.device", readonly=True)
product_id = fields.Many2one("product.product", domain=[("type", "=", "product")])
line_ids = fields.One2many("cubiscan.wizard.line", "wizard_id")
@api.onchange('product_id')
@api.onchange("product_id")
def onchange_product_id(self):
if self.product_id:
to_create = []
packaging_types = self.env['product.packaging.type'].search([])
packaging_types = self.env["product.packaging.type"].search([])
for seq, pack_type in enumerate(packaging_types):
pack = self.env['product.packaging'].search(
pack = self.env["product.packaging"].search(
[
('product_id', '=', self.product_id.id),
('packaging_type_id', '=', pack_type.id),
("product_id", "=", self.product_id.id),
("packaging_type_id", "=", pack_type.id),
],
limit=1,
)
vals = {
'wizard_id': self.id,
'sequence': seq + 1,
'name': pack_type.name,
'qty': 0,
'max_weight': 0,
'length': 0,
'width': 0,
'height': 0,
'barcode': False,
'packaging_type_id': pack_type.id,
"wizard_id": self.id,
"sequence": seq + 1,
"name": pack_type.name,
"qty": 0,
"max_weight": 0,
"length": 0,
"width": 0,
"height": 0,
"barcode": False,
"packaging_type_id": pack_type.id,
}
if pack:
vals.update(
{
'qty': pack.qty,
'max_weight': pack.max_weight,
'length': pack.length,
'width': pack.width,
'height': pack.height,
'barcode': pack.barcode,
'packaging_id': pack.id,
'packaging_type_id': pack_type.id,
"qty": pack.qty,
"max_weight": pack.max_weight,
"length": pack.length,
"width": pack.width,
"height": pack.height,
"barcode": pack.barcode,
"packaging_id": pack.id,
"packaging_type_id": pack_type.id,
}
)
to_create.append(vals)
recs = self.env['cubiscan.wizard.line'].create(to_create)
recs = self.env["cubiscan.wizard.line"].create(to_create)
self.line_ids = recs
else:
self.line_ids = [(5, 0, 0)]
@@ -65,7 +63,7 @@ class CubiscanWizard(models.TransientModel):
# Action to reopen wizard in fullscreen (e.g. after page refresh)
self.ensure_one()
res = self.device_id.open_wizard()
res['res_id'] = self.id
res["res_id"] = self.id
return res
def action_search_barcode(self):
@@ -80,7 +78,7 @@ class CubiscanWizard(models.TransientModel):
@api.multi
def on_barcode_scanned(self, barcode):
self.ensure_one()
prod = self.env['product.product'].search([('barcode', '=', barcode)])
prod = self.env["product.product"].search([("barcode", "=", barcode)])
self.product_id = prod
self.onchange_product_id()
@@ -90,14 +88,14 @@ class CubiscanWizard(models.TransientModel):
actions = []
for line in self.line_ids:
vals = {
'name': line.name,
'qty': line.qty,
'max_weight': line.max_weight,
'length': line.length,
'width': line.width,
'height': line.height,
'barcode': line.barcode,
'packaging_type_id': line.packaging_type_id.id,
"name": line.name,
"qty": line.qty,
"max_weight": line.max_weight,
"length": line.length,
"width": line.width,
"height": line.height,
"barcode": line.barcode,
"packaging_type_id": line.packaging_type_id.id,
}
pack = line.packaging_id
if pack:
@@ -109,33 +107,29 @@ class CubiscanWizard(models.TransientModel):
@api.multi
def action_close(self):
self.ensure_one()
action = self.env.ref(
'stock_cubiscan.action_cubiscan_device_form'
).read()[0]
action = self.env.ref("stock_cubiscan.action_cubiscan_device_form").read()[0]
action.update(
{
'res_id': self.device_id.id,
'target': 'main',
'views': [
"res_id": self.device_id.id,
"target": "main",
"views": [
(
self.env.ref(
'stock_cubiscan.view_cubiscan_device_form'
).id,
'form',
self.env.ref("stock_cubiscan.view_cubiscan_device_form").id,
"form",
)
],
'flags': {'headless': False, 'clear_breadcrumbs': True},
"flags": {"headless": False, "clear_breadcrumbs": True},
}
)
return action
class CubiscanWizardLine(models.TransientModel):
_name = 'cubiscan.wizard.line'
_description = 'Cubiscan Wizard Line'
_order = 'sequence'
_name = "cubiscan.wizard.line"
_description = "Cubiscan Wizard Line"
_order = "sequence"
wizard_id = fields.Many2one('cubiscan.wizard')
wizard_id = fields.Many2one("cubiscan.wizard")
sequence = fields.Integer()
name = fields.Char("Packaging", readonly=True)
qty = fields.Float("Quantity")
@@ -146,37 +140,31 @@ class CubiscanWizardLine(models.TransientModel):
volume = fields.Float(
"Volume (m³)",
digits=(8, 4),
compute='_compute_volume',
compute="_compute_volume",
readonly=True,
store=False,
)
barcode = fields.Char("GTIN")
packaging_id = fields.Many2one('product.packaging', readonly=True)
packaging_id = fields.Many2one("product.packaging", readonly=True)
packaging_type_id = fields.Many2one(
'product.packaging.type', readonly=True, required=True
)
required = fields.Boolean(
related='packaging_type_id.required', readonly=True
"product.packaging.type", readonly=True, required=True
)
required = fields.Boolean(related="packaging_type_id.required", readonly=True)
@api.depends('length', 'width', 'height')
@api.depends("length", "width", "height")
def _compute_volume(self):
for line in self:
line.volume = (
line.length * line.width * line.height
) / 1000.0 ** 3
line.volume = (line.length * 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 = {
k: (
v[0] if k in ['length', 'width', 'height', 'weight'] else False
)
k: (v[0] if k in ["length", "width", "height", "weight"] else False)
for k, v in measures.items()
}
weight = measures.pop('weight')
weight = measures.pop("weight")
measures = {k: int(v * 1000) for k, v in measures.items()}
measures['max_weight'] = weight
measures["max_weight"] = weight
self.write(measures)