Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions stock_tracking_validation/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
=============================
Product Lot/Serial Validation
=============================

This module adds a warning popup message while you are validating picking or manufacturing like "Please verify the Lot/Serial before validating, Product Name: 001 (i.e. All products names with the Lot/Serial number that is going to be used)". The popup warning has two buttons either validate with the Lot/Serial or cancel for change the Lot/Serial and you could change it manually.
1 change: 1 addition & 0 deletions stock_tracking_validation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models, wizard
28 changes: 28 additions & 0 deletions stock_tracking_validation/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "Product Lot/Serial Validation",
"version": "18.0.1.0.0",
"category": "Stock",
"author": "Nitrokey GmbH",
"website": "https://github.com/Nitrokey/odoo-modules/",
"summary": (
"This module adds a warning popup message while you are validating "
"picking or manufacturing like 'Please verify the Lot/Serial before "
"validating, Product Name: 001 (i.e. All products names with the "
"Lot/Serial number that is going to be used)'. The popup warning "
"has two buttons either validate with the Lot/Serial or cancel for "
"change the Lot/Serial and you could change it manually"
),
"depends": [
"stock",
"mrp",
],
"data": [
"security/ir.model.access.csv",
"wizard/stock_tracking_validation_view.xml",
"views/mrp_production_view.xml",
"views/stock_picking_view.xml",
],
"license": "AGPL-3",
"installable": True,
"auto_install": False,
}
1 change: 1 addition & 0 deletions stock_tracking_validation/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import mrp_production, stock_picking
51 changes: 51 additions & 0 deletions stock_tracking_validation/models/mrp_production.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from odoo import models


class MrpProduction(models.Model):
_inherit = "mrp.production"

def open_stock_tracking_wizard(self):
production_line_has_lot = self.move_raw_ids.filtered(
lambda m: m.move_line_ids.filtered(lambda lot: lot.lot_id)
)
if not production_line_has_lot:
return self.button_mark_done()
action = (
self.env.ref("stock_tracking_validation.action_product_stock_validation")
.sudo()
.read()[0]
)
product_data = """<table class="table table-sm w-100 table-bordered
table-striped table-hover m-2">
<thead class="thead-light"">
<tr>
<th>Product Name</th>
<th>Lot/Serial</th>
</tr>
</thead>
<tbody>"""
for production_line in self.move_raw_ids.filtered(lambda m: m.move_line_ids):
if not production_line.move_line_ids.mapped("lot_id"):
continue
name = production_line.product_id.name
lot_name = ""
for lot_line in production_line.move_line_ids:
if len(production_line.move_line_ids) == 1:
lot_name = lot_line.lot_id.name
else:
if lot_line == production_line.move_line_ids[-1]:
lot_name += lot_line.lot_id.name
else:
lot_name += lot_line.lot_id.name + ", "
product_data += f"""
<tr>
<td class="border">{name}</td>
<td>{lot_name}</td>
</tr>
"""
product_data += """
</tbody>
</table>
"""
action["context"] = {"default_product_data": product_data}
return action
52 changes: 52 additions & 0 deletions stock_tracking_validation/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from odoo import models


class StockPicking(models.Model):
_inherit = "stock.picking"

def open_stock_tracking_wizard(self):
move_line_has_lot = self.move_ids_without_package.filtered(
lambda m: m.move_line_ids.mapped("lot_id")
)
if not move_line_has_lot:
return self.button_validate()
action = (
self.env.ref("stock_tracking_validation.action_product_stock_validation")
.sudo()
.read()[0]
)
product_data = """<table class="table table-sm w-100 table-bordered
table-striped table-hover m-2">
<thead class="thead-light"">
<tr>
<th>Product Name</th>
<th>Lot/Serial</th>
</tr>
</thead>
<tbody>"""
for produce_line in self.move_ids_without_package:
name = produce_line.product_id.name
if not produce_line.move_line_ids.mapped("lot_id"):
continue
lot_name = ""
for lot_line in produce_line.move_line_ids:
if len(produce_line.move_line_ids) == 1:
lot_name = lot_line.lot_id.name
else:
if lot_line == produce_line.move_line_ids[-1]:
lot_name += lot_line.lot_id.name
else:
lot_name += lot_line.lot_id.name + ", "
product_data += f"""
<tr>
<td class="border">{name}</td>
<td>{lot_name}</td>
</tr>
"""
product_data += """
</tbody>
</table>
"""

action["context"] = {"default_product_data": product_data}
return action
2 changes: 2 additions & 0 deletions stock_tracking_validation/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_tracking_validation,access_stock_tracking_validation,model_stock_tracking_validation,base.group_user,1,1,1,1
74 changes: 74 additions & 0 deletions stock_tracking_validation/views/mrp_production_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?xml version='1.0' encoding='utf-8' ?>
<odoo>
<record id="mrp_production_form_view" model="ir.ui.view">
<field name="name">mrp.production.form.view</field>
<field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_form_view" />
<field name="arch" type="xml">
<xpath expr="//button[@name='button_mark_done'][1]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='button_mark_done'][2]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='button_mark_done'][3]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='button_mark_done'][4]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='button_mark_done'][1]" position="after">
<button
name="open_stock_tracking_wizard"
invisible="state in ('draft', 'cancel', 'done', 'to_close')
or qty_producing == 0
or move_raw_ids"
string="Validate"
type="object"
class="oe_highlight"
data-hotkey="g"
confirm="There are no components to consume. Are you still sure you want to continue?"
/>
</xpath>
<xpath expr="//button[@name='button_mark_done'][2]" position="after">
<button
name="open_stock_tracking_wizard"
invisible="state in ('draft', 'cancel', 'done', 'to_close')
or qty_producing == 0
or not move_raw_ids"
string="Validate"
type="object"
class="oe_highlight"
data-hotkey="g"
/>
</xpath>
<xpath expr="//button[@name='button_mark_done'][3]" position="after">
<button
name="open_stock_tracking_wizard"
invisible="not move_raw_ids
or ((state not in ('confirmed', 'progress')
or qty_producing != 0)
and state != 'to_close')"
string="Mark as Done"
type="object"
class="oe_highlight"
data-hotkey="g"
/>
</xpath>
<xpath expr="//button[@name='button_mark_done'][4]" position="after">
<button
name="open_stock_tracking_wizard"
invisible="move_raw_ids
or ((state not in ('confirmed', 'progress')
or qty_producing != 0)
and state != 'to_close')"
string="Mark as Done"
type="object"
class="oe_highlight"
data-hotkey="g"
confirm="There are no components to consume. Are you still sure you want to continue?"
/>
</xpath>
</field>
</record>
</odoo>
36 changes: 36 additions & 0 deletions stock_tracking_validation/views/stock_picking_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version='1.0' encoding='utf-8' ?>
<odoo>
<record id="view_picking_form" model="ir.ui.view">
<field name="name">view.picking.form.tracking</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form" />
<field name="arch" type="xml">
<xpath expr="//button[@name='button_validate'][1]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='button_validate'][2]" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='button_validate'][1]" position="after">
<button
name="open_stock_tracking_wizard"
invisible="state in ('draft', 'confirmed', 'done', 'cancel')"
string="Validate"
type="object"
class="oe_highlight"
groups="stock.group_stock_user"
/>
</xpath>
<xpath expr="//button[@name='button_validate'][2]" position="after">
<button
name="open_stock_tracking_wizard"
invisible="state in ('waiting', 'assigned', 'done', 'cancel')"
string="Validate"
type="object"
class="o_btn_validate"
groups="stock.group_stock_user"
/>
</xpath>
</field>
</record>
</odoo>
1 change: 1 addition & 0 deletions stock_tracking_validation/wizard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import stock_tracking_validation
18 changes: 18 additions & 0 deletions stock_tracking_validation/wizard/stock_tracking_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from odoo import fields, models


class StockTrackingValidation(models.TransientModel):
_name = "stock.tracking.validation"
_description = "Stock tracking validation"

product_data = fields.Html()

def confirm_stock_tracking_validate(self):
active_id = self.env.context.get("active_ids")
active_model = self.env.context.get("active_model")
if active_model == "mrp.production":
mrp_production = self.env["mrp.production"].sudo().browse(active_id)
return mrp_production.button_mark_done()
else:
stock_picking = self.env["stock.picking"].sudo().browse(active_id)
return stock_picking.button_validate()
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="product_stock_tracking_validation_popup" model="ir.ui.view">
<field name="name">Stock Tracking Validation</field>
<field name="model">stock.tracking.validation</field>
<field name="arch" type="xml">
<form string="Stock Tracking Validation">
<h5>
Please verify the lot/serial number. You will not be able
to change it after confirmation.
</h5>
<h6>
<field name="product_data" readonly="1" widget="html" />
</h6>
<footer>
<button
name="confirm_stock_tracking_validate"
string="Confirm"
type="object"
class="btn-primary"
/>
<button string="Discard" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>

<record id="action_product_stock_validation" model="ir.actions.act_window">
<field name="name">Stock Tracking Validation</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">stock.tracking.validation</field>
<field name="view_mode">form</field>
<field
name="view_id"
ref="stock_tracking_validation.product_stock_tracking_validation_popup"
/>
<field name="target">new</field>
</record>
</odoo>