first commit
This commit is contained in:
commit
df7545fb99
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Odoo
|
||||
*.po
|
||||
*.pot
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# System
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# MO Lock Consumed
|
||||
|
||||
This Odoo module customizes the behavior of Manufacturing Orders (MO) regarding ingredient consumption and validation.
|
||||
|
||||
## Features
|
||||
|
||||
1. **Lock Consumed Quantity**:
|
||||
- Prevents the automatic update of a component's "Consumed" quantity when the MO's "Quantity to Produce" is changed, **IF**:
|
||||
- The component already has a manually entered "Consumed" quantity (greater than 0).
|
||||
- OR the component has already been marked as picked.
|
||||
- If a component has 0 consumed quantity and is not picked, it will continue to scale automatically based on the BOM ratio (standard behavior).
|
||||
|
||||
2. **Safety Check for Negative Stock**:
|
||||
- Hides the **"Produce"** and **"Produce All"** buttons if proceeding with the production would cause the potential stock of any component to drop below zero (negative stock).
|
||||
- **Exception**: If a component's "Consumed" quantity is explicitly set to **0** (e.g., for custom productions where a BOM component is not used), it is skipped in this check, allowing production to proceed.
|
||||
|
||||
## Usage
|
||||
|
||||
- **Standard Flow**: Create an MO, confirm it. The behavior remains standard unless you manually intervene.
|
||||
- **Custom Consumption**: If you manually set a component's consumed quantity (e.g., to 5 units), changing the global "Quantity to Produce" will **not** override your manual entry of 5 units.
|
||||
- **Stock Validation**: If you try to produce a quantity that requires more components than you have in stock, the Produce buttons will disappear, preventing you from accidentally forcing negative stock. To fix this, either replenish stock or adjust the consumed quantity to 0 (if omitting the component).
|
||||
1
__init__.py
Normal file
1
__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from . import models
|
||||
19
__manifest__.py
Normal file
19
__manifest__.py
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
'name': 'MO Lock Consumed',
|
||||
'version': '1.0',
|
||||
'summary': 'Lock consumed quantity on MO when manually edited or picked, and hide produce buttons on negative stock.',
|
||||
'description': """
|
||||
Prevents automatic update of the 'Consumed' quantity on Manufacturing Orders when:
|
||||
1. The component already has a consumed quantity.
|
||||
2. The component transfer component is already picked.
|
||||
|
||||
Also hides 'Produce' and 'Produce All' buttons if the operation would result in negative potential stock for components.
|
||||
""",
|
||||
'category': 'Manufacturing',
|
||||
'author': 'Antigravity',
|
||||
'depends': ['mrp'],
|
||||
'data': [],
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
2
models/__init__.py
Normal file
2
models/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
from . import stock_move
|
||||
from . import mrp_production
|
||||
73
models/mrp_production.py
Normal file
73
models/mrp_production.py
Normal file
@ -0,0 +1,73 @@
|
||||
from odoo import models, api
|
||||
|
||||
class MrpProduction(models.Model):
|
||||
_inherit = 'mrp.production'
|
||||
|
||||
@api.depends('state', 'product_qty', 'qty_producing', 'move_raw_ids.quantity', 'move_raw_ids.product_uom_qty')
|
||||
def _compute_show_produce(self):
|
||||
"""
|
||||
Override to hide produce buttons if proceeding would cause negative stock.
|
||||
"""
|
||||
# First compute standard visibility
|
||||
super()._compute_show_produce()
|
||||
|
||||
for production in self:
|
||||
# If standard logic says hidden, no need to check further
|
||||
if not production.show_produce and not production.show_produce_all:
|
||||
continue
|
||||
|
||||
# Determine which action we are validating
|
||||
# If show_produce_all is True, we are producing the full remaining amount
|
||||
# If show_produce (partial) is True, we are producing 'qty_producing'
|
||||
|
||||
# This logic needs to mirror what happens when the button is clicked.
|
||||
# However, for visibility, we want to know if *current* configured production is possible.
|
||||
|
||||
# If "Produce All" is available, it means we plan to produce everything remaining.
|
||||
# If "Produce" (partial) is available, we plan to produce `qty_producing`.
|
||||
|
||||
# Check if any component would go negative
|
||||
potential_negative = False
|
||||
|
||||
# We need to check stock availability in the source location
|
||||
location = production.location_src_id
|
||||
|
||||
for move in production.move_raw_ids:
|
||||
if move.state in ('done', 'cancel'):
|
||||
continue
|
||||
|
||||
# User request:
|
||||
# "if the components qty consumed is 0 then still show produce and produce all button"
|
||||
# "only hide the visibility if components qty consumed will make the stock negative"
|
||||
|
||||
# If nothing is currently set to be consumed (0), we assume it's safe to proceed
|
||||
# (or the user intends to consume 0/different amount later).
|
||||
# We only block if the *Explicitly Consumed* amount exceeds available stock.
|
||||
if move.quantity == 0:
|
||||
continue
|
||||
|
||||
# Check availability based on the ACTUAL 'Consumed' quantity
|
||||
qty_to_consume = move.quantity
|
||||
|
||||
# Check availability
|
||||
product_in_location = move.product_id.with_context(location=location.id)
|
||||
available_qty = product_in_location.qty_available
|
||||
|
||||
if available_qty - qty_to_consume < 0:
|
||||
potential_negative = True
|
||||
break
|
||||
|
||||
if potential_negative:
|
||||
production.show_produce = False
|
||||
production.show_produce_all = False
|
||||
|
||||
# User request: "hide the produce if all components consumed is 0 (does not make sense right to produce without components)"
|
||||
# This should only apply if we are in "Partial Produce" mode (qty_producing > 0), where consumption should have been calculated/entered.
|
||||
# If qty_producing is 0 (Fresh MO), we usually show "Produce All", which will auto-calculate consumption, so we shouldn't hide it.
|
||||
if production.qty_producing > 0:
|
||||
# Check if ALL moves have 0 quantity
|
||||
# We filter out cancelled moves, and maybe we should focus on raw materials.
|
||||
relevant_moves = production.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
|
||||
if relevant_moves and all(m.quantity == 0 for m in relevant_moves):
|
||||
production.show_produce = False
|
||||
production.show_produce_all = False
|
||||
14
models/stock_move.py
Normal file
14
models/stock_move.py
Normal file
@ -0,0 +1,14 @@
|
||||
from odoo import models
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
def _should_bypass_set_qty_producing(self):
|
||||
"""
|
||||
Prevent auto-update of consumed quantity if:
|
||||
- The move already has a quantity set (partial consumption).
|
||||
- The move is already picked.
|
||||
"""
|
||||
if self.quantity > 0 or self.picked:
|
||||
return True
|
||||
return super()._should_bypass_set_qty_producing()
|
||||
Loading…
Reference in New Issue
Block a user