From f790a59cbb4052260d8320bfcacf702c1750d08b Mon Sep 17 00:00:00 2001 From: Miftahussalam Date: Mon, 7 Aug 2023 23:37:41 +0700 Subject: [PATCH 01/26] [ssi_product_website] 14.0.1.0.0 --- ssi_product_website/README.rst | 47 + ssi_product_website/__init__.py | 7 + ssi_product_website/__manifest__.py | 23 + ssi_product_website/controllers/__init__.py | 7 + ssi_product_website/controllers/main.py | 262 +++ ssi_product_website/data/data.xml | 13 + .../static/description/icon.png | Bin 0 -> 23279 bytes ssi_product_website/views/templates.xml | 1950 +++++++++++++++++ 8 files changed, 2309 insertions(+) create mode 100644 ssi_product_website/README.rst create mode 100644 ssi_product_website/__init__.py create mode 100644 ssi_product_website/__manifest__.py create mode 100644 ssi_product_website/controllers/__init__.py create mode 100644 ssi_product_website/controllers/main.py create mode 100644 ssi_product_website/data/data.xml create mode 100644 ssi_product_website/static/description/icon.png create mode 100644 ssi_product_website/views/templates.xml diff --git a/ssi_product_website/README.rst b/ssi_product_website/README.rst new file mode 100644 index 0000000..ed8436f --- /dev/null +++ b/ssi_product_website/README.rst @@ -0,0 +1,47 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +================================= +Product App - website Integration +================================= + + +Installation +============ + +To install this module, you need to: + +1. Clone the branch 14.0 of the repository https://github.com/open-synergy/ssi-product-attribute +2. Add the path to this repository in your configuration (addons-path) +3. Update the module list +4. Go to menu *Apps -> Apps -> Main Apps* +5. Search For *Product App - website Integration* +6. Install the module + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed +and welcomed feedback. + + +Credits +======= + +Contributors +------------ + +* Miftahussalam + +Maintainer +---------- + +.. image:: https://simetri-sinergi.id/logo.png + :alt: PT. Simetri Sinergi Indonesia + :target: https://simetri-sinergi.id.com + +This module is maintained by the PT. Simetri Sinergi Indonesia. diff --git a/ssi_product_website/__init__.py b/ssi_product_website/__init__.py new file mode 100644 index 0000000..4240b31 --- /dev/null +++ b/ssi_product_website/__init__.py @@ -0,0 +1,7 @@ +# Copyright 2023 OpenSynergy Indonesia +# Copyright 2023 PT. Simetri Sinergi Indonesia +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import ( + controllers, +) diff --git a/ssi_product_website/__manifest__.py b/ssi_product_website/__manifest__.py new file mode 100644 index 0000000..0871a78 --- /dev/null +++ b/ssi_product_website/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2023 OpenSynergy Indonesia +# Copyright 2023 PT. Simetri Sinergi Indonesia +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). +{ + "name": "Product App - website Integration", + "version": "14.0.1.0.0", + "website": "https://simetri-sinergi.id", + "author": "PT. Simetri Sinergi Indonesia, OpenSynergy Indonesia", + "license": "LGPL-3", + "installable": True, + "application": False, + "auto_install": True, + "depends": [ + "ssi_product", + "website", + "website_sale", + ], + "data": [ + # "views/templates.xml", + "data/data.xml", + ], + "demo": [], +} diff --git a/ssi_product_website/controllers/__init__.py b/ssi_product_website/controllers/__init__.py new file mode 100644 index 0000000..da9cef5 --- /dev/null +++ b/ssi_product_website/controllers/__init__.py @@ -0,0 +1,7 @@ +# Copyright 2023 OpenSynergy Indonesia +# Copyright 2023 PT. Simetri Sinergi Indonesia +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import ( + main, +) diff --git a/ssi_product_website/controllers/main.py b/ssi_product_website/controllers/main.py new file mode 100644 index 0000000..335ee87 --- /dev/null +++ b/ssi_product_website/controllers/main.py @@ -0,0 +1,262 @@ +# Copyright 2023 OpenSynergy Indonesia +# Copyright 2023 PT. Simetri Sinergi Indonesia +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +import json +import logging +from datetime import datetime +from werkzeug.exceptions import Forbidden, NotFound + +from odoo import fields, http, SUPERUSER_ID, tools, _ +from odoo.http import request +from odoo.addons.base.models.ir_qweb_fields import nl2br +from odoo.addons.http_routing.models.ir_http import slug +from odoo.addons.payment.controllers.portal import PaymentProcessing +from odoo.addons.website.controllers.main import QueryURL +from odoo.addons.website.models.ir_http import sitemap_qs2dom +from odoo.exceptions import ValidationError +from odoo.addons.portal.controllers.portal import _build_url_w_params +from odoo.addons.website.controllers.main import Website +from odoo.addons.website_form.controllers.main import WebsiteForm +from odoo.osv import expression +_logger = logging.getLogger(__name__) + + +class TableCompute(object): + + def __init__(self): + self.table = {} + + def _check_place(self, posx, posy, sizex, sizey, ppr): + res = True + for y in range(sizey): + for x in range(sizex): + if posx + x >= ppr: + res = False + break + row = self.table.setdefault(posy + y, {}) + if row.setdefault(posx + x) is not None: + res = False + break + for x in range(ppr): + self.table[posy + y].setdefault(x, None) + return res + + def process(self, products, ppg=20, ppr=4): + # Compute products positions on the grid + minpos = 0 + index = 0 + maxy = 0 + x = 0 + for p in products: + x = min(max(p.website_size_x, 1), ppr) + y = min(max(p.website_size_y, 1), ppr) + if index >= ppg: + x = y = 1 + + pos = minpos + while not self._check_place(pos % ppr, pos // ppr, x, y, ppr): + pos += 1 + # if 21st products (index 20) and the last line is full (ppr products in it), break + # (pos + 1.0) / ppr is the line where the product would be inserted + # maxy is the number of existing lines + # + 1.0 is because pos begins at 0, thus pos 20 is actually the 21st block + # and to force python to not round the division operation + if index >= ppg and ((pos + 1.0) // ppr) > maxy: + break + + if x == 1 and y == 1: # simple heuristic for CPU optimization + minpos = pos // ppr + + for y2 in range(y): + for x2 in range(x): + self.table[(pos // ppr) + y2][(pos % ppr) + x2] = False + self.table[pos // ppr][pos % ppr] = { + 'product': p, 'x': x, 'y': y, + 'ribbon': p.website_ribbon_id, + } + if index <= ppg: + maxy = max(maxy, y + (pos // ppr)) + index += 1 + + # Format table according to HTML needs + rows = sorted(self.table.items()) + rows = [r[1] for r in rows] + for col in range(len(rows)): + cols = sorted(rows[col].items()) + x += len(cols) + rows[col] = [r[1] for r in cols if r[1]] + + return rows + + +class ProductWebsite(http.Controller): + + def _get_pricelist_context(self): + pricelist_context = dict(request.env.context) + pricelist = False + if not pricelist_context.get('pricelist'): + pricelist = request.website.get_current_pricelist() + pricelist_context['pricelist'] = pricelist.id + else: + pricelist = request.env['product.pricelist'].browse(pricelist_context['pricelist']) + + return pricelist_context, pricelist + + def _get_search_order(self, post): + # OrderBy will be parsed in orm and so no direct sql injection + # id is added to be sure that order is a unique sort key + order = post.get('order') or 'website_sequence ASC' + return 'is_published desc, %s, id desc' % order + + def _get_search_domain(self, search, category, attrib_values, search_in_description=True): + 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 category: + domains.append([('public_categ_ids', 'child_of', int(category))]) + + if attrib_values: + attrib = None + 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) + + 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} + + @http.route([ + '''/product_catalog''', + '''/shop/page/''', + '''/shop/category/''', + '''/shop/category//page/''' + ], type='http', auth="public", website=True, sitemap=sitemap_shop) + def shop(self, page=0, category=None, search='', ppg=False, **post): + add_qty = int(post.get('add_qty', 1)) + Category = request.env['product.public.category'] + 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 + + 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) + + 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) + + url = "/shop" + if search: + post["search"] = search + if attrib_list: + post['attrib'] = attrib_list + + Product = request.env['product.template'].with_context(bin_size=True) + + search_product = Product.search(domain, order=self._get_search_order(post)) + website_domain = request.website.website_domain() + categs_domain = [('parent_id', '=', False)] + 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 = Category + categs = Category.search(categs_domain) + + 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) + offset = pager['offset'] + products = search_product[offset: offset + ppg] + + 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' + + values = { + 'search': search, + 'order': post.get('order', ''), + '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': categs, + 'attributes': attributes, + 'keep': keep, + 'search_categories_ids': search_categories.ids, + 'layout_mode': layout_mode, + } + if category: + values['main_object'] = category + return request.render("website_sale.products", values) diff --git a/ssi_product_website/data/data.xml b/ssi_product_website/data/data.xml new file mode 100644 index 0000000..7b60fb1 --- /dev/null +++ b/ssi_product_website/data/data.xml @@ -0,0 +1,13 @@ + + + + + + Product Catalog + /product_catalog + + 25 + + + + diff --git a/ssi_product_website/static/description/icon.png b/ssi_product_website/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fb45154c7432612e2193cd3ab3e02fb8c1cb4255 GIT binary patch literal 23279 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +