first commit
This commit is contained in:
commit
a14050004b
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Python compiled files and caches
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*~
|
||||||
26
README.md
Normal file
26
README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Purchase Custom Form Visibility
|
||||||
|
|
||||||
|
Custom Odoo 19 module to dynamically manage the visibility of buttons and financial fields on the Purchase Order form on a per-user basis.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
1. **Per-User Restricting Options**: Toggle restriction flags directly on individual user accounts.
|
||||||
|
2. **Hide RFQ & Confirmation Buttons**: Hide "Confirm Order" and "Send RFQ" buttons from the purchase order header for restricted users.
|
||||||
|
3. **Hide Financial Fields**: Hide unit price, subtotal, and totals on purchase lists, forms, line kanbans, and footer groups for restricted users.
|
||||||
|
4. **Flexible and Stateless**: Instant dynamically computed restrictions without storing redundant data in the database.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
1. Move the `purchase_custom_visibility` directory to Odoo's custom addons path.
|
||||||
|
2. Upgrade/Update Odoo addons list.
|
||||||
|
3. Install the module.
|
||||||
|
|
||||||
|
## Configuration (Per-User)
|
||||||
|
1. Go to **Settings** -> **Users & Companies** -> **Users**.
|
||||||
|
2. Select a User record and click **Edit**.
|
||||||
|
3. Open the **Purchase Restrictions** tab.
|
||||||
|
4. Check the desired restrictions:
|
||||||
|
- **Hide Confirm Order & Send RFQ**
|
||||||
|
- **Hide Price, Subtotal & Total**
|
||||||
|
5. Save the user record.
|
||||||
|
|
||||||
|
## Author
|
||||||
|
- **Suherdy Yacob**
|
||||||
2
__init__.py
Normal file
2
__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import models
|
||||||
16
__manifest__.py
Normal file
16
__manifest__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': 'Purchase Custom Form Visibility',
|
||||||
|
'version': '19.0.1.0.0',
|
||||||
|
'summary': 'Configure visibility of buttons and prices/totals on Purchase Order form per user.',
|
||||||
|
'category': 'Inventory/Purchase',
|
||||||
|
'author': 'Suherdy Yacob',
|
||||||
|
'depends': ['purchase'],
|
||||||
|
'data': [
|
||||||
|
'views/res_users_views.xml',
|
||||||
|
'views/purchase_order_views.xml',
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
||||||
3
models/__init__.py
Normal file
3
models/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import res_users
|
||||||
|
from . import purchase_order
|
||||||
93
models/purchase_order.py
Normal file
93
models/purchase_order.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from odoo import models, fields, api
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
class PurchaseOrder(models.Model):
|
||||||
|
_inherit = 'purchase.order'
|
||||||
|
|
||||||
|
hide_confirm_order_send_rfq = fields.Boolean(
|
||||||
|
compute='_compute_hide_fields',
|
||||||
|
store=False,
|
||||||
|
help="Technical field computed from user settings to determine button visibility"
|
||||||
|
)
|
||||||
|
hide_purchase_prices = fields.Boolean(
|
||||||
|
compute='_compute_hide_fields',
|
||||||
|
store=False,
|
||||||
|
help="Technical field computed from user settings to determine price visibility"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _compute_hide_fields(self):
|
||||||
|
# Retrieve the configuration settings dynamically from the current user
|
||||||
|
current_user = self.env.user
|
||||||
|
hide_buttons = current_user.hide_confirm_order_send_rfq
|
||||||
|
hide_prices = current_user.hide_purchase_prices
|
||||||
|
for order in self:
|
||||||
|
order.hide_confirm_order_send_rfq = hide_buttons
|
||||||
|
order.hide_purchase_prices = hide_prices
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def get_views(self, views, options=None):
|
||||||
|
res = super().get_views(views, options)
|
||||||
|
|
||||||
|
# Check current user configuration settings
|
||||||
|
current_user = self.env.user
|
||||||
|
hide_buttons = current_user.hide_confirm_order_send_rfq
|
||||||
|
hide_prices = current_user.hide_purchase_prices
|
||||||
|
|
||||||
|
if not (hide_buttons or hide_prices):
|
||||||
|
return res
|
||||||
|
|
||||||
|
for view_type, view_data in res.get('views', {}).items():
|
||||||
|
arch_str = view_data.get('arch')
|
||||||
|
if not arch_str:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
doc = etree.fromstring(arch_str.encode('utf-8'))
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
modified = False
|
||||||
|
|
||||||
|
# 1. Dynamically hide Confirm Order and Send RFQ buttons
|
||||||
|
if hide_buttons:
|
||||||
|
for btn in doc.xpath("//button[@name='action_rfq_send' or @name='button_confirm']"):
|
||||||
|
btn.set('invisible', '1')
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
# 2. Dynamically hide all price, subtotal, taxes, and total elements
|
||||||
|
if hide_prices:
|
||||||
|
price_fields = {
|
||||||
|
'price_unit', 'taxes_id', 'price_subtotal', 'price_total', 'price_tax',
|
||||||
|
'amount_untaxed', 'amount_tax', 'amount_total', 'amount_total_cc',
|
||||||
|
'tax_totals', 'discount'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check all <field> tags
|
||||||
|
for field in doc.xpath("//field"):
|
||||||
|
fname = field.get('name')
|
||||||
|
if fname in price_fields:
|
||||||
|
# Determine if this field is inside a list or tree view (columns)
|
||||||
|
is_column = False
|
||||||
|
p = field.getparent()
|
||||||
|
while p is not None:
|
||||||
|
if p.tag in ('tree', 'list'):
|
||||||
|
is_column = True
|
||||||
|
break
|
||||||
|
p = p.getparent()
|
||||||
|
|
||||||
|
if is_column:
|
||||||
|
field.set('column_invisible', 'True')
|
||||||
|
else:
|
||||||
|
field.set('invisible', '1')
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
# Hide any subtotal footer layouts
|
||||||
|
for el in doc.xpath("//group[contains(@class, 'oe_subtotal_footer')] | //div[contains(@class, 'oe_subtotal_footer')]"):
|
||||||
|
el.set('invisible', '1')
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
if modified:
|
||||||
|
view_data['arch'] = etree.tostring(doc, encoding='utf-8').decode('utf-8')
|
||||||
|
|
||||||
|
return res
|
||||||
15
models/res_users.py
Normal file
15
models/res_users.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
class ResUsers(models.Model):
|
||||||
|
_inherit = 'res.users'
|
||||||
|
|
||||||
|
hide_confirm_order_send_rfq = fields.Boolean(
|
||||||
|
string="Hide Confirm Order & Send RFQ",
|
||||||
|
help="Hide Confirm Order and Send RFQ buttons on Purchase Order form for this user."
|
||||||
|
)
|
||||||
|
|
||||||
|
hide_purchase_prices = fields.Boolean(
|
||||||
|
string="Hide Price, Subtotal & Total",
|
||||||
|
help="Hide Unit Price, Subtotal, and Totals on Purchase Order form for this user."
|
||||||
|
)
|
||||||
4
views/purchase_order_views.xml
Normal file
4
views/purchase_order_views.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<!-- Obsolete XML views have been successfully migrated to Python get_views in purchase_order.py -->
|
||||||
|
</odoo>
|
||||||
18
views/res_users_views.xml
Normal file
18
views/res_users_views.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_users_form_inherit_purchase_hide" model="ir.ui.view">
|
||||||
|
<field name="name">res.users.form.inherit.purchase.hide</field>
|
||||||
|
<field name="model">res.users</field>
|
||||||
|
<field name="inherit_id" ref="base.view_users_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//notebook" position="inside">
|
||||||
|
<page string="Purchase Restrictions" name="purchase_visibility_restrictions">
|
||||||
|
<group string="Purchase Form Restrictions">
|
||||||
|
<field name="hide_confirm_order_send_rfq"/>
|
||||||
|
<field name="hide_purchase_prices"/>
|
||||||
|
</group>
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
Loading…
Reference in New Issue
Block a user