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