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
|
* Aung Ko Ko Lin
|
||||||
|
|
||||||
|
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||||
|
|
||||||
|
* Víctor Martínez
|
||||||
|
|
||||||
Maintainers
|
Maintainers
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
50
mrp_subcontracting_skip_no_negative/i18n/es.po
Normal file
50
mrp_subcontracting_skip_no_negative/i18n/es.po
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# 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-04 08:50+0000\n"
|
||||||
|
"PO-Revision-Date: 2024-11-04 09:51+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.fields,field_description:mrp_subcontracting_skip_no_negative.field_stock_move__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr "Nombre mostrado"
|
||||||
|
|
||||||
|
#. module: mrp_subcontracting_skip_no_negative
|
||||||
|
#: model:ir.model.fields,field_description:mrp_subcontracting_skip_no_negative.field_stock_move__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr "ID"
|
||||||
|
|
||||||
|
#. module: mrp_subcontracting_skip_no_negative
|
||||||
|
#: model:ir.model.fields,field_description:mrp_subcontracting_skip_no_negative.field_stock_move____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr "Última modificación el"
|
||||||
|
|
||||||
|
#. 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
|
||||||
|
#: 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 '%s' would become negative (%s) on the stock location '%s' "
|
||||||
|
"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 '%s' se volvería negativo (%s) en la ubicación de stock "
|
||||||
|
"'%s' y no se permite stock negativo para este producto y/o ubicación."
|
||||||
@@ -6,6 +6,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 14.0\n"
|
"Project-Id-Version: Odoo Server 14.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2024-11-04 08:50+0000\n"
|
||||||
|
"PO-Revision-Date: 2024-11-04 08:50+0000\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@@ -32,3 +34,12 @@ msgstr ""
|
|||||||
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_move
|
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_move
|
||||||
msgid "Stock Move"
|
msgid "Stock Move"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: mrp_subcontracting_skip_no_negative
|
||||||
|
#: 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 '%s' would become negative (%s) on the stock location '%s'"
|
||||||
|
" and negative stock is not allowed for this product and/or location."
|
||||||
|
msgstr ""
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
# Copyright 2023 Quartile Limited
|
# Copyright 2023 Quartile Limited
|
||||||
|
# Copyright 2024 Tecnativa - Víctor Martínez
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
# 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):
|
class StockMove(models.Model):
|
||||||
@@ -35,6 +38,41 @@ class StockMove(models.Model):
|
|||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
moves_with_no_check -= move
|
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 '%s' would become "
|
||||||
|
"negative (%s) on the stock location '%s' and negative "
|
||||||
|
"stock is not allowed for this product and/or location."
|
||||||
|
)
|
||||||
|
% (
|
||||||
|
product.display_name,
|
||||||
|
new_qty,
|
||||||
|
location.complete_name,
|
||||||
|
)
|
||||||
|
)
|
||||||
res = super(StockMove, self - moves_with_no_check)._action_done(
|
res = super(StockMove, self - moves_with_no_check)._action_done(
|
||||||
cancel_backorder=cancel_backorder
|
cancel_backorder=cancel_backorder
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
* `Quartile <https://www.quartile.co>`__:
|
* `Quartile <https://www.quartile.co>`__:
|
||||||
|
|
||||||
* Aung Ko Ko Lin
|
* Aung Ko Ko Lin
|
||||||
|
|
||||||
|
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||||
|
|
||||||
|
* Víctor Martínez
|
||||||
|
|||||||
@@ -8,11 +8,10 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
:Author: David Goodger (goodger@python.org)
|
:Author: David Goodger (goodger@python.org)
|
||||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
|
||||||
:Copyright: This stylesheet has been placed in the public domain.
|
:Copyright: This stylesheet has been placed in the public domain.
|
||||||
|
|
||||||
Default cascading style sheet for the HTML output of Docutils.
|
Default cascading style sheet for the HTML output of Docutils.
|
||||||
Despite the name, some widely supported CSS2 features are used.
|
|
||||||
|
|
||||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||||
customize this style sheet.
|
customize this style sheet.
|
||||||
@@ -275,7 +274,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
|||||||
margin-left: 2em ;
|
margin-left: 2em ;
|
||||||
margin-right: 2em }
|
margin-right: 2em }
|
||||||
|
|
||||||
pre.code .ln { color: gray; } /* line numbers */
|
pre.code .ln { color: grey; } /* line numbers */
|
||||||
pre.code, code { background-color: #eeeeee }
|
pre.code, code { background-color: #eeeeee }
|
||||||
pre.code .comment, code .comment { color: #5C6576 }
|
pre.code .comment, code .comment { color: #5C6576 }
|
||||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||||
@@ -301,7 +300,7 @@ span.option {
|
|||||||
span.pre {
|
span.pre {
|
||||||
white-space: pre }
|
white-space: pre }
|
||||||
|
|
||||||
span.problematic, pre.problematic {
|
span.problematic {
|
||||||
color: red }
|
color: red }
|
||||||
|
|
||||||
span.section-subtitle {
|
span.section-subtitle {
|
||||||
@@ -414,14 +413,16 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
|||||||
<li>Aung Ko Ko Lin</li>
|
<li>Aung Ko Ko Lin</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
|
||||||
|
<li>Víctor Martínez</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="maintainers">
|
<div class="section" id="maintainers">
|
||||||
<h1>Maintainers</h1>
|
<h1>Maintainers</h1>
|
||||||
<p>This module is maintained by the OCA.</p>
|
<p>This module is maintained by the OCA.</p>
|
||||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
|
||||||
</a>
|
|
||||||
<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>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# Copyright 2023 Quartile Limited
|
# Copyright 2023 Quartile Limited
|
||||||
|
# Copyright 2024 Tecnativa - Víctor Martínez
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||||
|
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
from odoo.tests import Form
|
from odoo.tests import Form
|
||||||
|
from odoo.tools import mute_logger
|
||||||
|
|
||||||
from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon
|
from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon
|
||||||
|
|
||||||
@@ -17,40 +19,76 @@ class TestMrpSubcontractingSkipNoNegative(TestMrpSubcontractingCommon):
|
|||||||
test_stock_no_negative=True,
|
test_stock_no_negative=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
picking_form = Form(cls.env["stock.picking"])
|
||||||
def test_mrp_subcontracting_skip_no_negative(self):
|
picking_form.picking_type_id = cls.env.ref("stock.picking_type_in")
|
||||||
picking_form = Form(self.env["stock.picking"])
|
picking_form.partner_id = cls.subcontractor_partner1
|
||||||
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:
|
with picking_form.move_ids_without_package.new() as move:
|
||||||
move.product_id = self.finished
|
move.product_id = cls.finished
|
||||||
move.product_uom_qty = 1
|
move.product_uom_qty = 1
|
||||||
subcontracting_receipt = picking_form.save()
|
cls.subcontracting_receipt = picking_form.save()
|
||||||
subcontracting_receipt.action_confirm()
|
|
||||||
self.assertEqual(subcontracting_receipt.state, "assigned")
|
def _create_stock_quant(self, product, qty):
|
||||||
immediate_wizard = subcontracting_receipt.sudo().button_validate()
|
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")
|
self.assertEqual(immediate_wizard.get("res_model"), "stock.immediate.transfer")
|
||||||
immediate_wizard_form = Form(
|
immediate_wizard_form = Form(
|
||||||
self.env[immediate_wizard["res_model"]].with_context(
|
self.env[immediate_wizard["res_model"]].with_context(
|
||||||
**immediate_wizard["context"]
|
**immediate_wizard["context"]
|
||||||
)
|
)
|
||||||
).save()
|
).save()
|
||||||
with self.assertRaises(ValidationError):
|
# Component1 error
|
||||||
|
with self.assertRaises(ValidationError) as e1:
|
||||||
immediate_wizard_form.process()
|
immediate_wizard_form.process()
|
||||||
# Create component stock, and subcontracting receipt should now be successful.
|
self.assertIn("Component1", str(e1.exception))
|
||||||
self.env["stock.quant"].create(
|
# Create comp1 stock, and try subcontracting receipt process.
|
||||||
{
|
self._create_stock_quant(self.comp1, 10)
|
||||||
"product_id": self.comp1.id,
|
# Component2 error
|
||||||
"location_id": self.subcontractor_partner1.property_stock_subcontractor.id,
|
with self.assertRaises(ValidationError) as e2:
|
||||||
"quantity": 10,
|
immediate_wizard_form.process()
|
||||||
}
|
self.assertIn("Component2", str(e2.exception))
|
||||||
)
|
# Create comp2 stock, and subcontracting receipt should now be successful.
|
||||||
self.env["stock.quant"].create(
|
self._create_stock_quant(self.comp2, 10)
|
||||||
{
|
|
||||||
"product_id": self.comp2.id,
|
|
||||||
"location_id": self.subcontractor_partner1.property_stock_subcontractor.id,
|
|
||||||
"quantity": 10,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
immediate_wizard_form.process()
|
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