[IMP] stock_picking_product_kit_helper: black, isort

This commit is contained in:
ps-tubtim
2020-01-09 15:42:43 +07:00
committed by clementmbr
parent 8807cb2869
commit 6d23fd8d62
3 changed files with 112 additions and 103 deletions

View File

@@ -1,20 +1,15 @@
# Copyright 2019 Kitti U. - Ecosoft <kittiu@ecosoft.co.th> # Copyright 2019 Kitti U. - Ecosoft <kittiu@ecosoft.co.th>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{ {
'name': 'Stock Picking Product Kit Helper', "name": "Stock Picking Product Kit Helper",
'summary': 'Set quanity in picking line based on product kit quantity', "summary": "Set quanity in picking line based on product kit quantity",
'version': '12.0.1.0.0', "version": "13.0.1.0.0",
'category': 'Stock', "category": "Stock",
'website': 'https://github.com/OCA/manufacture', "website": "https://github.com/OCA/manufacture",
'author': 'Ecosoft, Odoo Community Association (OCA)', "author": "Ecosoft, Odoo Community Association (OCA)",
'license': 'AGPL-3', "license": "AGPL-3",
'installable': True, "installable": True,
'depends': [ "depends": ["sale_mrp"],
'sale_mrp', "data": ["security/ir.model.access.csv", "views/stock_view.xml"],
], "maintainers": ["kittiu"],
'data': [
'security/ir.model.access.csv',
'views/stock_view.xml',
],
'maintainers': ['kittiu']
} }

View File

@@ -1,100 +1,103 @@
# Copyright 2019 Kitti U. - Ecosoft <kittiu@ecosoft.co.th> # Copyright 2019 Kitti U. - Ecosoft <kittiu@ecosoft.co.th>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _ from odoo import _, api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
class StockPicking(models.Model): class StockPicking(models.Model):
_inherit = 'stock.picking' _inherit = "stock.picking"
product_kit_helper_ids = fields.One2many( product_kit_helper_ids = fields.One2many(
comodel_name='stock.picking.product.kit.helper', comodel_name="stock.picking.product.kit.helper",
string='Product Kit Helper Lines', string="Product Kit Helper Lines",
inverse_name='picking_id', inverse_name="picking_id",
readonly=False, readonly=False,
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, states={"done": [("readonly", True)], "cancel": [("readonly", True)]},
) )
has_product_kit = fields.Boolean( has_product_kit = fields.Boolean(
string='Has Product Kit', string="Has Product Kit",
compute='_compute_has_product_kit', compute="_compute_has_product_kit",
help="True if there is at least 1 product kit in the sales order", help="True if there is at least 1 product kit in the sales order",
) )
@api.model @api.model
def _is_product_kit(self, product, company): def _is_product_kit(self, product, company):
BOM = self.env['mrp.bom'].sudo() BOM = self.env["mrp.bom"].sudo()
bom = BOM._bom_find(product=product, bom = BOM._bom_find(product=product, company_id=company.id)
company_id=company.id) return bom and bom.type == "phantom"
return bom and bom.type == 'phantom'
@api.multi @api.multi
def _compute_has_product_kit(self): def _compute_has_product_kit(self):
for picking in self: for picking in self:
if any(self._is_product_kit(line.product_id, line.company_id) if any(
for line in picking.move_lines.mapped('sale_line_id')): self._is_product_kit(line.product_id, line.company_id)
for line in picking.move_lines.mapped("sale_line_id")
):
picking.has_product_kit = True picking.has_product_kit = True
@api.multi @api.multi
def show_product_kit(self): def show_product_kit(self):
"""Find move_lines with product kit to create helper line.""" """Find move_lines with product kit to create helper line."""
self.ensure_one() self.ensure_one()
BOM = self.env['mrp.bom'].sudo() BOM = self.env["mrp.bom"].sudo()
helpers = [] helpers = []
for sale_line in self.move_lines.mapped('sale_line_id'): for sale_line in self.move_lines.mapped("sale_line_id"):
bom = BOM._bom_find(product=sale_line.product_id, bom = BOM._bom_find(
company_id=sale_line.company_id.id) product=sale_line.product_id, company_id=sale_line.company_id.id
if bom and bom.type == 'phantom': # Create product kit line )
helpers.append((0, 0, {'sale_line_id': sale_line.id, if bom and bom.type == "phantom": # Create product kit line
'product_id': sale_line.product_id.id, helpers.append(
'product_uom_qty': 0.0, (
})) 0,
0,
{
"sale_line_id": sale_line.id,
"product_id": sale_line.product_id.id,
"product_uom_qty": 0.0,
},
)
)
self.product_kit_helper_ids.unlink() self.product_kit_helper_ids.unlink()
self.write({'product_kit_helper_ids': helpers}) self.write({"product_kit_helper_ids": helpers})
@api.multi @api.multi
def action_product_kit_helper(self): def action_product_kit_helper(self):
"""Assign product kit's quantity to stock move.""" """Assign product kit's quantity to stock move."""
self.ensure_one() self.ensure_one()
if self.state in ('done', 'cancel'): if self.state in ("done", "cancel"):
raise ValidationError( raise ValidationError(
_('Product Kit Helper is not allowed on current state')) _("Product Kit Helper is not allowed on current state")
)
for helper in self.product_kit_helper_ids: for helper in self.product_kit_helper_ids:
helper.action_explode_helper() helper.action_explode_helper()
class StockPickingProductKitHelper(models.Model): class StockPickingProductKitHelper(models.Model):
_name = 'stock.picking.product.kit.helper' _name = "stock.picking.product.kit.helper"
_description = """ _description = """
Product Kit Helper, allow user to specify quantity of product kit, Product Kit Helper, allow user to specify quantity of product kit,
to explode as product quantity in operations tab to explode as product quantity in operations tab
""" """
picking_id = fields.Many2one( picking_id = fields.Many2one(
comodel_name='stock.picking', comodel_name="stock.picking",
string='Picking', string="Picking",
required=True, required=True,
index=True, index=True,
ondelete='cascade', ondelete="cascade",
) )
sale_line_id = fields.Many2one( sale_line_id = fields.Many2one(
comodel_name='sale.order.line', comodel_name="sale.order.line", string="Sales Order Line", required=True
string='Sales Order Line',
required=True,
) )
product_id = fields.Many2one( product_id = fields.Many2one(
comodel_name='product.product', comodel_name="product.product", string="Product", required=True, readonly=True
string='Product',
required=True,
readonly=True,
)
product_uom_qty = fields.Float(
string='Quantity',
) )
product_uom_qty = fields.Float(string="Quantity")
product_uom = fields.Many2one( product_uom = fields.Many2one(
comodel_name='uom.uom', comodel_name="uom.uom",
string='Unit of Measure', string="Unit of Measure",
related='sale_line_id.product_uom', related="sale_line_id.product_uom",
readonly=True, readonly=True,
) )
@@ -103,31 +106,36 @@ class StockPickingProductKitHelper(models.Model):
"""Explodes product kit quantity to detailed product in stock move.""" """Explodes product kit quantity to detailed product in stock move."""
self.ensure_one() self.ensure_one()
# Mock stock.move, in order to resue stock.move's action_explode # Mock stock.move, in order to resue stock.move's action_explode
StockMove = self.env['stock.move'] StockMove = self.env["stock.move"]
mock_loc = self.env['stock.location'].sudo().search([], limit=1) mock_loc = self.env["stock.location"].sudo().search([], limit=1)
mock_pt = self.env['stock.picking.type'].sudo().search([], limit=1) mock_pt = self.env["stock.picking.type"].sudo().search([], limit=1)
mock_stock_move = StockMove.sudo().create({ mock_stock_move = StockMove.sudo().create(
'name': '/', {
'product_id': self.product_id.id, "name": "/",
'product_uom': self.product_uom.id, "product_id": self.product_id.id,
'product_uom_qty': self.product_uom_qty, "product_uom": self.product_uom.id,
'picking_type_id': mock_pt.id, "product_uom_qty": self.product_uom_qty,
'location_id': mock_loc.id, "picking_type_id": mock_pt.id,
'location_dest_id': mock_loc.id, "location_id": mock_loc.id,
}) "location_dest_id": mock_loc.id,
}
)
# Reuse explode function and assign quantity_done in stock.move # Reuse explode function and assign quantity_done in stock.move
mock_processed_moves = mock_stock_move.action_explode() mock_processed_moves = mock_stock_move.action_explode()
for mock_move in mock_processed_moves: for mock_move in mock_processed_moves:
stock_move = StockMove.search([ stock_move = StockMove.search(
('picking_id', '=', self.picking_id.id), [
('sale_line_id', '=', self.sale_line_id.id), ("picking_id", "=", self.picking_id.id),
('product_id', '=', mock_move.product_id.id)]) ("sale_line_id", "=", self.sale_line_id.id),
("product_id", "=", mock_move.product_id.id),
]
)
if not stock_move: if not stock_move:
continue continue
if len(stock_move) != 1: if len(stock_move) != 1:
raise ValidationError( raise ValidationError(
_('No matching detailed product %s for product kit %s') % _("No matching detailed product %s for product kit %s")
(mock_move.product_id.display_name, % (mock_move.product_id.display_name, self.product_id.display_name)
self.product_id.display_name)) )
stock_move.write({'quantity_done': mock_move.product_uom_qty}) stock_move.write({"quantity_done": mock_move.product_uom_qty})
mock_processed_moves.sudo().unlink() mock_processed_moves.sudo().unlink()

View File

@@ -1,16 +1,15 @@
# Copyright 2019 Kitti U. - Ecosoft <kittiu@ecosoft.co.th> # Copyright 2019 Kitti U. - Ecosoft <kittiu@ecosoft.co.th>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.tests import common, Form
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tests import Form, common
class TestStockPickingProductKitHelper(common.TransactionCase): class TestStockPickingProductKitHelper(common.TransactionCase):
def setUp(self): def setUp(self):
super(TestStockPickingProductKitHelper, self).setUp() super(TestStockPickingProductKitHelper, self).setUp()
self.partner = self.env.ref('base.res_partner_2') self.partner = self.env.ref("base.res_partner_2")
self.table_kit = self.env.ref('mrp.product_product_table_kit') self.table_kit = self.env.ref("mrp.product_product_table_kit")
def test_00_sale_product_kit_helper(self): def test_00_sale_product_kit_helper(self):
"""Test sale order with product kit, I expect, """Test sale order with product kit, I expect,
@@ -19,7 +18,7 @@ class TestStockPickingProductKitHelper(common.TransactionCase):
- After picking is done, do not allow to use helper - After picking is done, do not allow to use helper
""" """
# Create sales order of 10 table kit # Create sales order of 10 table kit
order_form = Form(self.env['sale.order']) order_form = Form(self.env["sale.order"])
order_form.partner_id = self.partner order_form.partner_id = self.partner
with order_form.order_line.new() as line: with order_form.order_line.new() as line:
line.product_id = self.table_kit line.product_id = self.table_kit
@@ -27,38 +26,45 @@ class TestStockPickingProductKitHelper(common.TransactionCase):
order = order_form.save() order = order_form.save()
order.action_confirm() order.action_confirm()
# In the picking, product line is exploded. # In the picking, product line is exploded.
picking = order.mapped('picking_ids') picking = order.mapped("picking_ids")
self.assertEqual(len(picking), 1) self.assertEqual(len(picking), 1)
stock_moves = picking.move_lines stock_moves = picking.move_lines
# 1 SO line exploded to 2 moves # 1 SO line exploded to 2 moves
moves = [{'product': x.product_id.name, 'qty': x.product_uom_qty} moves = [
for x in stock_moves] {"product": x.product_id.name, "qty": x.product_uom_qty}
self.assertEqual(moves, for x in stock_moves
[{'product': 'Wood Panel', 'qty': 10.0}, ]
{'product': 'Bolt', 'qty': 40.0}]) self.assertEqual(
moves,
[{"product": "Wood Panel", "qty": 10.0}, {"product": "Bolt", "qty": 40.0}],
)
self.assertTrue(picking.has_product_kit) self.assertTrue(picking.has_product_kit)
self.assertFalse(picking.product_kit_helper_ids) # Not show yet self.assertFalse(picking.product_kit_helper_ids) # Not show yet
picking.show_product_kit() picking.show_product_kit()
self.assertEqual(len(picking.product_kit_helper_ids), 1) self.assertEqual(len(picking.product_kit_helper_ids), 1)
# Assign product set 4 qty and test that it apply to stock.move # Assign product set 4 qty and test that it apply to stock.move
picking.product_kit_helper_ids[0].write({'product_uom_qty': 4.0}) picking.product_kit_helper_ids[0].write({"product_uom_qty": 4.0})
picking.action_product_kit_helper() picking.action_product_kit_helper()
moves = [{'product': x.product_id.name, 'qty': x.quantity_done} moves = [
for x in stock_moves] {"product": x.product_id.name, "qty": x.quantity_done} for x in stock_moves
self.assertEqual(moves, ]
[{'product': 'Wood Panel', 'qty': 4.0}, self.assertEqual(
{'product': 'Bolt', 'qty': 16.0}]) moves,
[{"product": "Wood Panel", "qty": 4.0}, {"product": "Bolt", "qty": 16.0}],
)
# Assign again to 10 qty # Assign again to 10 qty
picking.product_kit_helper_ids[0].write({'product_uom_qty': 10.0}) picking.product_kit_helper_ids[0].write({"product_uom_qty": 10.0})
picking.action_product_kit_helper() picking.action_product_kit_helper()
moves = [{'product': x.product_id.name, 'qty': x.quantity_done} moves = [
for x in stock_moves] {"product": x.product_id.name, "qty": x.quantity_done} for x in stock_moves
self.assertEqual(moves, ]
[{'product': 'Wood Panel', 'qty': 10.0}, self.assertEqual(
{'product': 'Bolt', 'qty': 40.0}]) moves,
[{"product": "Wood Panel", "qty": 10.0}, {"product": "Bolt", "qty": 40.0}],
)
# Validate Picking # Validate Picking
picking.button_validate() picking.button_validate()
self.assertEqual(picking.state, 'done') self.assertEqual(picking.state, "done")
# After done state, block the helper # After done state, block the helper
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
picking.action_product_kit_helper() picking.action_product_kit_helper()