From a9a3c3e8945dd11a0d81f64a5629876397a1e51d Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 25 Aug 2023 15:11:00 +0700 Subject: Update sync solr function --- indoteknik_custom/models/__init__.py | 2 +- indoteknik_custom/models/apache_solr.py | 295 ------------------- indoteknik_custom/models/product_pricelist.py | 123 +------- indoteknik_custom/models/product_template.py | 128 +-------- indoteknik_custom/models/solr/__init__.py | 5 + indoteknik_custom/models/solr/apache_solr.py | 316 +++++++++++++++++++++ .../models/solr/product_pricelist_item.py | 30 ++ indoteknik_custom/models/solr/product_product.py | 121 ++++++++ indoteknik_custom/models/solr/product_template.py | 158 +++++++++++ .../models/solr/website_categories_homepage.py | 57 ++++ .../models/website_categories_homepage.py | 30 +- indoteknik_custom/views/product_product.xml | 8 + indoteknik_custom/views/product_template.xml | 14 +- .../views/website_categories_homepage.xml | 6 +- 14 files changed, 718 insertions(+), 575 deletions(-) delete mode 100644 indoteknik_custom/models/apache_solr.py create mode 100644 indoteknik_custom/models/solr/__init__.py create mode 100644 indoteknik_custom/models/solr/apache_solr.py create mode 100644 indoteknik_custom/models/solr/product_pricelist_item.py create mode 100644 indoteknik_custom/models/solr/product_product.py create mode 100644 indoteknik_custom/models/solr/product_template.py create mode 100644 indoteknik_custom/models/solr/website_categories_homepage.py diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 255a12f6..2bf3be9d 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -62,7 +62,6 @@ from . import wati_contact from . import uangmuka_penjualan from . import uangmuka_pembelian from . import automatic_purchase -from . import apache_solr from . import raja_ongkir from . import procurement_monitoring_detail from . import brand_vendor @@ -81,3 +80,4 @@ from . import account_general_ledger from . import account_report_financial from . import account_report_general_ledger from . import price_group +from . import solr \ No newline at end of file diff --git a/indoteknik_custom/models/apache_solr.py b/indoteknik_custom/models/apache_solr.py deleted file mode 100644 index bd4dd3dc..00000000 --- a/indoteknik_custom/models/apache_solr.py +++ /dev/null @@ -1,295 +0,0 @@ -from odoo import models, api, fields -from odoo.exceptions import UserError -from datetime import datetime, timedelta -import logging -import pysolr -import time -from odoo.tools.config import config - -_logger = logging.getLogger(__name__) -_solr = pysolr.Solr('http://10.148.0.5:8983/solr/product/', always_commit=True, timeout=30) -_variants_solr = pysolr.Solr('http://10.148.0.5:8983/solr/variants/', always_commit=True, timeout=30) -# _solr = pysolr.Solr('http://34.101.189.218:8983/solr/product/', always_commit=True, timeout=30) # for development only - - -class ApacheSolr(models.Model): - _name = 'apache.solr' - _order = 'id desc' - - def get_single_doc(self, schema, id): - try: - return self.connect(schema).search(f'id:{id}').docs[0] - except: - return {} - - def connect(self, schema): - env = config.get('solr_env', 'development') - - url = '' - if env == 'development': - url = 'http://192.168.23.5:8983/solr/' - elif env == 'production': - url = 'http://10.148.0.5:8983/solr/' - - return pysolr.Solr(url + schema, always_commit=True, timeout=30) - - def _update_stock_product_to_solr(self, limit=10000): - current_time = datetime.now() - delta_time = current_time - timedelta(days=3) - - current_time = current_time.strftime('%Y-%m-%d %H:%M:%S') - delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') - - query = [('__last_update', '<', delta_time),] - # query = [('product_variant_id.id', '=', 204903)] - stocks = self.env['stock.vendor'].search(query, limit=limit) - documents = [] - for stock in stocks: - stock_total = int(stock.product_variant_id.product_tmpl_id.qty_stock_vendor) - # dict_stock = dict({"set": stock_total}) - document = { - "id": int(stock.product_variant_id.product_tmpl_id.id), - "stock_total_f": stock_total - } - documents.append(document) - _logger.info("[SYNC_PRODUCT_STOCK_TO_SOLR] Success Set to solr product %s" % stock.product_variant_id.product_tmpl_id.id) - _solr.add(documents, fieldUpdates={'stock_total_f':'set'}) - - def _update_rating_product_to_solr(self, limit=1000): - current_time = datetime.now() - delta_time = current_time - timedelta(days=30) - - current_time = current_time.strftime('%Y-%m-%d %H:%M:%S') - delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') - query = [ - '&','&', - ('type', '=', 'product'), - ('active', '=', True), - '|', - ('last_calculate_rating', '=', False), - ('last_calculate_rating', '<', delta_time), - ] - # query = [('id', '=', 97942)] - templates = self.env['product.template'].search(query, limit=limit) - documents=[] - for template in templates: - rating = int(template.virtual_rating) - # dict_rating = dict({'set':rating}) - document = { - 'id':template.id, - 'product_rating_f':rating - } - documents.append(document) - template.last_calculate_rating = current_time - _logger.info("[SYNC_PRODUCT_RATING_TO_SOLR] Success Set to solr product %s" % template.id) - _logger.info(documents) - _solr.add(documents, fieldUpdates={'product_rating_f':'set'}) - - def _sync_product_template_to_solr(self, limit=500): - start_time = time.time() - _logger.info('run sync to solr...') - query = ["&","&",("type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] - - templates = self.env['product.template'].search(query, limit=limit) - documents = [] - counter = 0 - for template in templates: - template_time = time.time() - counter += 1 - variants_name = variants_code = '' - if template.product_variant_count > 1: - for variant in template.product_variant_ids: - variants_name += variant.display_name or ''+', ' - variants_code += variant.default_code or ''+', ' - - category_id = '' - category_name = '' - for category in template.public_categ_ids: - category_id = category.id - category_name = category.name - - document = { - # Start Product Template - 'id': template.id, - 'display_name_s': template.display_name, - 'name_s': template.name, - 'default_code_s': template.default_code or '', - 'product_rating_f': template.virtual_rating, - 'product_id_i': template.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), - 'variant_total_i': template.product_variant_count, - 'stock_total_f': template.qty_stock_vendor, - 'weight_f': template.weight, - 'manufacture_id_i': template.x_manufacture.id or 0, - 'manufacture_name_s': template.x_manufacture.x_name or '', - 'manufacture_name': template.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), - 'variants_name_t': variants_name, - 'variants_code_t': variants_code, - 'search_rank_i': template.search_rank, - 'search_rank_weekly_i': template.search_rank_weekly, - 'category_id_i': category_id or 0, - 'category_name_s': category_name or '', - 'category_name': category_name or '', - # End Product Template - } - documents.append(document) - template.solr_flag = 1 - _logger.info('[SYNC_PRODUCT_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) - _logger.info('[SYNC_PRODUCT_TO_SOLR] Success add to solr product %s' % template.id) - _solr.add(documents) - end_time = time.time() - _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) - - def _sync_product_pricelist_to_solr(self, limit=500): - start_time = time.time() - _logger.info('run sync to solr...') - query = ["&","&",("type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] - - templates = self.env['product.template'].search(query, limit=limit) - documents = [] - counter = 0 - for template in templates: - template_time = time.time() - counter += 1 - price_excl_after_disc = price_excl = discount = tax = 0 - variants_name = variants_code = '' - flashsale_data = tier1 = tier2 = tier3 = {} - if template.product_variant_count > 1: - for variant in template.product_variant_ids: - if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: - price_excl = variant._get_website_price_exclude_tax() - price_excl_after_disc = variant._get_website_price_after_disc_and_tax() - discount = variant._get_website_disc(0) - tax = variant._get_website_tax() - flashsale_data = variant._get_flashsale_price() - # add price tiering for base price, discount, and price after discount (tier 1 - 3) - tier1 = variant._get_pricelist_tier1() - tier2 = variant._get_pricelist_tier2() - tier3 = variant._get_pricelist_tier3() - else: - price_excl_after_disc = price_excl_after_disc - price_excl = price_excl - discount = discount - tax = tax - flashsale_data = flashsale_data - tier1 = tier1 - tier2 = tier2 - tier3 = tier3 - variants_name += variant.display_name or ''+', ' - variants_code += variant.default_code or ''+', ' - else: - variants_name = template.display_name - price_excl = template.product_variant_id._get_website_price_exclude_tax() - discount = template.product_variant_id._get_website_disc(0) - price_excl_after_disc = template.product_variant_id._get_website_price_after_disc_and_tax() - tax = template.product_variant_id._get_website_tax() - flashsale_data = template.product_variant_id._get_flashsale_price() - tier1 = template.product_variant_id._get_pricelist_tier1() - tier2 = template.product_variant_id._get_pricelist_tier2() - tier3 = template.product_variant_id._get_pricelist_tier3() - - document = { - # Start Product Pricelist - 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, - 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', - 'flashsale_name_s': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, - 'discount_tier1_f': tier1['discount_tier1'] or 0, - 'price_tier1_f': tier1['price_tier1'] or 0, - 'discount_tier2_f': tier2['discount_tier2'] or 0, - 'price_tier2_f': tier2['price_tier2'] or 0, - 'discount_tier3_f': tier3['discount_tier3'] or 0, - 'price_tier3_f': tier3['price_tier3'] or 0 - # End Product Pricelist - } - documents.append(document) - template.solr_flag = 1 - # add counter for monitoring - _logger.info('[SYNC_PRODUCT_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) - _logger.info('[SYNC_PRODUCT_TO_SOLR] Success add to solr product %s' % template.id) - _solr.add(documents) - end_time = time.time() - _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) - - def _test_product_price(self, product_id=228178): - product = self.env['product.product'].search([('id', '=', product_id)], limit=1) - _logger.info('price incl tax: %s' % product._get_website_price_include_tax()) - _logger.info('price excl tax: %s' % product._get_website_price_exclude_tax()) - _logger.info('discount : %s' % product._get_website_disc(0)) - _logger.info('price after discount : %s' % product._get_website_price_after_disc()) - _logger.info('price excl after discount : %s' % product._get_website_price_after_disc_and_tax()) - _logger.info('tax : %s' % product._get_website_tax()) - - def _sync_variants_to_solr(self, limit=500): - start_time = time.time() - _logger.info('run sync to solr variants...') - query = ["&","&","&",("product_tmpl_id.active","=",True),("product_tmpl_id.type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] - # query = [('id', 'in', [184622, 204903])] - - variants = self.env['product.product'].search(query, limit=limit) - documents = [] - counter = 0 - for variant in variants: - template_time = time.time() - counter += 1 - - price_excl_after_disc = price_excl = discount = tax = 0 - price_excl = variant._get_website_price_exclude_tax() - price_excl_after_disc = variant._get_website_price_after_disc_and_tax() - discount = variant._get_website_disc(0) - tax = variant._get_website_tax() - flashsale_data = variant._get_flashsale_price() - - category_id = '' - category_name = '' - for category in variant.product_tmpl_id.public_categ_ids: - category_id = category.id - category_name = category.name - - document = { - 'id': variant.id, - 'display_name_s': variant.display_name, - 'name_s': variant.name, - 'default_code_s': variant.default_code or '', - 'product_rating_f': variant.product_tmpl_id.virtual_rating, - 'product_id_i': variant.id, - 'template_id_i': variant.product_tmpl_id.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', variant.product_tmpl_id.id), - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, - 'stock_total_f': variant.qty_stock_vendor, - 'weight_f': variant.product_tmpl_id.weight, - 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, - 'manufacture_name_s': variant.product_tmpl_id.x_manufacture.x_name or '', - 'manufacture_name': variant.product_tmpl_id.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', variant.product_tmpl_id.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', variant.product_tmpl_id.x_manufacture.id), - 'category_id_i': category_id or 0, - 'category_name_s': category_name or '', - 'category_name': category_name or '', - 'search_rank_i': variant.product_tmpl_id.search_rank, - 'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly, - 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, - 'flashsale_name_s': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - } - documents.append(document) - variant.solr_flag = 1 - # add counter for monitoring - _logger.info('[SYNC_VARIANTS_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) - _logger.info('[SYNC_VARIANTS_TO_SOLR] Success add to solr variants %s' % variant.id) - _variants_solr.add(documents) - end_time = time.time() - _logger.info("[SYNC_VARIANTS_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) diff --git a/indoteknik_custom/models/product_pricelist.py b/indoteknik_custom/models/product_pricelist.py index 73eebdcf..a55e3fdd 100644 --- a/indoteknik_custom/models/product_pricelist.py +++ b/indoteknik_custom/models/product_pricelist.py @@ -1,8 +1,6 @@ -from odoo import models, fields, api -from odoo.exceptions import UserError +from odoo import models, fields from datetime import datetime import logging -import time _logger = logging.getLogger(__name__) class ProductPricelist(models.Model): @@ -30,121 +28,4 @@ class ProductPricelist(models.Model): class ProductPricelistItem(models.Model): _inherit = 'product.pricelist.item' - manufacture_id = fields.Many2one('x_manufactures', string='Manufacture') - - @api.constrains('applied_on', 'product_id', 'base', 'base_pricelist_id', 'price_discount') - def _constrains_related_solr_field(self): - self.update_template_solr() - self.update_variant_solr() - - def update_template_solr(self): - price_excl_after_disc = price_excl = discount = tax = 0 - flashsale_data = tier1 = tier2 = tier3 = {} - - template = self.product_id.product_tmpl_id - if template.product_variant_count > 1: - for variant in template.product_variant_ids: - if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: - price_excl = variant._get_website_price_exclude_tax() - price_excl_after_disc = variant._get_website_price_after_disc_and_tax() - discount = variant._get_website_disc(0) - tax = variant._get_website_tax() - flashsale_data = variant._get_flashsale_price() - # add price tiering for base price, discount, and price after discount (tier 1 - 3) - tier1 = variant._get_pricelist_tier1() - tier2 = variant._get_pricelist_tier2() - tier3 = variant._get_pricelist_tier3() - else: - price_excl_after_disc = price_excl_after_disc - price_excl = price_excl - discount = discount - tax = tax - flashsale_data = flashsale_data - tier1 = tier1 - tier2 = tier2 - tier3 = tier3 - else: - price_excl = template.product_variant_id._get_website_price_exclude_tax() - discount = template.product_variant_id._get_website_disc(0) - price_excl_after_disc = template.product_variant_id._get_website_price_after_disc_and_tax() - tax = template.product_variant_id._get_website_tax() - flashsale_data = template.product_variant_id._get_flashsale_price() - tier1 = template.product_variant_id._get_pricelist_tier1() - tier2 = template.product_variant_id._get_pricelist_tier2() - tier3 = template.product_variant_id._get_pricelist_tier3() - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('product') - document = solr_model.get_single_doc('product', template.id) - document.update({ - 'id': template.id, - 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, - 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', - 'flashsale_name_s': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, - 'discount_tier1_f': tier1['discount_tier1'] or 0, - 'price_tier1_f': tier1['price_tier1'] or 0, - 'discount_tier2_f': tier2['discount_tier2'] or 0, - 'price_tier2_f': tier2['price_tier2'] or 0, - 'discount_tier3_f': tier3['discount_tier3'] or 0, - 'price_tier3_f': tier3['price_tier3'] or 0 - }) - solr.add([document]) - template.change_solr_data('Ada perubahan pada harga product') - - def update_variant_solr(self): - price_excl_after_disc = price_excl = discount = tax = 0 - flashsale_data = tier1 = tier2 = tier3 = {} - - product = self.product_id - for variant in product: - if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: - price_excl = variant._get_website_price_exclude_tax() - price_excl_after_disc = variant._get_website_price_after_disc_and_tax() - discount = variant._get_website_disc(0) - tax = variant._get_website_tax() - flashsale_data = variant._get_flashsale_price() - # add price tiering for base price, discount, and price after discount (tier 1 - 3) - tier1 = variant._get_pricelist_tier1() - tier2 = variant._get_pricelist_tier2() - tier3 = variant._get_pricelist_tier3() - else: - price_excl_after_disc = price_excl_after_disc - price_excl = price_excl - discount = discount - tax = tax - flashsale_data = flashsale_data - tier1 = tier1 - tier2 = tier2 - tier3 = tier3 - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('variants') - document = solr_model.get_single_doc('variants', product.id) - document.update({ - 'id': product.id, - 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, - 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', - 'flashsale_name_s': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, - 'discount_tier1_f': tier1['discount_tier1'] or 0, - 'price_tier1_f': tier1['price_tier1'] or 0, - 'discount_tier2_f': tier2['discount_tier2'] or 0, - 'price_tier2_f': tier2['price_tier2'] or 0, - 'discount_tier3_f': tier3['discount_tier3'] or 0, - 'price_tier3_f': tier3['price_tier3'] or 0 - }) - solr.add([document]) - product.change_solr_data('Ada perubahan pada harga product') \ No newline at end of file + manufacture_id = fields.Many2one('x_manufactures', string='Manufacture') \ No newline at end of file diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 3caa3125..f72fa763 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -1,6 +1,6 @@ from odoo import fields, models, api -from datetime import datetime, timedelta, timezone -from odoo.exceptions import AccessError, UserError, ValidationError +from datetime import datetime, timedelta +from odoo.exceptions import UserError import logging import requests import json @@ -50,13 +50,6 @@ class ProductTemplate(models.Model): is_new_product = fields.Boolean(string='Produk Baru', help='Centang jika ingin ditammpilkan di website sebagai segment Produk Baru') seq_new_product = fields.Integer(string='Seq New Product', help='Urutan Sequence New Product') - last_update_solr = fields.Datetime(string='Last Update Solr') - desc_update_solr = fields.Char(string='Desc Update Solr') - - def change_solr_data(self, desc): - current_time = datetime.utcnow() - self.desc_update_solr = desc - self.last_update_solr = current_time def _compute_virtual_rating(self): for product in self: @@ -251,62 +244,6 @@ class ProductTemplate(models.Model): } self.env['token.storage'].create([values]) return values - - @api.constrains( - 'name', - 'default_code', - 'weight', - 'x_manufacture', - 'public_categ_ids', - 'product_variant_ids.display_name', - 'product_variant_ids.default_code', - 'search_rank', - 'search_rank_weekly', - 'image_1920' - ) - def _sync_product_template_to_solr(self, limit=500): - template = self - if not template.active or template.type != 'product': - return - - variant_names = ', '.join([x.display_name or '' for x in template.product_variant_ids]) - variant_codes = ', '.join([x.default_code or '' for x in template.product_variant_ids]) - - category_id = 0 - category_name = '' - for category in template.public_categ_ids: - category_id, category_name = category.id, category.name - break - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('product') - document = solr_model.get_single_doc('product', template.id) - document.update({ - 'id': template.id, - 'display_name_s': template.display_name, - 'name_s': template.name, - 'default_code_s': template.default_code or '', - 'product_rating_f': template.virtual_rating, - 'product_id_i': template.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), - 'variant_total_i': template.product_variant_count, - 'stock_total_f': template.qty_stock_vendor, - 'weight_f': template.weight, - 'manufacture_id_i': template.x_manufacture.id or 0, - 'manufacture_name_s': template.x_manufacture.x_name or '', - 'manufacture_name': template.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), - 'variants_name_t': variant_names, - 'variants_code_t': variant_codes, - 'search_rank_i': template.search_rank, - 'search_rank_weekly_i': template.search_rank_weekly, - 'category_id_i': category_id, - 'category_name_s': category_name, - 'category_name': category_name, - }) - solr.add([document]) - self.change_solr_data('Perubahan pada data product') class ProductProduct(models.Model): _inherit = "product.product" @@ -329,13 +266,6 @@ class ProductProduct(models.Model): qty_onhand_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_onhand_bandengan') qty_incoming_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_incoming_bandengan') sla_version = fields.Integer(string="SLA Version", default=0) - last_update_solr = fields.Datetime(string='Last Update Solr') - desc_update_solr = fields.Char(string='Desc Update Solr') - - def change_solr_data(self, desc): - current_time = datetime.now() - self.desc_update_solr = desc - self.last_update_solr = current_time def _get_qty_incoming_bandengan(self): for product in self: @@ -380,56 +310,4 @@ class ProductProduct(models.Model): ('end_date', '>=', current_time) ], limit=1) return pricelist - - @api.constrains( - 'name', - 'default_code', - 'virtual_rating', - 'weight', - 'x_manufacture', - 'public_categ_ids', - 'product_tmpl_id.default_code', - 'product_tmpl_id.image_1920', - 'search_rank', - 'search_rank_weekly', - 'image_1920' - ) - def _sync_variants_to_solr(self): - variant = self - if not variant.product_tmpl_id.active and variant.product_tmpl_id.type != 'product': - return - - category_id = 0 - category_name = '' - for category in variant.product_tmpl_id.public_categ_ids: - category_id = category.id - category_name = category.name - break - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('variants') - document = solr_model.get_single_doc('variants', variant.id) - document.update({ - 'id': variant.id, - 'display_name_s': variant.display_name, - 'name_s': variant.name, - 'default_code_s': variant.default_code or '', - 'product_rating_f': variant.product_tmpl_id.virtual_rating, - 'product_id_i': variant.id, - 'template_id_i': variant.product_tmpl_id.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', variant.product_tmpl_id.id), - 'stock_total_f': variant.qty_stock_vendor, - 'weight_f': variant.product_tmpl_id.weight, - 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, - 'manufacture_name_s': variant.product_tmpl_id.x_manufacture.x_name or '', - 'manufacture_name': variant.product_tmpl_id.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', variant.product_tmpl_id.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', variant.product_tmpl_id.x_manufacture.id), - 'category_id_i': category_id, - 'category_name_s': category_name, - 'category_name': category_name, - 'search_rank_i': variant.product_tmpl_id.search_rank, - 'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly, - }) - solr.add([document]) - self.change_solr_data('Perubahan pada data product') \ No newline at end of file + \ No newline at end of file diff --git a/indoteknik_custom/models/solr/__init__.py b/indoteknik_custom/models/solr/__init__.py new file mode 100644 index 00000000..450e1dae --- /dev/null +++ b/indoteknik_custom/models/solr/__init__.py @@ -0,0 +1,5 @@ +from . import apache_solr +from . import product_pricelist_item +from . import product_product +from . import product_template +from . import website_categories_homepage \ No newline at end of file diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py new file mode 100644 index 00000000..cb44e7ed --- /dev/null +++ b/indoteknik_custom/models/solr/apache_solr.py @@ -0,0 +1,316 @@ +from odoo import models, api, fields +from odoo.exceptions import UserError +from datetime import datetime, timedelta +import logging +import pysolr +import time +from odoo.tools.config import config + +_logger = logging.getLogger(__name__) +_solr = pysolr.Solr('http://10.148.0.5:8983/solr/product/', always_commit=True, timeout=30) +_variants_solr = pysolr.Solr('http://10.148.0.5:8983/solr/variants/', always_commit=True, timeout=30) +# _solr = pysolr.Solr('http://34.101.189.218:8983/solr/product/', always_commit=True, timeout=30) # for development only + + +class ApacheSolr(models.Model): + _name = 'apache.solr' + _order = 'id desc' + + def connect(self, schema): + env = config.get('solr_env', 'development') + + url = '' + if env == 'development': + url = 'http://192.168.23.5:8983/solr/' + elif env == 'production': + url = 'http://10.148.0.5:8983/solr/' + + return pysolr.Solr(url + schema, always_commit=True, timeout=30) + + def get_single_doc(self, schema, id): + try: + return self.connect(schema).search(f'id:{id}').docs[0] + except: + return {} + + def get_docs(self, schema, ids): + ids_query = ' OR '.join(ids) + return self.connect(schema).search(f'id:({ids_query})').docs + + def clean_key_docs(self, docs): + cleaned_docs = [] + for doc in docs: + new_dict = self.clean_key_doc(doc) + cleaned_docs.append(new_dict) + return cleaned_docs + + def clean_key_doc(self, doc): + new_dict = {} + for key, value in doc.items(): + parts = key.split('_') + cleaned_parts = [part for part in parts if part not in ['s', 'i', 'f', 'd', 'b', 'l', 't', 'p']] + cleaned_key = '_'.join(cleaned_parts) + new_dict[cleaned_key] = value + return new_dict + + + def _update_stock_product_to_solr(self, limit=10000): + current_time = datetime.now() + delta_time = current_time - timedelta(days=3) + + current_time = current_time.strftime('%Y-%m-%d %H:%M:%S') + delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') + + query = [('__last_update', '<', delta_time),] + # query = [('product_variant_id.id', '=', 204903)] + stocks = self.env['stock.vendor'].search(query, limit=limit) + documents = [] + for stock in stocks: + stock_total = int(stock.product_variant_id.product_tmpl_id.qty_stock_vendor) + # dict_stock = dict({"set": stock_total}) + document = { + "id": int(stock.product_variant_id.product_tmpl_id.id), + "stock_total_f": stock_total + } + documents.append(document) + _logger.info("[SYNC_PRODUCT_STOCK_TO_SOLR] Success Set to solr product %s" % stock.product_variant_id.product_tmpl_id.id) + _solr.add(documents, fieldUpdates={'stock_total_f':'set'}) + + def _update_rating_product_to_solr(self, limit=1000): + current_time = datetime.now() + delta_time = current_time - timedelta(days=30) + + current_time = current_time.strftime('%Y-%m-%d %H:%M:%S') + delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') + query = [ + '&','&', + ('type', '=', 'product'), + ('active', '=', True), + '|', + ('last_calculate_rating', '=', False), + ('last_calculate_rating', '<', delta_time), + ] + # query = [('id', '=', 97942)] + templates = self.env['product.template'].search(query, limit=limit) + documents=[] + for template in templates: + rating = int(template.virtual_rating) + # dict_rating = dict({'set':rating}) + document = { + 'id':template.id, + 'product_rating_f':rating + } + documents.append(document) + template.last_calculate_rating = current_time + _logger.info("[SYNC_PRODUCT_RATING_TO_SOLR] Success Set to solr product %s" % template.id) + _logger.info(documents) + _solr.add(documents, fieldUpdates={'product_rating_f':'set'}) + + def _sync_product_template_to_solr(self, limit=500): + start_time = time.time() + _logger.info('run sync to solr...') + query = ["&","&",("type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] + + templates = self.env['product.template'].search(query, limit=limit) + documents = [] + counter = 0 + for template in templates: + template_time = time.time() + counter += 1 + variants_name = variants_code = '' + if template.product_variant_count > 1: + for variant in template.product_variant_ids: + variants_name += variant.display_name or ''+', ' + variants_code += variant.default_code or ''+', ' + + category_id = '' + category_name = '' + for category in template.public_categ_ids: + category_id = category.id + category_name = category.name + + document = { + # Start Product Template + 'id': template.id, + 'display_name_s': template.display_name, + 'name_s': template.name, + 'default_code_s': template.default_code or '', + 'product_rating_f': template.virtual_rating, + 'product_id_i': template.id, + 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), + 'variant_total_i': template.product_variant_count, + 'stock_total_f': template.qty_stock_vendor, + 'weight_f': template.weight, + 'manufacture_id_i': template.x_manufacture.id or 0, + 'manufacture_name_s': template.x_manufacture.x_name or '', + 'manufacture_name': template.x_manufacture.x_name or '', + 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), + 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), + 'variants_name_t': variants_name, + 'variants_code_t': variants_code, + 'search_rank_i': template.search_rank, + 'search_rank_weekly_i': template.search_rank_weekly, + 'category_id_i': category_id or 0, + 'category_name_s': category_name or '', + 'category_name': category_name or '', + # End Product Template + } + documents.append(document) + template.solr_flag = 1 + _logger.info('[SYNC_PRODUCT_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) + _logger.info('[SYNC_PRODUCT_TO_SOLR] Success add to solr product %s' % template.id) + _solr.add(documents) + end_time = time.time() + _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) + + def _sync_product_pricelist_to_solr(self, limit=500): + start_time = time.time() + _logger.info('run sync to solr...') + query = ["&","&",("type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] + + templates = self.env['product.template'].search(query, limit=limit) + documents = [] + counter = 0 + for template in templates: + template_time = time.time() + counter += 1 + price_excl_after_disc = price_excl = discount = tax = 0 + variants_name = variants_code = '' + flashsale_data = tier1 = tier2 = tier3 = {} + if template.product_variant_count > 1: + for variant in template.product_variant_ids: + if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: + price_excl = variant._get_website_price_exclude_tax() + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + discount = variant._get_website_disc(0) + tax = variant._get_website_tax() + flashsale_data = variant._get_flashsale_price() + # add price tiering for base price, discount, and price after discount (tier 1 - 3) + tier1 = variant._get_pricelist_tier1() + tier2 = variant._get_pricelist_tier2() + tier3 = variant._get_pricelist_tier3() + else: + price_excl_after_disc = price_excl_after_disc + price_excl = price_excl + discount = discount + tax = tax + flashsale_data = flashsale_data + tier1 = tier1 + tier2 = tier2 + tier3 = tier3 + variants_name += variant.display_name or ''+', ' + variants_code += variant.default_code or ''+', ' + else: + variants_name = template.display_name + price_excl = template.product_variant_id._get_website_price_exclude_tax() + discount = template.product_variant_id._get_website_disc(0) + price_excl_after_disc = template.product_variant_id._get_website_price_after_disc_and_tax() + tax = template.product_variant_id._get_website_tax() + flashsale_data = template.product_variant_id._get_flashsale_price() + tier1 = template.product_variant_id._get_pricelist_tier1() + tier2 = template.product_variant_id._get_pricelist_tier2() + tier3 = template.product_variant_id._get_pricelist_tier3() + + document = { + # Start Product Pricelist + 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, + 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', + 'flashsale_name_s': flashsale_data['flashsale_name'] or '', + 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, + 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, + 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, + 'price_f': price_excl, + 'discount_f': discount, + 'price_discount_f': price_excl_after_disc, + 'tax_f': tax, + 'discount_tier1_f': tier1['discount_tier1'] or 0, + 'price_tier1_f': tier1['price_tier1'] or 0, + 'discount_tier2_f': tier2['discount_tier2'] or 0, + 'price_tier2_f': tier2['price_tier2'] or 0, + 'discount_tier3_f': tier3['discount_tier3'] or 0, + 'price_tier3_f': tier3['price_tier3'] or 0 + # End Product Pricelist + } + documents.append(document) + template.solr_flag = 1 + # add counter for monitoring + _logger.info('[SYNC_PRODUCT_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) + _logger.info('[SYNC_PRODUCT_TO_SOLR] Success add to solr product %s' % template.id) + _solr.add(documents) + end_time = time.time() + _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) + + def _test_product_price(self, product_id=228178): + product = self.env['product.product'].search([('id', '=', product_id)], limit=1) + _logger.info('price incl tax: %s' % product._get_website_price_include_tax()) + _logger.info('price excl tax: %s' % product._get_website_price_exclude_tax()) + _logger.info('discount : %s' % product._get_website_disc(0)) + _logger.info('price after discount : %s' % product._get_website_price_after_disc()) + _logger.info('price excl after discount : %s' % product._get_website_price_after_disc_and_tax()) + _logger.info('tax : %s' % product._get_website_tax()) + + def _sync_variants_to_solr(self, limit=500): + start_time = time.time() + _logger.info('run sync to solr variants...') + query = ["&","&","&",("product_tmpl_id.active","=",True),("product_tmpl_id.type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] + # query = [('id', 'in', [184622, 204903])] + + variants = self.env['product.product'].search(query, limit=limit) + documents = [] + counter = 0 + for variant in variants: + template_time = time.time() + counter += 1 + + price_excl_after_disc = price_excl = discount = tax = 0 + price_excl = variant._get_website_price_exclude_tax() + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + discount = variant._get_website_disc(0) + tax = variant._get_website_tax() + flashsale_data = variant._get_flashsale_price() + + category_id = '' + category_name = '' + for category in variant.product_tmpl_id.public_categ_ids: + category_id = category.id + category_name = category.name + + document = { + 'id': variant.id, + 'display_name_s': variant.display_name, + 'name_s': variant.name, + 'default_code_s': variant.default_code or '', + 'product_rating_f': variant.product_tmpl_id.virtual_rating, + 'product_id_i': variant.id, + 'template_id_i': variant.product_tmpl_id.id, + 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', variant.product_tmpl_id.id), + 'price_f': price_excl, + 'discount_f': discount, + 'price_discount_f': price_excl_after_disc, + 'tax_f': tax, + 'stock_total_f': variant.qty_stock_vendor, + 'weight_f': variant.product_tmpl_id.weight, + 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, + 'manufacture_name_s': variant.product_tmpl_id.x_manufacture.x_name or '', + 'manufacture_name': variant.product_tmpl_id.x_manufacture.x_name or '', + 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', variant.product_tmpl_id.x_manufacture.id), + 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', variant.product_tmpl_id.x_manufacture.id), + 'category_id_i': category_id or 0, + 'category_name_s': category_name or '', + 'category_name': category_name or '', + 'search_rank_i': variant.product_tmpl_id.search_rank, + 'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly, + 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, + 'flashsale_name_s': flashsale_data['flashsale_name'] or '', + 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, + 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, + 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, + } + documents.append(document) + variant.solr_flag = 1 + # add counter for monitoring + _logger.info('[SYNC_VARIANTS_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) + _logger.info('[SYNC_VARIANTS_TO_SOLR] Success add to solr variants %s' % variant.id) + _variants_solr.add(documents) + end_time = time.time() + _logger.info("[SYNC_VARIANTS_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) diff --git a/indoteknik_custom/models/solr/product_pricelist_item.py b/indoteknik_custom/models/solr/product_pricelist_item.py new file mode 100644 index 00000000..6ab2f588 --- /dev/null +++ b/indoteknik_custom/models/solr/product_pricelist_item.py @@ -0,0 +1,30 @@ +from odoo import models, api + + +class ProductPricelistItem(models.Model): + _inherit = 'product.pricelist.item' + + @api.constrains('applied_on', 'product_id', 'base', 'base_pricelist_id', 'price_discount') + def _constrains_related_solr_field(self): + self.update_template_solr() + self.update_variant_solr() + + def update_template_solr(self): + updated_template_ids = [] + for rec in self: + template = rec.product_id.product_tmpl_id + if template.id in updated_template_ids: + continue + + template._sync_price_to_solr() + updated_template_ids.append(template.id) + + def update_variant_solr(self): + updated_product_ids = [] + for rec in self: + product = rec.product_id + if product.id in updated_product_ids: + continue + + product._sync_price_to_solr() + updated_product_ids.append(product.id) \ No newline at end of file diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py new file mode 100644 index 00000000..5090b8d5 --- /dev/null +++ b/indoteknik_custom/models/solr/product_product.py @@ -0,0 +1,121 @@ +from odoo import models, fields +from datetime import datetime + + +class ProductProduct(models.Model): + _inherit = 'product.product' + + last_update_solr = fields.Datetime(string='Last Update Solr') + desc_update_solr = fields.Char(string='Desc Update Solr') + + def change_solr_data(self, desc): + self.desc_update_solr = desc + self.last_update_solr = datetime.utcnow() + + def solr(self): + return self.env['apache.solr'].connect('variants') + + def _sync_variants_to_solr(self): + solr_model = self.env['apache.solr'] + + for variant in self: + if not variant.product_tmpl_id.active and variant.product_tmpl_id.type != 'product': + continue + + category_id = 0 + category_name = '' + for category in variant.product_tmpl_id.public_categ_ids: + category_id = category.id + category_name = category.name + break + + document = solr_model.get_single_doc('variants', variant.id) + document.update({ + 'id': variant.id, + 'display_name_s': variant.display_name, + 'name_s': variant.name, + 'default_code_s': variant.default_code or '', + 'product_rating_f': variant.product_tmpl_id.virtual_rating, + 'product_id_i': variant.id, + 'template_id_i': variant.product_tmpl_id.id, + 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', variant.product_tmpl_id.id), + 'stock_total_f': variant.qty_stock_vendor, + 'weight_f': variant.product_tmpl_id.weight, + 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, + 'manufacture_name_s': variant.product_tmpl_id.x_manufacture.x_name or '', + 'manufacture_name': variant.product_tmpl_id.x_manufacture.x_name or '', + 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', variant.product_tmpl_id.x_manufacture.id), + 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', variant.product_tmpl_id.x_manufacture.id), + 'category_id_i': category_id, + 'category_name_s': category_name, + 'category_name': category_name, + 'search_rank_i': variant.product_tmpl_id.search_rank, + 'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly, + 'has_product_info_b': True + }) + self.solr().add([document]) + variant.change_solr_data('Perubahan pada data product') + + if not document.get('has_price_info_b'): + variant._sync_price_to_solr() + + self.solr().commit() + + def _sync_price_to_solr(self): + solr_model = self.env['apache.solr'] + + for variant in self: + price_excl_after_disc = price_excl = discount = tax = 0 + flashsale_data = tier1 = tier2 = tier3 = {} + + if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: + price_excl = variant._get_website_price_exclude_tax() + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + discount = variant._get_website_disc(0) + tax = variant._get_website_tax() + flashsale_data = variant._get_flashsale_price() + # add price tiering for base price, discount, and price after discount (tier 1 - 3) + tier1 = variant._get_pricelist_tier1() + tier2 = variant._get_pricelist_tier2() + tier3 = variant._get_pricelist_tier3() + + document = solr_model.get_single_doc('variants', variant.id) + document.update({ + 'id': variant.id, + 'flashsale_id_i': flashsale_data.get('flashsale_id', 0), + 'flashsale_tag_s': flashsale_data.get('flashsale_tag', ''), + 'flashsale_name_s': flashsale_data.get('flashsale_name', ''), + 'flashsale_base_price_f': flashsale_data.get('flashsale_base_price', 0), + 'flashsale_discount_f': flashsale_data.get('flashsale_discount', 0), + 'flashsale_price_f': flashsale_data.get('flashsale_price', 0), + 'price_f': price_excl, + 'discount_f': discount, + 'price_discount_f': price_excl_after_disc, + 'tax_f': tax, + 'discount_tier1_f': tier1.get('discount_tier1', 0), + 'price_tier1_f': tier1.get('price_tier1', 0), + 'discount_tier2_f': tier2.get('discount_tier2', 0), + 'price_tier2_f': tier2.get('price_tier2', 0), + 'discount_tier3_f': tier3.get('discount_tier3', 0), + 'price_tier3_f': tier3.get('price_tier3', 0), + 'has_price_info_b': True + }) + self.solr().add([document]) + variant.change_solr_data('Ada perubahan pada harga product') + + if not document.get('has_product_info_b'): + variant._sync_variants_to_solr() + + self.solr().commit() + + def sync_to_solr(self): + product_ids = self.env.context.get('active_ids', []) + products = self.search([('id', 'in', product_ids)]) + + updated_template_ids = [] + for product in products: + template = product.product_tmpl_id + if template.id in updated_template_ids: + continue + template._sync_product_template_to_solr() + updated_template_ids.append(template.id) \ No newline at end of file diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py new file mode 100644 index 00000000..6089adda --- /dev/null +++ b/indoteknik_custom/models/solr/product_template.py @@ -0,0 +1,158 @@ +from odoo import models, fields, api +from datetime import datetime + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + last_update_solr = fields.Datetime(string='Last Update Solr') + desc_update_solr = fields.Char(string='Desc Update Solr') + + def change_solr_data(self, desc): + self.desc_update_solr = desc + self.last_update_solr = datetime.utcnow() + + def solr(self): + return self.env['apache.solr'].connect('product') + + @api.constrains('active') + def _sync_active_template_solr(self): + for template in self: + if not template.active or template.type != 'product': + self.solr().delete(template.id) + + variant_ids = [x.id for x in template.product_variant_ids] + template.product_variant_ids.solr().delete(variant_ids) + + self.solr().commit() + else: + template._sync_product_template_to_solr() + template._sync_price_to_solr() + + products = self.env['product.product'].search([('product_tmpl_id', '=', template.id), ('active', 'in', [True, False])]) + products._sync_variants_to_solr() + + @api.constrains( + 'name', + 'default_code', + 'weight', + 'x_manufacture', + 'public_categ_ids', + 'search_rank', + 'search_rank_weekly', + 'image_1920' + ) + def _sync_product_template_to_solr(self): + solr_model = self.env['apache.solr'] + + for template in self: + if not template.active or template.type != 'product': + continue + + variant_names = ', '.join([x.display_name or '' for x in template.product_variant_ids]) + variant_codes = ', '.join([x.default_code or '' for x in template.product_variant_ids]) + + category_id = 0 + category_name = '' + for category in template.public_categ_ids: + category_id, category_name = category.id, category.name + break + + document = solr_model.get_single_doc('product', template.id) + document.update({ + 'id': template.id, + 'display_name_s': template.display_name, + 'name_s': template.name, + 'default_code_s': template.default_code or '', + 'product_rating_f': template.virtual_rating, + 'product_id_i': template.id, + 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), + 'variant_total_i': template.product_variant_count, + 'stock_total_f': template.qty_stock_vendor, + 'weight_f': template.weight, + 'manufacture_id_i': template.x_manufacture.id or 0, + 'manufacture_name_s': template.x_manufacture.x_name or '', + 'manufacture_name': template.x_manufacture.x_name or '', + 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), + 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), + 'variants_name_t': variant_names, + 'variants_code_t': variant_codes, + 'search_rank_i': template.search_rank, + 'search_rank_weekly_i': template.search_rank_weekly, + 'category_id_i': category_id, + 'category_name_s': category_name, + 'category_name': category_name, + 'has_product_info_b': True + }) + self.solr().add([document]) + template.product_variant_ids._sync_variants_to_solr() + self.change_solr_data('Perubahan pada data product') + + if not document.get('has_price_info_b'): + template._sync_price_to_solr() + + self.solr().commit() + + def _sync_price_to_solr(self): + solr_model = self.env['apache.solr'] + solr = self.solr() + + for template in self: + price_excl_after_disc = price_excl = discount = tax = 0 + flashsale_data = tier1 = tier2 = tier3 = {} + + for variant in template.product_variant_ids: + if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: + price_excl = variant._get_website_price_exclude_tax() + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + discount = variant._get_website_disc(0) + tax = variant._get_website_tax() + flashsale_data = variant._get_flashsale_price() + # add price tiering for base price, discount, and price after discount (tier 1 - 3) + tier1 = variant._get_pricelist_tier1() + tier2 = variant._get_pricelist_tier2() + tier3 = variant._get_pricelist_tier3() + + if template.product_variant_count == 1: + price_excl = template.product_variant_id._get_website_price_exclude_tax() + discount = template.product_variant_id._get_website_disc(0) + price_excl_after_disc = template.product_variant_id._get_website_price_after_disc_and_tax() + tax = template.product_variant_id._get_website_tax() + flashsale_data = template.product_variant_id._get_flashsale_price() + tier1 = template.product_variant_id._get_pricelist_tier1() + tier2 = template.product_variant_id._get_pricelist_tier2() + tier3 = template.product_variant_id._get_pricelist_tier3() + + document = solr_model.get_single_doc('product', template.id) + document.update({ + 'id': template.id, + 'flashsale_id_i': flashsale_data.get('flashsale_id', 0), + 'flashsale_tag_s': flashsale_data.get('flashsale_tag', ''), + 'flashsale_name_s': flashsale_data.get('flashsale_name', ''), + 'flashsale_base_price_f': flashsale_data.get('flashsale_base_price', 0), + 'flashsale_discount_f': flashsale_data.get('flashsale_discount', 0), + 'flashsale_price_f': flashsale_data.get('flashsale_price', 0), + 'price_f': price_excl, + 'discount_f': discount, + 'price_discount_f': price_excl_after_disc, + 'tax_f': tax, + 'discount_tier1_f': tier1.get('discount_tier1', 0), + 'price_tier1_f': tier1.get('price_tier1', 0), + 'discount_tier2_f': tier2.get('discount_tier2', 0), + 'price_tier2_f': tier2.get('price_tier2', 0), + 'discount_tier3_f': tier3.get('discount_tier3', 0), + 'price_tier3_f': tier3.get('price_tier3', 0), + 'has_price_info_b':True + }) + self.solr().add([document]) + template.change_solr_data('Ada perubahan pada harga product') + + if not document.get('has_product_info_b'): + template._sync_product_template_to_solr() + + self.solr().commit() + + def sync_to_solr(self): + template_ids = self.env.context.get('active_ids', []) + templates = self.search([('id', 'in', template_ids)]) + templates._sync_product_template_to_solr() \ No newline at end of file diff --git a/indoteknik_custom/models/solr/website_categories_homepage.py b/indoteknik_custom/models/solr/website_categories_homepage.py new file mode 100644 index 00000000..59e7f32f --- /dev/null +++ b/indoteknik_custom/models/solr/website_categories_homepage.py @@ -0,0 +1,57 @@ +from odoo import models, fields, api +from datetime import datetime +import json + + +class WebsiteCategoriesHomepage(models.Model): + _inherit = 'website.categories.homepage' + + last_update_solr = fields.Datetime('Last Update Solr') + + def solr(self): + return self.env['apache.solr'].connect('product_category_homepage') + + def update_last_update_solr(self): + self.last_update_solr = datetime.utcnow() + + @api.constrains('status') + def _sync_status_category_homepage_solr(self): + for rec in self: + if rec.status == 'tayang': + rec._sync_category_homepage_to_solr() + else: + self.solr().delete(rec.id) + self.solr().commit() + + @api.constrains('category_id', 'image', 'url', 'sequence', 'product_ids') + def _sync_category_homepage_to_solr(self): + solr_model = self.env['apache.solr'] + + for category in self: + document = solr_model.get_single_doc('product_category_homepage', category.id) + products = [self.env['product.template'].api_single_response(x) for x in category.product_ids] + + document.update({ + 'id': category.id, + 'category_id_i': category.category_id.id, + 'name_s': category.category_id.name, + 'image_s': self.env['ir.attachment'].api_image('website.categories.homepage', 'image', category.id), + 'sequence_i': category.sequence or '', + 'url_s': category.url or '', + 'products_s': json.dumps(products, indent=None), + }) + self.solr().add([document]) + category.update_last_update_solr() + + self.solr().commit() + + def sync_to_solr(self): + category_ids = self.env.context.get('active_ids', []) + categories = self.search([('id', 'in', category_ids)]) + categories._sync_category_homepage_to_solr() + + def unlink(self): + res = super(WebsiteCategoriesHomepage, self).unlink() + self.solr().delete([x.id for x in self]) + self.solr().commit() + return res \ No newline at end of file diff --git a/indoteknik_custom/models/website_categories_homepage.py b/indoteknik_custom/models/website_categories_homepage.py index 2f5b3d92..04632960 100644 --- a/indoteknik_custom/models/website_categories_homepage.py +++ b/indoteknik_custom/models/website_categories_homepage.py @@ -1,5 +1,4 @@ -from odoo import fields, models, api -import json +from odoo import fields, models class WebsiteCategoriesHomepage(models.Model): @@ -15,30 +14,3 @@ class WebsiteCategoriesHomepage(models.Model): ('tidak_tayang', 'Tidak Tayang') ], string='Status') product_ids = fields.Many2many('product.template', string='Product category') - - - @api.constrains('category_id', 'image', 'url', 'sequence', 'status', 'product_ids') - def _sync_category_homepage_to_solr(self): - solr_model = self.env['apache.solr'] - solr = solr_model.connect('product_category_homepage') - - for category in self: - document = solr_model.get_single_doc(solr, category.id) - result = [self.env['product.template'].api_single_response(x) for x in category.product_ids] - products = json.dumps(result, indent=None) - - document.update({ - 'id': category.id, - 'category_id_i': category.category_id.id, - 'name_s': category.category_id.name, - 'image_s': self.env['ir.attachment'].api_image('website.categories.homepage', 'image', category.id), - 'sequence_i': category.sequence or '', - 'url_s': category.url or '', - 'products_s': products, - }) - solr.add([document]) - - def sync_to_solr(self): - categories_ids = self.env.context.get('active_ids', []) - categories = self.env['website.categories.homepage'].search([('id', 'in', categories_ids)]) - categories._sync_category_homepage_to_solr() diff --git a/indoteknik_custom/views/product_product.xml b/indoteknik_custom/views/product_product.xml index d3ef3e15..3a10b4e0 100644 --- a/indoteknik_custom/views/product_product.xml +++ b/indoteknik_custom/views/product_product.xml @@ -12,5 +12,13 @@ + + + Sync to solr + + + code + model.sync_to_solr() + \ No newline at end of file diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index 82b7ce4d..bbbcc4e1 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -9,11 +9,13 @@ - - + + + + @@ -74,5 +76,13 @@ + + + Sync to solr + + + code + model.sync_to_solr() + \ No newline at end of file diff --git a/indoteknik_custom/views/website_categories_homepage.xml b/indoteknik_custom/views/website_categories_homepage.xml index 0a3f684b..bd64f201 100644 --- a/indoteknik_custom/views/website_categories_homepage.xml +++ b/indoteknik_custom/views/website_categories_homepage.xml @@ -16,6 +16,7 @@ + @@ -33,6 +34,7 @@ + @@ -49,8 +51,8 @@ - - Sync To Solr + + Sync to solr code -- cgit v1.2.3 From 52f4b12c0b211f958c2704346d7da24d1d4767c6 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 25 Aug 2023 15:13:46 +0700 Subject: Update API product category homepage --- indoteknik_api/controllers/api_v1/category.py | 3 ++- indoteknik_api/controllers/api_v1/product.py | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/category.py b/indoteknik_api/controllers/api_v1/category.py index efbf52f2..3c5766e2 100644 --- a/indoteknik_api/controllers/api_v1/category.py +++ b/indoteknik_api/controllers/api_v1/category.py @@ -1,7 +1,7 @@ from .. import controller from odoo import http from odoo.http import request -import ast +import ast, json class Category(controller.Controller): @@ -58,6 +58,7 @@ class Category(controller.Controller): return self.response([x['id'] for x in categories]) + # TODO: Delete this function after unused by website @http.route(prefix + 'categories_homepage', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_categories_homepage(self, **kw): diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index e08ec97b..98e131da 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -2,9 +2,7 @@ from .. import controller from odoo import http from odoo.http import request from datetime import datetime, timedelta -import ast -import logging -import math +import ast, logging, math, json _logger = logging.getLogger(__name__) @@ -348,4 +346,20 @@ class Product(controller.Controller): elif order == 'latest': orders.append('create_date desc') return ','.join(orders) - \ No newline at end of file + + @http.route(prefix + 'product/category-homepage', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_product_category_homepage(self, **kw): + solr_model = request.env['apache.solr'] + + query = '*:*' + id = kw.get('id') + if id: + query = f'id:{id}' + + categories = solr_model.connect('product_category_homepage').search(query, sort='sequence_i asc').docs + categories = solr_model.clean_key_docs(categories) + for category in categories: + category['products'] = json.loads(category['products']) + + return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) \ No newline at end of file -- cgit v1.2.3 From 315b832420eb8314e809b1c0f549304d423b45f3 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sat, 26 Aug 2023 12:13:28 +0700 Subject: Create apache solr queue and implement to product.template and website.categories.homepage --- indoteknik_custom/__manifest__.py | 1 + indoteknik_custom/models/solr/__init__.py | 1 + indoteknik_custom/models/solr/apache_solr_queue.py | 69 ++++++++++++++++++++ indoteknik_custom/models/solr/product_product.py | 26 +++----- indoteknik_custom/models/solr/product_template.py | 48 ++++++++------ .../models/solr/website_categories_homepage.py | 52 +++++++++++---- indoteknik_custom/security/ir.model.access.csv | 1 + indoteknik_custom/views/apache_solr_queue.xml | 74 ++++++++++++++++++++++ indoteknik_custom/views/product_product.xml | 2 +- indoteknik_custom/views/product_template.xml | 2 +- .../views/website_categories_homepage.xml | 2 +- 11 files changed, 226 insertions(+), 52 deletions(-) create mode 100644 indoteknik_custom/models/solr/apache_solr_queue.py create mode 100644 indoteknik_custom/views/apache_solr_queue.xml diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 7c38382c..2e2b6761 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -91,6 +91,7 @@ 'views/product_attribute_value.xml', 'views/mail_template_po.xml', 'views/price_group.xml', + 'views/apache_solr_queue.xml', 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', diff --git a/indoteknik_custom/models/solr/__init__.py b/indoteknik_custom/models/solr/__init__.py index 450e1dae..45ef4299 100644 --- a/indoteknik_custom/models/solr/__init__.py +++ b/indoteknik_custom/models/solr/__init__.py @@ -1,4 +1,5 @@ from . import apache_solr +from . import apache_solr_queue from . import product_pricelist_item from . import product_product from . import product_template diff --git a/indoteknik_custom/models/solr/apache_solr_queue.py b/indoteknik_custom/models/solr/apache_solr_queue.py new file mode 100644 index 00000000..eb5a99a8 --- /dev/null +++ b/indoteknik_custom/models/solr/apache_solr_queue.py @@ -0,0 +1,69 @@ +from odoo import models, fields +from datetime import datetime +import logging + + +_logger = logging.getLogger(__name__) + +class ApacheSolrQueue(models.Model): + _name = 'apache.solr.queue' + + display_name = fields.Char('Display Name', compute="_compute_display_name") + res_model = fields.Char('Resource Model') + res_id = fields.Integer('Resource ID') + function_name = fields.Char('Function Name') + execute_status = fields.Selection([ + ('success', 'Success'), + ('failed', 'Failed'), + ('not_found', 'Record not found') + ], 'Execute Status') + execute_date = fields.Datetime('Execute Date') + + def _compute_display_name(self): + for rec in self: + try: + res_model = rec.res_model + res_id = int(rec.res_id) + model_instance = self.env[res_model].browse(res_id) + rec.display_name = model_instance.display_name or '' + except: + rec.display_name = '' + + def process_queue_item(self, limit=100): + records = self.search([('execute_status', '=', False)], order='create_date asc', limit=limit) + for rec in records: + rec.execute_queue() + + def execute_queue(self): + for rec in self: + try: + res_model = rec.res_model + res_id = int(rec.res_id) + function_name = rec.function_name + _logger.info(f'Execute Queue: {res_model}.{function_name}() -> {res_id}') + + domain = [('id', '=', res_id)] + if res_model in ['product.template']: + domain.append(('active', 'in', [True, False])) + + model_instance = self.env[res_model].search(domain) + if model_instance: + getattr(model_instance, function_name)() + rec.execute_status = 'success' + else: + rec.execute_status = 'not_found' + except: + rec.execute_status = 'failed' + rec.execute_date = datetime.utcnow() + self.env.cr.commit() + + def create_unique(self, payload={}): + count = self.search_count([ + ('res_model', '=', payload['res_model']), + ('res_id', '=', payload['res_id']), + ('function_name', '=', payload['function_name']), + ('execute_status', '=', False) + ]) + if count == 0: + self.create(payload) + diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py index 5090b8d5..f3107afa 100644 --- a/indoteknik_custom/models/solr/product_product.py +++ b/indoteknik_custom/models/solr/product_product.py @@ -14,6 +14,12 @@ class ProductProduct(models.Model): def solr(self): return self.env['apache.solr'].connect('variants') + + def action_sync_to_solr(self): + product_ids = self.env.context.get('active_ids', []) + products = self.search([('id', 'in', product_ids)]) + for product in products: + product.product_tmpl_id._create_solr_queue('_sync_product_template_to_solr') def _sync_variants_to_solr(self): solr_model = self.env['apache.solr'] @@ -59,8 +65,6 @@ class ProductProduct(models.Model): if not document.get('has_price_info_b'): variant._sync_price_to_solr() - self.solr().commit() - def _sync_price_to_solr(self): solr_model = self.env['apache.solr'] @@ -105,17 +109,7 @@ class ProductProduct(models.Model): if not document.get('has_product_info_b'): variant._sync_variants_to_solr() - - self.solr().commit() - - def sync_to_solr(self): - product_ids = self.env.context.get('active_ids', []) - products = self.search([('id', 'in', product_ids)]) - - updated_template_ids = [] - for product in products: - template = product.product_tmpl_id - if template.id in updated_template_ids: - continue - template._sync_product_template_to_solr() - updated_template_ids.append(template.id) \ No newline at end of file + + def _sync_delete_solr(self): + for rec in self: + self.solr().delete(rec.id) \ No newline at end of file diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index 6089adda..ba670a81 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -15,16 +15,31 @@ class ProductTemplate(models.Model): def solr(self): return self.env['apache.solr'].connect('product') + def _create_solr_queue(self, function_name): + for rec in self: + self.env['apache.solr.queue'].create_unique({ + 'res_model': self._name, + 'res_id': rec.id, + 'function_name': function_name + }) + @api.constrains('active') + def _create_solr_queue_sync_active(self): + self._create_solr_queue('_sync_active_template_solr') + + @api.constrains('name', 'default_code', 'weight', 'x_manufacture', 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920') + def _create_solr_queue_sync_product_template(self): + self._create_solr_queue('_sync_product_template_to_solr') + + def action_sync_to_solr(self): + template_ids = self.env.context.get('active_ids', []) + templates = self.search([('id', 'in', template_ids)]) + templates._create_solr_queue('_sync_product_template_to_solr') + def _sync_active_template_solr(self): for template in self: if not template.active or template.type != 'product': - self.solr().delete(template.id) - - variant_ids = [x.id for x in template.product_variant_ids] - template.product_variant_ids.solr().delete(variant_ids) - - self.solr().commit() + template._sync_delete_solr() else: template._sync_product_template_to_solr() template._sync_price_to_solr() @@ -32,16 +47,6 @@ class ProductTemplate(models.Model): products = self.env['product.product'].search([('product_tmpl_id', '=', template.id), ('active', 'in', [True, False])]) products._sync_variants_to_solr() - @api.constrains( - 'name', - 'default_code', - 'weight', - 'x_manufacture', - 'public_categ_ids', - 'search_rank', - 'search_rank_weekly', - 'image_1920' - ) def _sync_product_template_to_solr(self): solr_model = self.env['apache.solr'] @@ -152,7 +157,10 @@ class ProductTemplate(models.Model): self.solr().commit() - def sync_to_solr(self): - template_ids = self.env.context.get('active_ids', []) - templates = self.search([('id', 'in', template_ids)]) - templates._sync_product_template_to_solr() \ No newline at end of file + def _sync_delete_solr(self): + for rec in self: + self.solr().delete(rec.id) + for variant in rec.product_variant_ids: + variant._sync_delete_solr() + self.solr().optimize() + self.solr().commit() \ No newline at end of file diff --git a/indoteknik_custom/models/solr/website_categories_homepage.py b/indoteknik_custom/models/solr/website_categories_homepage.py index 59e7f32f..21812acf 100644 --- a/indoteknik_custom/models/solr/website_categories_homepage.py +++ b/indoteknik_custom/models/solr/website_categories_homepage.py @@ -14,20 +14,51 @@ class WebsiteCategoriesHomepage(models.Model): def update_last_update_solr(self): self.last_update_solr = datetime.utcnow() + def _create_solr_queue(self, function_name): + for rec in self: + self.env['apache.solr.queue'].create_unique({ + 'res_model': self._name, + 'res_id': rec.id, + 'function_name': function_name + }) + @api.constrains('status') + def _create_solr_queue_sync_status(self): + self._create_solr_queue('_sync_status_category_homepage_solr') + + @api.constrains('category_id', 'image', 'url', 'sequence', 'product_ids') + def _create_solr_queue_sync_category_homepage(self): + self._create_solr_queue('_sync_category_homepage_to_solr') + + def action_sync_to_solr(self): + category_ids = self.env.context.get('active_ids', []) + categories = self.search([('id', 'in', category_ids)]) + categories._create_solr_queue('_sync_category_homepage_to_solr') + + def unlink(self): + res = super(WebsiteCategoriesHomepage, self).unlink() + for rec in self: + self.env['apache.solr.queue'].create_unique({ + 'res_model': self._name, + 'res_id': rec.id, + 'function_name': '_sync_delete_solr' + }) + return res + def _sync_status_category_homepage_solr(self): for rec in self: if rec.status == 'tayang': rec._sync_category_homepage_to_solr() else: - self.solr().delete(rec.id) - self.solr().commit() + rec._sync_delete_solr() - @api.constrains('category_id', 'image', 'url', 'sequence', 'product_ids') def _sync_category_homepage_to_solr(self): solr_model = self.env['apache.solr'] for category in self: + if category.status == 'tidak_tayang': + continue + document = solr_model.get_single_doc('product_category_homepage', category.id) products = [self.env['product.template'].api_single_response(x) for x in category.product_ids] @@ -45,13 +76,8 @@ class WebsiteCategoriesHomepage(models.Model): self.solr().commit() - def sync_to_solr(self): - category_ids = self.env.context.get('active_ids', []) - categories = self.search([('id', 'in', category_ids)]) - categories._sync_category_homepage_to_solr() - - def unlink(self): - res = super(WebsiteCategoriesHomepage, self).unlink() - self.solr().delete([x.id for x in self]) - self.solr().commit() - return res \ No newline at end of file + def _sync_delete_solr(self): + for rec in self: + self.solr().delete(rec.id) + self.solr().optimize() + self.solr().commit() \ No newline at end of file diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 6f9ba9e4..c9732614 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -67,3 +67,4 @@ access_account_move_multi_update,access.account.move.multi_update,model_account_ access_airway_bill,access.airway.bill,model_airway_bill,,1,1,1,1 access_airway_bill_manifest,access.airway.bill.manifest,model_airway_bill_manifest,,1,1,1,1 access_price_group,access.price.group,model_price_group,,1,1,1,1 +access_apache_solr_queue,access.apache.solr.queue,model_apache_solr_queue,,1,1,1,1 diff --git a/indoteknik_custom/views/apache_solr_queue.xml b/indoteknik_custom/views/apache_solr_queue.xml new file mode 100644 index 00000000..092871d6 --- /dev/null +++ b/indoteknik_custom/views/apache_solr_queue.xml @@ -0,0 +1,74 @@ + + + apache.solr.queue.tree + apache.solr.queue + + + + + + + + + + + + + + + apache.solr.queue.search + apache.solr.queue + primary + + + + + + + + + + + + Solr Queue + apache.solr.queue + + {'search_default_active_queue': 1} + tree + + + + + + Execute + + + code + records.execute_queue() + + + + + Solr Queue: Process + 6 + minutes + -1 + + + model.process_queue_item(limit=100) + code + 55 + True + + + \ No newline at end of file diff --git a/indoteknik_custom/views/product_product.xml b/indoteknik_custom/views/product_product.xml index 3a10b4e0..6d547712 100644 --- a/indoteknik_custom/views/product_product.xml +++ b/indoteknik_custom/views/product_product.xml @@ -18,7 +18,7 @@ code - model.sync_to_solr() + model.action_sync_to_solr() \ No newline at end of file diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index bbbcc4e1..b2939867 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -82,7 +82,7 @@ code - model.sync_to_solr() + model.action_sync_to_solr() \ No newline at end of file diff --git a/indoteknik_custom/views/website_categories_homepage.xml b/indoteknik_custom/views/website_categories_homepage.xml index bd64f201..aa54ca7a 100644 --- a/indoteknik_custom/views/website_categories_homepage.xml +++ b/indoteknik_custom/views/website_categories_homepage.xml @@ -56,7 +56,7 @@ code - model.sync_to_solr() + model.action_sync_to_solr() Date: Tue, 29 Aug 2023 10:41:22 +0700 Subject: Update apache solr - Create get tier name pricelist - Create solr results on product.template and product.product - Fix get active flash sale on product template - Update name "get_single_doc" to "get_doc" in apache solr model - Add product ids on sync category homepage to solr --- indoteknik_api/controllers/api_v1/product.py | 5 +- indoteknik_api/models/product_product.py | 11 +-- indoteknik_custom/models/product_pricelist.py | 12 +++ indoteknik_custom/models/product_template.py | 5 +- indoteknik_custom/models/solr/apache_solr.py | 3 +- indoteknik_custom/models/solr/product_product.py | 59 +++++++++++- indoteknik_custom/models/solr/product_template.py | 103 +++++++++++++++++---- .../models/solr/website_categories_homepage.py | 6 +- 8 files changed, 165 insertions(+), 39 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 98e131da..e3b7701a 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -360,6 +360,9 @@ class Product(controller.Controller): categories = solr_model.connect('product_category_homepage').search(query, sort='sequence_i asc').docs categories = solr_model.clean_key_docs(categories) for category in categories: - category['products'] = json.loads(category['products']) + product_ids = category.get('product_ids', []) + category.pop('product_ids', None) + products = request.env['product.template'].browse(product_ids) + category['products'] = products.solr_results() return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) \ No newline at end of file diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index a2d2f8a2..bc1ce9a6 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -58,25 +58,16 @@ class ProductProduct(models.Model): def calculate_website_price(self, pricelist=False): pricelist = pricelist or self.env.user_pricelist - config = self.env['ir.config_parameter'] - product_pricelist_tier1 = int(config.get_param('product.pricelist.tier1')) - product_pricelist_tier2 = int(config.get_param('product.pricelist.tier2')) - product_pricelist_tier3 = int(config.get_param('product.pricelist.tier3')) - discount_percentage = self._get_website_disc(0) price_discount = self._get_website_price_after_disc_and_tax() - price_tier = False pricelists = { 'tier1': self._get_pricelist_tier1, 'tier2': self._get_pricelist_tier2, 'tier3': self._get_pricelist_tier3, } - pricelist_id = pricelist.id if pricelist else False - if pricelist_id == product_pricelist_tier1: price_tier = 'tier1' - if pricelist_id == product_pricelist_tier2: price_tier = 'tier2' - if pricelist_id == product_pricelist_tier3: price_tier = 'tier3' + price_tier = pricelist.get_tier_name() if price_tier: price = pricelists[price_tier]() discount_key = 'discount_%s' % price_tier diff --git a/indoteknik_custom/models/product_pricelist.py b/indoteknik_custom/models/product_pricelist.py index a55e3fdd..988b38b5 100644 --- a/indoteknik_custom/models/product_pricelist.py +++ b/indoteknik_custom/models/product_pricelist.py @@ -24,6 +24,18 @@ class ProductPricelist(models.Model): remaining_time = (self.end_date - datetime.now()).total_seconds() remaining_time = round(remaining_time) return max(remaining_time, 0) + + def get_tier_name(self): + config = self.env['ir.config_parameter'] + product_pricelist_tier1 = int(config.get_param('product.pricelist.tier1', 0)) + product_pricelist_tier2 = int(config.get_param('product.pricelist.tier2', 0)) + product_pricelist_tier3 = int(config.get_param('product.pricelist.tier3', 0)) + + price_tier = None + if self.id == product_pricelist_tier1: price_tier = 'tier1' + if self.id == product_pricelist_tier2: price_tier = 'tier2' + if self.id == product_pricelist_tier3: price_tier = 'tier3' + return price_tier class ProductPricelistItem(models.Model): _inherit = 'product.pricelist.item' diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index f72fa763..c7be3378 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -144,10 +144,13 @@ class ProductTemplate(models.Model): template.have_promotion_program = False def _get_active_flash_sale(self): + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') variant_ids = [x.id for x in self.product_variant_ids] pricelist = self.env['product.pricelist'].search([ ('is_flash_sale', '=', True), - ('item_ids.product_id', 'in', variant_ids) + ('item_ids.product_id', 'in', variant_ids), + ('start_date', '<=', current_time), + ('end_date', '>=', current_time) ], limit=1) return pricelist diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py index cb44e7ed..3be37a5a 100644 --- a/indoteknik_custom/models/solr/apache_solr.py +++ b/indoteknik_custom/models/solr/apache_solr.py @@ -27,7 +27,7 @@ class ApacheSolr(models.Model): return pysolr.Solr(url + schema, always_commit=True, timeout=30) - def get_single_doc(self, schema, id): + def get_doc(self, schema, id): try: return self.connect(schema).search(f'id:{id}').docs[0] except: @@ -53,7 +53,6 @@ class ApacheSolr(models.Model): new_dict[cleaned_key] = value return new_dict - def _update_stock_product_to_solr(self, limit=10000): current_time = datetime.now() delta_time = current_time - timedelta(days=3) diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py index f3107afa..48ee9daa 100644 --- a/indoteknik_custom/models/solr/product_product.py +++ b/indoteknik_custom/models/solr/product_product.py @@ -35,7 +35,7 @@ class ProductProduct(models.Model): category_name = category.name break - document = solr_model.get_single_doc('variants', variant.id) + document = solr_model.get_doc('variants', variant.id) document.update({ 'id': variant.id, 'display_name_s': variant.display_name, @@ -83,7 +83,7 @@ class ProductProduct(models.Model): tier2 = variant._get_pricelist_tier2() tier3 = variant._get_pricelist_tier3() - document = solr_model.get_single_doc('variants', variant.id) + document = solr_model.get_doc('variants', variant.id) document.update({ 'id': variant.id, 'flashsale_id_i': flashsale_data.get('flashsale_id', 0), @@ -112,4 +112,57 @@ class ProductProduct(models.Model): def _sync_delete_solr(self): for rec in self: - self.solr().delete(rec.id) \ No newline at end of file + self.solr().delete(rec.id) + + def solr_results(self): + solr_model = self.env['apache.solr'] + pricelist = self.env.user_pricelist + price_tier = pricelist.get_tier_name() + + results = [] + for product in self: + doc = solr_model.get_doc('variants', product.id) + if len(doc) == 0: continue + + discount_key = 'discount_f' + price_discount_key = 'price_discount_f' + if price_tier: + discount_key = f'discount_{price_tier}_f' + price_discount_key = f'price_{price_tier}_f' + + flashsale = product._get_active_flash_sale() + if flashsale: + discount_key = 'flashsale_discount_f' + price_discount_key = 'flashsale_price_f' + + result = { + 'id': doc.get('id'), + 'parent': { + 'id': doc.get('template_id_i'), + 'name': doc.get('name_s'), + 'image': doc.get('image_s'), + }, + 'code': doc.get('default_code_s'), + 'name': doc.get('display_name_s'), + 'price': { + 'price': doc.get('price_f'), + 'discount_percentage': doc.get(discount_key), + 'price_discount': doc.get(price_discount_key) + }, + 'stock': doc.get('stock_total_f'), + 'weight': doc.get('weight_f'), + 'manufacture': None + } + + manufacture_id = doc.get('manufacture_id_i') + if manufacture_id: + result['manufacture'] = { + 'id': manufacture_id, + 'name': doc.get('manufacture_name_s'), + 'image_promotion_1': doc.get('image_promotion_1_s'), + 'image_promotion_2': doc.get('image_promotion_2_s'), + } + + results.append(result) + + return results \ No newline at end of file diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index ba670a81..6ae0bec2 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -14,7 +14,7 @@ class ProductTemplate(models.Model): def solr(self): return self.env['apache.solr'].connect('product') - + def _create_solr_queue(self, function_name): for rec in self: self.env['apache.solr.queue'].create_unique({ @@ -22,11 +22,11 @@ class ProductTemplate(models.Model): 'res_id': rec.id, 'function_name': function_name }) - + @api.constrains('active') def _create_solr_queue_sync_active(self): self._create_solr_queue('_sync_active_template_solr') - + @api.constrains('name', 'default_code', 'weight', 'x_manufacture', 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920') def _create_solr_queue_sync_product_template(self): self._create_solr_queue('_sync_product_template_to_solr') @@ -43,13 +43,14 @@ class ProductTemplate(models.Model): else: template._sync_product_template_to_solr() template._sync_price_to_solr() - - products = self.env['product.product'].search([('product_tmpl_id', '=', template.id), ('active', 'in', [True, False])]) + + products = self.env['product.product'].search( + [('product_tmpl_id', '=', template.id), ('active', 'in', [True, False])]) products._sync_variants_to_solr() def _sync_product_template_to_solr(self): solr_model = self.env['apache.solr'] - + for template in self: if not template.active or template.type != 'product': continue @@ -63,7 +64,7 @@ class ProductTemplate(models.Model): category_id, category_name = category.id, category.name break - document = solr_model.get_single_doc('product', template.id) + document = solr_model.get_doc('product', template.id) document.update({ 'id': template.id, 'display_name_s': template.display_name, @@ -81,7 +82,7 @@ class ProductTemplate(models.Model): 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), 'variants_name_t': variant_names, - 'variants_code_t': variant_codes, + 'variants_code_t': variant_codes, 'search_rank_i': template.search_rank, 'search_rank_weekly_i': template.search_rank_weekly, 'category_id_i': category_id, @@ -95,14 +96,14 @@ class ProductTemplate(models.Model): if not document.get('has_price_info_b'): template._sync_price_to_solr() - + self.solr().commit() - + def _sync_price_to_solr(self): solr_model = self.env['apache.solr'] solr = self.solr() - - for template in self: + + for template in self: price_excl_after_disc = price_excl = discount = tax = 0 flashsale_data = tier1 = tier2 = tier3 = {} @@ -117,7 +118,7 @@ class ProductTemplate(models.Model): tier1 = variant._get_pricelist_tier1() tier2 = variant._get_pricelist_tier2() tier3 = variant._get_pricelist_tier3() - + if template.product_variant_count == 1: price_excl = template.product_variant_id._get_website_price_exclude_tax() discount = template.product_variant_id._get_website_disc(0) @@ -127,8 +128,8 @@ class ProductTemplate(models.Model): tier1 = template.product_variant_id._get_pricelist_tier1() tier2 = template.product_variant_id._get_pricelist_tier2() tier3 = template.product_variant_id._get_pricelist_tier3() - - document = solr_model.get_single_doc('product', template.id) + + document = solr_model.get_doc('product', template.id) document.update({ 'id': template.id, 'flashsale_id_i': flashsale_data.get('flashsale_id', 0), @@ -147,14 +148,14 @@ class ProductTemplate(models.Model): 'price_tier2_f': tier2.get('price_tier2', 0), 'discount_tier3_f': tier3.get('discount_tier3', 0), 'price_tier3_f': tier3.get('price_tier3', 0), - 'has_price_info_b':True + 'has_price_info_b': True }) self.solr().add([document]) template.change_solr_data('Ada perubahan pada harga product') if not document.get('has_product_info_b'): template._sync_product_template_to_solr() - + self.solr().commit() def _sync_delete_solr(self): @@ -163,4 +164,70 @@ class ProductTemplate(models.Model): for variant in rec.product_variant_ids: variant._sync_delete_solr() self.solr().optimize() - self.solr().commit() \ No newline at end of file + self.solr().commit() + + def solr_results(self, detail=False): + solr_model = self.env['apache.solr'] + pricelist = self.env.user_pricelist + price_tier = pricelist.get_tier_name() + + results = [] + for template in self: + doc = solr_model.get_doc('product', template.id) + if len(doc) == 0: continue + + discount_key = 'discount_f' + price_discount_key = 'price_discount_f' + if price_tier: + discount_key = f'discount_{price_tier}_f' + price_discount_key = f'price_{price_tier}_f' + + flashsale = template._get_active_flash_sale() + if flashsale: + discount_key = 'flashsale_discount_f' + price_discount_key = 'flashsale_price_f' + + result = { + 'id': doc.get('id'), + 'image': doc.get('image_s'), + 'code': doc.get('default_code_s'), + 'display_name': doc.get('display_name_s'), + 'name': doc.get('name_s'), + 'variant_total': doc.get('variant_total_i'), + 'weight': doc.get('weight_f'), + 'manufacture': None, + 'categories': [], + 'flash_sale': { + 'remaining_time': flashsale._remaining_time_in_second() or 0, + 'tag': flashsale.flashsale_tag or None + }, + 'lowest_price': { + 'price': doc.get('price_f'), + 'discount_percentage': doc.get(discount_key), + 'price_discount': doc.get(price_discount_key) + } + } + + manufacture_id = doc.get('manufacture_id_i') + if manufacture_id: + result['manufacture'] = { + 'id': manufacture_id, + 'name': doc.get('manufacture_name_s'), + 'image_promotion_1': doc.get('image_promotion_1_s'), + 'image_promotion_2': doc.get('image_promotion_2_s'), + } + + category_id = doc.get('category_id_i') + if category_id: + result['categories'] = [{ + 'id': category_id, + 'name': doc.get('category_name_s'), + }] + + if detail == True: + result['variants'] = template.product_variant_ids.solr_results() + result['description'] = template.website_description or '' + + results.append(result) + + return results diff --git a/indoteknik_custom/models/solr/website_categories_homepage.py b/indoteknik_custom/models/solr/website_categories_homepage.py index 21812acf..1b517ae6 100644 --- a/indoteknik_custom/models/solr/website_categories_homepage.py +++ b/indoteknik_custom/models/solr/website_categories_homepage.py @@ -59,9 +59,7 @@ class WebsiteCategoriesHomepage(models.Model): if category.status == 'tidak_tayang': continue - document = solr_model.get_single_doc('product_category_homepage', category.id) - products = [self.env['product.template'].api_single_response(x) for x in category.product_ids] - + document = solr_model.get_doc('product_category_homepage', category.id) document.update({ 'id': category.id, 'category_id_i': category.category_id.id, @@ -69,7 +67,7 @@ class WebsiteCategoriesHomepage(models.Model): 'image_s': self.env['ir.attachment'].api_image('website.categories.homepage', 'image', category.id), 'sequence_i': category.sequence or '', 'url_s': category.url or '', - 'products_s': json.dumps(products, indent=None), + 'product_ids': [x.id for x in category.product_ids] }) self.solr().add([document]) category.update_last_update_solr() -- cgit v1.2.3