This commit is contained in:
李鹏宇
2025-04-09 15:53:51 +08:00
parent a38e475962
commit ce4729fdf5
46 changed files with 2633 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
+32
View File
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
{
'name': "ro_wechat_redirect",
'summary': "自动登录",
'description': """
""",
'author': "",
# 'website': "https://www.yourcompany.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml
# for the full list
'category': 'basic',
'version': '0.1',
# any module necessary for this one to work correctly
# 'depends': ['base', 'base_address_extended', 'sale', 'purchase'],
'depends': ['base'],
# always loaded
'data': [
],
"assets": {
},
"application": True,
}
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import controllers
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from odoo import http
from odoo.addons.web.controllers.home import Home
from odoo.http import request
class HomeExtend(Home):
@http.route()
def web_login(self, redirect=None, **kw):
oauth_access_token = http.request.params.get('oauth_access_token')
if oauth_access_token:
login = kw.get('oauth_uid')
if login != False:
request.session.authenticate(request.session.db, login, oauth_access_token)
result = super(HomeExtend, self).web_login(redirect, **kw)
return result
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import res_users
+38
View File
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from odoo.models import INSERT_BATCH_SIZE
from odoo.tools import split_every
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
class ResUsers(models.Model):
_inherit = "res.users"
def _check_credentials(self, password, env):
""" Validates the current user's password.
Override this method to plug additional authentication methods.
Overrides should:
* call `super` to delegate to parents for credentials-checking
* catch AccessDenied and perform their own checking
* (re)raise AccessDenied if the credentials are still invalid
according to their own validation method
When trying to check for credentials validity, call _check_credentials
instead.
"""
""" Override this method to plug additional authentication methods"""
if len(self.env['res.users'].sudo().search([('oauth_access_token', '=', password)]))>0:
return True
return super(ResUsers, self)._check_credentials(password, env)
# user_id = self.env.user
# # 消息通知URL:
# url = f'/web/login?oauth_access_token={user_id.oauth_access_token}&oauth_uid={user_id.oauth_access_token}#action={action}&model={model}&view_type={view_type}&menu_id={menu_id}'
+27
View File
@@ -0,0 +1,27 @@
Odoo Proprietary License v1.0
This software and associated files (the "Software") may only be used (executed,
modified, executed after modifications) if you have purchased a valid license
from the authors, typically via Odoo Apps, or if you have received a written
agreement from the authors of the Software (see the COPYRIGHT file).
You may develop Odoo modules that use the Software as a library (typically
by depending on it, importing it and using its resources), but without copying
any source code or material from the Software. You may distribute those
modules under the license of your choice, provided that this license is
compatible with the terms of the Odoo Proprietary License (For example:
LGPL, MIT, or proprietary licenses similar to this one).
It is forbidden to publish, distribute, sublicense, or sell copies of the Software
or modified copies of the Software.
The above copyright notice and this permission notice must be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+1
View File
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
+74
View File
@@ -0,0 +1,74 @@
# Part of Odoo, Aktiv Software.
# See LICENSE file for full copyright & licensing details.
# Author: Aktiv Software.
# mail: odoo@aktivsoftware.com
# Copyright (C) 2015-Present Aktiv Software PVT. LTD.
# Contributions:
# Aktiv Software:
# - Kuldip Trapasiya
# - Tanvi Gajera
{
"name": "Tree View Advanced Search / Direct Filter in List",
"version": "17.0.1.0.0",
"category": "Advanced search on Tree view",
"summary": """This module allows a user to directly filter on the Tree / List View.
The data will be filtered Runtime.
List Filter ,
Filter List,
Column Filter,
Tree Filter,
Filter Tree,
Advance Search,
Search Advance,
Tree Search,
Direct Search,
Fast Search,
Quick Search,
Dynamic Search,
Dynamic Tree,
Data Search,
Search Data,
Data search in Tree,
X2many search,
X2many search in Tree
""",
"description": """
This module allows a user to directly single/multiple filter on the Tree / List View.
The data will be filtered Runtime. Columns can be directly searched on the Tree View.
List Filter
Column Filter
Tree Filter
Advance Search
Tree Search
Direct Search
Fast Search
Quick Search
Dynamic Search
Dynamic Tree
Data Search
Data search in Tree
X2many search
X2many search in Tree
""",
"author": "Aktiv Software",
"website": "http://www.aktivsoftware.com",
"license": "OPL-1",
"price": 95.00,
"currency": "USD",
"depends": ["web", "sale_management"],
"data": [],
"assets": {
"web.assets_backend": [
# Custum Library
"tree_view_advanced_filter/static/src/libs/**/*",
"tree_view_advanced_filter/static/src/tree_view_advanced_filter/**/*",
"tree_view_advanced_filter/static/src/web_list_num/**/*",
]
},
"images": ["static/description/banner.jpg"],
"installable": True,
"auto_install": False,
"application": False,
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 655 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

@@ -0,0 +1,542 @@
<div class="container">
<div class="oe_styling_v8">
<div class="container p-3 mb-3">
<div class="row">
<div class="col-12 d-lg-flex justify-content-between" style="border-bottom:1px solid #d5d5d5">
<div class="my-2 d-flex justify-content-center">
<img src="/default_icons/aktiv-logo.png" class="w-auto" style="height:50px !important">
</div>
<div
class="my-2 w-100 w-lg-auto d-md-flex align-items-center justify-content-around justify-content-lg-start">
<div class="text-white font-weight-bold text-center"
style="background-color:#875A7B !important; padding:5px 15px 8px !important; margin:0 5px 5px 5px !important; border-radius: 15px;">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div class="text-white font-weight-bold text-center"
style="background-color:#7C7BAD !important; padding:5px 15px 8px !important; margin:0 5px 5px 5px !important; border-radius: 15px;">
<i class="fa fa-check mr-1"></i>Community
</div>
<div class="text-white font-weight-bold text-center"
style="background-color:#875A7B !important; padding:5px 15px 8px !important; margin:0 5px 5px 5px !important; border-radius: 15px;">
<i class="fa fa-check mr-1"></i>Odoo.Sh
</div>
<div class="text-white font-weight-bold text-center"
style="background-color:#7C7BAD !important; padding:5px 15px 8px !important; margin:0 5px 5px 5px !important; border-radius: 15px;">
<i class="fa fa-check mr-1"></i>Self Hosted
</div>
</div>
</div>
</div>
</div>
<div class="container pt-0 px-4 pb-5">
<div class="row">
<div class="col-12 bg-white" style="padding:4rem 1rem !important;">
<div class="d-md-flex justify-content-center mb-2">
<img src="icon.png" class="mx-auto mr-md-2 ml-md-0 mb-2 mb-md-0" height="80px" width="80px">
<div>
<h1 class="text-center font-weight-bold display-3"
style="font-family:'Montserrat', sans-serif !important; color: #b01e2f !important">
Tree View Advanced Search / Direct Filter in List
</h1>
<p class="text-center pb-3"
style="font-family:'Montserrat', sans-serif !important; font-weight:300 !important; color:#040f3a !important; font-size:1.4rem !important;">
The module allows you to quickly search records from the list view.
</p>
</div>
</div>
<img src="GIF.gif" class="img-responsive w-100 h-auto" height="auto">
</div>
</div>
<!-- Demo video link -->
<div class="row mb-4 justify-content-center">
<a target="_blank" href="https://youtu.be/kvZ0dC6Cnnw"
style="background-color: #b01e2f !important; color: #fff !important; font-family:'Montserrat', sans-serif !important; font-size:1.4rem; border-radius: 5px; padding: 5px 15px;"
class="fw-bolder w-auto">
Video Tutorial
</a>
</div>
<div class="row">
<div class="col-12 px-3 text-center">
<h2 class="font-weight-bold"
style="color: #b01e2f !important; font-family:'Montserrat', sans-serif !important; font-size:2rem;">
Explore this module
</h2>
<div class="mt-3">
<a class="font-weight-bold" href="#overview" class="mr-5"
style="font-family:'Montserrat', sans-serif !important; font-size:1.3rem; color:#040f3a !important">Overview
<i class="fa fa-chevron-right ml-1" style="color:#282F33 !important"></i></a>
<a class="font-weight-bold" href="#features" class="mr-5"
style="font-family:'Montserrat', sans-serif !important; font-size:1.3rem; color:#040f3a !important">Key
Features <i class="fa fa-chevron-right ml-1" style="color:#282F33 !important"></i></a>
<a class="font-weight-bold" href="#setup" class="mr-5"
style="font-family:'Montserrat', sans-serif !important; font-size:1.3rem; color:#040f3a !important">Setup
&amp; Configuration
<i class="fa fa-chevron-right ml-1" style="color:#282F33 !important"></i></a>
<a class="font-weight-bold" href="#screenshots" class="mr-5"
style="font-family:'Montserrat', sans-serif !important; font-size:1.3rem; color:#040f3a !important">Screenshots
<i class="fa fa-chevron-right ml-1" style="color:#282F33 !important"></i></a>
</div>
<hr class="my-5" style="border-color:d5d5d5 !important">
</div>
</div>
<!-- OVERVIEW -->
<div class="row " id="overview">
<div class="col-12 px-4">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:2rem; color:#b01e2f !important">
Overview
</h2>
<hr
style="border: 2px solid #040f3a !important; background-color: #040f3a !important; width: 50px !important; margin-left: 0 !important; margin-bottom: 2rem !important; margin-top: 8px;">
<p class="mt-4"
style="font-size:1.1rem !important; color:#282F33 !important; font-weight:400 !important; line-height:1.85 !important">
Unlike the default search functionality of Odoo, this custom app allows user to use dynamic single/multiple
search filter on the Tree / List View in all the base and custom Odoo modules. The data will be
filtered Runtime.
For e.g., if user wants to search single/multiple quotation for customers in the invoice module, he/she can
search the single as well as multi customers by their invoice number, invoice creation date, delivery date, customer
name, invoice date, source document, sales person, company, due date, tax, total amount, amount
due, status, etc.
In short, each field/column in the list/tree view will contain an advanced single/multiple filter option to
easily access the data anywhere.
</p>
</div>
</div>
<!-- FEATURES -->
<div class="row my-5" id="features">
<div class="col-sm-12 col-md-12 col-lg-12 px-4">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:2rem; color:#b01e2f !important">
Features
</h2>
<hr
style="border: 2px solid #040f3a !important; background-color: #040f3a !important; width: 50px !important; margin-left: 0 !important; margin-bottom: 2rem !important; margin-top: 8px;">
<div class="row">
<div class="col-12">
<div class="row">
<div class="col-sm-12 col-md-6 my-3" style="border-bottom:2px solid #f0f0f0;">
<div class="d-flex" style="padding:1rem 0px !important;">
<img src="/default_icons/check.png" width="20px" height="20px" class="mr-2 me-2">
<h3 style="font-size:1.2rem !important">Single/multiple search runtime on every tree views with
advanced filter option</h3>
</div>
</div>
<div class="col-sm-12 col-md-6 my-3" style="border-bottom:2px solid #f0f0f0;">
<div class="d-flex" style="padding:1rem 0px !important;">
<img src="/default_icons/check.png" width="20px" height="20px" class="mr-2 me-2">
<h3 style="font-size:1.2rem !important">In Date or Datetime fields, a range
selection will be visible</h3>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="row">
<div class="col-sm-12 col-md-6 my-3" style="border-bottom:2px solid #f0f0f0;">
<div class="d-flex" style="padding:1rem 0px !important;">
<img src="/default_icons/check.png" width="20px" height="20px" class="mr-2 me-2">
<h3 style="font-size:1.2rem !important">User can easily search on text,
date/datetime, many2one, integer/float columns</h3>
</div>
</div>
<div class="col-sm-12 col-md-6 my-3" style="border-bottom:2px solid #f0f0f0;">
<div class="d-flex" style="padding:1rem 0px !important;">
<img src="/default_icons/check.png" width="20px" height="20px" class="mr-2 me-2">
<h3 style="font-size:1.2rem !important">Integer and Float columns will search
for the exact value</h3>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="row">
<div class="col-sm-12 col-md-6 my-3" style="border-bottom:2px solid #f0f0f0;">
<div class="d-flex" style="padding:1rem 0px !important;">
<img src="/default_icons/check.png" width="20px" height="20px" class="mr-2 me-2">
<h3 style="font-size:1.2rem !important">Single/multi Search runtime on every tree views of
the relational fields(X2many) with advanced filter option</h3>
</div>
</div>
<div class="col-sm-12 col-md-6 my-3" style="border-bottom:2px solid #f0f0f0;">
<div class="d-flex" style="padding:1rem 0px !important;">
<img src="/default_icons/check.png" width="20px" height="20px" class="mr-2 me-2">
<h3 style="font-size:1.2rem !important">Apply multiple search filters on single column.
</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- SETUP & CONFIGURATION -->
<div class="row mb-5" id="setup">
<div class="col-12 px-4">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:2rem; color:#b01e2f !important">
Setup &amp; Configuration
</h2>
<hr
style="border: 2px solid #040f3a !important; background-color: #040f3a !important; width: 50px !important; margin-left: 0 !important; margin-bottom: 2rem !important; margin-top: 8px;">
<div class="mt-5">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:1.2rem; color:#b01e2f !important">
No prerequisites required before installation.
</h2>
<ul class="mb-2 pb-2">
<li class="p-1" style="border-bottom: 2px solid #f0f0f0;">
<h3 style="font-size:1.2rem !important">Required Apps
</h3>
<p>
Web
</p>
</li>
</ul>
</div>
<div class="mt-5">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:1.2rem; color:#b01e2f !important">
Configuration.
</h2>
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">No configurations.
</h3>
</div>
</div>
</div>
</div>
</div>
<!-- SCREENSHOTS -->
<div class="row mb-5" id="screenshots">
<div class="col-12 px-4">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:2rem; color:#b01e2f !important">
Screenshots
</h2>
<hr
style="border: 2px solid #040f3a !important; background-color: #040f3a !important; width: 50px !important; margin-left: 0 !important; margin-bottom: 2rem !important; margin-top: 8px;">
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Single/multi search Runtime on Tree Views
</h3>
<p>
After Installing this module, User will see an extra row in every tree view which
includes the column filter.
User can easily search on text, date/datetime, many2one, integer/float columns.
</p>
</div>
</div>
<img src="Browser_Screen_Mockup_1.jpg" class="img-responsive img-thumbnail border">
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Apply multiple search filters on text, many2one, integer/float columns.
</h3>
</div>
</div>
<img src="Browser_Screen_Mockup_2.jpg" class="img-responsive img-thumbnail border">
</div>
<!-- <div class="mt-5">
<img src="Browser_Screen_Mockup_2.jpg" class="img-responsive img-thumbnail border">
</div> -->
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Filter will not be visible on widgets and
non-stored compute columns.
</h3>
</div>
</div>
<img src="Browser_Screen_Mockup_3.jpg" class="img-responsive img-thumbnail border">
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Single/multi search Runtime on Tree View of relational fields
(X2many)</h3>
</div>
</div>
<img src="Browser_Screen_Mockup_4.jpg" class="img-responsive img-thumbnail border">
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div class="">
<h3 style="font-size:1.2rem !important">Apply multiple search filters on single columns</h3>
</div>
</div>
<img src="Browser_Screen_Mockup_5.jpg" class="img-responsive img-thumbnail border">
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Single/ multi filter can be apply on the
folded list view i.e in group by mode.
</h3>
</div>
</div>
<img src="Browser_Screen_Mockup_6.jpg" class="img-responsive img-thumbnail border">
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Text and M2O Columns.
</h3>
<p>
It is very easy to search the data in Many2one and Selection fields.
The record count and the summation of the column value will also be adjusted based
on the data.
</p>
</div>
</div>
<img src="Browser_Screen_Mockup_7.jpg" class="img-responsive img-thumbnail border">
</div>
<div class="mt-5">
<div class="d-flex mb-2 pb-2">
<img src="/default_icons/arrow.png" width="20px" height="20px" class="mr-2 me-2">
<div>
<h3 style="font-size:1.2rem !important">Integer and Float Columns.
</h3>
<p>
Integer and Float columns will single/multi search for the exact value inputted by the user.
</p>
</div>
</div>
<img src="Browser_Screen_Mockup_8.jpg" class="img-responsive img-thumbnail border">
</div>
</div>
</div>
<!-- SUGGESTED APPS -->
<div class="row mt-3">
<div class="col-lg-12 d-flex flex-column justify-content-center" style="padding:2.5rem 15px !important">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:2rem; color:#b01e2f !important">
Suggested Apps
</h2>
<hr
style="border: 2px solid #040f3a !important; background-color: #040f3a !important; width: 50px !important; margin-left: 0 !important; margin-bottom: 2rem !important; margin-top: 8px;">
<div id="product_slider" class="row carousel slide mt-4 data-ride=" carousel="">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active" style="min-height: 193.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/13.0/garage_management/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100 h-auto"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./suggested_apps/garbage_management.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/product_social_share_aktiv/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100 h-auto"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./suggested_apps/product_social_media.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/ecommerce_country_product_restriction/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100 h-auto"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./suggested_apps/ecommerce_contry_restriction.jpg">
</div>
</a>
</div>
</div>
<div class="carousel-item" style="min-height: 193.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/user_recent_log/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100 h-auto"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./suggested_apps/user_activity_log.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/web_odoo_dynamic_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100 h-auto"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./suggested_apps/web_dynamic_dashboard.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/website_product_stock_aktiv/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100 h-auto"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./suggested_apps/website_product_stock.jpg">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#product_slider" data-slide="prev"
style="width:35px; color:#000"> <span class="carousel-control-prev-icon"><i
class="fa fa-chevron-left" style="font-size:24px"></i></span> </a> <a
class="carousel-control-next" href="#product_slider" data-slide="next"
style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF SUGGESTED PRODUCTS -->
<!-- OUR SERVICES -->
<section style="margin-top:2rem !important">
<div class="row">
<div class="col-lg-12">
<h2 class="font-weight-bold"
style="font-family:'Montserrat', sans-serif !important; font-size:2rem; color:#b01e2f !important">
Our Services
</h2>
<hr
style="border: 2px solid #040f3a !important; background-color: #040f3a !important; width: 50px !important; margin-left: 0 !important; margin-bottom: 2rem !important; margin-top: 8px;">
</div>
<div
class="col-md-4 col-sm-6 col-12 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="border-radius:15px !important; height:80px; width:80px">
<img src="/default_icons/Odoo_Consulting.png" class="img-responsive"
style="border-radius:15px !important; height:80px; width:80px">
</div>
<h6 class="text-center"
style="font-family:Montserrat, 'sans-serif' !important; font-weight:bold">
Odoo
Consulting
</h6>
</div>
<div
class="col-md-4 col-sm-6 col-12 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="border-radius:15px !important; height:80px; width:80px">
<img src="/default_icons/Odoo_Customization.png" class="img-responsive"
style="border-radius:15px !important; height:80px; width:80px">
</div>
<h6 class="text-center"
style="font-family:Montserrat, 'sans-serif' !important; font-weight:bold">
Odoo
Customization
</h6>
</div>
<div
class="col-md-4 col-sm-6 col-12 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="border-radius:15px !important; height:80px; width:80px">
<img src="/default_icons/Odoo_Implementation.png" class="img-responsive"
style="border-radius:15px !important; height:80px; width:80px">
</div>
<h6 class="text-center"
style="font-family:Montserrat, 'sans-serif' !important; font-weight:bold">
Odoo
Implementation
</h6>
</div>
<div
class="col-md-4 col-sm-6 col-12 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="border-radius:15px !important; height:80px; width:80px">
<img src="/default_icons/Odoo_Integration.png" class="img-responsive"
style="border-radius:15px !important; height:80px; width:80px">
</div>
<h6 class="text-center"
style="font-family:Montserrat, 'sans-serif' !important; font-weight:bold">
Odoo
Integration
</h6>
</div>
<div
class="col-md-4 col-sm-6 col-12 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="border-radius:15px !important; height:80px; width:80px">
<img src="/default_icons/Odoo_Migration.png" class="img-responsive"
style="border-radius:15px !important; height:80px; width:80px">
</div>
<h6 class="text-center"
style="font-family:Montserrat, 'sans-serif' !important; font-weight:bold">
Odoo
Migration
</h6>
</div>
<div
class="col-md-4 col-sm-6 col-12 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="border-radius:15px !important; height:80px; width:80px">
<img src="/default_icons/Odoo_Support.png" class="img-responsive"
style="border-radius:15px !important; height:80px; width:80px">
</div>
<h6 class="text-center"
style="font-family:Montserrat, 'sans-serif' !important; font-weight:bold">
Odoo
Support
</h6>
</div>
</div>
</section>
<!-- END OF END OF OUR SERVICES -->
<!-- FOOTER -->
<!-- Don't Remove Below Part -->
<div>
<h2 class="oe_slogan">
<a href="http://aktivsoftware.com/" target="new">
<img src="/default_icons/aktiv-logo.png" class="img img-responsive" />
</a>
<br />
<a href="mailto:sales@aktivsoftware.com" style="color: #000000 !important;">
Get Help &amp; Support
</a>
</h2>
<div class="oe_slogan oe_spaced text-center">
<a class="btn btn success mt8" title="website" target="new"
style="background-color: #b01e2f !important; border-radius: 5px !important; color: #ffffff !important; position:relative; overflow: hidden;"
href="http://aktivsoftware.com/"><b>Website</b></a>
<a class="btn btn success mt8" title="Contact Us"
style="background-color: #b01e2f !important; border-radius: 5px !important; color: #ffffff !important; position:relative; overflow: hidden;"
href="mailto:sales@aktivsoftware.com"><b>Contact Us</b></a>
<a class="btn btn success mt8" title="Request New Features Now!"
style="background-color: #b01e2f !important; border-radius: 5px !important; color: #ffffff !important; position:relative; overflow: hidden;"
href="mailto:sales@aktivsoftware.com"><b>Request For New Features</b></a>
</div>
</div>
<!-- END OF FOOTER -->
</div>
</div>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

@@ -0,0 +1,71 @@
.tree_search_item {
cursor: pointer;
}
.tree_search_item .selected a:before {
font-family: FontAwesome;
position: absolute;
left: 10px;
top: 10px;
}
input.input_text{
transition: all 0.3s ease;
}
.search_div{
display: flex;
align-items: center;
border: 1px solid #1a4040;
font-size: 15px !important;
border-radius: 8px;
text-align: center;
overflow: hidden;
padding: 2px;
}
.input_text{
flex: 2;
border: none!important;
}
.search_button{
margin: 0px 0px;
border:none
}
.search_button:hover{
color: blueviolet;
}
.remove_button{
border:none
}
.remove_button:hover{
color: indianred;
}
.hidden_button{
display:none
}
.table_layout
{
table-layout:auto
}
.auto-overflow {
overflow: auto !important;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.auto-overflow::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.auto-overflow {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.min-wp-50 {
min-width: 50px !important;
}
@@ -0,0 +1,13 @@
// /** @odoo-module */
import { SearchModel } from "@web/search/search_model";
import { patch } from "@web/core/utils/patch";
patch(SearchModel.prototype, {
async _reloadSections() {
super._reloadSections(...arguments);
if (this.ak_domains) {
this._domain = this.domain.concat(this.ak_domains);
}
},
});
@@ -0,0 +1,594 @@
/** @odoo-module */
import { ListRenderer } from "@web/views/list/list_renderer";
import { browser } from "@web/core/browser/browser";
import { patch } from "@web/core/utils/patch";
import { session } from "@web/session";
import { serialize } from "@web/core/l10n/dates";
import { serializeDateTime } from "@web/core/l10n/dates";
import { loadJS, loadCSS } from "@web/core/assets";
const { onMounted, onPatched } = owl;
const { DateTime } = luxon;
export const ListRendererCust = {
setup() {
super.setup();
browser.sessionStorage.setItem('domainlist', JSON.stringify([])); // Replaced localStorage with sessionStorage
onMounted(() => {
this._renderSearchPanel()
});
onPatched(() => {
this._renderSearchPanel()
});
},
_renderSearchPanel: async function () {
await loadJS("https://cdn.jsdelivr.net/jquery/latest/jquery.min.js")
await loadJS("https://cdn.jsdelivr.net/momentjs/latest/moment.min.js")
await loadJS("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js")
await loadCSS("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css")
var List = this.props.list;
const bm_params = List.model.__bm_load_params__;
const rootRef = this.rootRef.el
const tableRef = this.tableRef.el;
tableRef.removeAttribute('style')
var columns = this.allColumns.filter((col) => {
if (col.optional && this.optionalActiveFields[col.name] == false) {
return false;
}
if (col.column_invisible == true || col.column_invisible && col.invisible) {
return false;
}
// if (col.optional == 'hide'){
// return false;
// }
if (['in_invoice', 'in_refund', 'in_receipt'].includes(this.props.list.evalContext.default_move_type)){
if (['Vendor', 'Invoice Date'].includes(col.string)) {
return false;
}
}
if (['out_invoice', 'out_refund', 'out_receipt'].includes(this.props.list.evalContext.default_move_type)){
if (['Customer', 'Bill Date'].includes(col.string)) {
return false;
}
}
if (col.name == 'move_type'){
return false;
}
return true;
});
var $tr1 = $('<tr>').append(columns.map(columns => this._renderHeaderCellSearch(columns)));
if (this.hasSelectors) {
$tr1.prepend($('<td>').addClass('o_list_record_selector'));
}
if (this.isStudioEditable || this.displayOptionalFields) {
$tr1.append($('<td>').addClass('o_list_record_selector'));
}
if ($(tableRef).find('.search_td').length) {
$(tableRef).find('.search_td').parent().replaceWith($tr1)
}
else {
$tr1.insertAfter($(tableRef).find('tr')[0]);
}
rootRef.querySelectorAll('thead tr td.search_td input').forEach((a) => a.addEventListener('keyup', this._onfilter.bind(this)));
rootRef.querySelectorAll('.search_button').forEach((a) => a.addEventListener('click', this._onSearch.bind(this)));
rootRef.querySelectorAll('.remove_button').forEach((a) => a.addEventListener('click', this._onRemove.bind(this)));
rootRef.querySelectorAll('thead tr td').forEach((a) => a.addEventListener('keypress', this._onKeyPress.bind(this)));
},
_renderHeaderCellSearch: function (node) {
var List = this.props.list
var search_tr = $($('tr')[1]).find('input.input_text')
var old_domain = JSON.parse(browser.sessionStorage.getItem('domainlist'))
var input_dict = {}
var self = this;
var $td = $('<td>', {
class: 'search_td'
});
for (var i = 0; i < search_tr.length; i++) {
var field = $(search_tr[i]).attr('name')
var value = $(search_tr[i]).val()
input_dict[String(field)] = value
}
if (node.type != 'field') {
return $td
}
const {
name,
string,
widget,
} = node;
var searched_value = old_domain.filter(function (domain) {
return domain[0] == name;
});
var widget_list = ["monetary", "date", "many2one_avatar_user", "badge", "task_with_hours", "timesheet_uom", "sol_product_many2one"];
var value_of_tr = searched_value.length > 0 ? searched_value[0][2] : ""
var field = List.fields[name];
if (name) {
$td.attr('data-name', name);
} else if (string) {
$td.attr('data-string', string);
}
if (!field) {
return $td;
}
var description = string || field.string;
// search elements
var search_div = $('<div>').attr({
'class': 'search_div d-inline-flex auto-overflow'
});
var $input = $('<input>').attr({
name: name,
data_name: name,
data_text: string,
placeholder: description,
autocomplete: "autocomplete",
'class': 'input_text min-wp-50'
});
var search_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'search_button fa fa-search'
});
var remove_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'remove_button fa fa-remove',
});
// Prepare search bars
if (!widget || widget_list.includes(widget)) {
if (string !== " " && field.store) {
if (field.type == 'selection') {
var selection_options = []
for (let option = -1; option < field.selection.length - 1; option += 1) {
selection_options.push((field.selection[option], field.selection[option + 1]))
}
const selection_input = '<select class="input_text input_select" type="select" name=' + name + ' data_name=' + name + ' data_text=' + string + ' placeholder=' + description + ' style="height:25px;">'
var option = '<option selected="selected" class="text-muted" value> -- Select -- </option>';
$.each(field.selection, function (index, value) {
option += '<option value="' + value[0] + '">' + value[1] + '</option>'
$(selection_input).add('<option value="' + value[0] + '">' + value[1] + '</option>')
});
if (value_of_tr) {
if (typeof value_of_tr == 'string') {
value_of_tr = [value_of_tr];
}
value_of_tr.forEach((val) => {
var $value_tag = $('<span>').attr({
title: val,
name: val,
value: val,
class: 'd-inline-flex badge',
})
var tag_val = "";
field.selection.forEach((value) => {
if (val == value[0]) {
tag_val = value[1];
}
});
$value_tag.append($(
`<div class="o_tag_badge_text">${tag_val}</div>`
))
$value_tag.val(val);
$value_tag.css('background-color', '#dfdfdf');
$value_tag.css('border-radius', '20px');
$value_tag.css('font-size', '15px');
search_div.append($value_tag)
})
}
var sel_in = selection_input + option + '</select>'
search_div.find('span').append(remove_button);
search_div.append(sel_in)
search_div.append(search_button)
$td.append(search_div)
}
if (['integer', 'float', 'monetary'].includes(field.type)) {
$input.attr({ type: 'number' });
$input.text(description)
if (value_of_tr) {
if (typeof value_of_tr == 'number') {
value_of_tr = [value_of_tr];
}
value_of_tr.forEach((val) => {
var $value_tag = $('<span>').attr({
title: val,
name: val,
value: val,
class: 'd-inline-flex badge',
})
$value_tag.append($(
`<div class="o_tag_badge_text">${val}</div>`
))
$value_tag.val(val);
$value_tag.css('background-color', '#dfdfdf');
$value_tag.css('border-radius', '20px');
$value_tag.css('font-size', '15px');
search_div.append($value_tag)
})
}
search_div.find('span').append(remove_button);
search_div.append($input);
search_div.append(search_button);
$td.append(search_div);
}
if (['many2one', 'char'].includes(field.type)) {
$input.attr({ type: 'text' });
$input.text(description)
const values_of_tr = searched_value.map((val) => {
return val[2];
})
if (values_of_tr.length) {
values_of_tr.forEach((val) => {
var $value_tag = $('<span>').attr({
title: val,
name: val,
value: val,
class: 'd-inline-flex badge',
})
$value_tag.append($(
`<div class="o_tag_badge_text">${val}</div>`
))
$value_tag.val(val);
$value_tag.append(remove_button);
$value_tag.css('background-color', '#dfdfdf');
$value_tag.css('border-radius', '20px');
$value_tag.css('font-size', '15px');
search_div.append($value_tag)
})
}
search_div.find('span').append(remove_button);
search_div.append($input);
search_div.append(search_button);
$td.append(search_div);
}
if (field.type == 'datetime' || field.type == 'date') {
var value_of_tr1 = searched_value.length > 1 ? (searched_value[0][2]).split(' ')[0] + '/' + (searched_value[1][2]).split(' ')[0] : ""
var search_div = $('<div>').attr({
'class': 'search_div'
});
var $input_date1 = $('<input>').attr({
type: 'text',
name: name,
placeholder: 'Date Range',
autocomplete: "autocomplete",
width: '150px',
'class': 'input_text',
'style': 'min-width:200px !important'
});
var search_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'search_button fa fa-search'
});
var remove_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'remove_button fa fa-remove hidden_button',
});
$input_date1.daterangepicker();
$input_date1.on('apply.daterangepicker', function (ev, picker) {
$input_date1.val(picker.startDate.format('YYYY-MM-DD') + '/' + picker.endDate.format('YYYY-MM-DD'));
var e = $.Event("keypress", {
which: 13
});
$input_date1.trigger(e);
e.keyCode = 13
self._onfilter(e)
$input_date1.change()
});
$input_date1.on('cancel.daterangepicker', function (ev, picker) {
$input_date1.val('');
var e = $.Event("keypress", {
which: 13
});
$input_date1.trigger(e);
e.keyCode = 13
self._onfilter(e)
$input_date1.change()
});
$input_date1.text(description)
$input_date1.val(value_of_tr1)
if (value_of_tr1) {
$(search_button).addClass('hidden_button');
$(remove_button).removeClass('hidden_button');
}
if ($(search_button).hasClass('hidden_button')) {
$input_date1.attr('readonly', 'readonly');
$input_date1.css('background-color', '#dfdfdf');
$input_date1.css('border-radius', '20px');
}
search_div.append($input_date1)
search_div.append(remove_button)
search_div.append(search_button)
$td.append(search_div)
}
}
}
return $td;
},
_onKeyPress: function (ev) {
ev.stopPropagation(); // to prevent jquery's blockUI to cancel event
},
_onSearch: function (event) {
var self = this
var $target = $(event.currentTarget);
var field_name = $target.attr('name')
let all_input_tags = $target.parents('tr').find('input.input_text,select.input_text')
if (!all_input_tags.length) {
all_input_tags = $($('tr')[5]).find('input.input_text,select.input_text')
}
all_input_tags.each(function (el) {
if (all_input_tags[el].name == field_name) {
var e = $.Event("keypress", {
which: 13
});
$(all_input_tags[el]).trigger(e);
e.keyCode = 13
self._onfilter(e)
}
});
},
_onRemove: function (event) {
const List = this.props.list;
var self = this;
var updated_domain = [];
var old_domain = JSON.parse(browser.sessionStorage.getItem('domainlist'));
var field_name = $(event.currentTarget).attr('name');
var tag_value = $(event.currentTarget.parentElement).attr('value');
let all_input_tags = $($('tr')[1]).find('input.input_text');
if (!all_input_tags.length) {
all_input_tags = $($('tr')[5]).find('input.input_text')
}
const ListDomain = old_domain;
if (["monetary", "float", "integer", "selection"].includes(List.fields[field_name].type)) {
ListDomain.map(function (el) {
tag_value = !isNaN(tag_value) ? parseFloat(tag_value) : tag_value;
if (field_name == el[0] && el[2].includes(tag_value)) {
const index = el[2].indexOf(tag_value);
index > -1 ? el[2].splice(index, 1) : false;
el[2].length ? updated_domain.push(el) : false;
}
else {
updated_domain.push(el)
}
});
}
else if (["date", "datetime"].includes(List.fields[field_name].type)) {
ListDomain.map(function (el) {
if (field_name != el[0]) {
updated_domain.push(el)
}
});
}
else {
ListDomain.map(function (el) {
if (field_name != el[0] || tag_value != el[2]) {
updated_domain.push(el)
}
if (el == '|') {
let index = updated_domain.indexOf('|');
updated_domain.splice(index, 1);
}
});
}
browser.sessionStorage.setItem('domainlist', JSON.stringify(updated_domain));
var indexes = []
var to_update = []
var count = 0
updated_domain.forEach(el => {
if (indexes.length && el[1] == 'ilike' && updated_domain[indexes[indexes.length - 1]][0] == el[0]) {
to_update.push(indexes[indexes.length - 1])
} else if (el[1] == 'ilike') {
indexes.push(count)
}
count += 1;
})
to_update.reverse()
to_update.forEach(A => {
updated_domain.splice(A, 0, '|');
})
self.perform_search(self, updated_domain);
self._renderSearchPanel();
},
_onfilter: function (e) {
const List = this.props.list;
const old_domain = JSON.parse(browser.sessionStorage.getItem('domainlist'));
if (e.key === 'Enter' || e.keyCode === 13) {
var domain_list = [];
var self = this
var $target = $(e.target);
let all_input_tags = $target.parents('tr').find('input.input_text')
if (!all_input_tags.length) {
all_input_tags = $($('tr')[5]).find('input.input_text')
}
let all_select_tags = $target.parents('tr').find('select.input_text')
if (!all_select_tags.length) {
all_select_tags = $($('tr')[5]).find('select.input_text')
}
var search_tr = all_input_tags.filter(function (el) {
return all_input_tags[el].value
});
var search_select = all_select_tags.filter(function (el) {
return all_select_tags[el].value
});
/* Checking if both the variables `search_tr` and `search_select` are
empty. If both variables are empty, it will return without executing the further code. */
if (!search_tr.length && !search_select.length) {
// self.perform_search(self, domain_list);
return
}
for (var i = 0; i < search_tr.length; i++) {
var field = $(search_tr[i]).attr('name')
var string = search_tr[i].textContent
var value = $(search_tr[i]).val()
if (value) {
if (List.fields[field].type == "date") {
var startDate = moment(value.split('/')[0]).format('YYYY-MM-DD');
var endDate = moment(value.split('/')[1]).format('YYYY-MM-DD');
if (startDate == 'Invalid date' || endDate == 'Invalid date') {
window.alert("Please enter valid input for " + string);
} else {
domain_list.push([field, '>=', startDate])
domain_list.push([field, '<=', endDate])
}
} else if (List.fields[field].type == "datetime") {
var startDate = moment(value.split('/')[0]).format('YYYY-MM-DD 00:00:00');
var endDate = moment(value.split('/')[1]).format('YYYY-MM-DD 23:59:59');
if (startDate == 'Invalid date' || endDate == 'Invalid date') {
window.alert("Please enter valid input for " + string);
} else {
domain_list.push([field, '>=', startDate])
domain_list.push([field, '<=', endDate])
}
} else if (["monetary", "float", "integer"].includes(List.fields[field].type)) {
var domain = old_domain.filter((domain) => {
return domain[0] == field;
})
if (domain.length) {
if (!domain[0][2].includes(parseFloat(value))) {
domain[0][2].push(parseFloat(value));
}
domain_list.push(domain[0])
}
else {
domain_list.push([field, 'in', [parseFloat(value)]]);
}
} else {
if (old_domain.length) {
old_domain.forEach((domain) => {
if (domain[0] == field) {
domain_list.push(domain);
}
})
if (!(old_domain.map((d) => { return d[2] }).includes(value) &&
old_domain.map((d) => { return d[0] }).includes(field))) {
domain_list.push([field, 'ilike', value]);
}
}
else {
domain_list.push([field, 'ilike', value]);
}
}
}
}
$(all_select_tags).each(function (index, elem) {
var elem_value = $(elem).val();
var elem_field = $(elem).attr('data_name');
if (elem_value.length > 0) {
if (List.fields[elem_field].type == 'selection') {
var domain = old_domain.filter((domain) => {
return domain[0] == elem_field
})
if (domain.length) {
if (!domain[0][2].includes(elem_value)) {
domain[0][2].push(elem_value);
}
domain_list.push(domain[0])
}
else {
domain_list.push([elem_field, 'in', [elem_value]])
}
}
else {
domain_list.push([elem_field, '=', elem_value])
}
}
});
old_domain.forEach((domain) => {
var avail = domain_list.filter(a => {
if (domain[1] == 'in') {
return domain[2].every(f => a[2].includes(f)) && a[0] == domain[0]
}
else {
return a[2].toString() == domain[2].toString() && a[0] == domain[0]
}
}).length
if (!(avail)) {
domain_list.push(domain)
}
})
browser.sessionStorage.setItem('domainlist', JSON.stringify(domain_list));
var indexes = []
var to_update = []
var count = 0
domain_list.forEach(el => {
if (indexes.length && el[1] == 'ilike' && domain_list[indexes[indexes.length - 1]][0] == el[0]) {
to_update.push(indexes[indexes.length - 1])
} else if (el[1] == 'ilike') {
indexes.push(count)
}
count += 1;
})
to_update.reverse()
to_update.forEach(A => {
domain_list.splice(A, 0, '|');
})
self.perform_search(self, domain_list);
}
},
perform_search: async function (self, domain_list) {
const searchModel = self.env.searchModel;
const list = self.props.list;
if (self.isX2Many) {
const bm_params = list.model.config;
/**
* Function will not apply to new records.
*/
if (!(bm_params.resId || bm_params.resIds.length)) {
browser.sessionStorage.setItem('domainlist', JSON.stringify([]));
return;
}
var res_id = bm_params.resId ? bm_params.resId : bm_params.resIds[0]
const readIds = await self.env.model.orm.read(
self.props.nestedKeyOptionalFieldsData.model,
[res_id],
[self.props.nestedKeyOptionalFieldsData.field])
domain_list.push(['id', 'in', readIds[0][self.props.nestedKeyOptionalFieldsData.field]])
var resIds = await self.env.model.orm.search(list.resModel, domain_list, {
limit: session.active_ids_limit,
context: list.context,
});
await list._load({'nextCurrentIds': resIds})
}
else {
searchModel.ak_domains = domain_list;
searchModel._notify();
}
},
};
patch(ListRenderer.prototype, ListRendererCust);
@@ -0,0 +1,410 @@
.daterangepicker {
position: absolute;
color: inherit;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ddd;
width: 278px;
max-width: none;
padding: 0;
margin-top: 7px;
top: 100px;
left: 20px;
z-index: 3001;
display: none;
font-family: arial;
font-size: 15px;
line-height: 1em;
}
.daterangepicker:before, .daterangepicker:after {
position: absolute;
display: inline-block;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker:before {
top: -7px;
border-right: 7px solid transparent;
border-left: 7px solid transparent;
border-bottom: 7px solid #ccc;
}
.daterangepicker:after {
top: -6px;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
}
.daterangepicker.opensleft:before {
right: 9px;
}
.daterangepicker.opensleft:after {
right: 10px;
}
.daterangepicker.openscenter:before {
left: 0;
right: 0;
width: 0;
margin-left: auto;
margin-right: auto;
}
.daterangepicker.openscenter:after {
left: 0;
right: 0;
width: 0;
margin-left: auto;
margin-right: auto;
}
.daterangepicker.opensright:before {
left: 9px;
}
.daterangepicker.opensright:after {
left: 10px;
}
.daterangepicker.drop-up {
margin-top: -7px;
}
.daterangepicker.drop-up:before {
top: initial;
bottom: -7px;
border-bottom: initial;
border-top: 7px solid #ccc;
}
.daterangepicker.drop-up:after {
top: initial;
bottom: -6px;
border-bottom: initial;
border-top: 6px solid #fff;
}
.daterangepicker.single .daterangepicker .ranges, .daterangepicker.single .drp-calendar {
float: none;
}
.daterangepicker.single .drp-selected {
display: none;
}
.daterangepicker.show-calendar .drp-calendar {
display: block;
}
.daterangepicker.show-calendar .drp-buttons {
display: block;
}
.daterangepicker.auto-apply .drp-buttons {
display: none;
}
.daterangepicker .drp-calendar {
display: none;
max-width: 270px;
}
.daterangepicker .drp-calendar.left {
padding: 8px 0 8px 8px;
}
.daterangepicker .drp-calendar.right {
padding: 8px;
}
.daterangepicker .drp-calendar.single .calendar-table {
border: none;
}
.daterangepicker .calendar-table .next span, .daterangepicker .calendar-table .prev span {
color: #fff;
border: solid black;
border-width: 0 2px 2px 0;
border-radius: 0;
display: inline-block;
padding: 3px;
}
.daterangepicker .calendar-table .next span {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.daterangepicker .calendar-table .prev span {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
.daterangepicker .calendar-table th, .daterangepicker .calendar-table td {
white-space: nowrap;
text-align: center;
vertical-align: middle;
min-width: 32px;
width: 32px;
height: 24px;
line-height: 24px;
font-size: 12px;
border-radius: 4px;
border: 1px solid transparent;
white-space: nowrap;
cursor: pointer;
}
.daterangepicker .calendar-table {
border: 1px solid #fff;
border-radius: 4px;
background-color: #fff;
}
.daterangepicker .calendar-table table {
width: 100%;
margin: 0;
border-spacing: 0;
border-collapse: collapse;
}
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
background-color: #eee;
border-color: transparent;
color: inherit;
}
.daterangepicker td.week, .daterangepicker th.week {
font-size: 80%;
color: #ccc;
}
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {
background-color: #fff;
border-color: transparent;
color: #999;
}
.daterangepicker td.in-range {
background-color: #ebf4f8;
border-color: transparent;
color: #000;
border-radius: 0;
}
.daterangepicker td.start-date {
border-radius: 4px 0 0 4px;
}
.daterangepicker td.end-date {
border-radius: 0 4px 4px 0;
}
.daterangepicker td.start-date.end-date {
border-radius: 4px;
}
.daterangepicker td.active, .daterangepicker td.active:hover {
background-color: #357ebd;
border-color: transparent;
color: #fff;
}
.daterangepicker th.month {
width: auto;
}
.daterangepicker td.disabled, .daterangepicker option.disabled {
color: #999;
cursor: not-allowed;
text-decoration: line-through;
}
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
font-size: 12px;
padding: 1px;
height: auto;
margin: 0;
cursor: default;
}
.daterangepicker select.monthselect {
margin-right: 2%;
width: 56%;
}
.daterangepicker select.yearselect {
width: 40%;
}
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
width: 50px;
margin: 0 auto;
background: #eee;
border: 1px solid #eee;
padding: 2px;
outline: 0;
font-size: 12px;
}
.daterangepicker .calendar-time {
text-align: center;
margin: 4px auto 0 auto;
line-height: 30px;
position: relative;
}
.daterangepicker .calendar-time select.disabled {
color: #ccc;
cursor: not-allowed;
}
.daterangepicker .drp-buttons {
clear: both;
text-align: right;
padding: 8px;
border-top: 1px solid #ddd;
display: none;
line-height: 12px;
vertical-align: middle;
}
.daterangepicker .drp-selected {
display: inline-block;
font-size: 12px;
padding-right: 8px;
}
.daterangepicker .drp-buttons .btn {
margin-left: 8px;
font-size: 12px;
font-weight: bold;
padding: 4px 8px;
}
.daterangepicker.show-ranges.single.rtl .drp-calendar.left {
border-right: 1px solid #ddd;
}
.daterangepicker.show-ranges.single.ltr .drp-calendar.left {
border-left: 1px solid #ddd;
}
.daterangepicker.show-ranges.rtl .drp-calendar.right {
border-right: 1px solid #ddd;
}
.daterangepicker.show-ranges.ltr .drp-calendar.left {
border-left: 1px solid #ddd;
}
.daterangepicker .ranges {
float: none;
text-align: left;
margin: 0;
}
.daterangepicker.show-calendar .ranges {
margin-top: 8px;
}
.daterangepicker .ranges ul {
list-style: none;
margin: 0 auto;
padding: 0;
width: 100%;
}
.daterangepicker .ranges li {
font-size: 12px;
padding: 8px 12px;
cursor: pointer;
}
.daterangepicker .ranges li:hover {
background-color: #eee;
}
.daterangepicker .ranges li.active {
background-color: #08c;
color: #fff;
}
/* Larger Screen Styling */
@media (min-width: 564px) {
.daterangepicker {
width: auto;
}
.daterangepicker .ranges ul {
width: 140px;
}
.daterangepicker.single .ranges ul {
width: 100%;
}
.daterangepicker.single .drp-calendar.left {
clear: none;
}
.daterangepicker.single .ranges, .daterangepicker.single .drp-calendar {
float: left;
}
.daterangepicker {
direction: ltr;
text-align: left;
}
.daterangepicker .drp-calendar.left {
clear: left;
margin-right: 0;
}
.daterangepicker .drp-calendar.left .calendar-table {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.daterangepicker .drp-calendar.right {
margin-left: 0;
}
.daterangepicker .drp-calendar.right .calendar-table {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.daterangepicker .drp-calendar.left .calendar-table {
padding-right: 8px;
}
.daterangepicker .ranges, .daterangepicker .drp-calendar {
float: left;
}
}
@media (min-width: 730px) {
.daterangepicker .ranges {
width: auto;
}
.daterangepicker .ranges {
float: left;
}
.daterangepicker.rtl .ranges {
float: right;
}
.daterangepicker .drp-calendar.left {
clear: none !important;
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,71 @@
.tree_search_item {
cursor: pointer;
}
.tree_search_item .selected a:before {
font-family: FontAwesome;
position: absolute;
left: 10px;
top: 10px;
}
input.input_text{
transition: all 0.3s ease;
}
.search_div{
display: flex;
align-items: center;
border: 1px solid #1a4040;
font-size: 15px !important;
border-radius: 8px;
text-align: center;
overflow: hidden;
padding: 2px;
}
.input_text{
flex: 2;
border: none!important;
}
.search_button{
margin: 0px 0px;
border:none
}
.search_button:hover{
color: blueviolet;
}
.remove_button{
border:none
}
.remove_button:hover{
color: indianred;
}
.hidden_button{
display:none
}
.table_layout
{
table-layout:auto
}
.auto-overflow {
overflow: auto !important;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.auto-overflow::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.auto-overflow {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.min-wp-50 {
min-width: 50px !important;
}
@@ -0,0 +1,13 @@
// /** @odoo-module */
import { SearchModel } from "@web/search/search_model";
import { patch } from "@web/core/utils/patch";
patch(SearchModel.prototype, {
async _reloadSections() {
super._reloadSections(...arguments);
if (this.ak_domains) {
this._domain = this.domain.concat(this.ak_domains);
}
},
});
@@ -0,0 +1,605 @@
/** @odoo-module */
import { ListRenderer } from "@web/views/list/list_renderer";
import { browser } from "@web/core/browser/browser";
import { patch } from "@web/core/utils/patch";
import { session } from "@web/session";
import { serialize } from "@web/core/l10n/dates";
import { serializeDateTime } from "@web/core/l10n/dates";
import { loadJS, loadCSS } from "@web/core/assets";
const { onMounted, onPatched } = owl;
const { DateTime } = luxon;
export const ListRendererCust = {
setup() {
super.setup();
browser.sessionStorage.setItem('domainlist', JSON.stringify([])); // Replaced localStorage with sessionStorage
onMounted(() => {
this._renderSearchPanel()
});
onPatched(() => {
this._renderSearchPanel()
});
},
_renderSearchPanel: async function () {
// await loadJS("https://cdn.jsdelivr.net/jquery/latest/jquery.min.js")
// await loadJS("https://cdn.jsdelivr.net/momentjs/latest/moment.min.js")
// await loadJS("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js")
// await loadCSS("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css")
// await loadJS("/tree_view_advanced_filter/static/src/libs/jquery.min.js");
await loadJS("/tree_view_advanced_filter/static/src/libs/daterangepicker.min.js");
await loadCSS("/tree_view_advanced_filter/static/src/libs/daterangepicker.css");
await loadJS("/tree_view_advanced_filter/static/src/libs/moment/moment.min.js");
var List = this.props.list;
const bm_params = List.model.__bm_load_params__;
const rootRef = this.rootRef.el
const tableRef = this.tableRef.el;
tableRef.removeAttribute('style')
var columns = this.allColumns.filter((col) => {
if (col.optional && this.optionalActiveFields[col.name] == false) {
return false;
}
if (col.column_invisible == true || col.column_invisible && col.invisible) {
return false;
}
// if (col.optional == 'hide'){
// return false;
// }
if (['in_invoice', 'in_refund', 'in_receipt'].includes(this.props.list.evalContext.default_move_type)){
if (['Vendor', 'Invoice Date'].includes(col.string)) {
return false;
}
}
if (['out_invoice', 'out_refund', 'out_receipt'].includes(this.props.list.evalContext.default_move_type)){
if (['Customer', 'Bill Date'].includes(col.string)) {
return false;
}
}
if (col.name == 'move_type'){
return false;
}
return true;
});
var $tr1 = $('<tr>').append(columns.map(columns => this._renderHeaderCellSearch(columns)));
// 添加行号占位td
$tr1.prepend($('<td>').addClass('web_list_num'));
if (this.hasSelectors) {
$tr1.prepend($('<td>').addClass('o_list_record_selector'));
}
if (this.isStudioEditable || this.displayOptionalFields) {
$tr1.append($('<td>').addClass('o_list_record_selector'));
}
if ($(tableRef).find('.search_td').length) {
$(tableRef).find('.search_td').parent().replaceWith($tr1)
}
else {
$tr1.insertAfter($(tableRef).find('tr')[0]);
}
rootRef.querySelectorAll('thead tr td.search_td input').forEach((a) => a.addEventListener('keyup', this._onfilter.bind(this)));
rootRef.querySelectorAll('.search_button').forEach((a) => a.addEventListener('click', this._onSearch.bind(this)));
rootRef.querySelectorAll('.remove_button').forEach((a) => a.addEventListener('click', this._onRemove.bind(this)));
rootRef.querySelectorAll('thead tr td').forEach((a) => a.addEventListener('keypress', this._onKeyPress.bind(this)));
},
_renderHeaderCellSearch: function (node) {
var List = this.props.list
var search_tr = $($('tr')[1]).find('input.input_text')
var old_domain = JSON.parse(browser.sessionStorage.getItem('domainlist'))
var input_dict = {}
var self = this;
var $td = $('<td>', {
class: 'search_td'
});
for (var i = 0; i < search_tr.length; i++) {
var field = $(search_tr[i]).attr('name')
var value = $(search_tr[i]).val()
input_dict[String(field)] = value
}
if (node.type != 'field') {
return $td
}
const {
name,
string,
widget,
} = node;
var searched_value = old_domain.filter(function (domain) {
return domain[0] == name;
});
var widget_list = ["monetary", "date", "many2one_avatar_user", "badge", "task_with_hours", "timesheet_uom", "sol_product_many2one"];
var value_of_tr = searched_value.length > 0 ? searched_value[0][2] : ""
var field = List.fields[name];
if (name) {
$td.attr('data-name', name);
} else if (string) {
$td.attr('data-string', string);
}
if (!field) {
return $td;
}
var description = string || field.string;
// search elements
var search_div = $('<div>').attr({
'class': 'search_div d-inline-flex auto-overflow'
});
var $input = $('<input>').attr({
name: name,
data_name: name,
data_text: string,
placeholder: description,
autocomplete: "autocomplete",
'class': 'input_text min-wp-50'
});
var search_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'search_button fa fa-search'
});
var remove_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'remove_button fa fa-remove',
});
// Prepare search bars
if (!widget || widget_list.includes(widget)) {
if (string !== " " && field.store) {
if (field.type == 'selection') {
var selection_options = []
for (let option = -1; option < field.selection.length - 1; option += 1) {
selection_options.push((field.selection[option], field.selection[option + 1]))
}
const selection_input = '<select class="input_text input_select" type="select" name=' + name + ' data_name=' + name + ' data_text=' + string + ' placeholder=' + description + ' style="height:25px;">'
var option = '<option selected="selected" class="text-muted" value> -- 选择 -- </option>';
$.each(field.selection, function (index, value) {
option += '<option value="' + value[0] + '">' + value[1] + '</option>'
$(selection_input).add('<option value="' + value[0] + '">' + value[1] + '</option>')
});
if (value_of_tr) {
if (typeof value_of_tr == 'string') {
value_of_tr = [value_of_tr];
}
value_of_tr.forEach((val) => {
var $value_tag = $('<span>').attr({
title: val,
name: val,
value: val,
class: 'd-inline-flex badge',
})
var tag_val = "";
field.selection.forEach((value) => {
if (val == value[0]) {
tag_val = value[1];
}
});
$value_tag.append($(
`<div class="o_tag_badge_text">${tag_val}</div>`
))
$value_tag.val(val);
$value_tag.css('background-color', '#dfdfdf');
$value_tag.css('border-radius', '20px');
$value_tag.css('font-size', '15px');
search_div.append($value_tag)
})
}
var sel_in = selection_input + option + '</select>'
search_div.find('span').append(remove_button);
search_div.append(sel_in)
search_div.append(search_button)
$td.append(search_div)
}
if (['integer', 'float', 'monetary'].includes(field.type)) {
$input.attr({ type: 'number' });
$input.text(description)
if (value_of_tr) {
if (typeof value_of_tr == 'number') {
value_of_tr = [value_of_tr];
}
value_of_tr.forEach((val) => {
var $value_tag = $('<span>').attr({
title: val,
name: val,
value: val,
class: 'd-inline-flex badge',
})
$value_tag.append($(
`<div class="o_tag_badge_text">${val}</div>`
))
$value_tag.val(val);
$value_tag.css('background-color', '#dfdfdf');
$value_tag.css('border-radius', '20px');
$value_tag.css('font-size', '15px');
search_div.append($value_tag)
})
}
search_div.find('span').append(remove_button);
search_div.append($input);
search_div.append(search_button);
$td.append(search_div);
}
if (['many2one', 'char'].includes(field.type)) {
$input.attr({ type: 'text' });
$input.text(description)
const values_of_tr = searched_value.map((val) => {
return val[2];
})
if (values_of_tr.length) {
values_of_tr.forEach((val) => {
var $value_tag = $('<span>').attr({
title: val,
name: val,
value: val,
class: 'd-inline-flex badge',
})
$value_tag.append($(
`<div class="o_tag_badge_text">${val}</div>`
))
$value_tag.val(val);
$value_tag.append(remove_button);
$value_tag.css('background-color', '#dfdfdf');
$value_tag.css('border-radius', '20px');
$value_tag.css('font-size', '15px');
search_div.append($value_tag)
})
}
search_div.find('span').append(remove_button);
search_div.append($input);
search_div.append(search_button);
$td.append(search_div);
}
if (field.type == 'datetime' || field.type == 'date') {
var value_of_tr1 = searched_value.length > 1 ? (searched_value[0][2]).split(' ')[0] + '/' + (searched_value[1][2]).split(' ')[0] : ""
var search_div = $('<div>').attr({
'class': 'search_div'
});
var $input_date1 = $('<input>').attr({
type: 'text',
name: name,
placeholder: '日期选择',
autocomplete: "autocomplete",
width: '150px',
'class': 'input_text',
'style': 'min-width:200px !important'
});
var search_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'search_button fa fa-search'
});
var remove_button = $('<button>').attr({
type: 'button',
name: name,
'class': 'remove_button fa fa-remove hidden_button',
});
$input_date1.daterangepicker({
locale: {
applyLabel: '应用',
cancelLabel: '取消',
},
});
$input_date1.on('apply.daterangepicker', function (ev, picker) {
$input_date1.val(picker.startDate.format('YYYY-MM-DD') + '/' + picker.endDate.format('YYYY-MM-DD'));
var e = $.Event("keypress", {
which: 13
});
$input_date1.trigger(e);
e.keyCode = 13
self._onfilter(e)
$input_date1.change()
});
$input_date1.on('cancel.daterangepicker', function (ev, picker) {
$input_date1.val('');
var e = $.Event("keypress", {
which: 13
});
$input_date1.trigger(e);
e.keyCode = 13
self._onfilter(e)
$input_date1.change()
});
$input_date1.text(description)
$input_date1.val(value_of_tr1)
if (value_of_tr1) {
$(search_button).addClass('hidden_button');
$(remove_button).removeClass('hidden_button');
}
if ($(search_button).hasClass('hidden_button')) {
$input_date1.attr('readonly', 'readonly');
$input_date1.css('background-color', '#dfdfdf');
$input_date1.css('border-radius', '20px');
}
search_div.append($input_date1)
search_div.append(remove_button)
search_div.append(search_button)
$td.append(search_div)
}
}
}
return $td;
},
_onKeyPress: function (ev) {
ev.stopPropagation(); // to prevent jquery's blockUI to cancel event
},
_onSearch: function (event) {
var self = this
var $target = $(event.currentTarget);
var field_name = $target.attr('name')
let all_input_tags = $target.parents('tr').find('input.input_text,select.input_text')
if (!all_input_tags.length) {
all_input_tags = $($('tr')[5]).find('input.input_text,select.input_text')
}
all_input_tags.each(function (el) {
if (all_input_tags[el].name == field_name) {
var e = $.Event("keypress", {
which: 13
});
$(all_input_tags[el]).trigger(e);
e.keyCode = 13
self._onfilter(e)
}
});
},
_onRemove: function (event) {
const List = this.props.list;
var self = this;
var updated_domain = [];
var old_domain = JSON.parse(browser.sessionStorage.getItem('domainlist'));
var field_name = $(event.currentTarget).attr('name');
var tag_value = $(event.currentTarget.parentElement).attr('value');
let all_input_tags = $($('tr')[1]).find('input.input_text');
if (!all_input_tags.length) {
all_input_tags = $($('tr')[5]).find('input.input_text')
}
const ListDomain = old_domain;
if (["monetary", "float", "integer", "selection"].includes(List.fields[field_name].type)) {
ListDomain.map(function (el) {
tag_value = !isNaN(tag_value) ? parseFloat(tag_value) : tag_value;
if (field_name == el[0] && el[2].includes(tag_value)) {
const index = el[2].indexOf(tag_value);
index > -1 ? el[2].splice(index, 1) : false;
el[2].length ? updated_domain.push(el) : false;
}
else {
updated_domain.push(el)
}
});
}
else if (["date", "datetime"].includes(List.fields[field_name].type)) {
ListDomain.map(function (el) {
if (field_name != el[0]) {
updated_domain.push(el)
}
});
}
else {
ListDomain.map(function (el) {
if (field_name != el[0] || tag_value != el[2]) {
updated_domain.push(el)
}
if (el == '|') {
let index = updated_domain.indexOf('|');
updated_domain.splice(index, 1);
}
});
}
browser.sessionStorage.setItem('domainlist', JSON.stringify(updated_domain));
var indexes = []
var to_update = []
var count = 0
updated_domain.forEach(el => {
if (indexes.length && el[1] == 'ilike' && updated_domain[indexes[indexes.length - 1]][0] == el[0]) {
to_update.push(indexes[indexes.length - 1])
} else if (el[1] == 'ilike') {
indexes.push(count)
}
count += 1;
})
to_update.reverse()
to_update.forEach(A => {
updated_domain.splice(A, 0, '|');
})
self.perform_search(self, updated_domain);
self._renderSearchPanel();
},
_onfilter: function (e) {
const List = this.props.list;
const old_domain = JSON.parse(browser.sessionStorage.getItem('domainlist'));
if (e.key === 'Enter' || e.keyCode === 13) {
var domain_list = [];
var self = this
var $target = $(e.target);
let all_input_tags = $target.parents('tr').find('input.input_text')
if (!all_input_tags.length) {
all_input_tags = $($('tr')[5]).find('input.input_text')
}
let all_select_tags = $target.parents('tr').find('select.input_text')
if (!all_select_tags.length) {
all_select_tags = $($('tr')[5]).find('select.input_text')
}
var search_tr = all_input_tags.filter(function (el) {
return all_input_tags[el].value
});
var search_select = all_select_tags.filter(function (el) {
return all_select_tags[el].value
});
/* Checking if both the variables `search_tr` and `search_select` are
empty. If both variables are empty, it will return without executing the further code. */
if (!search_tr.length && !search_select.length) {
// self.perform_search(self, domain_list);
return
}
for (var i = 0; i < search_tr.length; i++) {
var field = $(search_tr[i]).attr('name')
var string = search_tr[i].textContent
var value = $(search_tr[i]).val()
if (value) {
if (List.fields[field].type == "date") {
var startDate = moment(value.split('/')[0]).format('YYYY-MM-DD');
var endDate = moment(value.split('/')[1]).format('YYYY-MM-DD');
if (startDate == 'Invalid date' || endDate == 'Invalid date') {
window.alert("Please enter valid input for " + string);
} else {
domain_list.push([field, '>=', startDate])
domain_list.push([field, '<=', endDate])
}
} else if (List.fields[field].type == "datetime") {
var startDate = moment(value.split('/')[0]).format('YYYY-MM-DD 00:00:00');
var endDate = moment(value.split('/')[1]).format('YYYY-MM-DD 23:59:59');
if (startDate == 'Invalid date' || endDate == 'Invalid date') {
window.alert("Please enter valid input for " + string);
} else {
domain_list.push([field, '>=', startDate])
domain_list.push([field, '<=', endDate])
}
} else if (["monetary", "float", "integer"].includes(List.fields[field].type)) {
var domain = old_domain.filter((domain) => {
return domain[0] == field;
})
if (domain.length) {
if (!domain[0][2].includes(parseFloat(value))) {
domain[0][2].push(parseFloat(value));
}
domain_list.push(domain[0])
}
else {
domain_list.push([field, 'in', [parseFloat(value)]]);
}
} else {
if (old_domain.length) {
old_domain.forEach((domain) => {
if (domain[0] == field) {
domain_list.push(domain);
}
})
if (!(old_domain.map((d) => { return d[2] }).includes(value) &&
old_domain.map((d) => { return d[0] }).includes(field))) {
domain_list.push([field, 'ilike', value]);
}
}
else {
domain_list.push([field, 'ilike', value]);
}
}
}
}
$(all_select_tags).each(function (index, elem) {
var elem_value = $(elem).val();
var elem_field = $(elem).attr('data_name');
if (elem_value.length > 0) {
if (List.fields[elem_field].type == 'selection') {
var domain = old_domain.filter((domain) => {
return domain[0] == elem_field
})
if (domain.length) {
if (!domain[0][2].includes(elem_value)) {
domain[0][2].push(elem_value);
}
domain_list.push(domain[0])
}
else {
domain_list.push([elem_field, 'in', [elem_value]])
}
}
else {
domain_list.push([elem_field, '=', elem_value])
}
}
});
old_domain.forEach((domain) => {
var avail = domain_list.filter(a => {
if (domain[1] == 'in') {
return domain[2].every(f => a[2].includes(f)) && a[0] == domain[0]
}
else {
return a[2].toString() == domain[2].toString() && a[0] == domain[0]
}
}).length
if (!(avail)) {
domain_list.push(domain)
}
})
browser.sessionStorage.setItem('domainlist', JSON.stringify(domain_list));
var indexes = []
var to_update = []
var count = 0
domain_list.forEach(el => {
if (indexes.length && el[1] == 'ilike' && domain_list[indexes[indexes.length - 1]][0] == el[0]) {
to_update.push(indexes[indexes.length - 1])
} else if (el[1] == 'ilike') {
indexes.push(count)
}
count += 1;
})
to_update.reverse()
to_update.forEach(A => {
domain_list.splice(A, 0, '|');
})
self.perform_search(self, domain_list);
}
},
perform_search: async function (self, domain_list) {
const searchModel = self.env.searchModel;
const list = self.props.list;
if (self.isX2Many) {
const bm_params = list.model.config;
/**
* Function will not apply to new records.
*/
if (!(bm_params.resId || bm_params.resIds.length)) {
browser.sessionStorage.setItem('domainlist', JSON.stringify([]));
return;
}
var res_id = bm_params.resId ? bm_params.resId : bm_params.resIds[0]
const readIds = await self.env.model.orm.read(
self.props.nestedKeyOptionalFieldsData.model,
[res_id],
[self.props.nestedKeyOptionalFieldsData.field])
domain_list.push(['id', 'in', readIds[0][self.props.nestedKeyOptionalFieldsData.field]])
var resIds = await self.env.model.orm.search(list.resModel, domain_list, {
limit: session.active_ids_limit,
context: list.context,
});
await list._load({'nextCurrentIds': resIds})
}
else {
searchModel.ak_domains = domain_list;
searchModel._notify();
}
},
};
patch(ListRenderer.prototype, ListRendererCust);
@@ -0,0 +1,52 @@
/** @odoo-module **/
import {patch} from "@web/core/utils/patch";
import {ListRenderer} from "@web/views/list/list_renderer";
patch(ListRenderer.prototype, {
setup(){
super.setup();
this.numSwitch = this.constructor.name === 'ListRenderer';
},
// The following code manipulates the DOM directly to avoid having to wait for a
// render + patch which would occur on the next frame and cause flickering.
freezeColumnWidths() {
if (!this.keepColumnWidths) {
this.columnWidths = null;
}
const table = this.tableRef.el;
const headers = [...table.querySelectorAll("thead th:not(.o_list_actions_header)")];
if (!this.columnWidths || !this.columnWidths.length) {
// no column widths to restore
table.style.tableLayout = "fixed";
const allowedWidth = table.parentNode.getBoundingClientRect().width;
// Set table layout auto and remove inline style to make sure that css
// rules apply (e.g. fixed width of record selector)
table.style.tableLayout = "auto";
headers.forEach((th) => {
th.style.width = null;
th.style.maxWidth = null;
});
this.setDefaultColumnWidths();
// Squeeze the table by applying a max-width on largest columns to
// ensure that it doesn't overflow
this.columnWidths = this.computeColumnWidthsFromContent(allowedWidth);
table.style.tableLayout = "fixed";
}
headers.forEach((th, index) => {
if (!th.style.width) {
th.style.width = `${Math.floor(this.columnWidths[index])}px`;
}
if (Array.from(th.classList).includes('list-number')){
th.style.width = `${String(this.props.list.offset || this.props.list.limit).length * 20}px`;
}
});
}
})
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-inherit="web.ListRenderer" t-inherit-mode="extension">
<xpath expr="//thead//th[@t-if='hasSelectors']" position="before">
<t t-if="numSwitch">
<th class="o_list_record_selector list-number">#</th>
</t>
</xpath>
<xpath expr="//tfoot//td[@t-if='hasSelectors']" position="before">
<t t-if="numSwitch">
<td class="o_list_record_selector"/>
</t>
</xpath>
</t>
<t t-inherit="web.ListRenderer.RecordRow" t-inherit-mode="extension">
<xpath expr="//td[@t-if='hasSelectors']" position="before">
<t t-if="numSwitch">
<t t-set="num" t-value="(record_index + 1) + list.offset"/>
<td t-esc="num" t-att-data-tooltip="num" class="cursor-pointer"/>
</t>
</xpath>
</t>
<t t-inherit="web.ListRenderer.Rows" t-inherit-mode="extension">
<xpath expr="//tr[@t-foreach='getEmptyRowIds']/td" position="before">
<t t-if="numSwitch">
<td/>
</t>
</xpath>
<xpath expr="//td[@t-if='withHandleColumn']" position="before">
<t t-if="numSwitch">
<td/>
</t>
</xpath>
</t>
<t t-inherit="web.ListRenderer.GroupRow" t-inherit-mode="extension">
<xpath expr="//th[@tabindex='-1']" position="before">
<t t-if="numSwitch">
<t t-set="num" t-value="(group_index + 1) + list.offset"/>
<td t-esc="num" t-att-data-tooltip="num" class="cursor-pointer"/>
</t>
</xpath>
</t>
</templates>