mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
@@ -76,6 +76,10 @@ Contributors
|
||||
|
||||
* Aung Ko Ko Lin
|
||||
|
||||
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||
|
||||
* Víctor Martínez
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
|
||||
43
mrp_subcontracting_skip_no_negative/i18n/es.po
Normal file
43
mrp_subcontracting_skip_no_negative/i18n/es.po
Normal file
@@ -0,0 +1,43 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * mrp_subcontracting_skip_no_negative
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-05 07:53+0000\n"
|
||||
"PO-Revision-Date: 2024-11-05 08:53+0100\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: \n"
|
||||
"X-Generator: Poedit 3.0.1\n"
|
||||
|
||||
#. module: mrp_subcontracting_skip_no_negative
|
||||
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr "Movimiento de existencias"
|
||||
|
||||
#. module: mrp_subcontracting_skip_no_negative
|
||||
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr "Transferencia"
|
||||
|
||||
#. module: mrp_subcontracting_skip_no_negative
|
||||
#. odoo-python
|
||||
#: code:addons/mrp_subcontracting_skip_no_negative/models/stock_move.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot validate this stock operation because the stock level of the "
|
||||
"component product '{name}' would become negative ({qty}) on the stock "
|
||||
"location '{location}' and negative stock is not allowed for this product and/"
|
||||
"or location."
|
||||
msgstr ""
|
||||
"No se puede validar esta operación de stock porque el nivel de stock del "
|
||||
"producto componente '{name}' se volvería negativo ({qty}) en la ubicación de "
|
||||
"stock '{location}' y no se permite stock negativo para este producto y/o "
|
||||
"ubicación."
|
||||
@@ -6,6 +6,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-05 07:53+0000\n"
|
||||
"PO-Revision-Date: 2024-11-05 07:53+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -22,3 +24,14 @@ msgstr ""
|
||||
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr ""
|
||||
|
||||
#. module: mrp_subcontracting_skip_no_negative
|
||||
#. odoo-python
|
||||
#: code:addons/mrp_subcontracting_skip_no_negative/models/stock_move.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot validate this stock operation because the stock level of the "
|
||||
"component product '{name}' would become negative ({qty}) on the stock "
|
||||
"location '{location}' and negative stock is not allowed for this product "
|
||||
"and/or location."
|
||||
msgstr ""
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
# Copyright 2023 Quartile Limited
|
||||
# Copyright 2024 Tecnativa - Víctor Martínez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo import models
|
||||
from odoo import _, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import config, float_compare
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
@@ -31,6 +34,41 @@ class StockMove(models.Model):
|
||||
):
|
||||
continue
|
||||
moves_with_no_check -= move
|
||||
# If you have not been able to allocate previously it is because there is
|
||||
# no stock, therefore it will leave the stock negative, we deduct the
|
||||
# quantity checking the components and show the corresponding error.
|
||||
test_condition = (
|
||||
config["test_enable"] and self.env.context.get("test_stock_no_negative")
|
||||
) or not config["test_enable"]
|
||||
if not test_condition:
|
||||
continue
|
||||
qty_precision = self.env["decimal.precision"].precision_get(
|
||||
"Product Unit of Measure"
|
||||
)
|
||||
for p_move in unassigned_productions.move_raw_ids.filtered(
|
||||
lambda x: x.state != "assigned"
|
||||
and not x.product_id.allow_negative_stock
|
||||
and not x.product_id.categ_id.allow_negative_stock
|
||||
and not x.location_id.allow_negative_stock
|
||||
):
|
||||
product = p_move.product_id.sudo()
|
||||
location = p_move.location_id
|
||||
location_qty = product.with_context(location=location.id).free_qty
|
||||
new_qty = location_qty - p_move.product_uom_qty
|
||||
if float_compare(new_qty, 0, precision_digits=qty_precision) == -1:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You cannot validate this stock operation because the "
|
||||
"stock level of the component product '{name}' would become "
|
||||
"negative ({qty}) on the stock location '{location}' and "
|
||||
"negative stock is not allowed for this product and/or "
|
||||
"location."
|
||||
).format(
|
||||
name=product.display_name,
|
||||
qty=new_qty,
|
||||
location=location.complete_name,
|
||||
)
|
||||
)
|
||||
res = super(StockMove, self - moves_with_no_check)._action_done(
|
||||
cancel_backorder=cancel_backorder
|
||||
)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
* `Quartile <https://www.quartile.co>`__:
|
||||
|
||||
* Aung Ko Ko Lin
|
||||
|
||||
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||
|
||||
* Víctor Martínez
|
||||
|
||||
@@ -413,6 +413,10 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
||||
<li>Aung Ko Ko Lin</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
|
||||
<li>Víctor Martínez</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
|
||||
@@ -1,50 +1,94 @@
|
||||
# Copyright 2023 Quartile Limited
|
||||
# Copyright 2024 Tecnativa - Víctor Martínez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import Form
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon
|
||||
|
||||
|
||||
class TestMrpSubcontractingSkipNoNegative(TestMrpSubcontractingCommon):
|
||||
def test_mrp_subcontracting_skip_no_negative(self):
|
||||
picking_form = Form(self.env["stock.picking"])
|
||||
picking_form.picking_type_id = self.env.ref("stock.picking_type_in")
|
||||
picking_form.partner_id = self.subcontractor_partner1
|
||||
with picking_form.move_ids_without_package.new() as move:
|
||||
move.product_id = self.finished
|
||||
move.product_uom_qty = 1
|
||||
subcontracting_receipt = picking_form.save()
|
||||
subcontracting_receipt = subcontracting_receipt.with_context(
|
||||
test_stock_no_negative=True
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
test_stock_no_negative=True,
|
||||
)
|
||||
)
|
||||
subcontracting_receipt.action_confirm()
|
||||
self.assertEqual(subcontracting_receipt.state, "assigned")
|
||||
immediate_wizard = subcontracting_receipt.button_validate()
|
||||
picking_form = Form(cls.env["stock.picking"])
|
||||
picking_form.picking_type_id = cls.env.ref("stock.picking_type_in")
|
||||
picking_form.partner_id = cls.subcontractor_partner1
|
||||
with picking_form.move_ids_without_package.new() as move:
|
||||
move.product_id = cls.finished
|
||||
move.product_uom_qty = 1
|
||||
cls.subcontracting_receipt = picking_form.save()
|
||||
|
||||
def _create_stock_quant(self, product, qty):
|
||||
self.env["stock.quant"].create(
|
||||
{
|
||||
"product_id": product.id,
|
||||
"location_id": self.subcontractor_partner1.property_stock_subcontractor.id,
|
||||
"quantity": qty,
|
||||
}
|
||||
)
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_mrp_subcontracting_skip_no_negative_01(self):
|
||||
self.subcontracting_receipt.action_confirm()
|
||||
self.assertEqual(self.subcontracting_receipt.state, "assigned")
|
||||
immediate_wizard = self.subcontracting_receipt.sudo().button_validate()
|
||||
self.assertEqual(immediate_wizard.get("res_model"), "stock.immediate.transfer")
|
||||
immediate_wizard_form = Form(
|
||||
self.env[immediate_wizard["res_model"]].with_context(
|
||||
**immediate_wizard["context"]
|
||||
)
|
||||
).save()
|
||||
with self.assertRaises(ValidationError):
|
||||
# Component1 error
|
||||
with self.assertRaises(ValidationError) as e1:
|
||||
immediate_wizard_form.process()
|
||||
|
||||
# Create component stock, and subcontracting receipt should now be successful.
|
||||
self.env["stock.quant"].create(
|
||||
{
|
||||
"product_id": self.comp1.id,
|
||||
"location_id": self.subcontractor_partner1.property_stock_subcontractor.id,
|
||||
"quantity": 10,
|
||||
}
|
||||
)
|
||||
self.env["stock.quant"].create(
|
||||
{
|
||||
"product_id": self.comp2.id,
|
||||
"location_id": self.subcontractor_partner1.property_stock_subcontractor.id,
|
||||
"quantity": 10,
|
||||
}
|
||||
)
|
||||
self.assertIn("Component1", str(e1.exception))
|
||||
# Create comp1 stock, and try subcontracting receipt process.
|
||||
self._create_stock_quant(self.comp1, 10)
|
||||
# Component2 error
|
||||
with self.assertRaises(ValidationError) as e2:
|
||||
immediate_wizard_form.process()
|
||||
self.assertIn("Component2", str(e2.exception))
|
||||
# Create comp2 stock, and subcontracting receipt should now be successful.
|
||||
self._create_stock_quant(self.comp2, 10)
|
||||
immediate_wizard_form.process()
|
||||
self.assertEqual(subcontracting_receipt.state, "done")
|
||||
self.assertEqual(self.subcontracting_receipt.state, "done")
|
||||
|
||||
def test_mrp_subcontracting_skip_no_negative_03(self):
|
||||
self._create_stock_quant(self.comp1, 10)
|
||||
self._create_stock_quant(self.comp2, 10)
|
||||
self.subcontracting_receipt.action_confirm()
|
||||
self.assertEqual(self.subcontracting_receipt.state, "assigned")
|
||||
immediate_wizard = self.subcontracting_receipt.sudo().button_validate()
|
||||
self.assertEqual(immediate_wizard.get("res_model"), "stock.immediate.transfer")
|
||||
immediate_wizard_form = Form(
|
||||
self.env[immediate_wizard["res_model"]].with_context(
|
||||
**immediate_wizard["context"]
|
||||
)
|
||||
).save()
|
||||
immediate_wizard_form.process()
|
||||
self.assertEqual(self.subcontracting_receipt.state, "done")
|
||||
|
||||
def test_mrp_subcontracting_skip_no_negative_04(self):
|
||||
self.subcontractor_partner1.property_stock_subcontractor.allow_negative_stock = (
|
||||
True
|
||||
)
|
||||
self.subcontracting_receipt.action_confirm()
|
||||
self.assertEqual(self.subcontracting_receipt.state, "assigned")
|
||||
immediate_wizard = self.subcontracting_receipt.sudo().button_validate()
|
||||
self.assertEqual(immediate_wizard.get("res_model"), "stock.immediate.transfer")
|
||||
immediate_wizard_form = Form(
|
||||
self.env[immediate_wizard["res_model"]].with_context(
|
||||
**immediate_wizard["context"]
|
||||
)
|
||||
).save()
|
||||
immediate_wizard_form.process()
|
||||
self.assertEqual(self.subcontracting_receipt.state, "done")
|
||||
|
||||
Reference in New Issue
Block a user