From 8ee7bd9211a75809e1819de32ddf974c3736ebde Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 5 Dec 2025 16:46:24 +0700 Subject: Initial COmmit baru --- indoteknik_custom/models/keywords.py | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 indoteknik_custom/models/keywords.py (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py new file mode 100644 index 00000000..38b6e2fe --- /dev/null +++ b/indoteknik_custom/models/keywords.py @@ -0,0 +1,52 @@ +from itertools import product +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__) + +class Keywords(models.Model): + _name = 'keywords' + _order= 'id desc' + + category_id = fields.Many2one('product.public.category', string='Category') + keywords = fields.Char('Keywords') + product_ids = fields.One2many('product.product', 'keyword_id', string='Products') + + @api.constrains('product_ids', 'keywords', 'category_id') + def action_generate_products(self): + for record in self: + if not record.keywords: + continue + + domain = [ + ('name', 'ilike', record.keywords), + ('product_rating', '>=', 8), + ('unpublish', '=', False) + ] + + # if record.category_id: + # domain += [(record.product_ids.id, 'in', record.category_id.id)] + + matched_products = self.env['product.product'].search(domain) + + record.product_ids = [(6, 0, matched_products.ids)] + + _logger.info('Generated %s products for keyword "%s"', len(matched_products), record.keywords) + + @api.model + def create(self, vals): + record = super().create(vals) + record.action_generate_products() + return record + + def write(self, vals): + result = super().write(vals) + self.action_generate_products() + return result -- cgit v1.2.3 From e27101a407ad9df9b341149b2b5ff5120062a464 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Mon, 8 Dec 2025 13:03:38 +0700 Subject: done temp --- indoteknik_custom/models/keywords.py | 69 +++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 17 deletions(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index 38b6e2fe..6e34642a 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -15,38 +15,73 @@ class Keywords(models.Model): _name = 'keywords' _order= 'id desc' - category_id = fields.Many2one('product.public.category', string='Category') - keywords = fields.Char('Keywords') - product_ids = fields.One2many('product.product', 'keyword_id', string='Products') + category_id = fields.Many2one('product.public.category', string='Category', required=True) + keywords = fields.Char('Keywords', required=True) + product_ids = fields.Many2many( + 'product.product', + 'keywords_product_rel', + 'keyword_id', + 'product_id', + string='Products' + ) + skip = fields.Boolean('Skip Generate Product', default=False) - @api.constrains('product_ids', 'keywords', 'category_id') - def action_generate_products(self): + + def generate_products(self): + """Generate product_ids menggunakan SQL mentah (super cepat).""" for record in self: if not record.keywords: continue - domain = [ - ('name', 'ilike', record.keywords), - ('product_rating', '>=', 8), - ('unpublish', '=', False) - ] + keyword = "%" + record.keywords.strip() + "%" + + # Query dasar + sql = """ + SELECT pp.id + FROM product_product pp + JOIN product_template pt ON pt.id = pp.product_tmpl_id + LEFT JOIN product_public_category_product_template_rel rel + ON rel.product_template_id = pt.id + WHERE ( + pt.name ILIKE %s + OR pt.website_description ILIKE %s + AND pt.unpublished = False + AND pt.product_rating >= 8 + ) + """ + + params = [keyword, keyword] + + # Filter kategori kalau ada + if record.category_id: + sql += " AND rel.product_public_category_id = %s" + params.append(record.category_id.id) - # if record.category_id: - # domain += [(record.product_ids.id, 'in', record.category_id.id)] + # Eksekusi SQL + self.env.cr.execute(sql, params) + rows = self.env.cr.fetchall() - matched_products = self.env['product.product'].search(domain) + product_ids = [r[0] for r in rows] - record.product_ids = [(6, 0, matched_products.ids)] + # Update Many2many + record.with_context(skip_generate=True).write({ + 'product_ids': [(6, 0, product_ids)] + }) - _logger.info('Generated %s products for keyword "%s"', len(matched_products), record.keywords) + _logger.info( + "SQL FAST MODE: Found %s products for keyword '%s'", + len(product_ids), + record.keywords + ) @api.model def create(self, vals): record = super().create(vals) - record.action_generate_products() + record.generate_products() return record def write(self, vals): result = super().write(vals) - self.action_generate_products() + if not self.env.context.get("skip_generate") and self.skip == False: + self.generate_products() return result -- cgit v1.2.3 From f71156bc5e0ce9ceb22215a4345518b02f5250ed Mon Sep 17 00:00:00 2001 From: Mqdd Date: Mon, 8 Dec 2025 15:19:36 +0700 Subject: solr --- indoteknik_custom/models/keywords.py | 76 ++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 8 deletions(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index 6e34642a..b1f2642d 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -7,9 +7,12 @@ from odoo.exceptions import UserError import base64 import xlrd, xlwt import io +from bs4 import BeautifulSoup _logger = logging.getLogger(__name__) +# solr = pysolr.Solr('http://10.148.0.5:8983/solr/keywords/', always_commit=True, timeout=30) +solr = pysolr.Solr('http://127.0.0.1:8983/solr/keywords/', always_commit=True, timeout=30) class Keywords(models.Model): _name = 'keywords' @@ -24,18 +27,22 @@ class Keywords(models.Model): 'product_id', string='Products' ) + name = fields.Char('Name', compute="_compute_name") skip = fields.Boolean('Skip Generate Product', default=False) + def _compute_name(self): + for record in self: + if not record.name: + record.name = record.keywords + def generate_products(self): - """Generate product_ids menggunakan SQL mentah (super cepat).""" for record in self: if not record.keywords: continue keyword = "%" + record.keywords.strip() + "%" - # Query dasar sql = """ SELECT pp.id FROM product_product pp @@ -52,28 +59,81 @@ class Keywords(models.Model): params = [keyword, keyword] - # Filter kategori kalau ada if record.category_id: sql += " AND rel.product_public_category_id = %s" params.append(record.category_id.id) - # Eksekusi SQL - self.env.cr.execute(sql, params) + # Exec query rows = self.env.cr.fetchall() product_ids = [r[0] for r in rows] - # Update Many2many record.with_context(skip_generate=True).write({ 'product_ids': [(6, 0, product_ids)] }) _logger.info( - "SQL FAST MODE: Found %s products for keyword '%s'", + "SQL : Found %s products for keyword '%s'", len(product_ids), record.keywords ) + + def sync_solr(self): + solr = self.env['apache.solr'] # pastikan ini model Solr sudah ada + documents = [] + + # Sync Keywords + for keyword in self.search([]): + doc = { + 'id': f'keyword_{keyword.id}', # prefix biar unik di Solr + 'type_s': 'keyword', + 'name_s': keyword.keywords, + 'category_id_i': keyword.category_id.id if keyword.category_id else 0, + 'product_ids_ii': keyword.product_ids.ids, + } + documents.append(doc) + _logger.info('Prepared Solr document for keyword %s', keyword.keywords) + + # Sync Products + products = self.env['product.product'].search([]) + for product in products: + category_ids = [c.id for c in product.public_categ_ids] + doc = { + 'id': f'product_{product.id}', + 'type_s': 'product', + 'name_s': product.name, + 'default_code_s': product.default_code or '', + 'category_ids_ii': category_ids, + 'website_description_t': product.website_description or '', + 'product_rating_f': getattr(product, 'virtual_rating', 0), + 'active_b': product.active, + } + documents.append(doc) + _logger.info('Prepared Solr document for product %s', product.name) + + # Sync Categories + categories = self.env['product.public.category'].search([]) + for cat in categories: + doc = { + 'id': f'category_{cat.id}', + 'type_s': 'category', + 'name_s': cat.name, + 'parent_id_i': cat.parent_id.id if cat.parent_id else 0, + } + documents.append(doc) + _logger.info('Prepared Solr document for category %s', cat.name) + + # Kirim ke Solr + if documents: + try: + solr.add(documents, softCommit=True) + _logger.info('Synced %d documents to Solr', len(documents)) + except Exception as e: + _logger.error('Failed to sync documents to Solr: %s', e) + else: + _logger.warning('No documents to sync to Solr') + @api.model def create(self, vals): record = super().create(vals) @@ -82,6 +142,6 @@ class Keywords(models.Model): def write(self, vals): result = super().write(vals) - if not self.env.context.get("skip_generate") and self.skip == False: + if not self.env.context.get("skip_generate") and not self.skip: self.generate_products() return result -- cgit v1.2.3 From b92137264988d43477da7d308ecc9ac7e68f36f1 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Tue, 9 Dec 2025 09:20:20 +0700 Subject: solr & fix cannot fetch data --- indoteknik_custom/models/keywords.py | 91 ++++++++++++++---------------------- 1 file changed, 36 insertions(+), 55 deletions(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index b1f2642d..de7636b7 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -35,6 +35,16 @@ class Keywords(models.Model): if not record.name: record.name = record.keywords + # @api.constrains('keywords') + # def check_already_exist(self): + # model = self.env['keywords'] + # for record in self: + # match = model.search([ + # ('name', 'ilike', record.name) + # ]) + # if match: + # raise UserError("Tidak bisa create/write/duplicate karena keywords sudah dipakai") + def generate_products(self): for record in self: @@ -43,6 +53,7 @@ class Keywords(models.Model): keyword = "%" + record.keywords.strip() + "%" + # Query dasar sql = """ SELECT pp.id FROM product_product pp @@ -59,11 +70,16 @@ class Keywords(models.Model): params = [keyword, keyword] + # Filter kategori ke child if record.category_id: - sql += " AND rel.product_public_category_id = %s" - params.append(record.category_id.id) - - # Exec query + 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) + + # Exec SQL + self.env.cr.execute(sql, params) rows = self.env.cr.fetchall() product_ids = [r[0] for r in rows] @@ -73,66 +89,31 @@ class Keywords(models.Model): }) _logger.info( - "SQL : Found %s products for keyword '%s'", + "Product Found: Found %s products for keyword '%s'", len(product_ids), record.keywords ) - def sync_solr(self): - solr = self.env['apache.solr'] # pastikan ini model Solr sudah ada + # solr_model = self.env['apache.solr'] documents = [] - - # Sync Keywords + data = {} for keyword in self.search([]): - doc = { - 'id': f'keyword_{keyword.id}', # prefix biar unik di Solr - 'type_s': 'keyword', - 'name_s': keyword.keywords, - 'category_id_i': keyword.category_id.id if keyword.category_id else 0, - 'product_ids_ii': keyword.product_ids.ids, - } - documents.append(doc) - _logger.info('Prepared Solr document for keyword %s', keyword.keywords) - - # Sync Products - products = self.env['product.product'].search([]) - for product in products: - category_ids = [c.id for c in product.public_categ_ids] - doc = { - 'id': f'product_{product.id}', - 'type_s': 'product', - 'name_s': product.name, - 'default_code_s': product.default_code or '', - 'category_ids_ii': category_ids, - 'website_description_t': product.website_description or '', - 'product_rating_f': getattr(product, 'virtual_rating', 0), - 'active_b': product.active, - } - documents.append(doc) - _logger.info('Prepared Solr document for product %s', product.name) - - # Sync Categories - categories = self.env['product.public.category'].search([]) - for cat in categories: - doc = { - 'id': f'category_{cat.id}', - 'type_s': 'category', - 'name_s': cat.name, - 'parent_id_i': cat.parent_id.id if cat.parent_id else 0, - } - documents.append(doc) - _logger.info('Prepared Solr document for category %s', cat.name) - - # Kirim ke Solr - if documents: try: - solr.add(documents, softCommit=True) - _logger.info('Synced %d documents to Solr', len(documents)) + doc = { + 'id': f'keyword_{keyword.id}', + 'type_s': 'keyword', + 'name_s': keyword.keywords, + 'category_id_i': keyword.category_id.id if keyword.category_id else 0, + 'product_ids_ii': keyword.product_ids.ids, + } + documents.append(doc) + data = doc except Exception as e: - _logger.error('Failed to sync documents to Solr: %s', e) - else: - _logger.warning('No documents to sync to Solr') + _logger.error('failed %s', e) + _logger.error('doc data: %s', data) + solr.add(documents) + return True @api.model def create(self, vals): -- cgit v1.2.3 From ea7edf0fee4949203e94360882590ea0c9bb3b0b Mon Sep 17 00:00:00 2001 From: Mqdd Date: Tue, 9 Dec 2025 10:32:27 +0700 Subject: done solr --- indoteknik_custom/models/keywords.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index de7636b7..fd8603c6 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -11,8 +11,8 @@ from bs4 import BeautifulSoup _logger = logging.getLogger(__name__) -# solr = pysolr.Solr('http://10.148.0.5:8983/solr/keywords/', always_commit=True, timeout=30) -solr = pysolr.Solr('http://127.0.0.1:8983/solr/keywords/', always_commit=True, timeout=30) +# 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' @@ -29,6 +29,18 @@ class Keywords(models.Model): ) name = fields.Char('Name', compute="_compute_name") skip = fields.Boolean('Skip Generate Product', default=False) + url = fields.Char('Website URL', compute="_compute_url") + + @api.depends('keywords') + def _compute_url(self): + prefix = "https://indoteknik.com/searchkey/" + for record in self: + if record.keywords: + slug = re.sub(r'[^a-zA-Z0-9]+', '-', record.keywords.strip().lower()) + slug = slug.strip('-') + record.url = prefix + slug + else: + record.url = False def _compute_name(self): for record in self: @@ -84,6 +96,9 @@ class Keywords(models.Model): product_ids = [r[0] for r in rows] + if not product_ids: + raise UserError("Tidak berhasil menemukan barang") + record.with_context(skip_generate=True).write({ 'product_ids': [(6, 0, product_ids)] }) @@ -101,11 +116,11 @@ class Keywords(models.Model): for keyword in self.search([]): try: doc = { - 'id': f'keyword_{keyword.id}', + 'id': keyword.id, 'type_s': 'keyword', - 'name_s': keyword.keywords, - 'category_id_i': keyword.category_id.id if keyword.category_id else 0, - 'product_ids_ii': keyword.product_ids.ids, + 'keywords_t': keyword.keywords, + 'url_s': keyword.url, + 'product_ids_is': keyword.product_ids.ids, } documents.append(doc) data = doc -- cgit v1.2.3 From c13ed8b1f00d513bec387c614ac785c7c91debf7 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Wed, 10 Dec 2025 07:53:30 +0700 Subject: Add count product --- indoteknik_custom/models/keywords.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index fd8603c6..a8d2fce6 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -30,6 +30,12 @@ class Keywords(models.Model): name = fields.Char('Name', compute="_compute_name") skip = fields.Boolean('Skip Generate Product', default=False) url = fields.Char('Website URL', compute="_compute_url") + sum = fields.Integer('Total Product', compute="_compute_total_product", readonly=True) + + @api.depends('product_ids') + def _compute_total_product(self): + for record in self: + record.sum = len(record.product_ids) @api.depends('keywords') def _compute_url(self): @@ -114,13 +120,15 @@ class Keywords(models.Model): documents = [] data = {} for keyword in self.search([]): + searchkey = (keyword.keywords or '').strip().lower().replace(' ', '-') try: doc = { 'id': keyword.id, - 'type_s': 'keyword', - 'keywords_t': keyword.keywords, + # 'type_s': 'keyword', + 'keywords_s': searchkey, + # 'searchkey_t': searchkey, 'url_s': keyword.url, - 'product_ids_is': keyword.product_ids.ids, + 'product_ids_is': [p.product_tmpl_id.id for p in keyword.product_ids] } documents.append(doc) data = doc -- cgit v1.2.3 From 2ae552a716040d65690bd20e6b1854d5201d32bd Mon Sep 17 00:00:00 2001 From: Mqdd Date: Wed, 10 Dec 2025 13:06:25 +0700 Subject: throw category to solr --- indoteknik_custom/models/keywords.py | 1 + 1 file changed, 1 insertion(+) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index a8d2fce6..cee189c4 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -125,6 +125,7 @@ class Keywords(models.Model): doc = { 'id': keyword.id, # 'type_s': 'keyword', + 'category_id_i': keyword.category_id.id, 'keywords_s': searchkey, # 'searchkey_t': searchkey, 'url_s': keyword.url, -- cgit v1.2.3 From 64da5a5b37a7c016e863b2c3d615a21bdb45839a Mon Sep 17 00:00:00 2001 From: Mqdd Date: Wed, 10 Dec 2025 13:25:56 +0700 Subject: remove unused solr field --- indoteknik_custom/models/keywords.py | 1 - 1 file changed, 1 deletion(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index cee189c4..03f5a11d 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -124,7 +124,6 @@ class Keywords(models.Model): try: doc = { 'id': keyword.id, - # 'type_s': 'keyword', 'category_id_i': keyword.category_id.id, 'keywords_s': searchkey, # 'searchkey_t': searchkey, -- cgit v1.2.3 From ed88e91aa769e07ba048fd8b3067442754c06065 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Thu, 11 Dec 2025 08:53:01 +0700 Subject: disable query --- indoteknik_custom/models/keywords.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models/keywords.py') diff --git a/indoteknik_custom/models/keywords.py b/indoteknik_custom/models/keywords.py index 03f5a11d..5faa94a6 100644 --- a/indoteknik_custom/models/keywords.py +++ b/indoteknik_custom/models/keywords.py @@ -146,6 +146,6 @@ class Keywords(models.Model): def write(self, vals): result = super().write(vals) - if not self.env.context.get("skip_generate") and not self.skip: - self.generate_products() + # if not self.env.context.get("skip_generate") and not self.skip: + # self.generate_products() return result -- cgit v1.2.3