[IMP] stock_quant_manual_assign: black, isort, prettier

This commit is contained in:
Tony Gu
2020-04-01 20:38:10 +08:00
committed by Fanha Giang
parent e33c84a0fe
commit 454ca05c6c
10 changed files with 324 additions and 229 deletions

View File

@@ -0,0 +1 @@
../../../../stock_quant_manual_assign

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -14,13 +14,13 @@ Stock - Manual Quant Assignment
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github
:target: https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_quant_manual_assign :target: https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_quant_manual_assign
:alt: OCA/stock-logistics-warehouse :alt: OCA/stock-logistics-warehouse
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-12-0/stock-logistics-warehouse-12-0-stock_quant_manual_assign :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-13-0/stock-logistics-warehouse-13-0-stock_quant_manual_assign
:alt: Translate me on Weblate :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/153/12.0 :target: https://runbot.odoo-community.org/runbot/153/13.0
:alt: Try me on Runbot :alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5| |badge1| |badge2| |badge3| |badge4| |badge5|
@@ -47,7 +47,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_. Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_quant_manual_assign%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. `feedback <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_quant_manual_assign%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues. Do not contact contributors directly about support or help with technical issues.
@@ -92,6 +92,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
This module is part of the `OCA/stock-logistics-warehouse <https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_quant_manual_assign>`_ project on GitHub. This module is part of the `OCA/stock-logistics-warehouse <https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_quant_manual_assign>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -7,21 +7,16 @@
{ {
"name": "Stock - Manual Quant Assignment", "name": "Stock - Manual Quant Assignment",
"version": "12.0.1.0.0", "version": "13.0.1.0.0",
"category": "Warehouse", "category": "Warehouse",
"license": "AGPL-3", "license": "AGPL-3",
"author": "AvanzOSC, " "author": "AvanzOSC, "
"Tecnativa, " "Tecnativa, "
"Eficent, " "Eficent, "
"Fanha Giang, " "Fanha Giang, "
"Odoo Community Association (OCA)", "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-warehouse", "website": "https://github.com/OCA/stock-logistics-warehouse",
"depends": [ "depends": ["stock"],
"stock", "data": ["wizard/assign_manual_quants_view.xml", "views/stock_move_view.xml"],
],
"data": [
"wizard/assign_manual_quants_view.xml",
"views/stock_move_view.xml",
],
"installable": True, "installable": True,
} }

View File

@@ -4,7 +4,7 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 12.0\n" "Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n" "Last-Translator: <>\n"
"Language-Team: \n" "Language-Team: \n"

View File

@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_quant_manual_assign"><img alt="OCA/stock-logistics-warehouse" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/stock-logistics-warehouse-12-0/stock-logistics-warehouse-12-0-stock_quant_manual_assign"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/153/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_quant_manual_assign"><img alt="OCA/stock-logistics-warehouse" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/stock-logistics-warehouse-13-0/stock-logistics-warehouse-13-0-stock_quant_manual_assign"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/153/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows you to manually change the automatic quant selection.</p> <p>This module allows you to manually change the automatic quant selection.</p>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
@@ -396,7 +396,7 @@ ul.auto-toc {
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_quant_manual_assign%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_quant_manual_assign%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
@@ -436,7 +436,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_quant_manual_assign">OCA/stock-logistics-warehouse</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_quant_manual_assign">OCA/stock-logistics-warehouse</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> <p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div> </div>
</div> </div>

View File

@@ -1,112 +1,142 @@
# Copyright 2015 Oihane Crucelaegui - AvanzOSC # Copyright 2015 Oihane Crucelaegui - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestStockQuantManualAssign(TransactionCase): class TestStockQuantManualAssign(TransactionCase):
def setUp(self): def setUp(self):
super(TestStockQuantManualAssign, self).setUp() super(TestStockQuantManualAssign, self).setUp()
self.quant_model = self.env['stock.quant'] self.quant_model = self.env["stock.quant"]
self.move_model = self.env['stock.move'] self.move_model = self.env["stock.move"]
self.quant_assign_wizard = self.env['assign.manual.quants'] self.quant_assign_wizard = self.env["assign.manual.quants"]
self.product = self.env['product.product'].create({ self.product = self.env["product.product"].create(
'name': 'Product 4 test', {"name": "Product 4 test", "type": "product"}
'type': 'product', )
}) self.location_src = self.env.ref("stock.stock_location_locations_virtual")
self.location_src = self.env.ref( self.location_dst = self.env.ref("stock.stock_location_customers")
'stock.stock_location_locations_virtual') self.location1 = self.env.ref("stock.location_inventory")
self.location_dst = self.env.ref('stock.stock_location_customers') self.location2 = self.env.ref("stock.location_procurement")
self.location1 = self.env.ref('stock.location_inventory') self.location3 = self.env.ref("stock.location_production")
self.location2 = self.env.ref('stock.location_procurement') self.quant1 = self.quant_model.sudo().create(
self.location3 = self.env.ref('stock.location_production') {
self.quant1 = self.quant_model.sudo().create({ "product_id": self.product.id,
'product_id': self.product.id, "quantity": 100.0,
'quantity': 100.0, "location_id": self.location1.id,
'location_id': self.location1.id, }
}) )
self.quant2 = self.quant_model.sudo().create({ self.quant2 = self.quant_model.sudo().create(
'product_id': self.product.id, {
'quantity': 100.0, "product_id": self.product.id,
'location_id': self.location2.id, "quantity": 100.0,
}) "location_id": self.location2.id,
self.quant3 = self.quant_model.sudo().create({ }
'product_id': self.product.id, )
'quantity': 100.0, self.quant3 = self.quant_model.sudo().create(
'location_id': self.location3.id, {
}) "product_id": self.product.id,
self.move = self.move_model.create({ "quantity": 100.0,
'name': self.product.name, "location_id": self.location3.id,
'product_id': self.product.id, }
'product_uom_qty': 400.0, )
'product_uom': self.product.uom_id.id, self.move = self.move_model.create(
'location_id': self.location_src.id, {
'location_dest_id': self.location_dst.id, "name": self.product.name,
}) "product_id": self.product.id,
"product_uom_qty": 400.0,
"product_uom": self.product.uom_id.id,
"location_id": self.location_src.id,
"location_dest_id": self.location_dst.id,
}
)
self.move._action_confirm() self.move._action_confirm()
def test_quant_assign_wizard(self): def test_quant_assign_wizard(self):
wizard = self.quant_assign_wizard.with_context( wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
active_id=self.move.id).create({ {}
}) )
self.assertEqual(len(wizard.quants_lines.ids), 3, self.assertEqual(
'Three quants created, three quants got by default') len(wizard.quants_lines.ids),
self.assertEqual(len(wizard.quants_lines.filtered('selected').ids), 0, 3,
'None of the quants must have been selected') "Three quants created, three quants got by default",
self.assertEqual(wizard.lines_qty, 0.0, )
'None selected must give 0') self.assertEqual(
self.assertEqual(sum(line.qty for line in wizard.quants_lines), len(wizard.quants_lines.filtered("selected").ids),
self.move.reserved_availability) 0,
"None of the quants must have been selected",
)
self.assertEqual(wizard.lines_qty, 0.0, "None selected must give 0")
self.assertEqual(
sum(line.qty for line in wizard.quants_lines),
self.move.reserved_availability,
)
self.assertEqual(wizard.move_qty, self.move.product_uom_qty) self.assertEqual(wizard.move_qty, self.move.product_uom_qty)
def test_quant_assign_wizard_constraint(self): def test_quant_assign_wizard_constraint(self):
wizard = self.quant_assign_wizard.with_context( wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
active_id=self.move.id).create({ {}
}) )
self.assertEqual(len(wizard.quants_lines.ids), 3, self.assertEqual(
'Three quants created, three quants got by default') len(wizard.quants_lines.ids),
self.assertEqual(len(wizard.quants_lines.filtered('selected').ids), 0, 3,
'None of the quants must have been selected') "Three quants created, three quants got by default",
self.assertEqual(wizard.lines_qty, 0.0, )
'None selected must give 0') self.assertEqual(
len(wizard.quants_lines.filtered("selected").ids),
0,
"None of the quants must have been selected",
)
self.assertEqual(wizard.lines_qty, 0.0, "None selected must give 0")
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
wizard.write({'quants_lines': [(1, wizard.quants_lines[:1].id, wizard.write(
{'selected': True, 'qty': 500})]}) {
"quants_lines": [
(1, wizard.quants_lines[:1].id, {"selected": True, "qty": 500})
]
}
)
def test_quant_manual_assign(self): def test_quant_manual_assign(self):
wizard = self.quant_assign_wizard.with_context( wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
active_id=self.move.id).create({ {}
}) )
self.assertEqual(len(wizard.quants_lines.ids), 3, self.assertEqual(
'Three quants created, three quants got by default') len(wizard.quants_lines.ids),
wizard.quants_lines[0].write({ 3,
'selected': True, "Three quants created, three quants got by default",
}) )
wizard.quants_lines[0].write({"selected": True})
wizard.quants_lines[0]._onchange_selected() wizard.quants_lines[0]._onchange_selected()
wizard.quants_lines[1].write({ wizard.quants_lines[1].write({"selected": True, "qty": 50.0})
'selected': True,
'qty': 50.0,
})
self.assertEqual(wizard.lines_qty, 150.0) self.assertEqual(wizard.lines_qty, 150.0)
self.assertEqual(wizard.move_qty, 250.0) self.assertEqual(wizard.move_qty, 250.0)
wizard.assign_quants() wizard.assign_quants()
self.assertAlmostEqual(len(self.move.move_line_ids), self.assertAlmostEqual(
len(wizard.quants_lines.filtered('selected'))) len(self.move.move_line_ids), len(wizard.quants_lines.filtered("selected"))
)
def test_quant_assign_wizard_after_availability_check(self): def test_quant_assign_wizard_after_availability_check(self):
self.move._action_assign() self.move._action_assign()
wizard = self.quant_assign_wizard.with_context( wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
active_id=self.move.id).create({ {}
}) )
self.assertEqual(len(wizard.quants_lines.ids), 3, self.assertEqual(
'Three quants created, three quants got by default') len(wizard.quants_lines.ids),
self.assertEqual(len(wizard.quants_lines.filtered('selected').ids), 3, 3,
'All the quants must have been selected') "Three quants created, three quants got by default",
)
self.assertEqual(
len(wizard.quants_lines.filtered("selected").ids),
3,
"All the quants must have been selected",
)
self.assertEqual(wizard.lines_qty, 300.0) self.assertEqual(wizard.lines_qty, 300.0)
self.assertEqual(wizard.move_qty, 100.0) self.assertEqual(wizard.move_qty, 100.0)
self.assertEqual(len(wizard.quants_lines.filtered('selected')), self.assertEqual(
len(self.move.move_line_ids)) len(wizard.quants_lines.filtered("selected")), len(self.move.move_line_ids)
self.assertEqual(sum(line.qty for line in wizard.quants_lines), )
self.move.reserved_availability) self.assertEqual(
sum(line.qty for line in wizard.quants_lines),
self.move.reserved_availability,
)

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<record model="ir.ui.view" id="stock_picking_manual_quants_form_view"> <record model="ir.ui.view" id="stock_picking_manual_quants_form_view">
<field name="name">stock.picking.form</field> <field name="name">stock.picking.form</field>
@@ -6,9 +6,14 @@
<field name="inherit_id" ref="stock.view_picking_form" /> <field name="inherit_id" ref="stock.view_picking_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<button name="action_show_details" position="before"> <button name="action_show_details" position="before">
<button name="%(assign_manual_quants_action)d" type="action" icon="fa-tags" <button
string="Manual Quants" options='{"warn": true}' name="%(assign_manual_quants_action)d"
attrs="{'invisible':['|',('picking_code','=','incoming'),('state','not in',('confirmed','assigned','partially_available'))]}"/> type="action"
icon="fa-tags"
string="Manual Quants"
options='{"warn": true}'
attrs="{'invisible':['|',('picking_code','=','incoming'),('state','not in',('confirmed','assigned','partially_available'))]}"
/>
</button> </button>
</field> </field>
</record> </record>

View File

@@ -6,45 +6,55 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.addons import decimal_precision as dp
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare from odoo.tools.float_utils import float_compare
from odoo.addons import decimal_precision as dp
class AssignManualQuants(models.TransientModel): class AssignManualQuants(models.TransientModel):
_name = 'assign.manual.quants' _name = "assign.manual.quants"
_description = "Assign Manual Quants" _description = "Assign Manual Quants"
@api.multi @api.multi
@api.constrains('quants_lines') @api.constrains("quants_lines")
def _check_qty(self): def _check_qty(self):
precision_digits = self.env[ precision_digits = self.env["decimal.precision"].precision_get(
'decimal.precision'].precision_get('Product Unit of Measure') "Product Unit of Measure"
for record in self.filtered('quants_lines'): )
if float_compare(record.lines_qty, record.move_id.product_qty, for record in self.filtered("quants_lines"):
precision_digits=precision_digits) > 0: if (
raise ValidationError( float_compare(
_('Quantity is higher than the needed one')) record.lines_qty,
record.move_id.product_qty,
precision_digits=precision_digits,
)
> 0
):
raise ValidationError(_("Quantity is higher than the needed one"))
@api.depends('move_id', 'quants_lines', 'quants_lines.qty') @api.depends("move_id", "quants_lines", "quants_lines.qty")
def _compute_qties(self): def _compute_qties(self):
for record in self: for record in self:
record.lines_qty = sum( record.lines_qty = sum(
record.quants_lines.filtered('selected').mapped('qty') record.quants_lines.filtered("selected").mapped("qty")
) )
record.move_qty = record.move_id.product_qty - record.lines_qty record.move_qty = record.move_id.product_qty - record.lines_qty
lines_qty = fields.Float( lines_qty = fields.Float(
string='Reserved qty', compute='_compute_qties', string="Reserved qty",
digits=dp.get_precision('Product Unit of Measure')) compute="_compute_qties",
move_qty = fields.Float(string='Remaining qty', compute='_compute_qties', digits=dp.get_precision("Product Unit of Measure"),
digits=dp.get_precision('Product Unit of Measure'))
quants_lines = fields.One2many('assign.manual.quants.lines',
'assign_wizard', string='Quants')
move_id = fields.Many2one(
comodel_name='stock.move',
string='Move',
) )
move_qty = fields.Float(
string="Remaining qty",
compute="_compute_qties",
digits=dp.get_precision("Product Unit of Measure"),
)
quants_lines = fields.One2many(
"assign.manual.quants.lines", "assign_wizard", string="Quants"
)
move_id = fields.Many2one(comodel_name="stock.move", string="Move",)
@api.multi @api.multi
def assign_quants(self): def assign_quants(self):
@@ -56,90 +66,103 @@ class AssignManualQuants(models.TransientModel):
for ml in move.move_line_ids: for ml in move.move_line_ids:
ml.qty_done = ml.product_qty ml.qty_done = ml.product_qty
move._recompute_state() move._recompute_state()
move.mapped('picking_id')._compute_state() move.mapped("picking_id")._compute_state()
return {} return {}
@api.model @api.model
def default_get(self, fields): def default_get(self, fields):
res = super(AssignManualQuants, self).default_get(fields) res = super(AssignManualQuants, self).default_get(fields)
move = self.env['stock.move'].browse(self.env.context['active_id']) move = self.env["stock.move"].browse(self.env.context["active_id"])
available_quants = self.env['stock.quant'].search([ available_quants = self.env["stock.quant"].search(
('location_id', 'child_of', move.location_id.id), [
('product_id', '=', move.product_id.id), ("location_id", "child_of", move.location_id.id),
('quantity', '>', 0), ("product_id", "=", move.product_id.id),
]) ("quantity", ">", 0),
]
)
quants_lines = [] quants_lines = []
for quant in available_quants: for quant in available_quants:
line = {} line = {}
line['quant_id'] = quant.id line["quant_id"] = quant.id
line['on_hand'] = quant.quantity line["on_hand"] = quant.quantity
line['location_id'] = quant.location_id.id line["location_id"] = quant.location_id.id
line['lot_id'] = quant.lot_id.id line["lot_id"] = quant.lot_id.id
line['package_id'] = quant.package_id.id line["package_id"] = quant.package_id.id
line['owner_id'] = quant.owner_id.id line["owner_id"] = quant.owner_id.id
line['selected'] = False line["selected"] = False
move_lines = move.move_line_ids.filtered( move_lines = move.move_line_ids.filtered(
lambda ml: (ml.location_id == quant.location_id and lambda ml: (
ml.lot_id == quant.lot_id and ml.location_id == quant.location_id
ml.owner_id == quant.owner_id and and ml.lot_id == quant.lot_id
ml.package_id == quant.package_id) and ml.owner_id == quant.owner_id
and ml.package_id == quant.package_id
)
) )
line['qty'] = sum(move_lines.mapped('product_uom_qty')) line["qty"] = sum(move_lines.mapped("product_uom_qty"))
line['selected'] = bool(line['qty']) line["selected"] = bool(line["qty"])
line['reserved'] = quant.reserved_quantity - line['qty'] line["reserved"] = quant.reserved_quantity - line["qty"]
quants_lines.append(line) quants_lines.append(line)
res.update({ res.update(
'quants_lines': [(0, 0, x) for x in quants_lines], {"quants_lines": [(0, 0, x) for x in quants_lines], "move_id": move.id}
'move_id': move.id, )
})
return res return res
class AssignManualQuantsLines(models.TransientModel): class AssignManualQuantsLines(models.TransientModel):
_name = 'assign.manual.quants.lines' _name = "assign.manual.quants.lines"
_description = "Assign Manual Quants Lines" _description = "Assign Manual Quants Lines"
_rec_name = 'quant_id' _rec_name = "quant_id"
assign_wizard = fields.Many2one( assign_wizard = fields.Many2one(
comodel_name='assign.manual.quants', string='Move', required=True, comodel_name="assign.manual.quants",
ondelete='cascade') string="Move",
required=True,
ondelete="cascade",
)
quant_id = fields.Many2one( quant_id = fields.Many2one(
comodel_name='stock.quant', string='Quant', required=True, comodel_name="stock.quant",
ondelete='cascade', oldname='quant') string="Quant",
required=True,
ondelete="cascade",
oldname="quant",
)
location_id = fields.Many2one( location_id = fields.Many2one(
comodel_name='stock.location', comodel_name="stock.location",
string='Location', string="Location",
related='quant_id.location_id', related="quant_id.location_id",
groups="stock.group_stock_multi_locations" groups="stock.group_stock_multi_locations",
) )
lot_id = fields.Many2one( lot_id = fields.Many2one(
comodel_name='stock.production.lot', string='Lot', comodel_name="stock.production.lot",
related='quant_id.lot_id', string="Lot",
groups="stock.group_production_lot") related="quant_id.lot_id",
groups="stock.group_production_lot",
)
package_id = fields.Many2one( package_id = fields.Many2one(
comodel_name='stock.quant.package', string='Package', comodel_name="stock.quant.package",
related='quant_id.package_id', string="Package",
groups="stock.group_tracking_lot") related="quant_id.package_id",
groups="stock.group_tracking_lot",
)
owner_id = fields.Many2one( owner_id = fields.Many2one(
comodel_name='res.partner', comodel_name="res.partner",
string='Owner', string="Owner",
related='quant_id.owner_id', related="quant_id.owner_id",
groups="stock.group_tracking_owner", groups="stock.group_tracking_owner",
) )
# This is not correctly shown as related or computed, so we make it regular # This is not correctly shown as related or computed, so we make it regular
on_hand = fields.Float( on_hand = fields.Float(
readonly=True, readonly=True,
string='On Hand', string="On Hand",
digits=dp.get_precision('Product Unit of Measure'), digits=dp.get_precision("Product Unit of Measure"),
) )
reserved = fields.Float( reserved = fields.Float(
string='Others Reserved', string="Others Reserved", digits=dp.get_precision("Product Unit of Measure")
digits=dp.get_precision('Product Unit of Measure')) )
selected = fields.Boolean(string='Select') selected = fields.Boolean(string="Select")
qty = fields.Float( qty = fields.Float(string="QTY", digits=dp.get_precision("Product Unit of Measure"))
string='QTY', digits=dp.get_precision('Product Unit of Measure'))
@api.onchange('selected') @api.onchange("selected")
def _onchange_selected(self): def _onchange_selected(self):
for record in self: for record in self:
if not record.selected: if not record.selected:
@@ -155,47 +178,66 @@ class AssignManualQuantsLines(models.TransientModel):
record.qty = min(quant_qty, remaining_qty) record.qty = min(quant_qty, remaining_qty)
@api.multi @api.multi
@api.constrains('qty') @api.constrains("qty")
def _check_qty(self): def _check_qty(self):
precision_digits = self.env[ precision_digits = self.env["decimal.precision"].precision_get(
'decimal.precision' "Product Unit of Measure"
].precision_get('Product Unit of Measure') )
for record in self.filtered('qty'): for record in self.filtered("qty"):
quant = record.quant_id quant = record.quant_id
move_lines = record.assign_wizard.move_id.move_line_ids.filtered( move_lines = record.assign_wizard.move_id.move_line_ids.filtered(
lambda ml: (ml.location_id == quant.location_id and lambda ml: (
ml.lot_id == quant.lot_id) ml.location_id == quant.location_id and ml.lot_id == quant.lot_id
)
) )
reserved = ( reserved = quant.reserved_quantity - sum(
quant.reserved_quantity - sum( move_lines.mapped("product_uom_qty")
move_lines.mapped('product_uom_qty'))
) )
if float_compare(record.qty, record.quant_id.quantity - reserved, if (
precision_digits=precision_digits) > 0: float_compare(
record.qty,
record.quant_id.quantity - reserved,
precision_digits=precision_digits,
)
> 0
):
raise ValidationError( raise ValidationError(
_('Selected line quantity is higher than the available ' _(
'one. Maybe an operation with this product has been ' "Selected line quantity is higher than the available "
'done meanwhile or you have manually increased the ' "one. Maybe an operation with this product has been "
'suggested value.') "done meanwhile or you have manually increased the "
"suggested value."
)
) )
def _assign_quant_line(self): def _assign_quant_line(self):
self.ensure_one() self.ensure_one()
quant = self.env['stock.quant'] quant = self.env["stock.quant"]
precision_digits = self.env[ precision_digits = self.env["decimal.precision"].precision_get(
'decimal.precision'].precision_get('Product Unit of Measure') "Product Unit of Measure"
)
move = self.assign_wizard.move_id move = self.assign_wizard.move_id
if float_compare(self.qty, 0.0, precision_digits=precision_digits) > 0: if float_compare(self.qty, 0.0, precision_digits=precision_digits) > 0:
available_quantity = quant._get_available_quantity( available_quantity = quant._get_available_quantity(
move.product_id, self.location_id, lot_id=self.lot_id, move.product_id,
package_id=self.package_id, owner_id=self.owner_id, self.location_id,
lot_id=self.lot_id,
package_id=self.package_id,
owner_id=self.owner_id,
) )
if float_compare( if (
available_quantity, 0.0, precision_digits=precision_digits float_compare(
) <= 0: available_quantity, 0.0, precision_digits=precision_digits
)
<= 0
):
return return
move._update_reserved_quantity( move._update_reserved_quantity(
self.qty, available_quantity, self.location_id, self.qty,
lot_id=self.lot_id, package_id=self.package_id, available_quantity,
owner_id=self.owner_id, strict=True self.location_id,
lot_id=self.lot_id,
package_id=self.package_id,
owner_id=self.owner_id,
strict=True,
) )

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<record model="ir.ui.view" id="assign_manual_quants_form_view"> <record model="ir.ui.view" id="assign_manual_quants_form_view">
<field name="name">assign.manual.quants.form</field> <field name="name">assign.manual.quants.form</field>
@@ -7,32 +7,48 @@
<form> <form>
<field name='quants_lines' colspan="4"> <field name='quants_lines' colspan="4">
<tree editable="top" delete="0" create="0"> <tree editable="top" delete="0" create="0">
<field name="lot_id"/> <field name="lot_id" />
<field name="package_id"/> <field name="package_id" />
<field name="owner_id"/> <field name="owner_id" />
<field name="location_id"/> <field name="location_id" />
<field name="on_hand"/> <field name="on_hand" />
<field name="reserved"/> <field name="reserved" />
<field name="selected"/> <field name="selected" />
<field name="qty" attrs="{'readonly':[('selected', '=', False)]}" sum="qty"/> <field
name="qty"
attrs="{'readonly':[('selected', '=', False)]}"
sum="qty"
/>
</tree> </tree>
</field> </field>
<group col='4' colspan="4"> <group col='4' colspan="4">
<field name="move_qty" colspan="2" readonly="1"/> <field name="move_qty" colspan="2" readonly="1" />
<field name="lines_qty" invisible="1" /> <field name="lines_qty" invisible="1" />
<field name="move_id" invisible="1"/> <field name="move_id" invisible="1" />
</group> </group>
<footer> <footer>
<button name="assign_quants" type="object" <button
string="Confirm" class="oe_highlight" /> name="assign_quants"
<button name="cancel" string="Cancel" class="oe_link" type="object"
special="cancel" /> string="Confirm"
class="oe_highlight"
/>
<button
name="cancel"
string="Cancel"
class="oe_link"
special="cancel"
/>
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<act_window
<act_window name="Manual assignment" res_model="assign.manual.quants" name="Manual assignment"
src_model="stock.move" view_mode="form" target="new" res_model="assign.manual.quants"
id="assign_manual_quants_action" /> src_model="stock.move"
view_mode="form"
target="new"
id="assign_manual_quants_action"
/>
</odoo> </odoo>