You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							398 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							398 lines
						
					
					
						
							18 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ################################################################################### | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). | |
| #    Author: Neeraj Krishnan V M (<https://www.cybrosys.com>) | |
| # | |
| #    This program is free software: you can modify | |
| #    it under the terms of the GNU Affero General Public License (AGPL) as | |
| #    published by the Free Software Foundation, either version 3 of the | |
| #    License, or (at your option) any later version. | |
| # | |
| #    This program is distributed in the hope that it will be useful, | |
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| #    GNU Affero General Public License for more details. | |
| # | |
| #    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/>. | |
| # | |
| ################################################################################### | |
| 
 | |
| from werkzeug.exceptions import NotFound | |
| from odoo.addons.http_routing.models.ir_http import slug | |
| from odoo.addons.website.controllers.main import QueryURL | |
| from odoo.addons.website_sale.controllers.main import TableCompute | |
| from odoo import http | |
| from ast import literal_eval | |
| from odoo.http import request | |
| from odoo.addons.website.models.ir_http import sitemap_qs2dom | |
| from odoo.addons.website_sale.controllers.main import WebsiteSale | |
| 
 | |
| from odoo.osv import expression | |
| from datetime import datetime | |
| from odoo.tools import lazy | |
| 
 | |
| 
 | |
| class ProductVisibilityCon(WebsiteSale): | |
| 
 | |
|     def sitemap_shop(env, rule, qs): | |
|         if not qs or qs.lower() in '/shop': | |
|             yield {'loc': '/shop'} | |
|         category = env['product.public.category'] | |
|         dom = sitemap_qs2dom(qs, '/shop/category', category._rec_name) | |
|         dom += env['website'].get_current_website().website_domain() | |
|         for cat in category.search(dom): | |
|             loc = '/shop/category/%s' % slug(cat) | |
|             if not qs or qs.lower() in loc: | |
|                 yield {'loc': loc} | |
| 
 | |
|     def reset_domain(self, search, categories, available_products, | |
|                      attrib_values, search_in_description=True): | |
|         ''' | |
|         Function returns a domain consist of filter conditions | |
|         :param search: search variable | |
|         :param categories: list of category available | |
|         :param available_products: list of available product ids from product.template | |
|         :param attrib_values:product attiribute values | |
|         :param search_in_description: boolean filed showing there is search variable exist or not''' | |
| 
 | |
|         domains = [request.website.sale_product_domain()] | |
|         if search: | |
|             for srch in search.split(" "): | |
|                 subdomains = [ | |
|                     [('name', 'ilike', srch)], | |
|                     [('product_variant_ids.default_code', 'ilike', srch)] | |
|                 ] | |
|                 if search_in_description: | |
|                     subdomains.append([('description', 'ilike', srch)]) | |
|                     subdomains.append([('description_sale', 'ilike', srch)]) | |
|                 domains.append(expression.OR(subdomains)) | |
|         if available_products: | |
|             domains.append([('id', 'in', available_products.ids)]) | |
|         if categories: | |
|             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) | |
| 
 | |
|     @http.route([ | |
|         '''/shop''', | |
|         '''/shop/page/<int:page>''', | |
|         '''/shop/category/<model("product.public.category"):category>''', | |
|         '''/shop/category/<model("product.public.category"):category>/page/<int:page>''' | |
|     ], type='http', auth="public", website=True, sitemap=sitemap_shop) | |
|     def shop(self, page=0, category=None, search='', ppg=False, **post): | |
|         ''''Override shop function.''' | |
|         available_categ = available_products = '' | |
|         user = request.env['res.users'].sudo().search( | |
|             [('id', '=', request.env.user.id)]) | |
|         if not user: | |
|             mode = request.env['ir.config_parameter'].sudo().get_param( | |
|                 'filter_mode') | |
|             products = literal_eval( | |
|                 request.env['ir.config_parameter'].sudo().get_param( | |
|                     'website_product_visibility.available_product_ids', | |
|                     'False')) | |
|             if mode == 'product_only': | |
|                 available_products = request.env['product.template'].search( | |
|                     [('id', 'in', products)]) | |
|             cat = literal_eval( | |
|                 request.env['ir.config_parameter'].sudo().get_param( | |
|                     'website_product_visibility.available_cat_ids', 'False')) | |
|             available_categ = request.env['product.public.category'].search( | |
|                 [('id', 'in', cat)]) | |
|         else: | |
|             partner = request.env['res.partner'].sudo().search( | |
|                 [('id', '=', user.partner_id.id)]) | |
|             mode = partner.filter_mode | |
|             if mode == 'product_only': | |
|                 available_products = self.availavle_products() | |
|             available_categ = partner.website_available_cat_ids | |
| 
 | |
|         Category_avail = [] | |
|         Category = request.env['product.public.category'] | |
| 
 | |
|         for ids in available_categ: | |
|             if not ids.parent_id.id in available_categ.ids: | |
|                 Category_avail.append(ids.id) | |
|         categ = request.env['product.public.category'].search( | |
|             [('id', 'in', Category_avail)]) | |
|         if mode == 'product_only': | |
|             categ = Category.search([('parent_id', '=', False), ( | |
|             'product_tmpl_ids', 'in', available_products.ids)]) | |
| 
 | |
|         # supering shop*** | |
| 
 | |
|         if not available_categ and not available_products: | |
|             return super(ProductVisibilityCon, self).shop(page, category, | |
|                                                           search, ppg, **post) | |
|         add_qty = int(post.get('add_qty', 1)) | |
| 
 | |
|         if category: | |
|             category = Category.search([('id', '=', int(category))], limit=1) | |
|             if not category or not category.can_access_from_current_website(): | |
|                 raise NotFound() | |
|         else: | |
|             category = Category | |
|         website = request.env['website'].get_current_website() | |
|         if ppg: | |
|             try: | |
|                 ppg = int(ppg) | |
|                 post['ppg'] = ppg | |
|             except ValueError: | |
|                 ppg = False | |
|         if not ppg: | |
|             ppg = request.env['website'].get_current_website().shop_ppg or 20 | |
|         ppr = request.env['website'].get_current_website().shop_ppr or 4 | |
|         attrib_list = request.httprequest.args.getlist('attrib') | |
|         attrib_values = [[int(x) for x in v.split("-")] for v in attrib_list if | |
|                          v] | |
|         attributes_ids = {v[0] for v in attrib_values} | |
|         attrib_set = {v[1] for v in attrib_values} | |
|         domain = self._get_search_domain(search, category, attrib_values) | |
|         Product = request.env['product.template'].with_context(bin_size=True) | |
|         if available_products: | |
|             domain_pro = self.reset_domain(search, category, available_products, | |
|                                            attrib_values) | |
|             Product = Product.search(domain_pro) | |
|         keep = QueryURL('/shop', category=category and int(category), | |
|                         search=search, attrib=attrib_list, | |
|                         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()) | |
|         pricelist = request.env['product.pricelist'].browse( | |
|             request.session.get('website_sale_current_pl')) | |
|         if not pricelist or request.session.get('website_sale_pricelist_time', | |
|                                                 0) < now - 60 * 60:  # test: 1 hour in session | |
|             pricelist = website.get_current_pricelist() | |
|             request.session['website_sale_pricelist_time'] = now | |
|             request.session['website_sale_current_pl'] = pricelist.id | |
| 
 | |
|         request.update_context(pricelist=pricelist.id, | |
|                                partner=request.env.user.partner_id) | |
| 
 | |
|         url = "/shop" | |
|         if search: | |
|             post["search"] = search | |
|         if attrib_list: | |
|             post['attrib'] = attrib_list | |
|         if not category: | |
|             domain = self.reset_domain(search, available_categ, | |
|                                        available_products, attrib_values) | |
|         search_product = Product.search(domain) | |
|         website_domain = request.website.website_domain() | |
|         categs_domain = [('parent_id', '=', False), ( | |
|         'product_tmpl_ids', 'in', search_product.ids)] + website_domain | |
|         if search: | |
|             search_categories = Category.search( | |
|                 [('product_tmpl_ids', 'in', | |
|                   search_product.ids)] + website_domain).parents_and_self | |
|             categs_domain.append(('id', 'in', search_categories.ids)) | |
|         else: | |
|             search_categories = available_categ | |
|         if category: | |
|             url = "/shop/category/%s" % slug(category) | |
|         product_count = len(search_product) | |
|         pager = request.website.pager(url=url, total=product_count, page=page, | |
|                                       step=ppg, scope=7, url_args=post) | |
|         products = Product.search(domain, limit=ppg, offset=pager['offset'], | |
|                                   order=self._get_search_order(post)) | |
|         if not category: | |
|             if available_products: | |
|                 products = Product.search(domain_pro, limit=ppg, | |
|                                           offset=pager['offset'], | |
|                                           order=self._get_search_order(post)) | |
|             else: | |
|                 products = Product.search(domain, limit=ppg, | |
|                                           offset=pager['offset'], | |
|                                           order=self._get_search_order(post)) | |
|         else: | |
|             if available_products: | |
|                 products = Product.search(domain_pro, limit=ppg, | |
|                                           offset=pager['offset'], | |
|                                           order=self._get_search_order(post)) | |
|             else: | |
|                 products = Product.search(domain, limit=ppg, | |
|                                           offset=pager['offset'], | |
|                                           order=self._get_search_order(post)) | |
|         ProductAttribute = request.env['product.attribute'] | |
|         if products: | |
|             # get all products without limit | |
|             attributes = ProductAttribute.search( | |
|                 [('product_tmpl_ids', 'in', search_product.ids)]) | |
|         else: | |
|             attributes = ProductAttribute.browse(attributes_ids) | |
| 
 | |
|         layout_mode = request.session.get('website_sale_shop_layout_mode') | |
|         if not layout_mode: | |
|             if request.website.viewref( | |
|                     'website_sale.products_list_view').active: | |
|                 layout_mode = 'list' | |
|             else: | |
|                 layout_mode = 'grid' | |
|             request.session['website_sale_shop_layout_mode'] = layout_mode | |
| 
 | |
|         products_prices = lazy(lambda: products._get_sales_prices(pricelist)) | |
|         values = { | |
|             'search': search, | |
|             'category': category, | |
|             'attrib_values': attrib_values, | |
|             'attrib_set': attrib_set, | |
|             'pager': pager, | |
|             'pricelist': pricelist, | |
|             'add_qty': add_qty, | |
|             'products': products, | |
|             'search_count': product_count,  # common for all searchbox | |
|             'bins': TableCompute().process(products, ppg, ppr), | |
|             'ppg': ppg, | |
|             'ppr': ppr, | |
|             'categories': categ, | |
|             'attributes': attributes, | |
|             'keep': keep, | |
|             'search_categories_ids': categ.ids, | |
|             'layout_mode': layout_mode, | |
|             'products_prices': products_prices, | |
|             'get_product_prices': lambda product: lazy( | |
|                 lambda: products_prices[product.id]), | |
|         } | |
| 
 | |
|         if category: | |
|             values['main_object'] = category | |
|         return request.render("website_sale.products", values) | |
| 
 | |
|     def availavle_products(self): | |
|         ''''Returns the available product (product.template) ids''' | |
|         user = request.env['res.users'].sudo().search( | |
|             [('id', '=', request.env.user.id)]) | |
|         partner = request.env['res.partner'].sudo().search( | |
|             [('id', '=', user.partner_id.id)]) | |
|         return partner.website_available_product_ids | |
| 
 | |
|     # -------------------------------------------------------------------------- | |
|     # Products Search Bar | |
|     # -------------------------------------------------------------------------- | |
| 
 | |
|     @http.route('/shop/products/autocomplete', type='json', auth='public', | |
|                 website=True) | |
|     def products_autocomplete(self, term, options={}, **kwargs): | |
|         """ | |
|         Returns list of products according to the term and product options | |
|  | |
|         Params: | |
|             term (str): search term written by the user | |
|             options (dict) | |
|                 - 'limit' (int), default to 5: number of products to consider | |
|                 - 'display_description' (bool), default to True | |
|                 - 'display_price' (bool), default to True | |
|                 - 'order' (str) | |
|                 - 'max_nb_chars' (int): max number of characters for the | |
|                                         description if returned | |
|  | |
|         Returns: | |
|             dict (or False if no result) | |
|                 - 'products' (list): products (only their needed field values) | |
|                         note: the prices will be strings properly formatted and | |
|                         already containing the currency | |
|                 - 'products_count' (int): the number of products in the database | |
|                         that matched the search query | |
|         """ | |
| 
 | |
|         user = request.env['res.users'].sudo().search( | |
|             [('id', '=', request.env.user.id)]) | |
|         available_categ = available_products = '' | |
|         if not user: | |
|             mode = request.env['ir.config_parameter'].sudo().get_param( | |
|                 'filter_mode') | |
|             products = literal_eval( | |
|                 request.env['ir.config_parameter'].sudo().get_param( | |
|                     'website_product_visibility.available_product_ids', | |
|                     'False')) | |
|             if mode == 'product_only': | |
|                 available_products = request.env['product.template'].search( | |
|                     [('id', 'in', products)]) | |
|             cat = literal_eval( | |
|                 request.env['ir.config_parameter'].sudo().get_param( | |
|                     'website_product_visibility.available_cat_ids', | |
|                     'False')) | |
|             available_categ = request.env['product.public.category'].search( | |
|                 [('id', 'in', cat)]) | |
|         else: | |
|             partner = request.env['res.partner'].sudo().search( | |
|                 [('id', '=', user.partner_id.id)]) | |
|             mode = partner.filter_mode | |
|             if mode != 'categ_only': | |
|                 available_products = self.availavle_products() | |
|             available_categ = partner.website_available_cat_ids | |
|         ProductTemplate = request.env['product.template'] | |
|         display_description = options.get('display_description', True) | |
|         display_price = options.get('display_price', True) | |
|         order = self._get_search_order(options) | |
|         max_nb_chars = options.get('max_nb_chars', 999) | |
|         category = options.get('category') | |
|         attrib_values = options.get('attrib_values') | |
| 
 | |
|         if not available_products and not available_categ: | |
|             domain = self._get_search_domain(term, category, attrib_values, | |
|                                              display_description) | |
|         else: | |
|             domain = self.reset_domain(term, available_categ, | |
|                                        available_products, attrib_values, | |
|                                        display_description) | |
|         products = ProductTemplate.search( | |
|             domain, | |
|             limit=min(20, options.get('limit', 5)), | |
|             order=order | |
|         ) | |
|         fields = ['id', 'name', 'website_url'] | |
|         if display_description: | |
|             fields.append('description_sale') | |
| 
 | |
|         res = { | |
|             'products': products.read(fields), | |
|             'products_count': ProductTemplate.search_count(domain), | |
|         } | |
| 
 | |
|         if display_description: | |
|             for res_product in res['products']: | |
|                 desc = res_product['description_sale'] | |
|                 if desc and len(desc) > max_nb_chars: | |
|                     res_product['description_sale'] = "%s..." % desc[:( | |
|                                 max_nb_chars - 3)] | |
| 
 | |
|         if display_price: | |
|             FieldMonetary = request.env['ir.qweb.field.monetary'] | |
|             monetary_options = { | |
|                 'display_currency': request.website.get_current_pricelist().currency_id, | |
|             } | |
|             for res_product, product in zip(res['products'], products): | |
|                 combination_info = product._get_combination_info( | |
|                     only_template=True) | |
|                 res_product.update(combination_info) | |
|                 res_product['list_price'] = FieldMonetary.value_to_html( | |
|                     res_product['list_price'], monetary_options) | |
|                 res_product['price'] = FieldMonetary.value_to_html( | |
|                     res_product['price'], monetary_options) | |
| 
 | |
|         return res
 | |
| 
 |