Browse Source

Aug 25 [FIX] : Bug Fixed 'product_visibility_website'

pull/277/head
AjmalCybro 2 years ago
parent
commit
3f7ed8b388
  1. 56
      product_visibility_website/README.rst
  2. 9
      product_visibility_website/__init__.py
  3. 17
      product_visibility_website/__manifest__.py
  4. 9
      product_visibility_website/controllers/__init__.py
  5. 195
      product_visibility_website/controllers/main.py
  6. 7
      product_visibility_website/doc/RELEASE_NOTES.md
  7. 9
      product_visibility_website/models/__init__.py
  8. 70
      product_visibility_website/models/website_product_visibility.py
  9. 5
      product_visibility_website/static/description/index.html
  10. 11
      product_visibility_website/views/website_product_visibility.xml

56
product_visibility_website/README.rst

@ -1,36 +1,52 @@
============================ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Website Product Visibility Website Product Visibility
============================ ============================
This module helps you to make visible only the filtered products and This module helps you to make visible only the filtered products and
product categories for a logged in and logged out users/visitors.Also, product categories for a logged in and logged out users/visitors.Also,
it enables the user to search products and product categories only from it enables the user to search products and product categories only from
those available products and categories. . those available products and categories.
Tech
====
* [Python] - Models
* [XML] - Odoo views
Installation Configuration
============ =============
- www.odoo.com/documentation/16.0/setup/install.html No additional configurations needed.
- Install our custom addon
Developer: Shijin V @Cybrosys Company
V14: Muhammed Nafih @Cybrosys -------
V15: Neeraj @Cybrosys * `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Bug Tracker License
=========== -------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. General Public License, Version 3 (AGPL v3).
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits Credits
======= -------
* Cybrosys Techno Solutions <https://www.cybrosys.com> Developers: Version 16 - Shijin V @Cybrosys
V14: Muhammed Nafih @Cybrosys
V15: Neeraj @Cybrosys
V16: Saneen K @cybrosys
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer Maintainer
---------- ==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies. This module is maintained by Cybrosys Technologies.
For support and more information, please visit https://www.cybrosys.com. For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

9
product_visibility_website/__init__.py

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################### ################################################################################
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). # Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>)
# Author: Shijin V (<https://www.cybrosys.com>) # Author: Neeraj Krishnan V M, Saneen K (<https://www.cybrosys.com>)
# #
# This program is free software: you can modify # This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as # it under the terms of the GNU Affero General Public License (AGPL) as
@ -19,7 +19,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
################################################################################### ################################################################################
from . import controllers from . import controllers
from . import models from . import models

17
product_visibility_website/__manifest__.py

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################### ################################################################################
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). # Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>)
# Author: Neeraj Krishnan V M (<https://www.cybrosys.com>) # Author: Neeraj Krishnan V M, Saneen K (<https://www.cybrosys.com>)
# #
# This program is free software: you can modify # This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as # it under the terms of the GNU Affero General Public License (AGPL) as
@ -19,18 +19,17 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
################################################################################### ################################################################################
{ {
'name': 'Website Product Visibility', 'name': 'Website Product Visibility',
'version': '16.0.1.1.0',
'category': 'Website',
'summary': 'Website Product visibility for Users', 'summary': 'Website Product visibility for Users',
'version': '16.0.1.0.0',
'description': """Website Product visibility for Users""", 'description': """Website Product visibility for Users""",
'author': 'Cybrosys Techno Solution', 'author': 'Cybrosys Techno Solution',
'maintainer': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com', 'website': 'https://www.cybrosys.com',
'category': 'Website',
'depends': ['contacts', 'website_sale','website'], 'depends': ['contacts', 'website_sale','website'],
'data': [ 'data': [
'views/website_product_visibility.xml', 'views/website_product_visibility.xml',
@ -38,6 +37,6 @@
'images': ['static/description/banner.png'], 'images': ['static/description/banner.png'],
'license': 'AGPL-3', 'license': 'AGPL-3',
'installable': True, 'installable': True,
'application': False,
'auto_install': False, 'auto_install': False,
'application': False,
} }

9
product_visibility_website/controllers/__init__.py

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################### ################################################################################
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). # Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>)
# Author: Neeraj Krishnan V M (<https://www.cybrosys.com>) # Author: Neeraj Krishnan V M, Saneen K (<https://www.cybrosys.com>)
# #
# This program is free software: you can modify # This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as # it under the terms of the GNU Affero General Public License (AGPL) as
@ -19,6 +19,5 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
################################################################################### ###############################################################################
from . import main from . import main

195
product_visibility_website/controllers/main.py

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################### ################################################################################
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). # Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>)
# Author: Neeraj Krishnan V M (<https://www.cybrosys.com>) # Author: Neeraj Krishnan V M , Saneen K(<https://www.cybrosys.com>)
# #
# This program is free software: you can modify # This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as # it under the terms of the GNU Affero General Public License (AGPL) as
@ -19,18 +19,16 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
################################################################################### ###############################################################################
from werkzeug.exceptions import NotFound from werkzeug.exceptions import NotFound
from odoo.addons.http_routing.models.ir_http import slug from odoo.addons.http_routing.models.ir_http import slug
from odoo.addons.website.controllers.main import QueryURL from odoo.addons.website.controllers.main import QueryURL
from odoo.addons.website_sale.controllers.main import TableCompute from odoo.addons.website_sale.controllers.main import TableCompute
from odoo import http from odoo import fields, http, tools
from ast import literal_eval from ast import literal_eval
from odoo.http import request from odoo.http import request
from odoo.addons.website.models.ir_http import sitemap_qs2dom from odoo.addons.website.models.ir_http import sitemap_qs2dom
from odoo.addons.website_sale.controllers.main import WebsiteSale from odoo.addons.website_sale.controllers.main import WebsiteSale
from odoo.osv import expression from odoo.osv import expression
from datetime import datetime from datetime import datetime
from odoo.tools import lazy from odoo.tools import lazy
@ -51,21 +49,22 @@ class ProductVisibilityCon(WebsiteSale):
def reset_domain(self, search, categories, available_products, def reset_domain(self, search, categories, available_products,
attrib_values, search_in_description=True): attrib_values, search_in_description=True):
''' """
Function returns a domain consist of filter conditions Function returns a domain consist of filter conditions
:param search: search variable :param search: search variable
:param categories: list of category available :param categories: list of category available
:param available_products: list of available product ids from product.template :param available_products: list of available product ids from
product.template
:param attrib_values:product attiribute values :param attrib_values:product attiribute values
:param search_in_description: boolean filed showing there is search variable exist or not''' :param search_in_description: boolean filed showing there is search
variable exist or not"""
domains = [request.website.sale_product_domain()] domains = [request.website.sale_product_domain()]
if search: if search:
for srch in search.split(" "): for srch in search.split(" "):
subdomains = [ subdomains = [
[('name', 'ilike', srch)], [('name', 'ilike', srch)],
[('product_variant_ids.default_code', 'ilike', srch)] [('product_variant_ids.default_code', 'ilike', srch)]]
]
if search_in_description: if search_in_description:
subdomains.append([('description', 'ilike', srch)]) subdomains.append([('description', 'ilike', srch)])
subdomains.append([('description_sale', 'ilike', srch)]) subdomains.append([('description_sale', 'ilike', srch)])
@ -74,34 +73,16 @@ class ProductVisibilityCon(WebsiteSale):
domains.append([('id', 'in', available_products.ids)]) domains.append([('id', 'in', available_products.ids)])
if categories: if categories:
domains.append([('public_categ_ids', 'child_of', categories.ids)]) domains.append([('public_categ_ids', 'child_of', categories.ids)])
if attrib_values:
print("hello world....")
# attrib = None
# ids = []
# print("hello...", ids)
# for value in attrib_values:
# if not attrib:
# attrib = value[0]
# ids.append(value[1])
# elif value[0] == attrib:
# ids.append(value[1])
# else:
# domains.append([('attribute_line_ids.value_ids', 'in', ids)])
# attrib = value[0]
# ids = [value[1]]
# if attrib:
# domains.append([('attribute_line_ids.value_ids', 'in', ids)])
return expression.AND(domains) return expression.AND(domains)
@http.route([ @http.route([
'''/shop''', '/shop',
'''/shop/page/<int:page>''', '/shop/page/<int:page>',
'''/shop/category/<model("product.public.category"):category>''', '/shop/category/<model("product.public.category"):category>',
'''/shop/category/<model("product.public.category"):category>/page/<int:page>''' '/shop/category/<model("product.public.category"):category>/page/<int:page>',
], type='http', auth="public", website=True, sitemap=sitemap_shop) ], type='http', auth="public", website=True, sitemap=sitemap_shop)
def shop(self, page=0, category=None, search='', ppg=False, **post): def shop(self, page=0, category=None, search='', min_price=0.0,
''''Override shop function.''' max_price=0.0, ppg=False, **post):
available_categ = available_products = '' available_categ = available_products = ''
user = request.env['res.users'].sudo().search( user = request.env['res.users'].sudo().search(
[('id', '=', request.env.user.id)]) [('id', '=', request.env.user.id)])
@ -125,12 +106,10 @@ class ProductVisibilityCon(WebsiteSale):
[('id', '=', user.partner_id.id)]) [('id', '=', user.partner_id.id)])
mode = partner.filter_mode mode = partner.filter_mode
if mode == 'product_only': if mode == 'product_only':
available_products = self.availavle_products() available_products = self.available_products()
available_categ = partner.website_available_cat_ids available_categ = partner.website_available_cat_ids
Category_avail = [] Category_avail = []
Category = request.env['product.public.category'] Category = request.env['product.public.category']
for ids in available_categ: for ids in available_categ:
if not ids.parent_id.id in available_categ.ids: if not ids.parent_id.id in available_categ.ids:
Category_avail.append(ids.id) Category_avail.append(ids.id)
@ -138,15 +117,21 @@ class ProductVisibilityCon(WebsiteSale):
[('id', 'in', Category_avail)]) [('id', 'in', Category_avail)])
if mode == 'product_only': if mode == 'product_only':
categ = Category.search([('parent_id', '=', False), ( categ = Category.search([('parent_id', '=', False), (
'product_tmpl_ids', 'in', available_products.ids)]) 'product_tmpl_ids', 'in', available_products.ids)])
# supering shop*** # supering shop***
if not available_categ and not available_products: if not available_categ and not available_products:
return super(ProductVisibilityCon, self).shop(page, category, return super(ProductVisibilityCon, self).shop(page, category,
search, ppg, **post) search, ppg, **post)
add_qty = int(post.get('add_qty', 1)) add_qty = int(post.get('add_qty', 1))
try:
min_price = float(min_price)
except ValueError:
min_price = 0
try:
max_price = float(max_price)
except ValueError:
max_price = 0
Category = request.env['product.public.category']
if category: if category:
category = Category.search([('id', '=', int(category))], limit=1) category = Category.search([('id', '=', int(category))], limit=1)
if not category or not category.can_access_from_current_website(): if not category or not category.can_access_from_current_website():
@ -174,49 +159,99 @@ class ProductVisibilityCon(WebsiteSale):
domain_pro = self.reset_domain(search, category, available_products, domain_pro = self.reset_domain(search, category, available_products,
attrib_values) attrib_values)
Product = Product.search(domain_pro) Product = Product.search(domain_pro)
keep = QueryURL('/shop', category=category and int(category), keep = QueryURL('/shop', **self._shop_get_query_url_kwargs(
search=search, attrib=attrib_list, category and int(category), search, min_price, max_price, **post))
order=post.get('order'))
# pricelist_context, pricelist = self._get_pricelist_context()
# request.context = dict(request.context, pricelist=pricelist.id, partner=request.env.user.partner_id)
now = datetime.timestamp(datetime.now()) now = datetime.timestamp(datetime.now())
pricelist = request.env['product.pricelist'].browse( pricelist = request.env['product.pricelist'].browse(
request.session.get('website_sale_current_pl')) request.session.get('website_sale_current_pl'))
if not pricelist or request.session.get('website_sale_pricelist_time', if not pricelist or request.session.get('website_sale_pricelist_time',
0) < now - 60 * 60: # test: 1 hour in session 0) < now - 60 * 60:
# test: 1 hour in session
pricelist = website.get_current_pricelist() pricelist = website.get_current_pricelist()
request.session['website_sale_pricelist_time'] = now request.session['website_sale_pricelist_time'] = now
request.session['website_sale_current_pl'] = pricelist.id request.session['website_sale_current_pl'] = pricelist.id
request.update_context(pricelist=pricelist.id, request.update_context(pricelist=pricelist.id,
partner=request.env.user.partner_id) partner=request.env.user.partner_id)
filter_by_price_enabled = website.is_view_active(
'website_sale.filter_products_price')
if filter_by_price_enabled:
company_currency = website.company_id.currency_id
conversion_rate = request.env['res.currency']._get_conversion_rate(
company_currency, pricelist.currency_id,
request.website.company_id, fields.Date.today())
else:
conversion_rate = 1
url = "/shop" url = "/shop"
if search: if search:
post["search"] = search post["search"] = search
if attrib_list: if attrib_list:
post['attrib'] = attrib_list post['attrib'] = attrib_list
options = self._get_search_options(
category=category,
attrib_values=attrib_values,
pricelist=pricelist,
min_price=min_price,
max_price=max_price,
conversion_rate=conversion_rate,
**post
)
fuzzy_search_term, product_count, search_product = self._shop_lookup_products(
attrib_set, options, post, search, website)
filter_by_price_enabled = website.is_view_active(
'website_sale.filter_products_price')
if filter_by_price_enabled:
# TODO Find an alternative way to obtain the domain through the search metadata.
Product = request.env['product.template'].with_context(
bin_size=True)
domain = self._get_search_domain(search, category, attrib_values)
# This is ~4 times more efficient than a search for the cheapest and most expensive products
from_clause, where_clause, where_params = Product._where_calc(
domain).get_sql()
query = f"""
SELECT COALESCE(MIN(list_price), 0) * {conversion_rate}, COALESCE(MAX(list_price), 0) * {conversion_rate}
FROM {from_clause}
WHERE {where_clause}
"""
request.env.cr.execute(query, where_params)
available_min_price, available_max_price = request.env.cr.fetchone()
if min_price or max_price:
# The if/else condition in the min_price / max_price value assignment
# tackles the case where we switch to a list of products with different
# available min / max prices than the ones set in the previous page.
# In order to have logical results and not yield empty product lists, the
# price filter is set to their respective available prices when the specified
# min exceeds the max, and / or the specified max is lower than the available min.
if min_price:
min_price = min_price if min_price <= available_max_price else available_min_price
post['min_price'] = min_price
if max_price:
max_price = max_price if max_price >= available_min_price else available_max_price
post['max_price'] = max_price
website_domain = website.website_domain()
categs_domain = [('parent_id', '=', False)] + website_domain
if not category: if not category:
domain = self.reset_domain(search, available_categ, domain = self.reset_domain(search, available_categ,
available_products, attrib_values) available_products, attrib_values)
search_product = Product.search(domain) search_product = Product.search(domain)
website_domain = request.website.website_domain() website_domain = request.website.website_domain()
categs_domain = [('parent_id', '=', False), ( categs_domain = [('parent_id', '=', False), (
'product_tmpl_ids', 'in', search_product.ids)] + website_domain 'product_tmpl_ids', 'in', search_product.ids)] + website_domain
if search: if search:
search_categories = Category.search( search_categories = Category.search(
[('product_tmpl_ids', 'in', [(
search_product.ids)] + website_domain).parents_and_self 'product_tmpl_ids', 'in',
search_product.ids)] + website_domain
).parents_and_self
categs_domain.append(('id', 'in', search_categories.ids)) categs_domain.append(('id', 'in', search_categories.ids))
else: else:
search_categories = available_categ search_categories = available_categ
categs = lazy(lambda: Category.search(categs_domain))
if category: if category:
url = "/shop/category/%s" % slug(category) url = "/shop/category/%s" % slug(category)
product_count = len(search_product) product_count = len(search_product)
pager = request.website.pager(url=url, total=product_count, page=page, pager = website.pager(url=url, total=product_count, page=page, step=ppg,
step=ppg, scope=7, url_args=post) scope=7, url_args=post)
offset = pager['offset']
products = Product.search(domain, limit=ppg, offset=pager['offset'], products = Product.search(domain, limit=ppg, offset=pager['offset'],
order=self._get_search_order(post)) order=self._get_search_order(post))
if not category: if not category:
@ -240,23 +275,24 @@ class ProductVisibilityCon(WebsiteSale):
ProductAttribute = request.env['product.attribute'] ProductAttribute = request.env['product.attribute']
if products: if products:
# get all products without limit # get all products without limit
attributes = ProductAttribute.search( attributes = lazy(lambda: ProductAttribute.search([
[('product_tmpl_ids', 'in', search_product.ids)]) ('product_tmpl_ids', 'in', search_product.ids),
('visibility', '=', 'visible'),
]))
else: else:
attributes = ProductAttribute.browse(attributes_ids) attributes = lazy(lambda: ProductAttribute.browse(attributes_ids))
layout_mode = request.session.get('website_sale_shop_layout_mode') layout_mode = request.session.get('website_sale_shop_layout_mode')
if not layout_mode: if not layout_mode:
if request.website.viewref( if website.viewref('website_sale.products_list_view').active:
'website_sale.products_list_view').active:
layout_mode = 'list' layout_mode = 'list'
else: else:
layout_mode = 'grid' layout_mode = 'grid'
request.session['website_sale_shop_layout_mode'] = layout_mode request.session['website_sale_shop_layout_mode'] = layout_mode
products_prices = lazy(lambda: products._get_sales_prices(pricelist)) products_prices = lazy(lambda: products._get_sales_prices(pricelist))
values = { values = {
'search': search, 'search': fuzzy_search_term or search,
'original_search': fuzzy_search_term and search,
'order': post.get('order', ''),
'category': category, 'category': category,
'attrib_values': attrib_values, 'attrib_values': attrib_values,
'attrib_set': attrib_set, 'attrib_set': attrib_set,
@ -264,6 +300,7 @@ class ProductVisibilityCon(WebsiteSale):
'pricelist': pricelist, 'pricelist': pricelist,
'add_qty': add_qty, 'add_qty': add_qty,
'products': products, 'products': products,
'search_product': search_product,
'search_count': product_count, # common for all searchbox 'search_count': product_count, # common for all searchbox
'bins': TableCompute().process(products, ppg, ppr), 'bins': TableCompute().process(products, ppg, ppr),
'ppg': ppg, 'ppg': ppg,
@ -276,14 +313,22 @@ class ProductVisibilityCon(WebsiteSale):
'products_prices': products_prices, 'products_prices': products_prices,
'get_product_prices': lambda product: lazy( 'get_product_prices': lambda product: lazy(
lambda: products_prices[product.id]), lambda: products_prices[product.id]),
'float_round': tools.float_round,
} }
if filter_by_price_enabled:
values['min_price'] = min_price or available_min_price
values['max_price'] = max_price or available_max_price
values['available_min_price'] = tools.float_round(
available_min_price, 2)
values['available_max_price'] = tools.float_round(
available_max_price, 2)
if category: if category:
values['main_object'] = category values['main_object'] = category
values.update(self._get_additional_shop_values(values))
return request.render("website_sale.products", values) return request.render("website_sale.products", values)
def availavle_products(self): def available_products(self):
''''Returns the available product (product.template) ids''' """Returns the available product (product.template) ids"""
user = request.env['res.users'].sudo().search( user = request.env['res.users'].sudo().search(
[('id', '=', request.env.user.id)]) [('id', '=', request.env.user.id)])
partner = request.env['res.partner'].sudo().search( partner = request.env['res.partner'].sudo().search(
@ -299,7 +344,6 @@ class ProductVisibilityCon(WebsiteSale):
def products_autocomplete(self, term, options={}, **kwargs): def products_autocomplete(self, term, options={}, **kwargs):
""" """
Returns list of products according to the term and product options Returns list of products according to the term and product options
Params: Params:
term (str): search term written by the user term (str): search term written by the user
options (dict) options (dict)
@ -309,7 +353,6 @@ class ProductVisibilityCon(WebsiteSale):
- 'order' (str) - 'order' (str)
- 'max_nb_chars' (int): max number of characters for the - 'max_nb_chars' (int): max number of characters for the
description if returned description if returned
Returns: Returns:
dict (or False if no result) dict (or False if no result)
- 'products' (list): products (only their needed field values) - 'products' (list): products (only their needed field values)
@ -318,7 +361,6 @@ class ProductVisibilityCon(WebsiteSale):
- 'products_count' (int): the number of products in the database - 'products_count' (int): the number of products in the database
that matched the search query that matched the search query
""" """
user = request.env['res.users'].sudo().search( user = request.env['res.users'].sudo().search(
[('id', '=', request.env.user.id)]) [('id', '=', request.env.user.id)])
available_categ = available_products = '' available_categ = available_products = ''
@ -343,7 +385,7 @@ class ProductVisibilityCon(WebsiteSale):
[('id', '=', user.partner_id.id)]) [('id', '=', user.partner_id.id)])
mode = partner.filter_mode mode = partner.filter_mode
if mode != 'categ_only': if mode != 'categ_only':
available_products = self.availavle_products() available_products = self.available_products()
available_categ = partner.website_available_cat_ids available_categ = partner.website_available_cat_ids
ProductTemplate = request.env['product.template'] ProductTemplate = request.env['product.template']
display_description = options.get('display_description', True) display_description = options.get('display_description', True)
@ -352,7 +394,6 @@ class ProductVisibilityCon(WebsiteSale):
max_nb_chars = options.get('max_nb_chars', 999) max_nb_chars = options.get('max_nb_chars', 999)
category = options.get('category') category = options.get('category')
attrib_values = options.get('attrib_values') attrib_values = options.get('attrib_values')
if not available_products and not available_categ: if not available_products and not available_categ:
domain = self._get_search_domain(term, category, attrib_values, domain = self._get_search_domain(term, category, attrib_values,
display_description) display_description)
@ -368,19 +409,16 @@ class ProductVisibilityCon(WebsiteSale):
fields = ['id', 'name', 'website_url'] fields = ['id', 'name', 'website_url']
if display_description: if display_description:
fields.append('description_sale') fields.append('description_sale')
res = { res = {
'products': products.read(fields), 'products': products.read(fields),
'products_count': ProductTemplate.search_count(domain), 'products_count': ProductTemplate.search_count(domain),
} }
if display_description: if display_description:
for res_product in res['products']: for res_product in res['products']:
desc = res_product['description_sale'] desc = res_product['description_sale']
if desc and len(desc) > max_nb_chars: if desc and len(desc) > max_nb_chars:
res_product['description_sale'] = "%s..." % desc[:( res_product['description_sale'] = "%s..." % desc[:(
max_nb_chars - 3)] max_nb_chars - 3)]
if display_price: if display_price:
FieldMonetary = request.env['ir.qweb.field.monetary'] FieldMonetary = request.env['ir.qweb.field.monetary']
monetary_options = { monetary_options = {
@ -394,5 +432,4 @@ class ProductVisibilityCon(WebsiteSale):
res_product['list_price'], monetary_options) res_product['list_price'], monetary_options)
res_product['price'] = FieldMonetary.value_to_html( res_product['price'] = FieldMonetary.value_to_html(
res_product['price'], monetary_options) res_product['price'], monetary_options)
return res return res

7
product_visibility_website/doc/RELEASE_NOTES.md

@ -4,6 +4,7 @@
#### Version 16.0.1.0.0 #### Version 16.0.1.0.0
##### ADD ##### ADD
#### 22.08.2023
#### Version 16.0.1.0.0
##### FIX
- Bug Fixed

9
product_visibility_website/models/__init__.py

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################### ################################################################################
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). # Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>)
# Author: Neeraj Krishnan V M (<https://www.cybrosys.com>) # Author: Neeraj Krishnan V M, Saneen K (<https://www.cybrosys.com>)
# #
# This program is free software: you can modify # This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as # it under the terms of the GNU Affero General Public License (AGPL) as
@ -19,6 +19,5 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
################################################################################### ################################################################################
from . import website_product_visibility from . import website_product_visibility

70
product_visibility_website/models/website_product_visibility.py

@ -1,11 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################### ################################################################################
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies ( # Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>)
# <https://www.cybrosys.com>). Author: Neeraj Krishnan V M( # Author: Neeraj Krishnan V M, Saneen K (<https://www.cybrosys.com>)
# <https://www.cybrosys.com>)
# #
# This program is free software: you can modify # This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as # it under the terms of the GNU Affero General Public License (AGPL) as
@ -20,57 +19,81 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
################################################################################### ################################################################################
from odoo import fields, models, api from odoo import fields, models, api
from ast import literal_eval from ast import literal_eval
class ProductVisibility(models.Model): class ProductVisibility(models.Model):
"""Inherit res.partner for adding the fields for selecting the products"""
_inherit = 'res.partner' _inherit = 'res.partner'
filter_mode = fields.Selection( filter_mode = fields.Selection(
[('null', 'No Filter'), ('product_only', 'Product Wise'), [('null', 'No Filter'), ('product_only', 'Product Wise'),
('categ_only', 'Category Wise')], string='Filter Mode', default='null') ('categ_only', 'Category Wise')], string='Filter Mode', default='null',
help="Select any mode")
website_available_product_ids = fields.Many2many('product.template', website_available_product_ids = fields.Many2many('product.template',
string='Available Product', string='Available Product',
domain="[('is_published', '=', True)]", domain="[('is_published"
help='The website will only display products which are within one ' "', '=', True)]",
'of the selected category trees. If no category is specified,' help='The website will '
' all available products will be shown') 'only display '
'products which are '
'within one'
'of the selected '
'category trees. If '
'no category is '
'specified,'
'all available '
'products will be '
'shown')
website_available_cat_ids = fields.Many2many('product.public.category', website_available_cat_ids = fields.Many2many('product.public.category',
string='Available Product Categories', string='Available Product '
help='The website will only display products which are selected.' 'Categories',
' If no product is specified,' help='The website will only '
' all available products will be shown') 'display products which '
'are selected.'
'If no product is '
'specified,'
'all available products '
'will be shown')
@api.onchange("filter_mode") @api.onchange("filter_mode")
def onchange_filter_mod(self): def onchange_filter_mod(self):
"""Function for viewing the modes and product/category"""
if self.filter_mode == 'null': if self.filter_mode == 'null':
self.website_available_cat_ids = None self.website_available_cat_ids = None
self.website_available_product_ids = None self.website_available_product_ids = None
class WebsiteGuestVisibility(models.TransientModel): class WebsiteGuestVisibility(models.TransientModel):
"""Inherit the model res.config.settings for adding the fields for
selecting the product for visitors"""
_inherit = 'res.config.settings' _inherit = 'res.config.settings'
product_visibility_guest_user = fields.Boolean( product_visibility_guest_user = fields.Boolean(
string="Product visibility Guest User") string="Product visibility Guest User", help="Product Visibility")
filter_mode = fields.Selection([('product_only', 'Product Wise'), filter_mode = fields.Selection([('product_only', 'Product Wise'),
('categ_only', 'Category Wise')], ('categ_only', 'Category Wise')],
string='Filter Mode', default='product_only') string='Filter Mode', default='product_only')
available_product_ids = fields.Many2many('product.template', available_product_ids = fields.Many2many('product.template',
string='Available Product', string='Available Product',
domain="[('is_published', '=', True)]", domain="[('is_published', '=', "
help='The website will only display products which are within one ' "True)]",
'of the selected category trees. If no category is specified,' help='The website will only '
' all available products will be shown') 'display products which are '
'within one of the selected'
' category trees. If no'
' category is specified,'
'all available products '
'will be shown')
available_cat_ids = fields.Many2many('product.public.category', available_cat_ids = fields.Many2many('product.public.category',
string='Available Product Categories', string='Available Product Categories',
help='The website will only display products which are selected.' help='The website will only display '
'products which are selected.'
' If no product is specified,' ' If no product is specified,'
' all available products will be shown') 'all available products will be '
'shown')
@api.model @api.model
def set_values(self): def set_values(self):
@ -89,7 +112,6 @@ class WebsiteGuestVisibility(models.TransientModel):
self.available_cat_ids = None self.available_cat_ids = None
elif self.filter_mode == 'categ_only': elif self.filter_mode == 'categ_only':
self.available_product_ids = None self.available_product_ids = None
self.env['ir.config_parameter'].sudo().set_param( self.env['ir.config_parameter'].sudo().set_param(
'website_product_visibility.available_product_ids', 'website_product_visibility.available_product_ids',
self.available_product_ids.ids) self.available_product_ids.ids)

5
product_visibility_website/static/description/index.html

@ -135,7 +135,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- END OF FEATURES SECTION --> <!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION --> <!-- SCREENSHOTS SECTION -->
@ -399,7 +398,7 @@
</div> </div>
<!-- END OF END OF OUR SERVICES --> <!--END OF OUR SERVICES -->
<!-- OUR INDUSTRIES --> <!-- OUR INDUSTRIES -->
@ -526,7 +525,7 @@
</div> </div>
</div> </div>
<!-- END OF END OF OUR INDUSTRIES --> <!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT --> <!-- SUPPORT -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> <div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">

11
product_visibility_website/views/website_product_visibility.xml

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<data> <data>
<record id="base_view_partner_form_inherit" model="ir.ui.view"> <record id="view_partner_form" model="ir.ui.view">
<field name="name"> base.view.partner.form.inherit</field> <field name="name"> res.partner.view.form.inherit.product.visibility.website</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/> <field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
@ -22,9 +22,8 @@
</field> </field>
</record> </record>
<record id="res_config_settings_view_form" model="ir.ui.view">
<record id="website_config_view_inherit" model="ir.ui.view"> <field name="name">res.config.settings.view.form.inherit.product.visibility.website</field>
<field name="name">website.config.view.inherit</field>
<field name="model">res.config.settings</field> <field name="model">res.config.settings</field>
<field name="inherit_id" ref="website.res_config_settings_view_form"/> <field name="inherit_id" ref="website.res_config_settings_view_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
@ -63,4 +62,4 @@
</field> </field>
</record> </record>
</data> </data>
</odoo> </odoo>

Loading…
Cancel
Save