first commit

This commit is contained in:
Suherdy Yacob 2026-05-29 20:17:40 +07:00
commit a14050004b
9 changed files with 187 additions and 0 deletions

10
.gitignore vendored Normal file
View 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
View 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
View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import models

16
__manifest__.py Normal file
View 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
View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import res_users
from . import purchase_order

93
models/purchase_order.py Normal file
View 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
View 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 &amp; 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 &amp; Total",
help="Hide Unit Price, Subtotal, and Totals on Purchase Order form for this user."
)

View 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
View 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>