update modules

This commit is contained in:
eslamabady 2024-08-12 15:09:29 +03:00
parent fc93591f59
commit 840be35b2f
62 changed files with 54400 additions and 828 deletions

0
odex25_base/advanced_web_domain_widget/__init__.py Normal file → Executable file
View File

6
odex25_base/advanced_web_domain_widget/__manifest__.py Normal file → Executable file
View File

@ -10,14 +10,12 @@
#################################################################################
{
'name': 'Advanced Web Domain Widget',
'version': '14.0.2.0.0',
'version': '14.0.3.0.0',
'summary': 'Set all relational fields domain by selecting its records unsing `in, not in` operator.',
'sequence': 1,
'author': 'Terabits Technolab',
'category': 'Odex25-base',
'license': 'OPL-1',
'website': 'https://www.terabits.xyz',
'website': 'https://www.terabits.xyz/apps/14.0/advanced_web_domain_widget',
'description':"""
""",

View File

View File

@ -1 +1,2 @@
from . import domain_prepare
from . import models

View File

12
odex25_base/advanced_web_domain_widget/models/models.py Normal file → Executable file
View File

@ -5,11 +5,9 @@ class BaseModel(models.AbstractModel):
_inherit = 'base'
@api.model
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, **read_kwargs):
res = super().search_read(domain, fields, offset, limit, order, **read_kwargs)
if self._context.get('web_domain_widget') and hasattr(self, 'company_id'):
for rec in res:
rec.update({'company_name': self.browse(rec.get('id')).company_id.name})
return res
def get_widget_name(self, domain=None, fields=None, offset=0, limit=None, order=None, **read_kwargs):
return self.sudo().search_read(domain, ['id', 'display_name'], offset, limit, order)
@api.model
def get_widget_count(self, args):
return self.sudo().search_count(args)

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 401 KiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -26,238 +26,140 @@
<div id="module-description">
<!-- Keep From Here -->
<img class="img img-responsive center-block" style="border-top-left-radius:10px; border-top-right-radius:10px" src="https://www.terabits.xyz/index/img/advanced_web_domain_widget/14.0/img.png">
<div class="container">
<div class="oe_styling_v8">
<!-- Nav START -->
<div class="position-relative my-5">
<div class="row no-gutters shadow-sm" style="border-radius: 14px">
<nav class="
navbar navbar-expand-lg navbar-light
bg-light
overflow-hidden
w-100
" style="
background-color: #fff !important;
border-radius: 14px;
padding: 0px;
border: 1px solid rgb(0 0 0 / 12%);
">
<span class="navbar-brand" style="
background-color: #0A0A0A;
padding: 18px 20px 11px 20px;
color:white;
height: 100%;
">
Terabits
</span>
<!-- elearning post starts -->
<section class="blog_post_01">
<div class="position-relative w-100" style="display: inline-grid;">
<img src="img/screens/domain_bg_img_01.png"
class="img-responsive img img-fluid w-100 h-100 img img-fluid position-absolute left_0" />
<div class="ml-auto text-right" id="navbarNav">
<ul class="nav navbar-nav ml-auto text-right">
</ul>
<div class="position-relative row justify-content-center align-items-center"
style="padding: 20px 10px 40px 10px;">
<div class="col-12 my-3 px-5">
<div class="header-img">
<img src="img/screens/domain_header_img.png" class="img img-fluid w-100"
style="width: 100% !important;" />
</div>
<div class="ml-auto text-right" id="navbarNav">
<ul class="nav navbar-nav ml-auto text-right">
<li class="nav-item" style="padding: 17px 10px">
<span class="badge badge-pill badge-primary" style="
background-color: #7c7bad;
border: 1px solid #7c7bbb4f;
font-size: 14px;
color: white;
margin: 3px;
padding-left: 23px;
">
<i class="fa fa-check-circle position-absolute" style="
font-size: 16px;
margin-left: -17px;
margin-top: -2px;
"></i>
Community
</span>
<span class="badge badge-pill badge-primary" style="
background-color: #660066;
border: 1px solid rgb(144 90 123 / 29%);
font-size: 14px;
color: white;
margin: 3px;
padding-left: 23px;
">
<i class="fa fa-check-circle position-absolute" style="
font-size: 16px;
margin-left: -17px;
margin-top: -2px;
"></i>
Enterprise
</span>
<span class="badge badge-pill badge-primary" style="
background-color: #330033;
border: 1px solid rgb(144 90 123 / 29%);
font-size: 14px;
color: white;
margin: 3px;
padding-left: 23px;
">
<i class="fa fa-check-circle position-absolute" style="
font-size: 16px;
margin-left: -17px;
margin-top: -2px;
"></i>
Odoo.sh
</span>
</li>
</ul>
</div>
</nav>
</div>
</div>
<!-- Nav END -->
<!-- main intro -->
<div class="position-relative">
<div class="row pb32 pt32 align-items-center bg-white my-5 shadow" style="border-radius: 14px">
<div class="col-12">
<h2 class="oe_slogan"
style="color:#660066; font-family:Montserrat; font-weight:700; text-align:center; text-transform:uppercase; margin-bottom:18px; margin-top:18px">
Advanced Web Domain Widget
</h2>
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="https://www.terabits.xyz/index/img/advanced_web_domain_widget/14.0/img.png">
<h3 style="color: #3c4858;text-align: center;margin-bottom:18px;">
<span style="color: #000066">
"Now use the feature of select any models record in domain while using any
relational field."
</span>
<div class="blg-01-content text-center my-5">
<h1
style="font-family: 'Inter', sans-serif; font-size: 45px; font-weight: 700;line-height: 51px;color: #151765;">
Advanced web domian widget
</h1>
<h3
style="font-family: 'Inter', sans-serif; font-size: 22px; font-weight: 600;line-height: 31px; color: #1947AE;margin-top: 10px;">
"Now use the feature of select any models record in domain while using any relational field."
</h3>
<p class="mb16 text-black-dark px-3"
style="font-family:Roboto; text-align: justify; font-weight:normal; color:#11335b; font-size:16px">
Odoo base domain widget allows you to only match value or id while user wants to create
domain using any relational fields. So, user confused when model has multiple record's
id and he/she does't remembered. So, we have simplified that by showing models
record to the user. so, he/she can select by finding record and select it. our module
will autometic adds ids of selected records in domain. To select related model's record
and create domain, we allowed additional
two domain operators ('in', 'not in').
<p
style="font-family: 'Inter', sans-serif; font-size: 18px; font-weight: 500;line-height: 27px; color: #000000; margin-top: 20px;">
Odoo base domain widget allows you to only match value or id while user wants to create <br/>
domain using any relational fields. So, user confused when model has multiple record's id <br/>
and he/she does't remembered. So, we have simplified that by showing models record to <br/>
the user. so, he/she can select by finding record and select it. our module will autometic <br/>
adds ids of selected records in domain. To select related model's record and create <br/>
domain, we allowed additional two domain operators ('in', 'not in').
</p>
<!-- <section id="ah_module_heading" style="padding-top:30px">
<div class="container">
<div class="ah_center text-center">
<h2 align="center">
<a style="background-color:#EF233C; color:white; border-color:#EF233C;
box-shadow: 0 3px 6px 0px #df4a4f75; padding:1%; text-decoration:none; border-radius:6px; display:inline-block" class="btn btn-success btn-lg" href="https://youtu.be/rgW9rnD0sJM" target="_blank" savefrom_lm_index="0" savefrom_lm="1"><span class="o_ripple d-block position-absolute rounded-circle" style="height:398px; width:398px"></span>How it works? click here to watch a demo
</a><span style="padding: 0; margin: 0; margin-left: 5px;"></span>
</h2>
</div>
</div>
</section> -->
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- elearning post end -->
<!-- features highlight -->
<section class="oe_container pb-5">
<div class="mt64 mb64">
<h2 style="color:#660066; font-family:'Montserrat'; text-align:center; margin:25px auto; text-transform:uppercase"
class="oe_slogan">
<b>Highlights</b>
<section class="domain_features_02">
<div class="position-relative w-100" style="display: inline-grid;">
<img src="img/screens/domain_bg_img_02.png" class="img-responsive w-100 h-100 img img-fluid position-absolute left_0"/>
<div class="position-relative row justify-content-center align-items-center" style="padding: 20px 10px 40px 10px;">
<div class="col-12 my-3 px-5">
<div class="title text-center">
<h2 style="font-family: 'Inter', sans-serif; font-size: 45px; font-weight: 700;line-height: 61px;color: #151765;">
Features
</h2>
<div class="row">
<div class="col-md-6 col-sm-12 mt32">
<div class="container shadow"
style="border-radius:10px; padding:10px 0px;height: 100%;">
<div class="col-md-3" style="float:left">
<img class="img img-responsive" src="img/feature2.png">
</div>
<div class="col-md-9" style="padding-left:0; float:left; width:70%">
<h3 class="mt16 mb0"
style="font-family:Roboto; font-weight:500; font-size:20px">Select any
models records</h3>
<p class=" mt8" style="font-family:Roboto">
Easy to create domain of relational fields by selecting any models record in
domain. We provide additional operators ('in' and 'not in') to create
relational fields domain.
<div class="d-flex justify-content-around align-items-center mt-4">
<div style="background-color: #F1F7FF; padding: 20px 40px 20px 25px; border-radius: 8px; width: 45% !important; height: 100% !important;" class="shadow-sm">
<h6 style="font-family: 'Inter', sans-serif; font-size: 25px; font-weight: 600;line-height: 36px;color: #151765;">
Select any models records
</h6>
<div class="mt-3">
<p style="font-family: 'Inter', sans-serif; font-size: 17px; font-weight: 500;line-height: 24px;color: #151765;">
Easy to create domain of relational fields by <br/>
selecting any models record in domain. We <br/>
provide additional operators ('in' and 'not in') <br/>
to create relational fields domain.
</p>
</div>
</div>
</div>
<div class="col-md-6 col-sm-12 mt32">
<div class="container shadow"
style="border-radius:10px; padding:10px 0px;height: 100%;">
<div class="col-md-3" style="float:left">
<img class="img img-responsive" src="img/feature7.png">
</div>
<div class="col-md-9" style="padding-left:0; float:left; width:70%">
<h3 class="mt16 mb0"
style="font-family:Roboto; font-weight:500; font-size:20px">Autometic id add
in domain</h3>
<p class=" mt8" style="font-family:Roboto">
When user select models records from popup, there will generate tags of
record's names and add records id in domain.
<div style="background-color: #F1F7FF; padding: 32px 40px 32px 25px; border-radius: 8px; width: 45% !important; height: 100% !important;" class="shadow-sm">
<h6 style="font-family: 'Inter', sans-serif; font-size: 25px; font-weight: 600;line-height: 36px;color: #151765;">
Autometic id add in domain
</h6>
<div class="mt-3">
<p style="font-family: 'Inter', sans-serif; font-size: 17px; font-weight: 500;line-height: 24px;color: #151765;">
When user select models records from popup, <br/>
there will generate tags of record's names and <br/>
add records id in domain.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- features highlight -->
<!-- tabs -->
<section class="info-tabs">
<section class="info-tabs mt-5">
<div>
<div class="tabs">
<div class="justify-content-center d-flex">
<!-- Nav pills -->
<ul class="nav my-3 o_tab_nav justify-content-center"
style="border-radius:6px 6px; background-color:transparent">
<li class="nav-item mx-1" style="border-radius:6px 0 0 6px">
<a class="nav-link px-md-4 list-group-item-default list-group-item-action"
id="v-guide-tab" data-bs-toggle="pill" aria-controls="v-guide" href="#pills-guide"
style="border-radius:6px; opacity:1; padding:16px">USERGUIDE</a>
<ul class="nav nav-tabs justify-content-center" style="border-radius: 6px 6px; background-color: #ededed; padding:9px 14px 8px 14px;" role="tablist" data-tabs="tabs">
<li class="nav-item">
<a class="show "
id="v-guide-tab" data-bs-toggle="pill" aria-controls="v-guide" href="#pills-guide" aria-expanded="true" style="padding: 11px 12px 8px 12px !important;">
<span class="m-0" style="font-weight: 600; font-family: 'Inter', sans-serif; color: #1c29da;font-size: 19px; line-height: 23px;">USERGUIDE</span>
</a>
</li>
<li class="nav-item mx-1">
<a class="nav-link px-md-4 list-group-item-default list-group-item-action active"
id="v-ss-tab" data-bs-toggle="pill" aria-controls="v-ss" href="#pills-screenshot"
style="border-radius:6px; opacity:1; padding:16px">SCREENSHOTS</a>
<a class="show active"
id="v-demo-tab" data-bs-toggle="pill" aria-controls="v-ss" href="#pills-screenshot" aria-expanded="true" style="padding: 11px 12px 8px 12px !important;">
<span class="m-0" style="font-weight: 600; font-family: 'Inter', sans-serif; color: #1c29da;font-size: 19px; line-height: 23px">DEMO</span>
</a>
</li>
<li class="nav-item mx-1">
<a class="nav-link px-md-4 list-group-item-default list-group-item-action"
id="v-faqs-tab" data-bs-toggle="pill" aria-controls="v-faqs" href="#pills-faqs"
style="border-radius:6px; opacity:1; padding:16px">FAQs</a>
<a class="show"
id="v-faqs-tab" data-bs-toggle="pill" aria-controls="v-faqs" href="#pills-faqs" aria-expanded="true" style="padding: 11px 12px 8px 12px !important;">
<span class="m-0" style="font-weight: 600; font-family: 'Inter', sans-serif; color: #1c29da;font-size: 19px; line-height: 23px">FAQS</span>
</a>
</li>
<li class="nav-item mx-1">
<a class="nav-link px-md-4 list-group-item-default list-group-item-action"
id="v-release-tab" data-bs-toggle="pill" aria-controls="v-release" href="#pills-release"
style="border-radius:6px; opacity:1; padding:16px">RELEASES</a>
<li class="nav-item ">
<a class="show"
id="v-release-tab" data-bs-toggle="pill" aria-controls="v-release" href="#pills-release" aria-expanded="true" style="padding: 11px 12px 8px 12px !important;">
<span class="m-0" style="font-weight: 600; font-family: 'Inter', sans-serif; color: #1c29da;font-size: 19px; line-height: 23px">RELEASES</span>
</a>
</li>
</ul>
</div>
<div class="tab-content shadow" style="border-radius: 10px;padding: 10px 0px;"
<div class="tab-content" style="border-radius: 10px;"
id="pills-tabContent">
<!-- user-guide -->
<div class="tab-pane fade" id="pills-guide" role="tabpanel" aria-labelledby="v-guide-tab"
aria-labelledby="pills-guide-tab">
<div class="tab-pane fade py-3 shadow" id="pills-guide" role="tabpanel"
aria-labelledby="v-guide-tab" aria-labelledby="pills-guide-tab">
<div class="screenshot-description" style="margin: 1% 3%;">
<div style="border-radius: 10px;background-color: #f9f9f9;text-align:center;">
@ -287,68 +189,127 @@
</div>
<!-- screenshots tab -->
<div class="tab-pane fade text-center active show" id="pills-screenshot" role="tabpanel" aria-labelledby="v-ss-tab"
aria-labelledby="pills-screenshot-tab">
<div class="screenshot-description" style="margin: 1% 3%;">
<div style="border-radius: 10px;background-color: #f9f9f9;">
<h4 style='font-weight: 600;padding: 20px;'>Here is odoo's 'domain' widget
for domain creation.</h4>
<div class="tab-pane fade text-center active show" id="pills-screenshot" role="tabpanel"
aria-labelledby="v-ss-tab" aria-labelledby="pills-screenshot-tab">
<!-- 01 -->
<section class="blog_post_01">
<div class="position-relative w-100" style="display: inline-grid;">
<img src="img/screens/domain_bg_img_03.png"
class="img-responsive w-100 h-100 img img-fluid position-absolute left_0" />
<div class="position-relative row justify-content-center align-items-center"
style="padding: 20px 20px 40px 20px;">
<div class="col-12 my-3 px-5">
<div class="mt-2">
<div class="content-note d-flex">
<div class="icon-img">
<img src="img/screens/icon_img.png"
class="img img-fluid" />
</div>
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/ss1.png" alt="Odoo domain widget" />
</div>
<div class="screenshot-description" style="margin: 1% 3%;">
<div style="border-radius: 10px;background-color: #f9f9f9;">
<h4 style='font-weight: 600;padding: 20px;'>Here is customized
'terabits_domain' widget for domain creation.</h4>
</div>
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/ss2.png" alt="Terabits domain widget" />
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/ss3.png" alt="Terabits domain widget" />
</div>
<div class="screenshot-description" style="margin: 1% 3%;">
<div style="border-radius: 10px;background-color: #f9f9f9;">
<h4 style='font-weight: 600;padding: 20px;'>Here is customized 'date and
filter'
widget for domain creation.</h4>
</div>
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/date_filter_ss4.png" alt="Odoo domain widget" />
</div>
<div class="screenshot-description" style="margin: 1% 3%;">
<div style="border-radius: 10px;background-color: #f9f9f9;">
<h4 style='font-weight: 600;padding: 20px;'>Here is how you can select
environment company and user.</h4>
</div>
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/date_filter_ss5.png" alt="Odoo domain widget" />
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/date_filter_ss6.png" alt="Odoo domain widget" />
</div>
<div class="screenshot" style="text-align: center;">
<img class="img img-fluid oe_screenshot" style="width: 90%;margin: 2%;"
src="img/screens/date_filter_ss7.png" alt="Odoo domain widget" />
<div class="content"
style="margin-left: 15px !important;">
<p
style="font-family: 'Inter', sans-serif; font-size: 20px; font-weight: 500;line-height: 26px;color: #151765;">
Here is odoo's 'domain' widget for domain creation.
</p>
</div>
</div>
<div class="content-img text-center mt-3 mx-5">
<img src="img/screens/ss1.png"
class="img img-fluid img-responsive" />
</div>
</div>
<div class="mt-5">
<div class="content-note d-flex ">
<div class="icon-img">
<img src="img/screens/icon_img.png"
class="img img-fluid" />
</div>
<div class="content"
style="margin-left: 15px !important;">
<p
style="font-family: 'Inter', sans-serif; font-size: 20px; font-weight: 500;line-height: 26px;color: #151765;">
Here is customized 'terabits_domain' widget for domain creation.
</p>
</div>
</div>
<div class="content-img text-center mt-3 mx-5">
<img src="img/screens/ss2.png"
class="img img-fluid img-responsive" />
</div>
<div class="content-img text-center mt-4 mx-5">
<img src="img/screens/ss3.png"
class="img img-fluid img-responsive" />
</div>
</div>
<div class="mt-5">
<div class="content-note d-flex ">
<div class="icon-img">
<img src="img/screens/icon_img.png"
class="img img-fluid" />
</div>
<div class="content"
style="margin-left: 15px !important;">
<p
style="font-family: 'Inter', sans-serif; font-size: 20px; font-weight: 500;line-height: 26px;color: #151765;">
Here is customized 'date and filter' widget for domain creation.
</p>
</div>
</div>
<div class="content-img text-center mt-3 mx-5">
<img src="img/screens/date_filter_ss4.png"
class="img img-fluid img-responsive" />
</div>
</div>
<div class="mt-5">
<div class="content-note d-flex ">
<div class="icon-img">
<img src="img/screens/icon_img.png"
class="img img-fluid" />
</div>
<div class="content"
style="margin-left: 15px !important;">
<p
style="font-family: 'Inter', sans-serif; font-size: 20px; font-weight: 500;line-height: 26px;color: #151765;">
Here is how you can select environment company and user.
</p>
</div>
</div>
<div class="content-img text-center mt-3 mx-5">
<img src="img/screens/date_filter_ss5.png"
class="img img-fluid img-responsive" />
</div>
<div class="content-img text-center mt-4 mx-5">
<img src="img/screens/date_filter_ss6.png"
class="img img-fluid img-responsive" />
</div>
<div class="content-img text-center mt-4 mx-5">
<img src="img/screens/date_filter_ss7.png"
class="img img-fluid img-responsive" />
</div>
</div>
</div>
</div>
</div>
</section>
</div>
<!-- faq tab -->
<div class="tab-pane fade" id="pills-faqs" role="tabpanel" aria-labelledby="v-faqs-tab"
<div class="tab-pane fade shadow py-3" id="pills-faqs" role="tabpanel" aria-labelledby="v-faqs-tab"
aria-labelledby="pills-faqs-tab">
<div class="s_faq mt32 mb32"
style="background-color: transparent !important;padding: 0px 50px;">
style="background-color: transparent !important;padding: 40px 50px;">
<div class="panel-group" id="accordion" role="tablist"
aria-multiselectable="true">
@ -360,9 +321,9 @@
style="border:1px solid transparent !important">
<h4 class="panel-title" style="margin: 0;">
<a class="collapsed"
style="color: #000;font-size: 20px;font-weight: 500;font-family: Roboto;padding: 15px 15px 15px 50px;line-height: 158%;"
data-bs-toggle="collapse" href="#collapse1" aria-expanded="false">
<span class="panelcontent">
data-bs-toggle="collapse" href="#collapse1"
aria-expanded="false">
<span class="panelcontent" style="font-family: 'Inter', sans-serif;font-size: 20px;font-weight: 500;line-height: 25px;color: #000;">
Why should I use this app?
</span>
</a>
@ -373,7 +334,8 @@
class="panel-collapse collapse">
<div>
<p class="mb0"
style="height: auto;font-family: Roboto;padding-left: 2%;margin-left: 2%;">
style="font-family: 'Inter', sans-serif;font-size: 16px;font-weight: 400;line-height: 25px;
color: #000; padding-left:2%; margin-left:2%">
This module provides domains with an additional feature
to select any models record while using any relational
field and create a domain after selecting it. for that,
@ -395,10 +357,9 @@
style="border:1px solid transparent !important">
<h4 class="panel-title" style="margin: 0;">
<a class="collapsed"
style="color: #000;font-size: 20px;font-weight: 500;font-family: Roboto;padding: 15px 15px 15px 50px;line-height: 158%;"
data-bs-toggle="collapse" href="#collapse2"
aria-expanded="false">
<span class="panelcontent">
<span class="panelcontent" style="font-family: 'Inter', sans-serif;font-size: 20px;font-weight: 500;line-height: 25px;color: #000;">
What is user's main benifit ?
</span>
</a>
@ -409,7 +370,8 @@
class="panel-collapse collapse">
<div>
<p class="mb0"
style="height: auto;font-family: Roboto;padding-left: 2%;margin-left: 2%;">
style="font-family: 'Inter', sans-serif;font-size: 16px;font-weight: 400;line-height: 25px;
color: #000; padding-left:2%; margin-left:2%">
User's main benifit is that, he/she does not have to
remember models record id while he/she have to create
domain based on relational fields, because we direct
@ -429,10 +391,9 @@
style="border:1px solid transparent !important">
<h4 class="panel-title" style="margin: 0;">
<a class="collapsed"
style="color: #000;font-size: 20px;font-weight: 500;font-family: Roboto;padding: 15px 15px 15px 50px;line-height: 158%;"
data-bs-toggle="collapse" href="#collapse3"
aria-expanded="false">
<span class="panelcontent">
<span class="panelcontent" style="font-family: 'Inter', sans-serif;font-size: 20px;font-weight: 500;line-height: 25px;color: #000;">
Need some customization in this app, whom can I
contact?
</span>
@ -444,7 +405,8 @@
class="panel-collapse collapse">
<div>
<p class="mb0"
style="height: auto;font-family: Roboto;padding-left: 2%;margin-left: 2%;">
style="font-family: 'Inter', sans-serif;font-size: 16px;font-weight: 400;line-height: 25px;
color: #000; padding-left:2%; margin-left:2%">
Please drop an email at info@terabits.xyz or raise a
ticket through the Odoo store itself.
@ -461,10 +423,9 @@
style="border:1px solid transparent !important">
<h4 class="panel-title" style="margin: 0;">
<a class="collapsed"
style="color: #000;font-size: 20px;font-weight: 500;font-family: Roboto;padding: 15px 15px 15px 50px;line-height: 158%;"
data-bs-toggle="collapse" href="#collapse4"
aria-expanded="false">
<span class="panelcontent">
<span class="panelcontent" style="font-family: 'Inter', sans-serif;font-size: 20px;font-weight: 500;line-height: 25px;color: #000;">
Do you provide any free support?
</span>
</a>
@ -475,7 +436,8 @@
class="panel-collapse collapse">
<div>
<p class="mb0"
style="height: auto;font-family: Roboto;padding-left: 2%;margin-left: 2%;">
style="font-family: 'Inter', sans-serif;font-size: 16px;font-weight: 400;line-height: 25px;
color: #000; padding-left:2%; margin-left:2%">
Yes, I do provide free support for 90 days for any
queries or any bug/issue fixing.
@ -492,10 +454,9 @@
style="border:1px solid transparent !important">
<h4 class="panel-title" style="margin: 0;">
<a class="collapsed"
style="color: #000;font-size: 20px;font-weight: 500;font-family: Roboto;padding: 15px 15px 15px 50px;line-height: 158%;"
data-bs-toggle="collapse" href="#collapse5"
aria-expanded="false">
<span class="panelcontent">
<span class="panelcontent" style="font-family: 'Inter', sans-serif;font-size: 20px;font-weight: 500;line-height: 25px;color: #000;">
What is Support Policy of this Module?
</span>
</a>
@ -506,7 +467,8 @@
class="panel-collapse collapse">
<div>
<p class="mb0"
style="height: auto;font-family: Roboto;padding-left: 2%;margin-left: 2%;">
style="font-family: 'Inter', sans-serif;font-size: 16px;font-weight: 400;line-height: 25px;
color: #000; padding-left:2%; margin-left:2%">
In case of if any bug raised in the listed features of
this module, I am committed to providing support free of
cost. You will need to provide me server ssh access or
@ -522,42 +484,34 @@
</div>
<!-- release tab -->
<div class="tab-pane px-0 px-sm-5 fade" id="pills-release" aria-labelledby="v-release-tab"
style="padding-top: 0.25rem !important;" role="tabpanel"
aria-labelledby="pills-release-tab">
<div class="tab-pane px-0 px-sm-5 shadow fade" id="pills-release" aria-labelledby="v-release-tab" style="padding-top: 0.25rem !important;" role="tabpanel" aria-labelledby="pills-release-tab">
<div class="row my-4 p-3 pb-2 position-relative">
<div class="col-12 p-4 shadow-sm bg-white">
<h2>Changelog(s)</h2>
<div class="row my-2 p-4 position-relative">
<div class="col-12 px-0 bg-white">
<h2 style="font-family: 'Inter', sans-serif;font-size: 35px;color: #000;font-weight: 600;">Changelog(s)</h2>
<hr class="mb-4 mt-0">
<!-- v14.0.1.0.2 -->
<h2 class="h4 pb-2">
<span style="color:#00B5DB" class="pr-2">v14.0.1.0.2</span>-<span
class="pl-2">December
10, 2022</span>
<span style=" font-family: 'Inter', sans-serif; color:#00B5DB;font-size: 22px;font-weight: 600;" class="pe-2">v14.0.1.0.2</span>
<span>-</span>
<span class="ps-2" style="font-family: 'Inter', sans-serif;font-size: 23px;font-weight: 500;color: #000;">December 10, 2022</span>
</h2>
<ul class="list-unstyled">
<li class="d-flex align-items-start mb-3">
<p style="font-family: 'Inter', sans-serif;color: #000;font-size: 18px; font-weight: 500; line-height: 28px;">
Minor bug fix.
</li>
</ul>
</p>
<!-- v14.0.0.0.0 -->
<h2 class="h4 pb-2">
<span style="color:#00B5DB" class="pr-2">v14.0.0.0.0</span>-<span
class="pl-2">November
23, 2022</span>
<span style=" font-family: 'Inter', sans-serif; color:#00B5DB;font-size: 22px;font-weight: 600;" class="pe-2">v14.0.0.0.0</span>
<span>-</span>
<span class="ps-2" style="font-family: 'Inter', sans-serif;font-size: 23px;font-weight: 500;color: #000;">November 23, 2022</span>
</h2>
<ul class="list-unstyled">
<li class="d-flex align-items-start mb-3">
<p style="font-family: 'Inter', sans-serif;color: #000;font-size: 18px; font-weight: 500; line-height: 28px;">
Initial release for v14
</li>
</ul>
</p>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -12,7 +12,7 @@ var config = require('web.config');
var core = require('web.core');
var Domain = require('web.Domain');
var DomainSelector = require('advanced_web_domain_widget.TerabitsDomainSelector');
var DomainSelectorDialog = require('advanced_web_domain_widget.DomainSelectorDialog');
var {DomainSelectorDialog, DomainSelectorDialog2} = require('advanced_web_domain_widget.DomainSelectorDialog');
var view_dialogs = require('web.view_dialogs');
require("web.zoomodoo");
@ -439,8 +439,61 @@ var TerabitsFieldDomain = AbstractField.extend({
},
});
var TerabitsFieldDomain2 = TerabitsFieldDomain.extend({
_replaceContent: function () {
if (this._$content) {
this._$content.remove();
}
this._$content = $(qweb.render("TerabitsFieldDomain.content2", {
hasModel: !!this._domainModel,
isValid: !!this._isValidForModel,
nbRecords: this.record.specialData[this.name].nbRecords || 0,
inDialogEdit: this.inDialog && this.mode === "edit",
isDateFilter: this.value[0] && this.value[0]?.length>0? this.value[0][1] == "date_filter": false
}));
this._$content.appendTo(this.$el);
},
_render: function () {
// If there is no model, only change the non-domain-selector content
if (!this._domainModel) {
this._replaceContent();
return Promise.resolve();
}
// Convert char value to array value
var value = this.value || "[]";
// Create the domain selector or change the value of the current one...
var def;
if (!this.domainSelector) {
this.domainSelector = new DomainSelector.TerabitsDomainSelector2(this, this._domainModel, value, {
readonly: this.mode === "readonly" || this.inDialog,
filters: this.fsFilters,
debugMode: config.isDebug(),
});
def = this.domainSelector.prependTo(this.$el);
} else {
def = this.domainSelector.setDomain(value);
}
// ... then replace the other content (matched records, etc)
return def.then(this._replaceContent.bind(this));
},
_onDialogEditButtonClick: function (e) {
e.preventDefault();
new DomainSelectorDialog2(this, this._domainModel, this.value || "[]", {
readonly: this.mode === "readonly",
filters: this.fsFilters,
debugMode: config.isDebug(),
}).open();
},
})
return {
TerabitsFieldDomain: TerabitsFieldDomain,
TerabitsFieldDomain2: TerabitsFieldDomain2
};
});

View File

@ -239,7 +239,7 @@ BasicModel.include({
});
self._rpc({
model: domainModel,
method: 'search_count',
method: 'get_widget_count',
args: [newDomain],
context: context
})

View File

@ -6,6 +6,7 @@ odoo.define('advanced_web_domain_widget._terabits_field_registry', function (req
// Basic fields
fieldRegistry.add('terabits_domain', basic_fields.TerabitsFieldDomain);
fieldRegistry.add('terabits_field_domain', basic_fields.TerabitsFieldDomain2);
});

View File

@ -5,7 +5,7 @@ odoo.define("advanced_web_domain_widget.TerabitsDomainSelector", function (requi
var datepicker = require("web.datepicker");
var Domain = require("web.Domain");
var field_utils = require("web.field_utils");
var ModelFieldSelector = require("advanced_web_domain_widget.ModelFieldSelector");
var {ModelFieldSelector, ModelFieldSelector2} = require("advanced_web_domain_widget.ModelFieldSelector");
var ModelRecordSelector = require("advanced_web_domain_widget.ModelRecordSelector");
var Widget = require("web.Widget");
var _t = core._t;
@ -451,6 +451,33 @@ odoo.define("advanced_web_domain_widget.TerabitsDomainSelector", function (requi
},
});
var TerabitsDomainTree2 = TerabitsDomainTree.extend({
_addChild: function (domain, afterNode) {
var i = afterNode ? _.indexOf(this.children, afterNode) : this.children.length;
if (i < 0) return false;
this.children.splice(i + 1, 0, instantiateNode2(this, this.model, domain, this.options));
this.trigger_up("domain_changed", { child: this });
return true;
},
_addFlattenedChildren: function (domain) {
var node = instantiateNode2(this, this.model, domain, this.options);
if (node === null) {
return;
}
if (!node.children || node.operator !== this.operator) {
this.children.push(node);
return;
}
_.each(node.children, (function (child) {
child.setParent(this);
this.children.push(child);
}).bind(this));
node.destroy();
},
})
/**
* The TerabitsDomainSelector widget can be used to build prefix char domain. It is the
* TerabitsDomainTree specialization to use to have a fully working widget.
@ -611,6 +638,154 @@ odoo.define("advanced_web_domain_widget.TerabitsDomainSelector", function (requi
},
});
var TerabitsDomainSelector2 = TerabitsDomainTree2.extend({
template: "TerabitsDomainSelector",
events: _.extend({}, TerabitsDomainTree.prototype.events, {
"click .o_domain_add_first_node_button": "_onAddFirstButtonClick",
"change .o_domain_debug_input": "_onDebugInputChange",
}),
custom_events: _.extend({}, TerabitsDomainTree.prototype.custom_events, {
domain_changed: "_onDomainChange",
}),
start: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
if (self.invalidDomain) {
var msg = _t("This domain is not supported.");
self.$el.html(msg);
}
});
},
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* Changes the internal domain value and forces a reparsing and rerendering.
* If the internal domain value was already equal to the given one, this
* does nothing.
*
* @param {string} domain
* @returns {Promise} resolved when the rerendering is finished
*/
setDomain: function (domain) {
if (domain === Domain.prototype.arrayToString(this.getDomain())) {
return Promise.resolve();
}
var parsedDomain = this._parseDomain(domain);
if (parsedDomain) {
return this._redraw(parsedDomain);
}
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @see TerabitsDomainTree._initialize
*/
_initialize: function (domain) {
// Check if the domain starts with implicit "&" operators and make them
// explicit. As the TerabitsDomainSelector is a specialization of a TerabitsDomainTree,
// it is waiting for a tree and not a leaf. So [] and [A] will be made
// explicit with ["&"], ["&", A] so that tree parsing is made correctly.
// Note: the domain is considered to be a valid one
if (domain.length > 1) {
Domain.prototype.normalizeArray(domain);
} else {
domain = ["&"].concat(domain);
}
return this._super(domain);
},
/**
* @see TerabitsDomainTree._postRender
* Warns the user if the domain is not valid after rendering.
*/
_postRender: function () {
this._super.apply(this, arguments);
// Display technical domain if in debug mode
this.$debugInput = this.$(".o_domain_debug_input");
if (this.$debugInput.length) {
this.$debugInput.val(Domain.prototype.arrayToString(this.getDomain()));
}
// Warn the user if the domain is not valid after rendering
if (!this._isValid) {
this.do_warn(false, _t("Domain not supported"));
}
},
/**
* This method is ugly but achieves the right behavior without flickering.
*
* @param {Array|string} domain
* @returns {Promise}
*/
_redraw: function (domain) {
var oldChildren = this.children.slice();
this._initialize(domain || this.getDomain());
return this._renderChildrenTo($("<div/>")).then((function () {
_.each(oldChildren, function (child) { child.destroy(); });
this.renderElement();
this._postRender();
_.each(this.children, (function (child) {
if(child.$el){
child.$el.appendTo(this.$childrenContainer);
}
}).bind(this));
}).bind(this));
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Called when the "add a filter" button is clicked -> adds a first domain
* node
*/
_onAddFirstButtonClick: function () {
this._addChild(this.options.default || [["id", "=", 1]]);
},
/**
* Called when the debug input value is changed -> constructs the tree
* representation if valid or warn the user if invalid.
*
* @param {Event} e
*/
_onDebugInputChange: function (e) {
// When the debug input changes, the string prefix domain is read. If it
// is syntax-valid the widget is re-rendered and notifies the parents.
// If not, a warning is shown to the user and the input is ignored.
var domain;
try {
domain = Domain.prototype.stringToArray($(e.currentTarget).val());
} catch (err) { // If there is a syntax error, just ignore the change
this.do_warn(_t("Syntax error"), _t("Domain not properly formed"));
return;
}
this._redraw(domain).then((function () {
this.trigger_up("domain_changed", { child: this, alreadyRedrawn: true });
}).bind(this));
},
/**
* Called when a (child's) domain has changed -> redraw the entire tree
* representation if necessary
*
* @param {OdooEvent} e
*/
_onDomainChange: function (e) {
// If a subdomain notifies that it underwent some modifications, the
// TerabitsDomainSelector catches the message and performs a full re-rendering.
if (!e.data.alreadyRedrawn) {
this._redraw();
}
},
});
/**
* TerabitsDomainNode which handles a domain which cannot be split in another
* subdomains, i.e. composed of a field chain, an operator and a value.
@ -711,13 +886,21 @@ odoo.define("advanced_web_domain_widget.TerabitsDomainSelector", function (requi
const ids = (this.value) ? this.value : [];
wDefs.push(this._rpc({
model: model_rel,
method: 'search_read',
method: 'get_widget_name',
kwargs: {
domain: [['id', 'in', ids]],
fields: ['id', 'display_name'],
},
}).then(function (data) {
self.value = [];
if(model_rel == 'res.users' && _.contains(ids,0)){
self.tagsvalues.push([0, 'Environment User']);
self.value.push(0);
}
if(model_rel == 'res.company' && _.contains(ids,0)){
self.tagsvalues.push([0, 'Environment Company']);
self.value.push(0);
}
_.each(data, function (rec, index) {
self.tagsvalues.push([rec.id, rec.display_name]);
// to remove invalid id which is not in records
@ -1065,6 +1248,126 @@ odoo.define("advanced_web_domain_widget.TerabitsDomainSelector", function (requi
},
});
var TerabitsDomainLeaf2 = TerabitsDomainLeaf.extend({
willStart: function () {
var defs = [this._super.apply(this, arguments)];
// In edit mode, instantiate a field selector. This is done here in
// willStart and prepared by appending it to a dummy element because the
// TerabitsDomainLeaf rendering need some information which cannot be computed
// before the ModelFieldSelector is fully rendered (TODO).
this.fieldSelector = new ModelFieldSelector2(
this,
this.model,
this.chain !== undefined ? this.chain.toString().split(".") : [],
this.options
);
defs.push(this.fieldSelector.appendTo($("<div/>")).then((function () {
var wDefs = [];
var selectedField = this.fieldSelector.getSelectedField() || {};
if ((this.operator == 'in' && _.contains(['many2one', 'many2many', 'one2many'], selectedField.type) || selectedField.name == "id") && typeof (this.currentDomain[0][2][0]) == 'string') {
this.value = [];
} else {
this.value = this.currentDomain[0][2];
}
this.title = selectedField.string;
this.recordReader = new ModelRecordSelector(
this,
selectedField.relation,
this.chain !== undefined ? this.chain.toString().split(".") : [],
this.options,
this.title
);
if (!this.readonly) {
// Set list of operators according to field type
this.displayValue = this.value;
this.operators = this._getOperatorsFromType(selectedField.type, selectedField.name);
if (_.contains(["child_of", "parent_of", "like", "not like", "=like", "=ilike"], this.operator)) {
// In case user entered manually or from demo data
this.operators[this.operator] = operator_mapping[this.operator];
} else if (!this.operators[this.operator]) {
// In case the domain uses an unsupported operator for the
// field type
this.operators[this.operator] = "?";
}
// Set list of values according to field type
this.selectionChoices = null;
if (selectedField.type === "boolean") {
this.selectionChoices = [["1", _t("set (true)")], ["0", _t("not set (false)")]];
} else if (selectedField.type === "selection") {
this.selectionChoices = selectedField.selection;
}
else if ((_.contains(['many2one', 'many2many', 'one2many'], selectedField.type) || selectedField.name == "id") && (_.contains(['in', 'not in'], this.operator))) {
var model_rel = selectedField.name == "id"? selectedField.model: selectedField.relation
// var def = this.get_rec(model_rel)
// var model_rel = selectedField.relation
this.selectionChoices = null
// this.recordReader.appendTo($("<div/>"))
var self = this;
const ids = (this.value) ? this.value : [];
wDefs.push(this._rpc({
model: model_rel,
method: 'get_widget_name',
kwargs: {
domain: [['id', 'in', ids]],
fields: ['id', 'display_name'],
},
}).then(function (data) {
self.value = [];
if(model_rel == 'res.users' && _.contains(ids,0)){
self.tagsvalues.push([0, 'Environment User']);
self.value.push(0);
}
if(model_rel == 'res.company' && _.contains(ids,0)){
self.tagsvalues.push([0, 'Environment Company']);
self.value.push(0);
}
_.each(data, function (rec, index) {
self.tagsvalues.push([rec.id, rec.display_name]);
// to remove invalid id which is not in records
self.value.push(rec.id);
})
}));
wDefs.push(this.recordReader.appendTo($('<div/>')).then((function () {
this.displayValue = [];
// this.value = [];
}).bind(this)));
}
// Adapt display value and operator for rendering
try {
if (selectedField && !selectedField.relation && !_.isArray(this.value)) {
this.displayValue = field_utils.format[selectedField.type](this.value, selectedField);
}
} catch (err) {/**/ }
this.displayOperator = this.operator;
if (selectedField.type === "boolean") {
this.displayValue = this.value ? "1" : "0";
} else if ((this.operator === "!=" || this.operator === "=") && this.value === false) {
this.displayOperator = this.operator === "!=" ? "set" : "not set";
}
// TODO the value could be a m2o input, etc...
if (_.contains(["date", "datetime"], selectedField.type)) {
this.valueWidget = new (selectedField.type === "datetime" ? datepicker.DateTimeWidget : datepicker.DateWidget)(this);
wDefs.push(this.valueWidget.appendTo("<div/>").then((function () {
this.valueWidget.$el.addClass("o_domain_leaf_value_input");
this.valueWidget.setValue(moment(this.value));
this.valueWidget.on("datetime_changed", this, function () {
this._changeValue(this.valueWidget.getValue());
});
}).bind(this)));
}
return Promise.all(wDefs);
}
}).bind(this)));
return Promise.all(defs);
},
})
/**
@ -1086,8 +1389,19 @@ odoo.define("advanced_web_domain_widget.TerabitsDomainSelector", function (requi
return null
}
function instantiateNode2(parent, model, domain, options) {
if (domain.length > 1) {
return new TerabitsDomainTree2(parent, model, domain, options);
} else if (domain.length === 1) {
return new TerabitsDomainLeaf2(parent, model, domain, options);
}
return null
}
return {
TerabitsDomainSelector:TerabitsDomainSelector,
TerabitsDomainLeaf:TerabitsDomainLeaf
TerabitsDomainSelector2:TerabitsDomainSelector2,
TerabitsDomainLeaf:TerabitsDomainLeaf,
TerabitsDomainLeaf2:TerabitsDomainLeaf2,
};
});

View File

@ -10,7 +10,7 @@ odoo.define("advanced_web_domain_widget.DomainSelectorDialog", function (require
/**
* @class DomainSelectorDialog
*/
return Dialog.extend({
var DomainSelectorDialog = Dialog.extend({
init: function (parent, model, domain, options) {
this.model = model;
this.options = _.extend({
@ -51,5 +51,40 @@ odoo.define("advanced_web_domain_widget.DomainSelectorDialog", function (require
]);
},
});
var DomainSelectorDialog2 = DomainSelectorDialog.extend({
init: function (parent, model, domain, options) {
this.model = model;
this.options = _.extend({
readonly: true,
debugMode: false,
}, options || {});
var buttons;
if (this.options.readonly) {
buttons = [
{text: _t("Close"), close: true},
];
} else {
buttons = [
{text: _t("Save"), classes: "btn-primary", close: true, click: function () {
this.trigger_up("domain_selected", {domain: this.domainSelector.getDomain()});
}},
{text: _t("Discard"), close: true},
];
}
this._super(parent, _.extend({}, {
title: _t("Domain"),
buttons: buttons,
}, options || {}));
this.domainSelector = new DomainSelector.TerabitsDomainSelector2(this, model, domain, options);
},
})
return {
DomainSelectorDialog: DomainSelectorDialog,
DomainSelectorDialog2: DomainSelectorDialog2
}
});

View File

@ -586,7 +586,66 @@ var TerabitsModelFieldSelector = Widget.extend({
}
});
return TerabitsModelFieldSelector;
var TerabitsModelFieldSelector2 = TerabitsModelFieldSelector.extend({
_render: function () {
// Render the chain value
this.$value.html(core.qweb.render(this.template + ".value", {
chain: this.chain,
pages: this.pages,
}));
// Toggle the warning message
this.$valid.toggleClass('d-none', !!this.isValid());
// Adapt the popover content
var page = _.last(this.pages);
var title = "";
if (this.pages.length > 1) {
var prevField = _.findWhere(this.pages[this.pages.length - 2], {
name: (this.chain.length === this.pages.length) ? this.chain[this.chain.length - 2] : _.last(this.chain),
});
if (prevField) title = prevField.string;
}
this.$(".o_field_selector_popover_header .o_field_selector_title").text(title);
var lines = _.filter(page, this.options.filter);
if (this.searchValue) {
var matches = fuzzy.filter(this.searchValue, _.pluck(lines, 'string'));
lines = _.map(_.pluck(matches, 'index'), function (i) {
return lines[i];
});
}
this.$(".o_field_selector_page").replaceWith(core.qweb.render(this.template + ".page2", {
lines: lines,
followRelations: this.options.followRelations,
debug: this.options.debugMode,
}));
this.$input.val(this.chain.join("."));
},
_pushPageData: function (model) {
var def;
if (this.model === model && this.options.fields) {
def = Promise.resolve(sortFields(this.options.fields, model, this.options.order));
} else {
def = this._getModelFieldsFromCache(model, this.options.filters);
}
return def.then((function (fields) {
if(this.pages.length <= 0)
this.pages.push(fields);
}).bind(this));
},
_onPrevPageClick: function () {
// this._goToPrevPage();
},
})
return {ModelFieldSelector: TerabitsModelFieldSelector,
ModelFieldSelector2: TerabitsModelFieldSelector2};
/**
* Allows to transform a mapping field name -> field info in an array of the

View File

@ -104,7 +104,7 @@ odoo.define("advanced_web_domain_widget.ModelRecordSelector", function (require)
;
var def = this._rpc({
model: model,
method: 'search_read',
method: 'get_widget_name',
kwargs: {
domain: [],
fields: ['id', 'display_name'],
@ -113,6 +113,12 @@ odoo.define("advanced_web_domain_widget.ModelRecordSelector", function (require)
if (data) {
this.records = data
}
if(model == 'res.users'){
this.records.push({'id': 0, 'display_name': 'Environment User'})
}
if(model == 'res.company'){
this.records.push({'id': 0, 'display_name': 'Environment Company'})
}
// if(model == 'res.users'){
// this.records.push({'id':0,'display_name':'Environment User'})
// }

View File

View File

@ -16,6 +16,22 @@
</div>
<div t-else="">Select a model to add a filter.</div>
</t>
<t t-name="TerabitsFieldDomain.content2">
<div t-if="hasModel" class="o_field_domain_panel">
<!-- <i class="fa fa-arrow-right" role="img" aria-label="Domain" title="Domain"/>
<button t-if="isValid" class="btn btn-sm btn-secondary o_domain_show_selection_button" type="button">
<t t-esc="nbRecords"/> record(s)
</button> -->
<t t-if="!isValid">
<span class="text-warning" role="alert"><i class="fa fa-exclamation-triangle" role="img" aria-label="Warning" title="Warning"/> Invalid domain</span>
</t>
<button t-if="inDialogEdit" class="btn btn-sm btn-primary o_field_domain_dialog_button">Edit Domain</button>
</div>
<div t-else="">Select a model to add a filter.</div>
</t>
<t t-name="TerabitsDomainNode.ControlPanel">
<div t-if="!widget.readonly &amp;&amp; !widget.noControlPanel" class="o_domain_node_control_panel" role="toolbar" aria-label="Domain node">
<button class="btn o_domain_delete_node_button" title="Delete node" aria-label="Delete node"><i class="fa fa-times"/></button>
@ -259,6 +275,18 @@
</li>
</t>
</ul>
<ul t-name="TerabitsModelFieldSelector.page2" class="o_field_selector_page">
<t t-foreach="lines" t-as="line">
<t t-set="relationToFollow" t-value="followRelations(line) &amp;&amp; line.relation"/>
<li t-attf-class="o_field_selector_item #{relationToFollow and 'o_field_selector_next_page' or 'o_field_selector_select_button'}#{line_index == 0 and ' active' or ''}"
t-att-data-name="line.name">
<t t-esc="line.string"/>
<div t-if="debug" class="text-muted o_field_selector_item_title"><t t-esc="line.name"/> (<t t-esc="line.type"/>)</div>
<!-- <i t-if="relationToFollow" class="fa fa-chevron-right o_field_selector_relation_icon" role="img" aria-label="Relation to follow" title="Relation to follow"/> -->
</li>
</t>
</ul>
<ul t-name="TerabitsModelRecordSelector.page" class="o_record_selector_page">
<t t-foreach="lines" t-as="line">
<!-- <t t-set="relationToFollow" t-value="followRelations(line) &amp;&amp; line.relation"/> -->

View File

View File

@ -14,5 +14,4 @@ def post_install_action_dup_hook(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
action_data_obj = env['action.data']
for action in env['ir.actions.actions'].search([]):
print(action.name,"===================")
action_data_obj.create({'name':action.name,'action_id':action.id})

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#################################################################################
# Author : Terabits Technolab (<www.terabits.xyz>)
# Copyright(c): 2021-23
# Copyright(c): 2023-24
# All Rights Reserved.
#
# This module is copyright property of the author mentioned above.
@ -11,12 +11,12 @@
{
'name': 'Simplify Access Management',
'version': '14.0.11.4.5',
'version': '14.0.12.8.5',
'sequence': 5,
'author': 'Terabits Technolab',
'license': 'OPL-1',
'category': 'Odex25-base',
'website': 'https://www.terabits.xyz/r/SNS',
'category': 'Services',
'website': 'https://www.terabits.xyz/apps/14.0/simplify_access_management',
'summary': """All In One Access Management App for setting the correct access rights for fields, models, menus, views for any module and for any user.
All in one access management App,
Easier then Record rules setup,
@ -160,11 +160,11 @@
""",
"images": ["static/description/banner.gif"],
"price": "370.99",
"price": "280.99",
"currency": "USD",
'data': [
'security/ir.model.access.csv',
'security/res_groups.xml',
'security/ir.model.access.csv',
'data/view_data.xml',
'views/access_management_view.xml',
'views/assets.xml',

View File

@ -1,3 +1,3 @@
# from . import main
from . import action
from . import export

View File

@ -0,0 +1,22 @@
from odoo import http
from odoo.exceptions import UserError
from odoo.addons.web.controllers.main import Export
from odoo.http import request
class Export(Export):
def fields_get(self, model):
fields=super().fields_get(model)
invisible_field_ids = request.env['hide.field'].sudo().search(
[('access_management_id.company_ids', 'in', request.env.company.id),
('model_id.model', '=', model), ('access_management_id.active', '=', True),
('access_management_id.user_ids', 'in', request.env.user.id),
('invisible','=',True)])
if not invisible_field_ids:
return fields
else :
for key, value in list(fields.items()):
for invisible_field in invisible_field_ids.field_id:
if key == invisible_field.name and key != "id":
del fields[key]
return fields

View File

@ -10,14 +10,15 @@ class access_domain_ah(models.Model):
'ir.model', string='Model', index=True, required=True, ondelete='cascade')
model_name = fields.Char(string='Model Name', related='model_id.model', readonly=True, store=True)
apply_domain = fields.Boolean('Apply Filter')
domain = fields.Char(string='Filter', default='[]')
domain = fields.Char(string='Filter', default='[]',
help="The create customised domain rule where we can customise rule by selecting specific fields and records")
access_management_id = fields.Many2one('access.management','Access Management')
read_right = fields.Boolean('Read',default=True)
create_right = fields.Boolean('Create')
write_right = fields.Boolean('Write')
delete_right = fields.Boolean('Delete')
read_right = fields.Boolean('Read',default=True, help="The set 'Read' access of the selected model for the specified users")
create_right = fields.Boolean('Create', help="The set 'Create' access of the selected model for the specified users")
write_right = fields.Boolean('Write', help="The set 'Write' access of the selected model for the specified users")
delete_right = fields.Boolean('Delete', help="The set 'Delete' access of the selected model for the specified users")
@api.onchange('apply_domain')
def _check_domain(self):

View File

@ -14,7 +14,8 @@ class access_management(models.Model):
active = fields.Boolean('Active', default=True)
hide_menu_ids = fields.Many2many('ir.ui.menu', 'access_management_menu_rel_ah', 'access_management_id', 'menu_id',
'Hide Menu')
'Hide Menu',
help="The menu or submenu added on above list will be hidden from the defined users.")
hide_field_ids = fields.One2many('hide.field', 'access_management_id', 'Hide Field', copy=True)
remove_action_ids = fields.One2many('remove.action', 'access_management_id', 'Remove Action', copy=True)
@ -32,16 +33,21 @@ class access_management(models.Model):
# Chatter
hide_chatter_ids = fields.One2many('hide.chatter', 'access_management_id', 'Hide Chatter', copy=True)
hide_chatter = fields.Boolean('Hide Chatter')
hide_send_mail = fields.Boolean('Hide Send Message')
hide_log_notes = fields.Boolean('Hide Log Notes')
hide_schedule_activity = fields.Boolean('Hide Schedule Activity')
hide_chatter = fields.Boolean('Hide Chatter',
help="The Chatter will be hidden in all model from the specified users.")
hide_send_mail = fields.Boolean('Hide Send Message',
help="The Send Message button will be hidden in chatter of all model from the specified users.")
hide_log_notes = fields.Boolean('Hide Log Notes',
help="The Log Notes button will be hidden in chatter of all model from the specified users.")
hide_schedule_activity = fields.Boolean('Hide Schedule Activity',
help="The Schedule Activity button will be hidden in chatter of all model from the specified users.")
hide_export = fields.Boolean()
hide_import = fields.Boolean()
disable_login = fields.Boolean('Disable Login')
hide_export = fields.Boolean(help="The Export button will be hidden in all model from the specified users.")
hide_import = fields.Boolean(help="The Import button will be hidden in all model from the specified users.")
disable_login = fields.Boolean('Disable Login',help="The Users can not login if this button is chek.")
disable_debug_mode = fields.Boolean('Disable Developer Mode')
disable_debug_mode = fields.Boolean('Disable Developer Mode',
help="Developer mode will be hidden from the defined users.")
company_ids = fields.Many2many('res.company', 'access_management_comapnay_rel', 'access_management_id',
'company_id', 'Companies', required=True, default=lambda self: self.env.company)
@ -49,6 +55,7 @@ class access_management(models.Model):
hide_filters_groups_ids = fields.One2many('hide.filters.groups', 'access_management_id', 'Hide Filters/Group By',
copy=True)
is_apply_on_without_company = fields.Boolean()
def _count_total_rules(self):
for rec in self:
rule = 0
@ -110,7 +117,7 @@ class access_management(models.Model):
return res
def get_remove_options(self, model):
restrict_export = self.env['access.management'].search([('company_ids', 'in', self.env.company.id),
restrict_export = self.env['access.management'].sudo().search([('company_ids', 'in', self.env.company.id),
('active', '=', True),
('user_ids', 'in', self.env.user.id),
('hide_export', '=', True)], limit=1).id
@ -158,7 +165,7 @@ class access_management(models.Model):
hide_schedule_activity = False
if model and hide_send_mail or hide_log_notes or hide_schedule_activity:
hide_ids = self.env['hide.chatter'].search([('access_management_id.company_ids', 'in', company_id),
hide_ids = self.env['hide.chatter'].sudo().search([('access_management_id.company_ids', 'in', company_id),
('access_management_id.active', '=', True),
('access_management_id.user_ids', 'in', user_id),
('model_id.model', '=', model)])
@ -192,9 +199,23 @@ class access_management(models.Model):
break
if not hide_export and model:
if self.env['remove.action'].search([('access_management_id', 'in', access_ids.ids),
if self.env['remove.action'].sudo().search([('access_management_id', 'in', access_ids.ids),
('model_id.model', '=', model),
('restrict_export', '=', True)]):
hide_export = True
return hide_export
def get_hidden_field(self, model=False):
if model:
hidden_fields = []
hide_field_obj = self.env['hide.field'].sudo()
for hide_field in hide_field_obj.search(
[('access_management_id.company_ids', 'in', self.env.company.id),
('model_id.model', '=', model), ('access_management_id.active', '=', True),
('access_management_id.user_ids', 'in', self._uid), ('invisible', '=', True)]):
for field in hide_field.field_id:
if field.name:
hidden_fields.append(field.name)
return hidden_fields
return []

View File

@ -9,7 +9,9 @@ class hide_chatter(models.Model):
access_management_id = fields.Many2one('access.management', 'Access Management')
model_id = fields.Many2one('ir.model', 'Model')
hide_chatter = fields.Boolean('Chatter')
hide_send_mail = fields.Boolean('Send Message')
hide_log_notes = fields.Boolean('Log Notes')
hide_schedule_activity = fields.Boolean('Schedule Activity')
hide_chatter = fields.Boolean('Chatter'
,help="The Chatter will be hidden in selected model from the specified users.")
hide_send_mail = fields.Boolean('Send Message'
,help="The Send Message button will be hidden in chatter of selected model from the specified users.")
hide_log_notes = fields.Boolean('Log Notes', help="The Log Notes button will be hidden in chatter of selected model from the specified users.")
hide_schedule_activity = fields.Boolean('Schedule Activity',help="The Schedule Activity button will be hidden in chatter of selected model from the specified users.")

View File

@ -11,8 +11,8 @@ class hide_field(models.Model):
field_id = fields.Many2many('ir.model.fields', 'hide_field_ir_model_fields_rel', 'hide_field_id', 'ir_field_id', 'Field')
invisible = fields.Boolean('Invisible')
readonly = fields.Boolean('Read-Only')
required = fields.Boolean('Required')
external_link = fields.Boolean('Remove External Link')
invisible = fields.Boolean('Invisible', help="Selected Field will be hidden in selected model from the defined users.")
readonly = fields.Boolean('Read-Only', help="Selected Field will be Read only in selected model from the defined users.")
required = fields.Boolean('Required', help="Selected Field will be set as required for selected model from the defined users.")
external_link = fields.Boolean('Remove External Link',help="External Link will be hidden for relational fields in selected model from the defined users.")

View File

@ -9,9 +9,11 @@ class hide_filters_groups(models.Model):
model_name = fields.Char(string='Model Name', related='model_id.model', readonly=True, store=True)
filters_store_model_nodes_ids = fields.Many2many('store.filters.groups', 'filters_hide_filters_groups_store_filters_groups_rel',
'hide_id', 'store_id', string='Hide Filters', domain="[('node_option','=','filter')]")
'hide_id', 'store_id', string='Hide Filters', domain="[('node_option','=','filter')]",
help="The Defalut filter are added on list will be hidden in search view of selected model from the specified users.")
groups_store_model_nodes_ids = fields.Many2many('store.filters.groups', 'groups_hide_filters_groups_store_filters_groups_rel',
'hide_id', 'store_id', string='Hide Groups', domain="[('node_option','=','group')]")
'hide_id', 'store_id', string='Hide Groups', domain="[('node_option','=','group')]",
help="The Defalut Group are added on list will be hidden in search view of selected model from the specified users.")
access_management_id = fields.Many2one('access.management', 'Access Management')

View File

@ -12,9 +12,12 @@ class hide_view_nodes(models.Model):
model_name = fields.Char(string='Model Name', related='model_id.model', readonly=True, store=True)
btn_store_model_nodes_ids = fields.Many2many('store.model.nodes','btn_hide_view_nodes_store_model_nodes_rel','hide_id','store_id',string='Hide Button',domain="[('node_option','=','button')]")
page_store_model_nodes_ids = fields.Many2many('store.model.nodes','page_hide_view_nodes_store_model_nodes_rel','hide_id','store_id',string='Hide Tab/Page',domain="[('node_option','=','page')]")
link_store_model_nodes_ids = fields.Many2many('store.model.nodes','link_hide_view_nodes_store_model_nodes_rel','hide_id','store_id',string='Hide Kanban Link',domain="[('node_option','=','link')]")
btn_store_model_nodes_ids = fields.Many2many('store.model.nodes','btn_hide_view_nodes_store_model_nodes_rel','hide_id','store_id',string='Hide Button',domain="[('node_option','=','button')]",
help="The Buttons are added on list will be hidden in selected model from the defined users.")
page_store_model_nodes_ids = fields.Many2many('store.model.nodes','page_hide_view_nodes_store_model_nodes_rel','hide_id','store_id',string='Hide Tab/Page',domain="[('node_option','=','page')]",
help="The Tabs(pages) are added on list will be hidden in selected model from the defined users.")
link_store_model_nodes_ids = fields.Many2many('store.model.nodes','link_hide_view_nodes_store_model_nodes_rel','hide_id','store_id',string='Hide Kanban Link',domain="[('node_option','=','link')]",
help="The Kanban view action are added on list will be hidden in selected model from the defined users.")
access_management_id = fields.Many2one('access.management','Access Management')

View File

@ -5,10 +5,11 @@ from odoo import api, fields, models, tools, _
from odoo.exceptions import Warning, ValidationError,AccessError
_logger = logging.getLogger(__name__)
class ir_model_access(models.Model):
_inherit = 'ir.model.access'
# The context parameter is useful when the method translates error messages.
# But as the method raises an exception in that case, the key 'lang' might
# not be really necessary as a cache key, unless the `ormcache_context`
@ -31,6 +32,7 @@ class ir_model_access(models.Model):
self.flush(self._fields)
"""
This part is writen to by pass base access rule and apply dynamic rule of access management rule,
In case of any record found in access management.
@ -56,10 +58,11 @@ class ir_model_access(models.Model):
""",[model_numeric_id, self.env.user.id])
except:
pass
access_domain_ah_ids = self.env['access.domain.ah'].browse(row[0] for row in self._cr.fetchall()).filtered(lambda line: self.env.company in line.access_management_id.company_ids)
access_domain_ah_ids = self.env['access.domain.ah'].sudo().browse(row[0] for row in self._cr.fetchall()).filtered(lambda line: self.env.company in line.access_management_id.company_ids)
if access_domain_ah_ids:
return True
# We check if a specific rule exists
self._cr.execute("""SELECT MAX(CASE WHEN perm_{mode} THEN 1 ELSE 0 END)
FROM ir_model_access a
@ -102,7 +105,11 @@ class ir_model_access(models.Model):
resolution_info = _("Contact your administrator to request access if necessary.")
_logger.info('Access Denied by ACLs for operation: %s, uid: %s, model: %s', mode, self._uid, model)
msg = """{operation_error} {group_info} {resolution_info}""".format(
msg = """{operation_error}
{group_info}
{resolution_info}""".format(
operation_error=operation_error,
group_info=group_info,
resolution_info=resolution_info)
@ -116,10 +123,7 @@ class ir_model_access(models.Model):
if data and data[0] != 'installed':
read_value = False
if self.env.user.id and read_value:
company_id = request.httprequest.cookies.get('cids') and request.httprequest.cookies.get('cids').split(',')[0] or request.env.company.id
a = "select access_management_id from access_management_comapnay_rel where company_id = " + company_id
if not company_id:
a = "select access_management_id from access_management_comapnay_rel where company_id = NULL"
a = "select access_management_id from access_management_comapnay_rel where company_id = " + str(request.httprequest.cookies.get('cids') and request.httprequest.cookies.get('cids').split(',')[0] or request.env.company.id)
self._cr.execute(a)
a = self._cr.fetchall()
if a:
@ -136,4 +140,5 @@ class ir_model_access(models.Model):
except:
pass
return bool(r)

View File

@ -33,14 +33,14 @@ class ir_rule(models.Model):
model_list = ['mail.activity','res.users.log','res.users','mail.channel','mail.alias','bus.presence','res.lang']
if self.env.user.id and read_value and not all_data:
if model_name not in model_list:
# self._cr.execute("""SELECT am.id FROM access_management as am
# WHERE active='t' AND readonly = True AND am.id
# IN (SELECT au.access_management_id
# FROM access_management_users_rel_ah as au
# WHERE user_id = %s AND am.id
# IN (SELECT ac.access_management_id
# FROM access_management_comapnay_rel as ac
# WHERE ac.company_id=%s))"""%(self.env.user.id, self.env.company.id))
self._cr.execute("""SELECT am.id FROM access_management as am
WHERE active='t' AND readonly = True AND am.id
IN (SELECT au.access_management_id
FROM access_management_users_rel_ah as au
WHERE user_id = %s AND am.id
IN (SELECT ac.access_management_id
FROM access_management_comapnay_rel as ac
WHERE ac.company_id=%s))"""%(self.env.user.id, self.env.company.id))
# a = "select access_management_id from access_management_comapnay_rel where company_id = " + str(self.env.company.id)
# self._cr.execute(a)
# a = self._cr.fetchall()
@ -85,11 +85,13 @@ class ir_rule(models.Model):
""", [model_numeric_id, self.env.user.id])
except:
pass
access_domain_ah_ids = self.env['access.domain.ah'].browse(
access_domain_ah_ids = self.env['access.domain.ah'].sudo().browse(
row[0] for row in self._cr.fetchall()).filtered(
lambda line: self.env.company in line.access_management_id.company_ids)
# access_domain_ah_ids = access_domain_ah_ids.filtered(lambda line: self.env.company in line.access_management_id.company_ids)
if access_domain_ah_ids:
all_company = self.env['res.company'].sudo().search([]).ids
company_domain = []
domain_list = []
if model_name == 'res.partner':
# jo aya user related jetala partner 6 ana access alag thi apididha 6 error no ave atle
@ -99,8 +101,23 @@ class ir_rule(models.Model):
eval_context = self._eval_context()
# only domain records
length = len(access_domain_ah_ids.sudo()) if access_domain_ah_ids.sudo() else 0
com_domain=[]
for access in access_domain_ah_ids.sudo():
dom = safe_eval(access.domain, eval_context) if access.domain else []
if not dom and isinstance(dom,list):
if length>1:
domain_list.insert(0,'|')
domain_list += [('id', '!=', False)]
length -= 1
company_domain=[]
if self.env[model_name]._fields.get('company_id'):
if res:
for domain_tuple in res:
if isinstance(domain_tuple,tuple) and domain_tuple[0] == 'company_id':
all_company = self.env['res.company'].sudo().browse(domain_tuple[2]).ids
company_domain_tuple = ('company_id','in',access.access_management_id.company_ids.ids)
company_domain.append(company_domain_tuple)
if dom:
dom = expression.normalize_domain(dom)
for dom_tuple in dom:
@ -138,6 +155,14 @@ class ir_rule(models.Model):
right_value[zero_index] = self.env.company.id
if operator_value == 'date_filter':
domain_list += prepare_domain_v2(dom_tuple)
domain_list.insert(0,'&')
domain_list+= company_domain
else:
if company_domain:
company_domain.append(dom_tuple)
domain_list.insert(0,'&')
domain_list+= company_domain
else:
domain_list.append(dom_tuple)
else:
@ -145,7 +170,34 @@ class ir_rule(models.Model):
if length > 1:
domain_list.insert(0, '|')
length -= 1
if self.env[model_name]._fields.get('company_id'):
if res:
for domain_tuple in res:
dom = domain_tuple
if isinstance(dom,tuple):
if domain_tuple[0] == 'company_id':
if len(all_company)>1:
for company in access.access_management_id.company_ids.ids:
if company in all_company:
all_company.remove(company)
if all_company and False not in all_company:
if access.access_management_id.is_apply_on_without_company:
domain = ('company_id','in',all_company+[False])
else:
domain = ('company_id','in',all_company)
if domain not in com_domain:
com_domain.append(('company_id','in',all_company))
else:
if isinstance(domain_tuple[2],list):
if domain_tuple[2][0] not in access.access_management_id.company_ids.ids:
com_domain.append(domain_tuple)
else:
com_domain.append(domain_tuple)
if domain_list:
if com_domain:
domain_list.insert(0, '|')
domain_list+=com_domain
return domain_list
return res

View File

@ -13,12 +13,12 @@ class ir_ui_view(models.Model):
hide_button_obj = self.env['hide.view.nodes']
if name_manager.Model._name == 'res.config.settings' and node.tag == 'div' and node.get('string'):
for setting_tab in hide_button_obj.sudo().search([('access_management_id.company_ids','in',self.env.company.id),('model_id.model','=',name_manager.Model._name),('access_management_id.active','=',True),('access_management_id.user_ids','in',self._uid)]).mapped('page_store_model_nodes_ids'):
if node.get('string') == setting_tab.attribute_string and node.get('data-key') == setting_tab.attribute_name:
if node.get('data-key') == setting_tab.attribute_name:
node_info['modifiers']['invisible'] = True
node.set('invisible', '1')
if node.tag == 'a':
if node.text and '\n' not in node.text and 'type' in node.attrib.keys() and node.attrib['type'] and 'name' in node.attrib.keys() and node.attrib['name']:
if hide_view_node_obj.search([
if hide_view_node_obj.sudo().search([
('model_id.model','=',name_manager.Model._name),
('access_management_id.active','=',True),
('access_management_id.company_ids','in',self.env.company.id),
@ -38,7 +38,7 @@ class ir_ui_view(models.Model):
if hide_field.external_link:
options_dict = {}
if 'widget' in node.attrib.keys():
if node.attrib['widget'] == 'product_configurator':
if node.attrib['widget'] == 'product_configurator' or node.attrib['widget'] == 'many2one_avatar_user':
del node.attrib['widget']
if 'options' in node.attrib.keys():
options_dict = ast.literal_eval(node.attrib['options'])

View File

@ -15,7 +15,7 @@ class BaseModel(models.AbstractModel):
@api.model
def load_views(self, views, options=None):
actions_and_prints = []
for access in self.env['remove.action'].search([('access_management_id.company_ids', 'in', self.env.company.id),
for access in self.env['remove.action'].sudo().search([('access_management_id.company_ids', 'in', self.env.company.id),
('access_management_id', 'in',
self.env.user.access_management_ids.ids),
('model_id.model', '=', self._name)]):
@ -49,13 +49,13 @@ class BaseModel(models.AbstractModel):
res = super().fields_view_get(view_id, view_type, toolbar, submenu)
access_management_obj = self.env['access.management']
cids = request.httprequest.cookies.get('cids') and request.httprequest.cookies.get('cids').split(',')[0] or request.env.company.id
readonly_access_id = access_management_obj.search([('company_ids','in',int(cids)),('active','=',True),('user_ids','in',self.env.user.id),('readonly','=',True)])
readonly_access_id = access_management_obj.sudo().search([('company_ids','in',int(cids)),('active','=',True),('user_ids','in',self.env.user.id),('readonly','=',True)])
access_recs = self.env['access.domain.ah'].search([('access_management_id.company_ids','in',self.env.company.id),('access_management_id.user_ids','in',self.env.user.id),('access_management_id.active','=',True),('model_id.model','=',res['model'])])
access_model_recs = self.env['remove.action'].search([('access_management_id.company_ids','in',self.env.company.id),('access_management_id.user_ids','in',self.env.user.id),('access_management_id.active','=',True),('model_id.model','=',res['model'])])
access_recs = self.env['access.domain.ah'].sudo().search([('access_management_id.company_ids','in',self.env.company.id),('access_management_id.user_ids','in',self.env.user.id),('access_management_id.active','=',True),('model_id.model','=',res['model'])])
access_model_recs = self.env['remove.action'].sudo().search([('access_management_id.company_ids','in',self.env.company.id),('access_management_id.user_ids','in',self.env.user.id),('access_management_id.active','=',True),('model_id.model','=',res['model'])])
if view_type == 'form':
access_management_id = access_management_obj.search([('company_ids', 'in', self.env.company.id),
access_management_id = access_management_obj.sudo().search([('company_ids', 'in', self.env.company.id),
('active', '=', True),
('user_ids', 'in', self.env.user.id),
('hide_chatter', '=', True)],
@ -66,7 +66,7 @@ class BaseModel(models.AbstractModel):
div.getparent().remove(div)
res['arch'] = etree.tostring(doc, encoding='unicode')
else:
if self.env['hide.chatter'].search([('access_management_id.company_ids', 'in', self.env.company.id),
if self.env['hide.chatter'].sudo().search([('access_management_id.company_ids', 'in', self.env.company.id),
('access_management_id.active', '=', True),
('access_management_id.user_ids', 'in', self.env.user.id),
('model_id.model', '=', self._name),
@ -78,7 +78,7 @@ class BaseModel(models.AbstractModel):
div.getparent().remove(div)
res['arch'] = etree.tostring(doc, encoding='unicode')
restrict_import = access_management_obj.search([('company_ids', 'in', self.env.company.id),
restrict_import = access_management_obj.sudo().search([('company_ids', 'in', self.env.company.id),
('active', '=', True),
('user_ids', 'in', self.env.user.id),
('hide_import', '=', True)], limit=1).id
@ -187,7 +187,7 @@ class BaseModel(models.AbstractModel):
FROM access_management_users_rel_ah as amusr
WHERE amusr.user_id=%s))
""",[model_numeric_id, self.env.user.id])
records = self.env['access.domain.ah'].browse(row[0] for row in self._cr.fetchall())
records = self.env['access.domain.ah'].sudo().browse(row[0] for row in self._cr.fetchall())
except:
pass
return records
@ -214,10 +214,10 @@ class BaseModel(models.AbstractModel):
domain_list += partner_domain
# eval_context = rec._eval_context()
dom = safe_eval(record.domain) if record.domain else []
if dom:
dom = expression.normalize_domain(dom)
model_name = self._name
if isinstance(dom,list):
remove_tuple = False
for dom_tuple in dom:
if isinstance(dom_tuple, tuple):
left_value = dom_tuple[0]

View File

@ -7,16 +7,23 @@ class remove_action(models.Model):
access_management_id = fields.Many2one('access.management', 'Access Management')
model_id = fields.Many2one('ir.model', 'Model')
view_data_ids = fields.Many2many('view.data', 'remove_action_view_data_rel_ah', 'remove_action_id', 'view_data_id', 'Hide Views')
server_action_ids = fields.Many2many('action.data' ,'remove_action_server_action_data_rel_ah', 'remove_action_id', 'server_action_id', 'Hide Actions', domain="[('action_id.binding_model_id','=',model_id),('action_id.type','!=','ir.actions.report')]")
report_action_ids = fields.Many2many('action.data' ,'remove_action_report_action_data_rel_ah', 'remove_action_id', 'report_action_id', 'Hide Reports', domain="[('action_id.binding_model_id','=',model_id),('action_id.type','=','ir.actions.report')]")
restrict_export = fields.Boolean('Hide Export')
restrict_import = fields.Boolean('Hide Import')
view_data_ids = fields.Many2many('view.data', 'remove_action_view_data_rel_ah', 'remove_action_id', 'view_data_id', 'Hide Views',
help="The views are added on list will be hidden in selected model from the defined users.")
server_action_ids = fields.Many2many('action.data' ,'remove_action_server_action_data_rel_ah', 'remove_action_id', 'server_action_id', 'Hide Actions', domain="[('action_id.binding_model_id','=',model_id),('action_id.type','!=','ir.actions.report')]",
help="The actions are added on list will be hidden in selected model from the defined users.")
report_action_ids = fields.Many2many('action.data' ,'remove_action_report_action_data_rel_ah', 'remove_action_id', 'report_action_id', 'Hide Reports', domain="[('action_id.binding_model_id','=',model_id),('action_id.type','=','ir.actions.report')]",
help="The Reports are added on list will be hidden in selected model from the defined users.")
restrict_export = fields.Boolean('Hide Export',
help="Export Button will be hidden in selected model from the defined users.")
restrict_import = fields.Boolean('Hide Import',
help="Import Button will be hidden in selected model from the defined users.")
readonly = fields.Boolean('Read-Only')
restrict_create = fields.Boolean('Hide Create')
restrict_edit = fields.Boolean('Hide Edit')
restrict_delete = fields.Boolean('Hide Delete')
restrict_archive_unarchive = fields.Boolean('Hide Archive/Unarchive')
restrict_duplicate = fields.Boolean('Hide Duplicate')
restrict_chatter = fields.Boolean('Hide Chatter')
restrict_create = fields.Boolean('Hide Create',help="Create Button will be hidden in selected model from the defined users.")
restrict_edit = fields.Boolean('Hide Edit',
help="Edit Button will be hidden in selected model from the defined users.")
restrict_delete = fields.Boolean('Hide Delete',
help="Delete Button will be hidden in selected model from the defined users.")
restrict_archive_unarchive = fields.Boolean('Hide Archive/Unarchive',help="Archive and Unarchive action will be hidden in selected model from the defined users.")
restrict_duplicate = fields.Boolean('Hide Duplicate',help="Duplicate action will be hidden in selected model from the defined users.")
restrict_chatter = fields.Boolean('Hide Chatter',help="The Chatter will be hidden in selected model from the defined users.")

View File

@ -37,7 +37,7 @@ class res_users(models.Model):
self = api.Environment(cr, SUPERUSER_ID, {})[cls._name]
access_management_obj = self.env['access.management']
if access_management_obj.search([('user_ids','in',res),('disable_login','=',True)]).id:
if access_management_obj.sudo().search([('user_ids','in',res),('disable_login','=',True)]).id:
raise AccessDenied()
except AccessDenied:
_logger.info("Login failed for db:%s login:%s from ", db, login)

View File

@ -1,12 +1,22 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_access_management,access.access.management,model_access_management,,1,1,1,1
access_remove_action,access.remove.action,model_remove_action,,1,1,1,1
access_hide_field,access.hide.field,model_hide_field,,1,1,1,1
access_access_management_portal_user,access.access.management.portal.user,model_access_management,,1,0,0,0
access_remove_action_portal_user,access.remove.action.portal.user,model_remove_action,,1,0,0,0
access_hide_field_portal_user,access.hide.field.portal.user,model_hide_field,,1,0,0,0
access_access_domain_ah_portal_user,access.access.domain.ah.portal.user,model_access_domain_ah,,1,0,0,0
access_hide_view_nodes_portal_user,access.hide.view.nodes.portal.user,model_hide_view_nodes,,1,0,0,0
access_hide_filters_groups_portal_user,access_hide_filters_groups_portal_user,model_hide_filters_groups,base.group_user,1,0,0,0
access_hide_chatter_portal_user,access.hide.chatter.portal.user,model_hide_chatter,,1,0,0,0
access_action_data,access.action.data,model_action_data,,1,1,1,1
access_view_data,access.view.data,model_view_data,,1,1,1,1
access_access_domain_ah,access.access.domain.ah,model_access_domain_ah,,1,1,1,1
access_hide_view_nodes,access.hide.view.nodes,model_hide_view_nodes,,1,1,1,1
access_store_model_nodes,access.store.model.nodes,model_store_model_nodes,,1,1,1,1
access_hide_filters_groups,access_hide_filters_groups,model_hide_filters_groups,base.group_user,1,1,1,1
access_store_filters_groups,access_store_filters_groups,model_store_filters_groups,base.group_user,1,1,1,1
access_hide_chatter,access.hide.chatter,model_hide_chatter,,1,1,1,1
access_menu_item,access.menu.item,model_menu_item,,1,1,1,1
access_access_management,access.access.management,model_access_management,simplify_access_management.group_access_management_bits,1,1,1,1
access_access_domain_ah,access.access.domain.ah,model_access_domain_ah,simplify_access_management.group_access_management_bits,1,1,1,1
access_remove_action,access.remove.action,model_remove_action,simplify_access_management.group_access_management_bits,1,1,1,1
access_hide_field,access.hide.field,model_hide_field,simplify_access_management.group_access_management_bits,1,1,1,1
access_hide_view_nodes,access.hide.view.nodes,model_hide_view_nodes,simplify_access_management.group_access_management_bits,1,1,1,1
access_hide_filters_groups,access_hide_filters_groups,model_hide_filters_groups,simplify_access_management.group_access_management_bits,1,1,1,1
access_hide_chatter,access.hide.chatter,model_hide_chatter,simplify_access_management.group_access_management_bits,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_access_management access_access_management_portal_user access.access.management access.access.management.portal.user model_access_management 1 1 0 1 0 1 0
3 access_remove_action access_remove_action_portal_user access.remove.action access.remove.action.portal.user model_remove_action 1 1 0 1 0 1 0
4 access_hide_field access_hide_field_portal_user access.hide.field access.hide.field.portal.user model_hide_field 1 1 0 1 0 1 0
5 access_access_domain_ah_portal_user access.access.domain.ah.portal.user model_access_domain_ah 1 0 0 0
6 access_hide_view_nodes_portal_user access.hide.view.nodes.portal.user model_hide_view_nodes 1 0 0 0
7 access_hide_filters_groups_portal_user access_hide_filters_groups_portal_user model_hide_filters_groups base.group_user 1 0 0 0
8 access_hide_chatter_portal_user access.hide.chatter.portal.user model_hide_chatter 1 0 0 0
9 access_action_data access.action.data model_action_data 1 1 1 1
10 access_action_data access_view_data access.action.data access.view.data model_action_data model_view_data 1 1 1 1
11 access_view_data access_store_model_nodes access.view.data access.store.model.nodes model_view_data model_store_model_nodes 1 1 1 1
access_access_domain_ah access.access.domain.ah model_access_domain_ah 1 1 1 1
access_hide_view_nodes access.hide.view.nodes model_hide_view_nodes 1 1 1 1
12 access_store_model_nodes access_store_filters_groups access.store.model.nodes access_store_filters_groups model_store_model_nodes model_store_filters_groups base.group_user 1 1 1 1
access_hide_filters_groups access_hide_filters_groups model_hide_filters_groups base.group_user 1 1 1 1
13 access_store_filters_groups access_menu_item access_store_filters_groups access.menu.item model_store_filters_groups model_menu_item base.group_user 1 1 1 1
14 access_hide_chatter access_access_management access.hide.chatter access.access.management model_hide_chatter model_access_management simplify_access_management.group_access_management_bits 1 1 1 1
15 access_access_domain_ah access.access.domain.ah model_access_domain_ah simplify_access_management.group_access_management_bits 1 1 1 1
16 access_remove_action access.remove.action model_remove_action simplify_access_management.group_access_management_bits 1 1 1 1
17 access_hide_field access.hide.field model_hide_field simplify_access_management.group_access_management_bits 1 1 1 1
18 access_hide_view_nodes access.hide.view.nodes model_hide_view_nodes simplify_access_management.group_access_management_bits 1 1 1 1
19 access_hide_filters_groups access_hide_filters_groups model_hide_filters_groups simplify_access_management.group_access_management_bits 1 1 1 1
20 access_hide_chatter access.hide.chatter model_hide_chatter simplify_access_management.group_access_management_bits 1 1 1 1
21
22

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="group_access_management_spt" model="res.groups">
<record id="group_access_management_bits" model="res.groups">
<field name="name">Access Management</field>
</record>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,35 @@
odoo.define("simpily_access_management.custom_filter_item", function (require) {
"use strict";
const ControlPanel = require("web.ControlPanel");
const { patch } = require("web.utils");
var rpc = require("web.rpc");
patch(ControlPanel, "ControlPanelPatchBits", {
async mounted() {
var self = this;
this._super(...arguments);
self.removedFields = await rpc.query({
model: "access.management",
method: "get_hidden_field",
args: ["", this?.props?.view?.model],
});
this.removedFields.forEach((element) => {
delete self.fields[element];
});
},
async patched() {
var self = this;
this._super(...arguments);
self.removedFields = await rpc.query({
model: "access.management",
method: "get_hidden_field",
args: ["", this?.props?.view?.model],
});
this.removedFields.forEach((element) => {
delete self.fields[element];
});
},
});
});

View File

@ -0,0 +1,24 @@
odoo.define(
"simpily_access_management.group_by_menu",
function (require) {
"use strict";
const { patch } = require("web.utils");
const GroupByMenu = require("web.GroupByMenu");
var rpc = require("web.rpc");
patch(GroupByMenu, "GroupByMenuHideFieldPatch", {
async willStart() {
await this._super(...arguments);
const res = await rpc.query({
model: "access.management",
method: "get_hidden_field",
args: ["", this?.env?.searchModel?.config?.modelName],
});
debugger
this.fields = this.fields.filter((ele) => !res.includes(ele.name));
},
});
}
);

View File

@ -2,25 +2,29 @@ odoo.define('simplify_access_management.hide_chatter', function (require) {
"use strict";
var FormRenderer = require('web.FormRenderer');
var Session = require("web.Session");
var session = require("web.Session");
var rpc = require('web.rpc');
FormRenderer.include({
_render: function () {
const res = this._super.apply(this, arguments);
_render: async function () {
const res = await this._super.apply(this, arguments);
const self = this;
// this._super.apply(this, arguments);
var hash = window.location.hash.substring(1);
hash = JSON.parse('{"' + hash.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { return key===""?value:decodeURIComponent(value) })
if(!hash.cids) {
const session = this.getSession();
hash.cids = String(session.company_id);
var hash = window.location.hash.replace("#", '').split("&");
let cids;
if(hash.findIndex(ele => ele.includes("cid")) == -1)
cids = session.company_id;
else {
cids = hash.filter(ele => ele.includes("cid"))[0].split("=")[1].split(",");
cids = cids.length > 0? parseInt(cids[0]): session.company_id;
}
let model = hash.filter(ele=>ele.includes("model"))?.[0];
model = model? model.split("=")?.[1].split(",")?.[0]: model;
if(cids && model) {
rpc.query({
model:'access.management',
method: 'get_chatter_hide_details',
args: [parseInt(hash.cids.charAt(0)), hash.model]
args: [cids, model]
}).then(function(result){
if(result['hide_send_mail'] == false)
{
@ -51,6 +55,7 @@ odoo.define('simplify_access_management.hide_chatter', function (require) {
}
});
}
return res;
},
});

View File

@ -2,7 +2,7 @@ odoo.define('simplify_access_management.hide_export', function (require) {
"use strict";
var ListRenderer = require('web.ListRenderer');
var session
var session = require("web.Session");
var rpc = require('web.rpc');
ListRenderer.include({
@ -10,22 +10,25 @@ odoo.define('simplify_access_management.hide_export', function (require) {
_render: function () {
const res = this._super.apply(this, arguments);
const self = this;
// this._super.apply(this, arguments);
this._super.apply(this, arguments);
var hash = window.location.hash.substring(1);
hash = JSON.parse('{"' + hash.replace(/&/g, '","').replace(/=/g,'":"') + '"}', function(key, value) { return key===""?value:decodeURIComponent(value) })
if(!hash.cids) {
const session = this.getSession();
hash.cids = String(session.company_id);
var hash = window.location.hash.replace("#", '').split("&");
let cids;
if(hash.findIndex(ele => ele.includes("cid")) == -1)
cids = session.company_id;
else {
cids = hash.filter(ele => ele.includes("cid"))[0].split("=")[1].split(",");
cids = cids.length > 0? parseInt(cids[0]): session.company_id;
}
let model = hash.filter(ele=>ele.includes("model"))?.[0];
model = model? model.split("=")?.[1].split(",")?.[0]: model;
if(cids && model) {
rpc.query({
model:'access.management',
method: 'is_export_hide',
args: [parseInt(hash.cids.charAt(0)), hash.model]
args: [cids, model]
}).then(function(result){
debugger
if(result) {
debugger
var btn1 = setInterval(function() {
if ($('.o_list_export_xlsx').length) {
$('.o_list_export_xlsx').remove();
@ -34,6 +37,7 @@ odoo.define('simplify_access_management.hide_export', function (require) {
}, 50);
}
});
}
return res;
},

View File

@ -0,0 +1,24 @@
odoo.define(
"simpily_access_management.pivot_renderer_patch",
function (require) {
"use strict";
const { patch } = require("web.utils");
const PivotRenderer = require("web.PivotRenderer");
var rpc = require("web.rpc");
patch(PivotRenderer, "PivotRendererHideFieldPatch", {
async _updateTooltip() {
await this._super(...arguments);
const res = await rpc.query({
model: "access.management",
method: "get_hidden_field",
args: ["", this?.props?.modelName],
});
this.props.selectionGroupBys = this.props.selectionGroupBys.filter(
(ele) => !res.includes(ele.name)
);
},
});
}
);

View File

@ -49,7 +49,6 @@ odoo.define("advanced_web_domain_widget.DomainSelector", function (require) {
if (!this.readonly) {
// Set list of operators according to field type
this.displayValue = this.value;
debugger
this.operators = this._getOperatorsFromType(selectedField.type, selectedField.name);
if (_.contains(["child_of", "parent_of", "like", "not like", "=like", "=ilike"], this.operator)) {
// In case user entered manually or from demo data

View File

@ -4,7 +4,7 @@
<record id="access_management_form_view_ah" model="ir.ui.view">
<field name="name">access_management_form_view_ah</field>
<field name="groups_id" eval="[(4, ref('group_access_management_spt'))]"/>
<field name="groups_id" eval="[(4, ref('group_access_management_bits'))]"/>
<field name="model">access.management</field>
<field name="arch" type="xml">
<form>
@ -40,6 +40,7 @@
<group>
<field name="name" default_focus="1" required='1'/>
<field name="readonly"/>
<field name="is_apply_on_without_company"/>
<field name="company_ids" options="{'no_create': True}" widget="many2many_tags"
groups="base.group_multi_company"/>
<field name="self_model_ids" widget="many2many_tags" invisible="1"/>
@ -130,15 +131,17 @@
<!-- <field name="model_id" options="{'no_create': True}" domain="[('id','not in',parent.self_model_ids),('abstract','=',False)]" /> -->
<field name="model_id" context="{'is_access_rights': True}"
options="{'no_open': True, 'no_create': True, 'no_create_edit': True}"
required='1' domain="[('id','not in',parent.self_model_ids)]"/>
required='1' domain="[('id','not in',parent.self_model_ids)]"
width='10'/>
<field name="field_id" context="{'is_access_rights': True}"
options="{'no_open': True, 'no_create': True, 'no_create_edit': True}"
widget='many2many_tags' domain="[('model_id','=',model_id)]"/>
<field name="invisible" width='1'/>
<field name="readonly" width='1'
widget='many2many_tags' domain="[('model_id','=',model_id)]"
width='10'/>
<field name="invisible" width='10'/>
<field name="readonly" width='10'
attrs="{'column_invisible' : [('parent.readonly','=',True)]}"/>
<field name="required" width='1'/>
<field name="external_link" width='1'/>
<field name="required" width='10'/>
<field name="external_link" width='10'/>
</tree>
</field>
<p role="alert"
@ -189,12 +192,12 @@
</sheet>
</form>
<tree>
<field name="model_id"/>
<field name="domain"/>
<field name="read_right"/>
<field name="create_right"/>
<field name="write_right"/>
<field name="delete_right"/>
<field name="model_id" width='10'/>
<field name="domain" width='10'/>
<field name="read_right" width='10'/>
<field name="create_right" width='10'/>
<field name="write_right" width='10'/>
<field name="delete_right" width='10'/>
</tree>
</field>
<p role="alert"
@ -366,7 +369,7 @@
<record id="access_management_tree_view_ah" model="ir.ui.view">
<field name="name">access_management_tree_view_ah</field>
<field name="groups_id" eval="[(4, ref('group_access_management_spt'))]"/>
<field name="groups_id" eval="[(4, ref('group_access_management_bits'))]"/>
<field name="model">access.management</field>
<field name="arch" type="xml">
<tree decoration-muted="(not active)">
@ -389,8 +392,8 @@
</record>
<menuitem id="main_menu_simplify_access_management" name="Access Studio" action="action_access_management_ah"
groups="group_access_management_spt"
/>
groups="group_access_management_bits"
web_icon="simplify_access_management,static/description/icon.png"/>
</data>
</odoo>

View File

@ -5,12 +5,15 @@
<template id="assets_backend" name="simplify_access_management_view assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/simplify_access_management/static/src/js/action_items.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/widget/DomainSelector.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/widget/ModelRecordSelector.js"></script>
<!-- <script type="text/javascript" src="/simplify_access_management/static/src/js/widget/DomainSelector.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/widget/ModelRecordSelector.js"></script> -->
<script type="text/javascript" src="/simplify_access_management/static/src/js/data_manager.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/action_manager.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/hide_chatter.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/hide_export.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/pivot_renderer_patch.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/custom_filter_item.js"></script>
<script type="text/javascript" src="/simplify_access_management/static/src/js/groupby_menu.js"></script>
</xpath>
</template>
</data>

View File

@ -8,7 +8,7 @@
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<page string='Access Management' groups="simplify_access_management.group_access_management_spt">
<page string='Access Management' groups="simplify_access_management.group_access_management_bits">
<field name='access_management_ids'>
<tree>
<field name="name" />