@ -0,0 +1,50 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
||||
|
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
Conditional Formatting in Pivot View |
||||
|
==================================== |
||||
|
This module helps you to setup conditional formatting in the pivot view of a |
||||
|
model. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
* No additional configurations needed |
||||
|
|
||||
|
Company |
||||
|
------- |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
License |
||||
|
------- |
||||
|
General Public License, Version 3 (AGPL v3). |
||||
|
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
||||
|
|
||||
|
Credits |
||||
|
------- |
||||
|
* Developers: (V18) Manasa T P |
||||
|
(V17) Shikhil Raj |
||||
|
|
||||
|
* Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from . import models |
@ -0,0 +1,55 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
{ |
||||
|
"name": "Conditional Formatting in Pivot View", |
||||
|
"version": "18.0.1.0.0", |
||||
|
"category": "Extra Tools", |
||||
|
"summary": "This Module allows to setup conditional formatting in " |
||||
|
"the pivot view of models", |
||||
|
"description": "The module is used for using conditional formatting option" |
||||
|
"in the pivot view of different models, you can setup" |
||||
|
" default formatting rules in the settings or add new rules" |
||||
|
" from the UI.", |
||||
|
"author": "Cybrosys Techno Solutions", |
||||
|
"company": "Cybrosys Techno Solutions", |
||||
|
"maintainer": "Cybrosys Techno Solutions", |
||||
|
"website": "https://www.cybrosys.com", |
||||
|
"depends": ["base", "web"], |
||||
|
"data": [ |
||||
|
"security/pivot_conditional_formatting_groups.xml", |
||||
|
"security/pivot_conditional_settings_security.xml", |
||||
|
"security/ir.model.access.csv", |
||||
|
"views/pivot_conditional_settings_views.xml", |
||||
|
], |
||||
|
"assets": { |
||||
|
"web.assets_backend": [ |
||||
|
"pivot_conditional_formatting/static/src/xml/pivot_conditional_formatting.xml", |
||||
|
"pivot_conditional_formatting/static/src/css/pivot_conditional_formatting.css", |
||||
|
"pivot_conditional_formatting/static/src/js/pivot_conditional_formatting.js", |
||||
|
], |
||||
|
}, |
||||
|
"images": ["static/description/banner.jpg"], |
||||
|
"license": "AGPL-3", |
||||
|
"installable": True, |
||||
|
"auto_install": False, |
||||
|
"application": False, |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
## Module <pivot_conditional_formatting> |
||||
|
|
||||
|
#### 26.06.2025 |
||||
|
#### Version 18.0.1.0.0 |
||||
|
#### ADD |
||||
|
- Initial Commit for Conditional Formatting in Pivot View |
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
"""init file""" |
||||
|
from . import conditional_rules |
||||
|
from . import pivot_conditional_settings |
@ -0,0 +1,59 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class ConditionalRules(models.Model): |
||||
|
"""Model Class for the different Pivot view table, conditional formatting |
||||
|
rules""" |
||||
|
_name = 'conditional.rules' |
||||
|
_description = 'Conditional formatting' |
||||
|
_rec_name = "rule" |
||||
|
|
||||
|
|
||||
|
rule = fields.Selection(string='Rule', |
||||
|
selection=[('greater_than', 'Greater Than'), |
||||
|
('less_than', 'Less Than'), |
||||
|
('is_empty', 'Is Empty'), |
||||
|
('in_between', 'In Between')], |
||||
|
help="Different conditions for rules") |
||||
|
value = fields.Float( string='Value', help="Value for comparing the rule") |
||||
|
second_value = fields.Float(string='Second Value', |
||||
|
help="Second value for comparing the " |
||||
|
"'In Between' rule") |
||||
|
color = fields.Char(string='Color', required=True, |
||||
|
help="Background color for the cells") |
||||
|
text_color = fields.Char(string='Text Color', required=True, |
||||
|
help="Text color for the cells") |
||||
|
model_id = fields.Many2one('ir.model', |
||||
|
related='conditional_id.model_id', |
||||
|
string="Model", help="Model related to the rule") |
||||
|
view_id = fields.Many2one('ir.ui.view', |
||||
|
related='conditional_id.view_id', string="View", |
||||
|
help="View related to the rule") |
||||
|
conditional_id = fields.Many2one('pivot.conditional.settings', |
||||
|
string="Condition", |
||||
|
help="Pivot Condition setting related to " |
||||
|
"the rule") |
||||
|
company_id = fields.Many2one('res.company', string='Company', |
||||
|
default=lambda self: self.env.company, |
||||
|
help="Company ID related to the rule") |
@ -0,0 +1,60 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
"""Models for setting conditional formatting rules in settings""" |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class PivotConditionalSetting(models.Model): |
||||
|
"""Model Class for choosing the model and view to set the default rules""" |
||||
|
_name = 'pivot.conditional.settings' |
||||
|
_description = 'Pivot conditional setting' |
||||
|
_rec_name = "model_id" |
||||
|
|
||||
|
model_id = fields.Many2one('ir.model', string="Model", |
||||
|
help="The model to set the rules for") |
||||
|
view_id = fields.Many2one('ir.ui.view', string="View", |
||||
|
help="Pivot view of the model") |
||||
|
rules_ids = fields.One2many('conditional.rules', |
||||
|
'conditional_id', string="Rules", |
||||
|
help="List View Showing details of different rules") |
||||
|
company_id = fields.Many2one('res.company', string='Company', |
||||
|
default=lambda self: self.env.company, |
||||
|
help="Company id related to the Pivot " |
||||
|
"Condition setting") |
||||
|
view_id_domain = fields.Binary(string="View Domain", |
||||
|
compute="_compute_view_id_domain") |
||||
|
|
||||
|
|
||||
|
@api.depends('model_id') |
||||
|
def _compute_view_id_domain(self): |
||||
|
""" |
||||
|
This method is called when the 'model_id' field is changed. It |
||||
|
updates the domain of the 'view_id' field to filter records based |
||||
|
on the selected model and view type as 'pivot'. |
||||
|
|
||||
|
:return: Dictionary containing the updated domain for the 'view_id' |
||||
|
field. |
||||
|
:rtype: dict |
||||
|
""" |
||||
|
for rec in self: |
||||
|
rec.view_id_domain = [('model', '=', rec.model_id.model), |
||||
|
('type', '=', 'pivot')] |
|
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
<!-- Groups for Pivot Conditional Rules --> |
||||
|
<record id="pivot_conditional_settings_group_user" model="res.groups"> |
||||
|
<field name="name">Allow to Set Pivot Conditional Rules</field> |
||||
|
<field name="category_id" ref="base.module_category_hidden"/> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
<!-- Multi Company Rule for pivot.conditional.settings Model --> |
||||
|
<record id="pivot_conditional_settings_rule_multi_company" model="ir.rule" > |
||||
|
<field name="name">Pivot Conditional Formatting Rule</field> |
||||
|
<field name="model_id" ref="model_pivot_conditional_settings"/> |
||||
|
<field name="domain_force">['|',('company_id','=',False),('company_id', 'in', company_ids)]</field> |
||||
|
</record> |
||||
|
<!-- Multi Company Rule for conditional Rules Model --> |
||||
|
<record id="conditional_rules_rule_multi_company" model="ir.rule"> |
||||
|
<field name="name">Pivot Conditional Formatting Rule2</field> |
||||
|
<field name="model_id" ref="model_conditional_rules"/> |
||||
|
<field name="domain_force">['|',('company_id','=',False),('company_id', 'in', company_ids)]</field> |
||||
|
</record> |
||||
|
</odoo> |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 628 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 188 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 767 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 760 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 697 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 880 KiB |
After Width: | Height: | Size: 803 KiB |
After Width: | Height: | Size: 38 KiB |
@ -0,0 +1,107 @@ |
|||||
|
.selected_cell{ |
||||
|
border: 4px solid red !important; |
||||
|
opacity: 0.75; |
||||
|
} |
||||
|
.prevent-select { |
||||
|
-webkit-user-select: none; /* Safari */ |
||||
|
-ms-user-select: none; /* IE 10 and IE 11 */ |
||||
|
user-select: none; /* Standard syntax */ |
||||
|
} |
||||
|
.conditional_container{ |
||||
|
display: flex; |
||||
|
width: 30vw; |
||||
|
min-height:20vh; |
||||
|
background: #e3eaf0; |
||||
|
position: relative; |
||||
|
padding: 5px; |
||||
|
margin-top: 1vh; |
||||
|
box-shadow: 3px 3px 5px 0px rgb(0 0 0 / 32%); |
||||
|
margin-left: 1vw; |
||||
|
margin-bottom: 1vh; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
|
||||
|
.sub_container1{ |
||||
|
height: 100%; |
||||
|
background: #e3eaf0; |
||||
|
display: flex; |
||||
|
justify-content: space-evenly; |
||||
|
align-items: center; |
||||
|
flex-direction: column; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.condition_select{ |
||||
|
width: 30%; |
||||
|
background: #71639e; |
||||
|
color: black; |
||||
|
font-weight: 500; |
||||
|
margin: 3%; |
||||
|
text-align: center; |
||||
|
padding: 1%; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
|
||||
|
.condition_val{ |
||||
|
width: 61%; |
||||
|
height: 29px; |
||||
|
margin: 2%; |
||||
|
border: 2px solid #71639e; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
|
||||
|
.condition_button{ |
||||
|
border: none; |
||||
|
background: #8b93d2; |
||||
|
margin: 4% 0; |
||||
|
padding: 1% 6%; |
||||
|
border-radius: 3px; |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
.condition_button:hover{ |
||||
|
background: #5b64ad; |
||||
|
} |
||||
|
|
||||
|
.rule_container{ |
||||
|
background: #e3eaf0; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
flex-direction: column; |
||||
|
height: 100px; |
||||
|
border: 1px solid black; |
||||
|
} |
||||
|
.input_container{ |
||||
|
display:flex; |
||||
|
} |
||||
|
|
||||
|
.sub_input_container{ |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
flex-direction: column; |
||||
|
color: black; |
||||
|
} |
||||
|
.sub_color_container{ |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
flex-direction: column; |
||||
|
padding: 0px 30px; |
||||
|
color: black; |
||||
|
} |
||||
|
.color_container{ |
||||
|
display: flex; |
||||
|
} |
||||
|
|
||||
|
.color-input{ |
||||
|
width: 34px; |
||||
|
height: 32px; |
||||
|
border: none; |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
.validation-error{ |
||||
|
display: none; |
||||
|
color: red; |
||||
|
} |
@ -0,0 +1,248 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import { PivotRenderer } from "@web/views/pivot/pivot_renderer"; |
||||
|
import { useService } from "@web/core/utils/hooks"; |
||||
|
import { patch } from '@web/core/utils/patch'; |
||||
|
import { useExternalListener, useEffect } from "@odoo/owl"; |
||||
|
|
||||
|
patch(PivotRenderer.prototype,{ |
||||
|
setup() { |
||||
|
super.setup(); |
||||
|
this.orm = useService("orm"); |
||||
|
this.isMouseDown = false; |
||||
|
this.startRowIndex = null; |
||||
|
this.startCellIndex = null; |
||||
|
useExternalListener(document, 'mouseup', this.mouse_up_function) |
||||
|
useEffect(() => { |
||||
|
this.set_default_rules() |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
async set_default_rules(){ |
||||
|
// function for default rules to be applied on the pivot table
|
||||
|
var self = this |
||||
|
var viewId = this.env.config.viewId |
||||
|
var model = this.env.searchModel.resModel |
||||
|
await this.orm.call("conditional.rules","search_read", [],{ |
||||
|
domain: [['model_id','=',model],['view_id','=',viewId]], |
||||
|
}).then(function(res){ |
||||
|
self.conditional_rules = res |
||||
|
}) |
||||
|
var cells = this.__owl__.bdom.parentEl.querySelectorAll('td') |
||||
|
cells.forEach(function(data){ |
||||
|
data.style.backgroundColor = "#f8f9fa" |
||||
|
data.style.color = "black" |
||||
|
}) |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll('.o_pivot.table-responsive table .selected_cell').forEach(cell => { |
||||
|
cell.classList.remove('selected_cell')}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_button').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_container').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
|
||||
|
for (let i = 0, len = this.conditional_rules.length; i < len; i++){ |
||||
|
var condition = this.conditional_rules[i].rule |
||||
|
var condition_val = this.conditional_rules[i].value |
||||
|
var second_condition_val = this.conditional_rules[i].second_value |
||||
|
var color_val = this.conditional_rules[i].color |
||||
|
var text_color_val = this.conditional_rules[i].text_color |
||||
|
|
||||
|
for (let j = 0, len = cells.length; j < len; j++){ |
||||
|
var cell_val = cells[j].innerText |
||||
|
if(cell_val){ |
||||
|
cell_val = cell_val.replace(',','') |
||||
|
} |
||||
|
if(condition == 'less_than'){ |
||||
|
if(parseFloat(condition_val)>parseFloat(cell_val)){ |
||||
|
cells[j].classList.remove("bg-100") |
||||
|
cells[j].style.backgroundColor = color_val |
||||
|
cells[j].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
if(condition == "greater_than"){ |
||||
|
if(parseFloat(condition_val)< parseFloat(cell_val)){ |
||||
|
cells[j].classList.remove("bg-100") |
||||
|
cells[j].style.backgroundColor = color_val |
||||
|
cells[j].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
if(condition == "is_empty"){ |
||||
|
if(cells[j].innerText == ""){ |
||||
|
cells[j].classList.remove("bg-100") |
||||
|
cells[j].style.backgroundColor = color_val |
||||
|
cells[j].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
if(condition == "in_between"){ |
||||
|
if(parseFloat(cell_val)> parseFloat(condition_val) && parseFloat(cell_val)< parseFloat(second_condition_val)){ |
||||
|
cells[j].classList.remove("bg-100") |
||||
|
cells[j].style.backgroundColor = color_val |
||||
|
cells[j].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
async conditional_format_tab(){ |
||||
|
// This function is called to display the conditional formatting
|
||||
|
// window/wizard in the UI.
|
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_container').forEach(el => { |
||||
|
el.style.display = "block"; |
||||
|
}); |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll("#condition_val")[0].value = '' |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll("#secondcondition_val")[0].value = '' |
||||
|
if(this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.validation-error')[0].style.display == "inline"){ |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.validation-error')[0].style.display = "none"; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
conditional_formattoo(e){ |
||||
|
// function for selecting table columns and adding and removing
|
||||
|
// classes
|
||||
|
if (e.target.localName == 'td' || e.target.className == 'o_value'){ |
||||
|
this.isMouseDown = true; |
||||
|
var cell; |
||||
|
if(e.target.className == 'o_value'){ |
||||
|
cell = e.target.parentElement; |
||||
|
}else{ |
||||
|
cell = e.target |
||||
|
} |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll('.o_pivot.table-responsive table .selected_cell').forEach(cell => { |
||||
|
cell.classList.remove('selected_cell'); |
||||
|
}); |
||||
|
cell.className = 'selected_cell prevent-select' |
||||
|
this.startCellIndex = cell.cellIndex; |
||||
|
this.startRowIndex = cell.parentElement.cellIndex; |
||||
|
return false; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
mouse_over_function(e){ |
||||
|
// function for selecting table columns
|
||||
|
if (!this.isMouseDown) return; |
||||
|
if (e.target.localName == 'td' || e.target.className == 'o_value'){ |
||||
|
var cell = e.target.parentElement; |
||||
|
if(e.target.className == 'o_value'){ |
||||
|
cell = e.target.parentElement; |
||||
|
}else{ |
||||
|
cell = e.target |
||||
|
} |
||||
|
cell.classList.add("selected_cell") |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_button').forEach(el => { |
||||
|
el.style.display = "block"}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
mouse_up_function(){ |
||||
|
// function for changing variable value to stop table cell selection
|
||||
|
this.isMouseDown = false; |
||||
|
}, |
||||
|
|
||||
|
display_field(){ |
||||
|
// function for hiding and showing input fields inside popup window
|
||||
|
var condition = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.condition_select')[0].value |
||||
|
if(this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.validation-error')[0].style.display == "inline"){ |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.validation-error')[0].style.display = "none"; |
||||
|
} |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'#condition_val')[0].value = '' |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'#secondcondition_val')[0].value = '' |
||||
|
if(condition == 'in between'){ |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#secondcondition_val').forEach(el => { |
||||
|
el.style.display = "block"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label').forEach(el => { |
||||
|
el.style.display = "block"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container2').forEach(el => { |
||||
|
el.style.display = "flex"}); |
||||
|
}else{ |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#secondcondition_val').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container2').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
} |
||||
|
if(condition === 'null'){ |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#condition_val').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label1').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container1').forEach(el => { |
||||
|
el.style.display = "none"}); |
||||
|
}else{ |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#condition_val').forEach(el => { |
||||
|
el.style.display = "block"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label1').forEach(el => { |
||||
|
el.style.display = "block"}); |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container1').forEach(el => { |
||||
|
el.style.display = "flex"}); |
||||
|
} |
||||
|
}, |
||||
|
set_rule(){ |
||||
|
// function for applying rules through popup window
|
||||
|
var condition = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.condition_select')[0].value |
||||
|
var color_val = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.colorpicker')[0].value |
||||
|
var text_color_val = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.text_color')[0].value |
||||
|
var cells = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'.selected_cell') |
||||
|
var condition_val = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'#condition_val')[0].value |
||||
|
var second_condition_val = this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'#secondcondition_val')[0].value |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'#condition_val')[0].value = '' |
||||
|
this.__owl__.bdom.parentEl.querySelectorAll( |
||||
|
'#secondcondition_val')[0].value = '' |
||||
|
if(condition == 'in between'){ |
||||
|
if(condition_val > second_condition_val){ |
||||
|
this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.validation-error').forEach(el => { |
||||
|
el.style.display = "inline"}); |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
for (let i = 0, len = cells.length; i < len; i++){ |
||||
|
var cell_val = cells[i].innerText |
||||
|
if(cell_val){ |
||||
|
cell_val = cell_val.replace(',','') |
||||
|
} |
||||
|
if(condition == 'less than'){ |
||||
|
if(parseFloat(condition_val)>parseFloat(cell_val)){ |
||||
|
cells[i].classList.remove("bg-100") |
||||
|
cells[i].style.backgroundColor = color_val |
||||
|
cells[i].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
if(condition == 'greater than'){ |
||||
|
if(parseFloat(condition_val)< parseFloat(cell_val)){ |
||||
|
cells[i].classList.remove("bg-100") |
||||
|
cells[i].style.backgroundColor = color_val |
||||
|
cells[i].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
if(condition == "null"){ |
||||
|
if(cells[i].innerText == ""){ |
||||
|
cells[i].classList.remove("bg-100") |
||||
|
cells[i].classList.remove("bg-100") |
||||
|
cells[i].style.backgroundColor = color_val |
||||
|
cells[i].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
if(condition == 'in between'){ |
||||
|
if(parseFloat(cell_val)> parseFloat(condition_val) && parseFloat(cell_val)< parseFloat(second_condition_val)){ |
||||
|
cells[i].classList.remove("bg-100") |
||||
|
cells[i].style.backgroundColor = color_val |
||||
|
cells[i].style.color = text_color_val |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,85 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!--XML Template for Pivot Conditional Formatting |
||||
|
|
||||
|
This XML code represents a template for implementing conditional formatting functionality in a pivot view. It defines a set of elements and attributes that can be used to create a user interface for setting conditional formatting rules in a pivot table. |
||||
|
|
||||
|
The template includes options for selecting the type of condition (e.g., "greater than," "less than"), entering the condition values, selecting colors for highlighting, and saving the formatting rule. |
||||
|
|
||||
|
Usage: |
||||
|
1. Include this XML template in the appropriate location in your application's codebase. |
||||
|
2. Customize the template as needed to match the desired user interface and functionality. |
||||
|
3. Use the defined elements and attributes to implement the conditional formatting feature in your pivot view. |
||||
|
|
||||
|
Note: This code is a template and may require integration with the rest of your application's code to fully function. It provides a starting point for implementing conditional formatting but may need additional logic and event handlers to make it work seamlessly within your application. |
||||
|
--> |
||||
|
<templates id="template" xml:space="preserve"> |
||||
|
<!-- PivotConditions template --> |
||||
|
<t t-name="pivot_conditional_formatting.PivotConditions" |
||||
|
t-inherit="web.PivotRenderer" t-inherit-mode="extension" |
||||
|
owl="1"> |
||||
|
<xpath expr="//table" position="before"> |
||||
|
<!-- Conditional formatting container --> |
||||
|
<div class="conditional_container" style="display:none"> |
||||
|
<div class="sub_container1"> |
||||
|
<!-- Dropdown for selecting condition --> |
||||
|
<select class="condition_select" |
||||
|
t-on-change="display_field"> |
||||
|
<option value="greater than">Greater Than</option> |
||||
|
<option value="in between">In Between</option> |
||||
|
<option value="null">Is Empty</option> |
||||
|
<option value="less than">Less Than</option> |
||||
|
</select> |
||||
|
<div class="input_container"> |
||||
|
<div class="sub_input_container" |
||||
|
id="sub_input_container1"> |
||||
|
<label for="condition_val" id="value_label1">Value :</label> |
||||
|
<input type="number" class="condition_val" |
||||
|
id="condition_val"/> |
||||
|
</div> |
||||
|
<div class="sub_input_container" |
||||
|
id="sub_input_container2" style="display:none"> |
||||
|
<label for="secondcondition_val" id="value_label" |
||||
|
style="display:none">Second Value :</label> |
||||
|
<input type="number" class="condition_val" |
||||
|
id="secondcondition_val" |
||||
|
style="display:none"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<span class="validation-error" > |
||||
|
First input should be greater than Second</span> |
||||
|
<div class="color_container"> |
||||
|
<div class="sub_color_container"> |
||||
|
<label for="colorpicker">Color :</label> |
||||
|
<input type="color" class="colorpicker color-input" |
||||
|
id="colorpicker"/> |
||||
|
</div> |
||||
|
<div class="sub_color_container"> |
||||
|
<label for="text_color">Text-Color :</label> |
||||
|
<input type="color" class="text_color color-input" |
||||
|
id="text_color"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- Button to save the conditional formatting rule --> |
||||
|
<button class="condition_button" |
||||
|
t-on-click="set_rule">save</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
<xpath expr="//table" position="attributes"> |
||||
|
<attribute name="t-on-mousedown">conditional_formattoo</attribute> |
||||
|
<attribute name="t-on-mouseover">mouse_over_function</attribute> |
||||
|
</xpath> |
||||
|
</t> |
||||
|
<!-- PivotConditionButton template --> |
||||
|
<t t-name="pivot_conditional_formatting.PivotConditionButton" |
||||
|
t-inherit="web.PivotView.Buttons" t-inherit-mode="extension" |
||||
|
owl="1"> |
||||
|
<xpath expr="//div[hasclass('btn-group')]" position="after"> |
||||
|
<!-- Conditional formatting button --> |
||||
|
<div class='conditional_button' style="display:none"> |
||||
|
<button class='btn btn-primary' |
||||
|
t-on-click="conditional_format_tab">Conditional Formatting</button> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</t> |
||||
|
</templates> |
@ -0,0 +1,103 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!-- |
||||
|
This XML configuration file defines views and menus for the Pivot Conditional module in Odoo. It includes view definitions for conditional rules and settings, as well as menu items to access the settings. The views are used to customize the appearance and behavior of pivot tables in Odoo. |
||||
|
--> |
||||
|
<odoo> |
||||
|
<!-- Form view for conditional.rules Model--> |
||||
|
<record id="conditional_rules_view_form" model="ir.ui.view"> |
||||
|
<field name="name">conditional.rules.view.form</field> |
||||
|
<field name="model">conditional.rules</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="rule"/> |
||||
|
<field name="value" |
||||
|
invisible="rule == 'is_empty'"/> |
||||
|
<field name="second_value" |
||||
|
invisible="rule != 'in_between'"/> |
||||
|
<field name="color" widget="color"/> |
||||
|
<field name="text_color" widget="color"/> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- List view for conditional.rules Model--> |
||||
|
<record id="conditional_rules_view_list" model="ir.ui.view"> |
||||
|
<field name="name">conditional.rule.view.list</field> |
||||
|
<field name="model">conditional.rules</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<list> |
||||
|
<field name="rule"/> |
||||
|
<field name="value" required="True" |
||||
|
invisible="rule == 'is_empty'"/> |
||||
|
<field name="second_value" |
||||
|
invisible="rule != 'in_between'"/> |
||||
|
<field name="color" widget="color"/> |
||||
|
<field name="text_color" widget="color"/> |
||||
|
</list> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- List view for pivot.conditional.settings Model--> |
||||
|
<record id="pivot_conditional_settings_view_list" model="ir.ui.view"> |
||||
|
<field name="name">pivot.conditional.settings.view.list</field> |
||||
|
<field name="model">pivot.conditional.settings</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<list> |
||||
|
<field name="model_id"/> |
||||
|
<field name="view_id"/> |
||||
|
</list> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- Form view for pivot.conditional.settings Model--> |
||||
|
<record id="pivot_conditional_settings_view_form" model="ir.ui.view"> |
||||
|
<field name="name">pivot.conditional.settings.view.form</field> |
||||
|
<field name="model">pivot.conditional.settings</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="model_id" required="True"/> |
||||
|
<field name="view_id_domain" invisible="True"/> |
||||
|
<field name="view_id" required="True" |
||||
|
invisible="model_id == False" |
||||
|
options='{"no_open": True, "no_create": True}' |
||||
|
domain="view_id_domain"/> |
||||
|
<field name="rules_ids"> |
||||
|
<list editable="bottom"> |
||||
|
<field name="rule"/> |
||||
|
<field name="value" |
||||
|
invisible="rule == 'is_empty'"/> |
||||
|
<field name="second_value" |
||||
|
invisible = "rule != 'in_between'"/> |
||||
|
<field name="color" widget="color" |
||||
|
string="Cell Color"/> |
||||
|
<field name="text_color" widget="color" |
||||
|
string="Text Color"/> |
||||
|
</list> |
||||
|
</field> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- Action for pivot.conditional.settings Model--> |
||||
|
<record id="pivot_conditional_settings_action" |
||||
|
model="ir.actions.act_window"> |
||||
|
<field name="name">Pivot Conditional Settings Action</field> |
||||
|
<field name="res_model">pivot.conditional.settings</field> |
||||
|
<field name="view_mode">list,form</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- Menu for pivot.conditional.settings Model--> |
||||
|
<menuitem id="pivot_conditional_settings_menu" name="Pivot Settings" |
||||
|
parent="base.menu_administration" sequence="1"/> |
||||
|
<menuitem id="pivot_conditional_settings_sub_menu" name="Settings" |
||||
|
parent="pivot_conditional_settings_menu" |
||||
|
action="pivot_conditional_settings_action"/> |
||||
|
</odoo> |