mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] stock_cubiscan: black, isort
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.",
|
||||
)
|
||||
]
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user