from itertools import product from multiprocessing import Condition from odoo import fields, models, api, tools, _ import logging import re import pysolr from odoo.exceptions import UserError import base64 import xlrd, xlwt import io _logger = logging.getLogger(__name__) # solr = pysolr.Solr('http://10.148.0.5:8983/solr/searchkey/', always_commit=True, timeout=30) solr = pysolr.Solr('http://127.0.0.1:8983/solr/searchkey/', always_commit=True, timeout=30) class Keywords(models.Model): _name = 'keywords' _order= 'id desc' category_id = fields.Many2one('product.public.category', string='Category', required=True, help="Category to filter products when generating products for this keyword and to throw to solr") keywords = fields.Char('Keywords', required=True) brand_id = fields.Many2one( comodel_name="x_manufactures", string="Brand" ) product_ids = fields.Many2many( 'product.product', 'keywords_product_rel', 'keyword_id', 'product_id', string='Products' ) name = fields.Char('Name', compute="_compute_name") skip = fields.Boolean('Skip Generate Product', default=False, help="If checked, the system will not generate products for this keyword") url = fields.Char('Website URL', compute="_compute_url", help="Generated website url based on keywords") sum = fields.Integer('Total Product', compute="_compute_total_product", readonly=True, help="Total products found for this keyword including variants") @api.depends('product_ids') def _compute_total_product(self): for record in self: record.sum = len(record.product_ids) @api.depends('keywords', 'brand_id') def _compute_url(self): prefix = "https://indoteknik.com/searchkey/" for record in self: if not record.keywords: record.url = False continue slug = re.sub(r'[^a-zA-Z0-9]+', '-', record.keywords.strip().lower()).strip('-') if record.brand_id: brand_slug = re.sub( r'[^a-zA-Z0-9]+', '-', record.brand_id.x_name.strip().lower() ).strip('-') record.url = f"{prefix}{slug}-{brand_slug}" else: record.url = f"{prefix}{slug}" def _compute_name(self): for record in self: if not record.name: record.name = record.keywords @api.constrains('keywords', 'category_id') def check_already_exist(self): for record in self: if not (record.keywords and record.category_id): continue match = self.search([ ('id', '!=', record.id), ('keywords', '=', record.keywords), ('category_id', '=', record.category_id.id) ], limit = 1) if match: raise UserError("Tidak bisa create karena keywords sudah dipakai") def copy(self): raise UserError("Duplicate Record not allowed") def clear_products(self): for record in self: record.product_ids = [(5, 0, 0)] def generate_products(self): for record in self: if record.skip: continue if not record.keywords: raise UserError("Keyword wajib diisi") if not record.category_id: raise UserError( f"Category wajib diisi untuk keyword '{record.keywords}'" ) keyword_raw = record.keywords.strip() keyword = f"%{keyword_raw}%" sql = """ SELECT DISTINCT pp.id FROM product_product pp JOIN product_template pt ON pt.id = pp.product_tmpl_id JOIN product_public_category_product_template_rel rel ON rel.product_template_id = pt.id WHERE pt.product_rating >= 8 AND pp.active IS TRUE AND ( pt.name ILIKE %s OR pt.website_description ILIKE %s ) """ params = [keyword, keyword] # ====================== # CATEGORY (WAJIB) # ====================== child_categs = self.env['product.public.category'].search([ ('id', 'child_of', record.category_id.id) ]) sql += " AND rel.product_public_category_id = ANY(%s)" params.append(child_categs.ids) # ====================== # BRAND (OPTIONAL) # ====================== if record.brand_id: brand = record.brand_id.x_name brand_kw_1 = f"%{brand} {keyword_raw}%" brand_kw_2 = f"%{keyword_raw} {brand}%" keyword = f"%{keyword_raw}%" sql += "AND pt.x_manufacture = %s" sql += """ AND ( pt.name ILIKE %s OR pt.name ILIKE %s OR pt.website_description ILIKE %s OR pt.website_description ILIKE %s ) OR ( pt.x_manufacture = %s AND (pt.name ilike %s OR pt.website_description ilike %s) ) """ params.extend([ record.brand_id.id, brand_kw_1, brand_kw_2, brand_kw_1, brand_kw_2, record.brand_id.id, keyword, keyword ]) # ====================== # EXECUTE # ====================== self.env.cr.execute(sql, params) rows = self.env.cr.fetchall() product_ids = [r[0] for r in rows] if not product_ids: raise UserError( f"Tidak menemukan product untuk keyword " f"'{record.keywords}' di category '{record.category_id.name}'" ) record.with_context(skip_generate=True).write({ 'product_ids': [(6, 0, product_ids)] }) _logger.info( "Product Found: %s products | keyword='%s' | category='%s'", len(product_ids), record.keywords, record.category_id.name ) def sync_solr(self): active_ids = self.env.context.get('active_ids', []) if not active_ids: _logger.warning("No active_ids found, nothing to sync") return True elif active_ids and self.sum < 1: raise UserError("Tidak ada product untuk keyword ini, sync ke solr dibatalkan") keywords = self.browse(active_ids) documents = [] for keyword in keywords: searchkey = (keyword.keywords or '').strip().lower().replace(' ', '-') if keyword.brand_id: searchkey = f"{searchkey}-{keyword.brand_id.x_name.strip().lower().replace(' ', '-')}" try: doc = { 'id': keyword.id, 'category_id_i': keyword.category_id.id, 'keywords_s': searchkey, 'url_s': keyword.url, 'product_ids_is': [p.product_tmpl_id.id for p in keyword.product_ids], } documents.append(doc) except Exception as e: _logger.error('failed %s', e) _logger.error('doc data: %s', doc) if documents: solr.add(documents) return True @api.model def create(self, vals): record = super().create(vals) # self.check_already_exist() # record.generate_products() return record def write(self, vals): result = super().write(vals) # self.check_already_exist() # if not self.env.context.get("skip_generate") and not self.skip: # self.generate_products() return result