Initial commit: OCA Mrp packages (117 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:05 +02:00
commit 277e84fd7a
4403 changed files with 395154 additions and 0 deletions

View file

@ -0,0 +1,45 @@
# MRP Subcontracting Skip No Negative
Odoo addon: mrp_subcontracting_skip_no_negative
## Installation
```bash
pip install odoo-bringout-oca-manufacture-mrp_subcontracting_skip_no_negative
```
## Dependencies
This addon depends on:
- mrp_subcontracting
- stock_no_negative
## Manifest Information
- **Name**: MRP Subcontracting Skip No Negative
- **Version**: 16.0.1.0.3
- **Category**: Manufacturing
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/manufacture](https://github.com/OCA/manufacture) branch 16.0, addon `mrp_subcontracting_skip_no_negative`.
## License
This package maintains the original AGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Mrp_subcontracting_skip_no_negative Module - mrp_subcontracting_skip_no_negative
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for mrp_subcontracting_skip_no_negative. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,6 @@
# Dependencies
This addon depends on:
- [mrp_subcontracting](../../odoo-bringout-oca-ocb-mrp_subcontracting)
- [stock_no_negative](../../odoo-bringout-oca-stock-logistics-workflow-stock_no_negative)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon mrp_subcontracting_skip_no_negative or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-manufacture-mrp_subcontracting_skip_no_negative"
# or
uv pip install odoo-bringout-oca-manufacture-mrp_subcontracting_skip_no_negative"
```

View file

@ -0,0 +1,13 @@
# Models
Detected core models and extensions in mrp_subcontracting_skip_no_negative.
```mermaid
classDiagram
class stock_move
class stock_picking
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: mrp_subcontracting_skip_no_negative. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon mrp_subcontracting_skip_no_negative
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,8 @@
# Security
This module does not define custom security rules or access controls beyond Odoo defaults.
Default Odoo security applies:
- Base user access through standard groups
- Model access inherited from dependencies
- No custom row-level security rules

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon mrp_subcontracting_skip_no_negative
```

View file

@ -0,0 +1,3 @@
# Wizards
This module does not include UI wizards.

View file

@ -0,0 +1,102 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association
===================================
MRP Subcontracting Skip No Negative
===================================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:04d1caad6753651574d56c53a5636eea079186ef520899c1391b1d215121f1e3
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github
:target: https://github.com/OCA/manufacture/tree/16.0/mrp_subcontracting_skip_no_negative
:alt: OCA/manufacture
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/manufacture-16-0/manufacture-16-0-mrp_subcontracting_skip_no_negative
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/manufacture&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module skips the negative quantity check, provided by stock_no_negative, for
subcontracting receipts.
Background:
~~~~~~~~~~~
Odoo processes subcontracting receipt in the order of:
1. Transfer of the subcontracted product from the subcontractor location to the internal
location.
2. Production of the subcontracted product in the subcontractor location.
This sequence does not represent the reality where production is done before transfer, and therefore
the above Step 1 would fail with negative stock in the subcontractor location, when stock_no_negative
is installed, unless the product/location is configured to allow negative stock.
ref. https://github.com/odoo/odoo/pull/75065
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/manufacture/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/manufacture/issues/new?body=module:%20mrp_subcontracting_skip_no_negative%0Aversion:%2016.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.
Credits
=======
Authors
~~~~~~~
* Quartile Limited
Contributors
~~~~~~~~~~~~
* `Quartile <https://www.quartile.co>`__:
* Aung Ko Ko Lin
* `Tecnativa <https://www.tecnativa.com>`_:
* Víctor Martínez
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/manufacture <https://github.com/OCA/manufacture/tree/16.0/mrp_subcontracting_skip_no_negative>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,13 @@
# Copyright 2023 Quartile Limited
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
{
"name": "MRP Subcontracting Skip No Negative",
"version": "16.0.1.0.3",
"license": "AGPL-3",
"author": "Quartile Limited, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/manufacture",
"category": "Manufacturing",
"depends": ["mrp_subcontracting", "stock_no_negative"],
"installable": True,
"auto_install": True,
}

View file

@ -0,0 +1,35 @@
# 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 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: mrp_subcontracting_skip_no_negative
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_move
msgid "Stock Move"
msgstr "Skladišno kretanje"
#. module: mrp_subcontracting_skip_no_negative
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_picking
msgid "Transfer"
msgstr "Prijenos"
#. 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 ""

View 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."

View file

@ -0,0 +1,42 @@
# 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 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-11-08 09:35+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"
#. module: mrp_subcontracting_skip_no_negative
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_move
msgid "Stock Move"
msgstr "Movimento di magazzino"
#. module: mrp_subcontracting_skip_no_negative
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_picking
msgid "Transfer"
msgstr "Trasferimento"
#. 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 ""
"Non è possibile convalidare questa operazione di magazzino perché il livello "
"di magazzino del prodotto componente '{name}' diventerebbe negativo ({qty}) "
"nell'ubicazione di magazzino '{location}' e per questo prodotto e/o "
"posizione non è consentito un magazzino negativo."

View file

@ -0,0 +1,35 @@
# 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 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: mrp_subcontracting_skip_no_negative
#: model:ir.model,name:mrp_subcontracting_skip_no_negative.model_stock_move
msgid "Stock Move"
msgstr ""
#. module: mrp_subcontracting_skip_no_negative
#: 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 ""

View file

@ -0,0 +1,2 @@
from . import stock_move
from . import stock_picking

View file

@ -0,0 +1,78 @@
# 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.exceptions import ValidationError
from odoo.tools import config, float_compare
class StockMove(models.Model):
_inherit = "stock.move"
def _action_done(self, cancel_backorder=False):
moves_with_no_check = self.filtered(lambda x: x.is_subcontract).with_context(
skip_negative_qty_check=True
)
# For rather unlikely occassions where linked production is not in the right
# state.
for move in moves_with_no_check:
production_moves = self.search(
[
("move_dest_ids", "=", move.id),
("state", "not in", ("done", "cancel")),
]
)
productions = production_moves.production_id
unassigned_productions = productions.filtered(
lambda p: p.reservation_state != "assigned"
)
unassigned_productions.action_assign()
if all(
state == "assigned"
for state in unassigned_productions.mapped("reservation_state")
):
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, moves_with_no_check)._action_done(
cancel_backorder=cancel_backorder
)
res += super(StockMove, self - moves_with_no_check)._action_done(
cancel_backorder=cancel_backorder
)
return res

View file

@ -0,0 +1,44 @@
# Copyright 2023 Quartile Limited
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import models
class StockPicking(models.Model):
_inherit = "stock.picking"
def _action_done(self):
res = super()._action_done()
self._check_negative_quants_after_process()
return res
def _check_negative_quants_after_process(self):
product_ids = self.mapped("move_ids.product_id.id")
quants = self.env["stock.quant"].search(
[
("product_id", "in", product_ids),
]
)
quants.check_negative_qty()
def _get_moves_to_backorder(self):
self.ensure_one()
moves = super()._get_moves_to_backorder()
if self.env.context.get("skip_negative_qty_check"):
return moves.filtered(lambda x: x.is_subcontract)
return moves
def _create_backorder_picking(self):
self.ensure_one()
existing_backorder_picking = self.env["stock.picking"].search(
[("backorder_id", "=", self.id)]
)
existing_subcontract_moves = existing_backorder_picking.move_ids.filtered(
lambda x: x.is_subcontract
)
if (
self.move_ids.filtered(lambda x: x.state == "done" and x.is_subcontract)
and existing_subcontract_moves
):
return existing_backorder_picking
return super()._create_backorder_picking()

View file

@ -0,0 +1,7 @@
* `Quartile <https://www.quartile.co>`__:
* Aung Ko Ko Lin
* `Tecnativa <https://www.tecnativa.com>`_:
* Víctor Martínez

View file

@ -0,0 +1,17 @@
This module skips the negative quantity check, provided by stock_no_negative, for
subcontracting receipts.
Background:
~~~~~~~~~~~
Odoo processes subcontracting receipt in the order of:
1. Transfer of the subcontracted product from the subcontractor location to the internal
location.
2. Production of the subcontracted product in the subcontractor location.
This sequence does not represent the reality where production is done before transfer, and therefore
the above Step 1 would fail with negative stock in the subcontractor location, when stock_no_negative
is installed, unless the product/location is configured to allow negative stock.
ref. https://github.com/odoo/odoo/pull/75065

View file

@ -0,0 +1,443 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
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
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document">
<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="mrp-subcontracting-skip-no-negative">
<h1>MRP Subcontracting Skip No Negative</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:04d1caad6753651574d56c53a5636eea079186ef520899c1391b1d215121f1e3
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" 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 image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/manufacture/tree/16.0/mrp_subcontracting_skip_no_negative"><img alt="OCA/manufacture" src="https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/manufacture-16-0/manufacture-16-0-mrp_subcontracting_skip_no_negative"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/manufacture&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module skips the negative quantity check, provided by stock_no_negative, for
subcontracting receipts.</p>
<div class="section" id="background">
<h2>Background:</h2>
<p>Odoo processes subcontracting receipt in the order of:</p>
<p>1. Transfer of the subcontracted product from the subcontractor location to the internal
location.
2. Production of the subcontracted product in the subcontractor location.</p>
<p>This sequence does not represent the reality where production is done before transfer, and therefore
the above Step 1 would fail with negative stock in the subcontractor location, when stock_no_negative
is installed, unless the product/location is configured to allow negative stock.</p>
<p>ref. <a class="reference external" href="https://github.com/odoo/odoo/pull/75065">https://github.com/odoo/odoo/pull/75065</a></p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a></li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h3><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h3>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/manufacture/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/manufacture/issues/new?body=module:%20mrp_subcontracting_skip_no_negative%0Aversion:%2016.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>
</div>
<div class="section" id="credits">
<h3><a class="toc-backref" href="#toc-entry-2">Credits</a></h3>
</div>
</div>
<div class="section" id="authors">
<h2>Authors</h2>
<ul class="simple">
<li>Quartile Limited</li>
</ul>
</div>
<div class="section" id="contributors">
<h2>Contributors</h2>
<ul class="simple">
<li><a class="reference external" href="https://www.quartile.co">Quartile</a>:<ul>
<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">
<h2>Maintainers</h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<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
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/manufacture/tree/16.0/mrp_subcontracting_skip_no_negative">OCA/manufacture</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>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1 @@
from . import test_mrp_subcontracting_skip_no_negative

View file

@ -0,0 +1,131 @@
# 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):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(
context=dict(
cls.env.context,
test_stock_no_negative=True,
)
)
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()
# Component1 error
with self.assertRaises(ValidationError) as e1:
immediate_wizard_form.process()
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(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")
def test_mrp_subcontracting_with_normal_product(self):
another_product = self.env["product.product"].create(
{
"name": "Another Product",
"type": "product",
}
)
self.env["stock.move"].create(
{
"picking_id": self.subcontracting_receipt.id,
"product_id": another_product.id,
"name": another_product.name,
"product_uom": another_product.uom_id.id,
"product_uom_qty": 1,
"location_id": self.subcontracting_receipt.location_id.id,
"location_dest_id": self.subcontracting_receipt.location_dest_id.id,
}
)
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")
products = self.subcontracting_receipt.move_ids.mapped("product_id")
self.assertIn(self.finished, products)
self.assertIn(another_product, products)
for move in self.subcontracting_receipt.move_ids:
self.assertEqual(move.quantity_done, 1)

View file

@ -0,0 +1,43 @@
[project]
name = "odoo-bringout-oca-manufacture-mrp_subcontracting_skip_no_negative"
version = "16.0.0"
description = "MRP Subcontracting Skip No Negative - Odoo addon"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-manufacture-mrp_subcontracting>=16.0.0",
"odoo-bringout-oca-manufacture-stock_no_negative>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["mrp_subcontracting_skip_no_negative"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]