from datetime import datetime from bs4 import BeautifulSoup from odoo import api, fields, models class ProductTemplate(models.Model): _inherit = "product.template" unpublished = fields.Boolean(string='Unpublished') 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') 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('name', 'default_code', 'weight', 'x_manufacture', 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920', 'unpublished','image_carousel_lines') def _create_solr_queue_sync_product_template(self): self._create_solr_queue('_sync_product_template_to_solr') @api.constrains('active') def _constrains_active(self): for rec in self: if not rec.active: rec.unpublished = True 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 solr_flag_to_solr(self, limit=500): template_products = self.search([('solr_flag', '=', 2), ('active', 'in', [True, False])], limit=limit) for product in template_products: product._create_solr_queue('_sync_product_template_to_solr') product._create_solr_queue('_sync_price_to_solr') product.solr_flag = 1 def _sync_product_stock_to_solr(self): self._sync_product_template_to_solr() def get_voucher_pastihemat(self, brand_id): voucher_line = self.env['voucher.line'].search([('voucher_id', '=', 146), ('manufacture_id', 'in', [brand_id])]) return voucher_line def _sync_product_template_to_solr(self): solr_model = self.env['apache.solr'] for template in self: voucher = None if template.x_manufacture: voucher = self.get_voucher_pastihemat(template.x_manufacture.id) 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]) # Mengumpulkan semua kategori category_ids = [category.id for category in template.public_categ_ids] category_names = [category.name for category in template.public_categ_ids] # Check if the product's inventory location is in ID 57 or 83 target_locations = [57, 83] stock_quant = self.env['stock.quant'].search([ ('product_id', 'in', template.product_variant_ids.ids), ('location_id', 'in', target_locations), ]) is_in_bu = False for quant in stock_quant: if quant.product_id.qty_free_bandengan > 0: is_in_bu = True break cleaned_desc = BeautifulSoup(template.website_description or '', "html.parser").get_text() website_description = template.website_description if cleaned_desc else '' # carousel_images = ', '.join([self.env['ir.attachment'].api_image('image.carousel', 'image', carousel.id) for carousel in template.image_carousel_lines]) carousel_images = [] for carousel in template.image_carousel_lines: image_url = self.env['ir.attachment'].api_image('image.carousel', 'image', carousel.id) if image_url: # Hanya tambahkan jika URL valid carousel_images.append(image_url) document = solr_model.get_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), "image_carousel_ss": carousel_images if carousel_images else [], 'image_mobile_s': self.env['ir.attachment'].api_image('product.template', 'image_256', template.id), "variant_total_i": template.product_variant_count, "stock_total_f": template.qty_stock_vendor, "weight_f": template.weight, # "attribute_set_id_i": template.x_attribute_set_id or 0, # "attribute_set_name_s": template.x_attribute_set_name or '', "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), 'x_logo_manufacture_s': self.env['ir.attachment'].api_image('x_manufactures', 'x_logo_manufacture', 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_ids": category_ids, # ID kategori sebagai string yang dipisahkan koma "category_parent_ids": self.get_category_hierarchy_ids(category_ids), # ID kategori sebagai string yang dipisahkan koma "category_name_s": ', '.join(category_names), # Nama kategori sebagai string yang dipisahkan koma "category_name": category_names, # Nama kategori sebagai list "description_t": template.website_description or '', "description_clean_t": cleaned_desc or '', 'has_product_info_b': True, 'publish_b': not template.unpublished, 'sni_b': template.sni, 'tkdn_b': template.tkdn, "qty_sold_f": template.qty_sold, "is_in_bu_b": is_in_bu, "voucher_min_purchase_f" : voucher.min_purchase_amount or 0, "voucher_discount_type_s" : voucher.discount_type or '', "voucher_discount_amount_f" : voucher.discount_amount or 0, "voucher_max_discount_f" : voucher.max_discount_amount or 0 }) self.solr().add(docs=[document], softCommit=True) products = self.env['product.product'].search([ ('product_tmpl_id', '=', template.id), ('active', 'in', [True, False]) ]) products._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() def get_category_hierarchy_ids(self, category_id): """ Function to get category hierarchy IDs including the category itself and its parents. Args: category_id (int): The ID of the category you want to retrieve. env (Environment): The Odoo environment. Returns: list: A list of IDs for the category and its parents. """ category_ids = [] def traverse_category(cat_id): # Retrieve category object based on ID category = self.env['product.public.category'].browse(cat_id) # Add the current category ID to the list category_ids.append(category.id) # If there is a parent category, traverse upwards if category.parent_id: traverse_category(category.parent_id.id) # Start traversal from the initial category if category_id: # Check if category_id is not an empty value traverse_category(category_id) # Reverse the list to get the hierarchy from top level to the current level return list(reversed(category_ids)) else: # If category_id is empty, return an empty list return [] def _sync_price_to_solr(self): solr_model = self.env['apache.solr'] TIER_NUMBERS = ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2'] for template in self: cheapest_flashsale = {} for variant in template.product_variant_ids: variant_flashsale = variant.with_context(price_for="web")._get_flashsale_price() variant_flashsale_price = variant_flashsale.get('flashsale_price', 0) cheapest_flashsale_price = cheapest_flashsale.get('flashsale_price', 0) if cheapest_flashsale_price == 0 or (variant_flashsale_price != 0 and variant_flashsale_price < cheapest_flashsale_price): cheapest_flashsale = variant_flashsale flashsale_doc = { "flashsale_id_i": cheapest_flashsale.get('flashsale_id', 0), "flashsale_tag_s": cheapest_flashsale.get('flashsale_tag', ''), "flashsale_name_s": cheapest_flashsale.get('flashsale_name', ''), "flashsale_start_date_s": cheapest_flashsale.get('flashsale_start_date', ''), "flashsale_end_date_s": cheapest_flashsale.get('flashsale_end_date', ''), "flashsale_base_price_f": cheapest_flashsale.get('flashsale_base_price', 0), "flashsale_discount_f": cheapest_flashsale.get('flashsale_discount', 0), "flashsale_price_f": cheapest_flashsale.get('flashsale_price', 0) } price_doc = {} # Loop tier to get each variant price for tier_number in TIER_NUMBERS: for variant in template.product_variant_ids: tier = variant._get_pricelist_tier(tier_number) discount_tier_key = f'discount_tier{tier_number}' price_tier_key = f'price_tier{tier_number}' variant_discount = tier.get(discount_tier_key, 0) variant_price = tier.get(price_tier_key, 0) price_tier = price_doc.get(f"{price_tier_key}_f", 0) # When price tier is 0 or variant_price less than price tier then use variant price if price_tier == 0 or (variant_price < price_tier and variant_price > 0): price_doc[f"{discount_tier_key}_f"] = variant_discount price_doc[f"{price_tier_key}_f"] = variant_price document = solr_model.get_doc('product', template.id) document['id'] = template.id document.update(flashsale_doc) document.update(price_doc) document.update({"has_price_info_b": True}) self.solr().add(docs=[document], softCommit=True) template.product_variant_ids._sync_price_to_solr() template.change_solr_data('Ada perubahan pada harga product') if not document.get('has_product_info_b'): template._sync_product_template_to_solr() def solr_results(self, detail=False): solr_model = self.env['apache.solr'] pricelist = self.env.context.get('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': doc.get('flashsale_tag_s') }, '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 @api.constrains('active') def constrains_active(self): for rec in self: rec._create_solr_queue_sync_product_template()