summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-08-29 11:15:58 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-08-29 11:15:58 +0700
commita1400f8ccdfb829a4193c5e8d3f910211e0d5830 (patch)
tree4211e0c4acbffba80f56c2c8e15085c22bbfadbc
parent203feb6018c55c108c31f4c0e03d38a8f39af52e (diff)
parent6ed2316f6aa446bcd5bc7e6cd4d0c0a1136096dd (diff)
Merge branch 'change/feature/sync-solr' into production
-rw-r--r--indoteknik_api/controllers/api_v1/category.py3
-rw-r--r--indoteknik_api/controllers/api_v1/product.py25
-rw-r--r--indoteknik_api/models/product_product.py11
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py2
-rw-r--r--indoteknik_custom/models/product_pricelist.py27
-rwxr-xr-xindoteknik_custom/models/product_template.py12
-rw-r--r--indoteknik_custom/models/solr/__init__.py6
-rw-r--r--indoteknik_custom/models/solr/apache_solr.py (renamed from indoteknik_custom/models/apache_solr.py)38
-rw-r--r--indoteknik_custom/models/solr/apache_solr_queue.py69
-rw-r--r--indoteknik_custom/models/solr/product_pricelist_item.py30
-rw-r--r--indoteknik_custom/models/solr/product_product.py168
-rw-r--r--indoteknik_custom/models/solr/product_template.py233
-rw-r--r--indoteknik_custom/models/solr/website_categories_homepage.py81
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/apache_solr_queue.xml74
-rw-r--r--indoteknik_custom/views/product_product.xml8
-rwxr-xr-xindoteknik_custom/views/product_template.xml12
-rw-r--r--indoteknik_custom/views/website_categories_homepage.xml10
19 files changed, 775 insertions, 36 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..e3b7701a 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,23 @@ 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:
+ 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/__manifest__.py b/indoteknik_custom/__manifest__.py
index 6d07fd05..0d38a7d7 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -92,6 +92,7 @@
'views/mail_template_po.xml',
'views/price_group.xml',
'views/mrp_production.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/__init__.py b/indoteknik_custom/models/__init__.py
index b1b22e29..cf2597b0 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
@@ -85,3 +84,4 @@ from . import po_sync_price
from . import base_import_import
from . import product_attribute
from . import mrp_production
+from . import solr
diff --git a/indoteknik_custom/models/product_pricelist.py b/indoteknik_custom/models/product_pricelist.py
index 2053accc..49368948 100644
--- a/indoteknik_custom/models/product_pricelist.py
+++ b/indoteknik_custom/models/product_pricelist.py
@@ -1,5 +1,4 @@
-from odoo import models, fields, api
-from odoo.exceptions import UserError
+from odoo import models, fields
from datetime import datetime
@@ -25,21 +24,19 @@ class ProductPricelist(models.Model):
remaining_time = round(remaining_time)
return max(remaining_time, 0)
- def update_product_solr_flag(self):
- for item in self.item_ids:
- item.product_id.product_tmpl_id.solr_flag = 2
- return {
- 'type': 'ir.actions.client',
- 'tag': 'display_notification',
- 'params': { 'title': 'Notification', 'message': f'{len(self.item_ids)} produk akan diupdate ke SOLR' }
- }
+ 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'
manufacture_id = fields.Many2one('x_manufactures', string='Manufacture')
-
- @api.constrains('fixed_price','price_discount')
- def update_product_solr_flag(self):
- for item in self:
- item.product_id.product_tmpl_id.solr_flag = 2 \ No newline at end of file
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 52f72729..d6b9fcfe 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
-from odoo.exceptions import AccessError, UserError, ValidationError
+from odoo.exceptions import UserError
import logging
import requests
import json
@@ -164,10 +164,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
@@ -264,8 +267,7 @@ class ProductTemplate(models.Model):
}
self.env['token.storage'].create([values])
return values
-
-
+
class ProductProduct(models.Model):
_inherit = "product.product"
web_price = fields.Float(
@@ -346,4 +348,4 @@ class ProductProduct(models.Model):
('start_date', '<=', current_time),
('end_date', '>=', current_time)
], limit=1)
- return pricelist \ No newline at end of file
+ return pricelist
diff --git a/indoteknik_custom/models/solr/__init__.py b/indoteknik_custom/models/solr/__init__.py
new file mode 100644
index 00000000..45ef4299
--- /dev/null
+++ b/indoteknik_custom/models/solr/__init__.py
@@ -0,0 +1,6 @@
+from . import apache_solr
+from . import apache_solr_queue
+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/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py
index 086fb6d0..518280ac 100644
--- a/indoteknik_custom/models/apache_solr.py
+++ b/indoteknik_custom/models/solr/apache_solr.py
@@ -4,6 +4,7 @@ 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)
@@ -15,6 +16,43 @@ 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_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)
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_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..48ee9daa
--- /dev/null
+++ b/indoteknik_custom/models/solr/product_product.py
@@ -0,0 +1,168 @@
+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 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']
+
+ 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_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()
+
+ 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_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()
+
+ def _sync_delete_solr(self):
+ for rec in self:
+ 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
new file mode 100644
index 00000000..6ae0bec2
--- /dev/null
+++ b/indoteknik_custom/models/solr/product_template.py
@@ -0,0 +1,233 @@
+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')
+
+ 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':
+ template._sync_delete_solr()
+ 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()
+
+ 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_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_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_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()
+
+ 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
new file mode 100644
index 00000000..1b517ae6
--- /dev/null
+++ b/indoteknik_custom/models/solr/website_categories_homepage.py
@@ -0,0 +1,81 @@
+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()
+
+ 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:
+ rec._sync_delete_solr()
+
+ 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_doc('product_category_homepage', category.id)
+ 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 '',
+ 'product_ids': [x.id for x in category.product_ids]
+ })
+ self.solr().add([document])
+ category.update_last_update_solr()
+
+ self.solr().commit()
+
+ 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 42744f35..c41587c0 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -70,3 +70,4 @@ access_price_group,access.price.group,model_price_group,,1,1,1,1
access_po_sync_price,access.po.sync.price,model_po_sync_price,,1,1,1,1
access_product_attribute_value,access.product.attribute.value,model_product_attribute_value,,1,1,1,1
access_mrp_production,access.mrp.production,model_mrp_production,,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 @@
+<odoo>
+ <record id="view_apache_solr_queue" model="ir.ui.view">
+ <field name="name">apache.solr.queue.tree</field>
+ <field name="model">apache.solr.queue</field>
+ <field name="arch" type="xml">
+ <tree editable="top" default_order="execute_date desc">
+ <field name="display_name" readonly="1" />
+ <field name="res_model" required="1" />
+ <field name="res_id" required="1" />
+ <field name="function_name" required="1" />
+ <field name="execute_status" widget="badge" readonly="1"
+ decoration-danger="execute_status == 'failed'"
+ decoration-success="execute_status == 'success'"
+ decoration-primary="execute_status == 'not_found'"
+ />
+ <field name="execute_date" readonly="1" />
+ <field name="create_date" readonly="1" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="apache_solr_queue_view_search" model="ir.ui.view">
+ <field name="name">apache.solr.queue.search</field>
+ <field name="model">apache.solr.queue</field>
+ <field name="mode">primary</field>
+ <field name="arch" type="xml">
+ <search string="Search Queue">
+ <field name="res_model"/>
+ <field name="res_id"/>
+ <field name="function_name"/>
+ <filter string="Active Queue" name="active_queue" domain="[('execute_status', '=', False)]"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="action_apache_solr_queue" model="ir.actions.act_window">
+ <field name="name">Solr Queue</field>
+ <field name="res_model">apache.solr.queue</field>
+ <field name="search_view_id" ref="apache_solr_queue_view_search"/>
+ <field name="context">{'search_default_active_queue': 1}</field>
+ <field name="view_mode">tree</field>
+ </record>
+
+ <menuitem
+ id="menu_apache_solr_queue"
+ name="Solr Queue"
+ parent="base.menu_users"
+ sequence="32"
+ action="action_apache_solr_queue"
+ />
+
+ <record id="ir_actions_server_apache_solr_queue_execute" model="ir.actions.server">
+ <field name="name">Execute</field>
+ <field name="model_id" ref="indoteknik_custom.model_apache_solr_queue"/>
+ <field name="binding_model_id" ref="indoteknik_custom.model_apache_solr_queue"/>
+ <field name="state">code</field>
+ <field name="code">records.execute_queue()</field>
+ </record>
+
+ <data noupdate="1">
+ <record id="cron_apache_solr_queue_process" model="ir.cron">
+ <field name="name">Solr Queue: Process</field>
+ <field name="interval_number">6</field>
+ <field name="interval_type">minutes</field>
+ <field name="numbercall">-1</field>
+ <field name="doall" eval="False"/>
+ <field name="model_id" ref="model_apache_solr_queue"/>
+ <field name="code">model.process_queue_item(limit=100)</field>
+ <field name="state">code</field>
+ <field name="priority">55</field>
+ <field name="active">True</field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/product_product.xml b/indoteknik_custom/views/product_product.xml
index d3ef3e15..6d547712 100644
--- a/indoteknik_custom/views/product_product.xml
+++ b/indoteknik_custom/views/product_product.xml
@@ -12,5 +12,13 @@
</field>
</field>
</record>
+
+ <record id="ir_actions_server_product_product_sync_to_solr" model="ir.actions.server">
+ <field name="name">Sync to solr</field>
+ <field name="model_id" ref="product.model_product_product"/>
+ <field name="binding_model_id" ref="product.model_product_product"/>
+ <field name="state">code</field>
+ <field name="code">model.action_sync_to_solr()</field>
+ </record>
</data>
</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml
index 558805b1..b2939867 100755
--- a/indoteknik_custom/views/product_template.xml
+++ b/indoteknik_custom/views/product_template.xml
@@ -12,6 +12,10 @@
<field name="x_model_product"/>
<field name="x_studio_field_tGhJR" widget="many2many_tags"/>
</field>
+ <field name="uom_po_id" position="after">
+ <field name="desc_update_solr" readonly="1" />
+ <field name="last_update_solr" readonly="1" />
+ </field>
<page name="inventory" position="after">
<page string="Marketplace" name="marketplace">
<group>
@@ -72,5 +76,13 @@
</field>
</field>
</record>
+
+ <record id="ir_actions_server_product_template_sync_to_solr" model="ir.actions.server">
+ <field name="name">Sync to solr</field>
+ <field name="model_id" ref="product.model_product_template"/>
+ <field name="binding_model_id" ref="product.model_product_template"/>
+ <field name="state">code</field>
+ <field name="code">model.action_sync_to_solr()</field>
+ </record>
</data>
</odoo> \ 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 0a7ef2c2..aa54ca7a 100644
--- a/indoteknik_custom/views/website_categories_homepage.xml
+++ b/indoteknik_custom/views/website_categories_homepage.xml
@@ -16,6 +16,7 @@
<field name="category_id"/>
<field name="url"/>
<field name="status"/>
+ <field name="last_update_solr"/>
</tree>
</field>
</record>
@@ -33,6 +34,7 @@
<field name="image" widget="image"/>
<field name="url"/>
<field name="status"/>
+ <field name="last_update_solr" readonly="1" />
</group>
</group>
<notebook>
@@ -49,6 +51,14 @@
</field>
</record>
+ <record id="ir_actions_server_website_categories_homepage_sync_to_solr" model="ir.actions.server">
+ <field name="name">Sync to solr</field>
+ <field name="model_id" ref="indoteknik_custom.model_website_categories_homepage"/>
+ <field name="binding_model_id" ref="indoteknik_custom.model_website_categories_homepage"/>
+ <field name="state">code</field>
+ <field name="code">model.action_sync_to_solr()</field>
+ </record>
+
<menuitem
id="website_categories_homepage"
name="Website Categories Homepage"