Skip to content

Commit 16948e6

Browse files
committed
[IMP] onhand qty : Improved the positioning and handling of onhand quantity
In this commit we have introduced following changes: - Removed header button and stat button related to onhand quantity. - Moved other two header buttons to action buttons. - Update the stat button of forecasted quantities to also display on hand quantities. - added onhand quantities to form view and also made that editable directly if multi locations is not enabled. - Added a button after that to update quantities if multi locations is enabled.
1 parent 4c650f3 commit 16948e6

File tree

5 files changed

+168
-0
lines changed

5 files changed

+168
-0
lines changed

onhand_qty/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import models

onhand_qty/__manifest__.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
'name': 'On Hand Qty',
3+
'sequence': 1,
4+
'category': 'Tutorials/onhand_qty',
5+
'version': '1.0',
6+
'application': True,
7+
'installable': True,
8+
'license': 'LGPL-3',
9+
'depends': [
10+
'base',
11+
'stock',
12+
],
13+
'data': [
14+
'views/product_template_views.xml'
15+
]
16+
}

onhand_qty/models/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import product_template

onhand_qty/models/product_template.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from odoo import fields, api, models
2+
3+
4+
class product_template(models.Model):
5+
_inherit="product.template"
6+
7+
qty_input = fields.Float(
8+
string="Quantity On Hand ",
9+
compute='_compute_qty_input',
10+
inverse='_inverse_qty_input',
11+
store=True,
12+
)
13+
14+
is_multi_location = fields.Boolean(
15+
compute="_compute_is_multi_location", store=False
16+
)
17+
18+
@api.depends('qty_available')
19+
def _compute_qty_input(self):
20+
for rec in self:
21+
rec.qty_input = rec.qty_available
22+
23+
@api.depends("company_id")
24+
def _compute_is_multi_location(self):
25+
for product in self:
26+
product.is_multi_location = self.env.user.has_group(
27+
"stock.group_stock_multi_locations"
28+
)
29+
30+
@api.onchange('qty_input')
31+
def _onchange_qty_input(self):
32+
for product in self:
33+
quant = self.env['stock.quant'].sudo().search([
34+
('product_id', '=', product.product_variant_id.id),
35+
('location_id.usage', '=', 'internal')
36+
], limit=1)
37+
38+
if quant:
39+
quant.quantity = product.qty_input
40+
else:
41+
self.env['stock.quant'].sudo().create({
42+
'product_id': product.product_variant_id.id,
43+
'location_id': 8,
44+
'quantity': product.qty_input,
45+
})
46+
47+
def _inverse_qty_input(self):
48+
pass
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<record id="view_template_property_form" model="ir.ui.view">
4+
<field name="name">product.template.stock.property.form.inherit</field>
5+
<field name="model">product.template</field>
6+
<field name="inherit_id" ref="product.product_template_form_view"/>
7+
<field name="arch" type="xml">
8+
<xpath expr="//header" position="attributes">
9+
<attribute name="invisible">1</attribute>
10+
</xpath>
11+
</field>
12+
</record>
13+
14+
<record id="view_template_property_form3" model="ir.ui.view">
15+
<field name="name">product.template.stock</field>
16+
<field name="model">product.template</field>
17+
<field name="inherit_id" ref="stock.product_template_form_view_procurement_button"/>
18+
<field name="arch" type="xml">
19+
<xpath expr="//t[@groups='stock.group_stock_user']//button[@name='action_update_quantity_on_hand']" position="attributes">
20+
<attribute name="invisible">1</attribute>
21+
</xpath>
22+
<xpath expr="//t[@groups='stock.group_stock_user']//button[@name='action_product_tmpl_forecast_report']" position="attributes">
23+
<attribute name="invisible">1</attribute>
24+
</xpath>
25+
<xpath expr="//t[@groups='stock.group_stock_user']" position="inside">
26+
<button type="object"
27+
name="action_product_tmpl_forecast_report"
28+
invisible="not show_forecasted_qty_status_button"
29+
context="{'default_product_tmpl_id': id}"
30+
class="oe_stat_button" icon="fa-area-chart">
31+
32+
<div class="o_field_widget o_stat_info d-flex align-items-center">
33+
<div class="d-flex flex-column ps-2">
34+
<span class="o_stat_value d-flex gap-1">
35+
<field name="qty_available" nolabel="1" class="oe_inline"/>
36+
<field name="uom_name" class="oe_inline"/>
37+
</span>
38+
<span class="o_stat_value d-flex gap-1">
39+
<field name="virtual_available" nolabel="1" class="oe_inline" decoration-danger="virtual_available &lt; 0" decoration-success="virtual_available &gt; 0"/>
40+
<span class="text-muted">Forecasted</span>
41+
</span>
42+
</div>
43+
</div>
44+
</button>
45+
</xpath>
46+
</field>
47+
</record>
48+
49+
<record id="view_template_property_form2" model="ir.ui.view">
50+
<field name="name">product.template.stock.property.form.inherit2</field>
51+
<field name="model">product.template</field>
52+
<field name="inherit_id" ref="product.product_template_form_view"/>
53+
<field name="arch" type="xml">
54+
<xpath expr="//group[@name='group_general']" position="inside">
55+
<label for="qty_input" class="oe_inline"/>
56+
<div class="o_row" invisible ="is_multi_location">
57+
<field name="qty_input"/>
58+
<field name="uom_name"/>
59+
</div>
60+
<div class="o_row" invisible ="not is_multi_location">
61+
<field name="qty_available"/>
62+
<field name="uom_name"/>
63+
<button name="action_open_quants" type="object"
64+
string="Update Quantity"
65+
class="btn-link mb-1 px-0" icon="fa-refresh" />
66+
</div>
67+
</xpath>
68+
<xpath expr="//field[@name='product_tooltip']" position="attributes">
69+
<attribute name="invisible">1</attribute>
70+
</xpath>
71+
</field>
72+
</record>
73+
74+
<record id="action_open_label_layout_from_action" model="ir.actions.server">
75+
<field name="name">Print Labels</field>
76+
<field name="model_id" ref="product.model_product_template"/>
77+
<field name="state">code</field>
78+
<field name="binding_model_id" ref="product.model_product_template"/>
79+
<field name="binding_view_types">form</field>
80+
<field name="code">
81+
action = records.action_open_label_layout()
82+
</field>
83+
</record>
84+
85+
<record id="action_open_replenish_action" model="ir.actions.server">
86+
<field name="name">Replenish</field>
87+
<field name="model_id" ref="product.model_product_template"/>
88+
<field name="state">code</field>
89+
<field name="binding_model_id" ref="product.model_product_template"/>
90+
<field name="binding_view_types">form</field>
91+
<field name="code">
92+
action = {
93+
'type': 'ir.actions.act_window',
94+
'res_model': 'product.replenish',
95+
'view_mode': 'form',
96+
'target': 'new',
97+
'context': {'default_product_tmpl_id': records.id},
98+
}
99+
</field>
100+
</record>
101+
</odoo>
102+

0 commit comments

Comments
 (0)