From 35e308b24e8a9ae6c158d65c68d4a30e0be40cba Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 10 Oct 2023 09:27:49 +0700 Subject: Add sync to solr on model - promotion program - promotion program line --- indoteknik_custom/models/__init__.py | 2 +- indoteknik_custom/models/solr/__init__.py | 4 +- indoteknik_custom/models/solr/promotion_program.py | 61 +++++++++++++++++++++ .../models/solr/promotion_program_line.py | 62 ++++++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 indoteknik_custom/models/solr/promotion_program.py create mode 100644 indoteknik_custom/models/solr/promotion_program_line.py diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 95defed6..2eb4b9b9 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -81,11 +81,11 @@ from . import po_sync_price from . import base_import_import from . import product_attribute from . import mrp_production +from . import promotion from . import solr from . import cost_centre from . import account_account from . import account_move_line from . import stock_scheduler_compute -from . import promotion from . import sale_orders_multi_update from . import quotation_so_multi_update \ No newline at end of file diff --git a/indoteknik_custom/models/solr/__init__.py b/indoteknik_custom/models/solr/__init__.py index f2d13116..606c0035 100644 --- a/indoteknik_custom/models/solr/__init__.py +++ b/indoteknik_custom/models/solr/__init__.py @@ -8,4 +8,6 @@ from . import website_categories_homepage from . import x_manufactures from . import x_banner_banner from . import product_public_category -from . import x_banner_category \ No newline at end of file +from . import x_banner_category +from . import promotion_program +from . import promotion_program_line \ No newline at end of file diff --git a/indoteknik_custom/models/solr/promotion_program.py b/indoteknik_custom/models/solr/promotion_program.py new file mode 100644 index 00000000..c288c165 --- /dev/null +++ b/indoteknik_custom/models/solr/promotion_program.py @@ -0,0 +1,61 @@ +from odoo import models, api +from datetime import datetime +from pytz import timezone +from typing import Type +import pysolr + + +class PromotionProgram(models.Model): + _inherit = 'promotion.program' + _solr_schema = 'promotion_programs' + + def solr(self) -> Type[pysolr.Solr]: + return self.env['apache.solr'].connect(self._solr_schema) + + def _create_solr_queue(self, function_name: str): + for rec in self: + self.env['apache.solr.queue'].create_unique({ + 'res_model': self._name, + 'res_id': rec.id, + 'function_name': function_name + }) + + def _sync_to_solr(self): + ir_attachment = self.env['ir.attachment'] + solr_model = self.env['apache.solr'] + + for rec in self: + document = solr_model.get_doc(self._solr_schema, rec.id) + document.update({ + 'id': rec.id, + 'name_s': rec.name, + 'banner_s': ir_attachment.api_image(self._name, 'banner', rec.id) if rec.banner else '', + 'keywords': [x.name for x in rec.keyword_ids], + 'line_ids': [x.id for x in rec.program_line], + 'start_time_s': self._time_format(rec.start_time), + 'end_time_s': self._time_format(rec.end_time), + 'applies_to_s': rec.applies_to, + 'icon_s': ir_attachment.api_image(self._name, 'icon', rec.id) if rec.icon else '', + 'icon_top_s': ir_attachment.api_image(self._name, 'icon_top', rec.id) if rec.icon_top else '', + 'icon_bottom_s': ir_attachment.api_image(self._name, 'icon_bottom', rec.id) if rec.icon_bottom else '', + }) + + self.solr().add([document]) + + self.solr().commit() + + def _time_format(self, object) -> str: + time = '' + tz_jakarta = timezone('Asia/Jakarta') + if isinstance(object, datetime): + time = object.astimezone(tz_jakarta).strftime("%Y-%m-%d %H:%M:%S") + return time + + @api.model + def create(self, vals): + self._create_solr_queue('_sync_to_solr') + return super(PromotionProgram, self).create(vals) + + def write(self, vals): + self._create_solr_queue('_sync_to_solr') + return super(PromotionProgram, self).write(vals) diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py new file mode 100644 index 00000000..581783d1 --- /dev/null +++ b/indoteknik_custom/models/solr/promotion_program_line.py @@ -0,0 +1,62 @@ +from odoo import models, api +from typing import Type +import pysolr, json + + +class PromotionProgramLine(models.Model): + _inherit = 'promotion.program.line' + _solr_schema = 'promotion_program_lines' + + def solr(self) -> Type[pysolr.Solr]: + return self.env['apache.solr'].connect(self._solr_schema) + + def _create_solr_queue(self, function_name: str): + for rec in self: + self.env['apache.solr.queue'].create_unique({ + 'res_model': self._name, + 'res_id': rec.id, + 'function_name': function_name + }) + + def _sync_to_solr(self): + solr_model = self.env['apache.solr'] + + for rec in self: + document = solr_model.get_doc(self._solr_schema, rec.id) + + products = [{ + 'product_id': x.product_id.id, + 'qty': x.qty + } for x in rec.product_ids] + + free_products = [{ + 'product_id': x.product_id.id, + 'qty': x.qty + } for x in rec.free_product_ids] + + document.update({ + 'id': rec.id, + 'program_id': rec.program_id.id, + 'name_s': rec.name, + 'image_s': self.env['ir.attachment'].api_image(self._name, 'image', rec.id) if rec.image else '', + 'type_s': json.dumps(rec._res_promotion_type()), + 'package_limit_i': rec.package_limit, + 'package_limit_user_i': rec.package_limit_user, + 'package_limit_trx_i': rec.package_limit_trx, + 'price_f': rec.price, + 'products_s': json.dumps(products), + 'free_products_s': json.dumps(free_products) + }) + + self.solr().add([document]) + + self.solr().commit() + + @api.model + def create(self, vals): + self._create_solr_queue('_sync_to_solr') + return super(PromotionProgramLine, self).create(vals) + + def write(self, vals): + self._create_solr_queue('_sync_to_solr') + return super(PromotionProgramLine, self).write(vals) \ No newline at end of file -- cgit v1.2.3 From ce3f0c1b8f9fee54caf2047190151b6caf80664c Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 10 Oct 2023 09:53:01 +0700 Subject: Update program line response --- indoteknik_custom/models/solr/promotion_program_line.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py index 581783d1..e5f22e74 100644 --- a/indoteknik_custom/models/solr/promotion_program_line.py +++ b/indoteknik_custom/models/solr/promotion_program_line.py @@ -36,7 +36,7 @@ class PromotionProgramLine(models.Model): document.update({ 'id': rec.id, - 'program_id': rec.program_id.id, + 'program_id_i': rec.program_id.id, 'name_s': rec.name, 'image_s': self.env['ir.attachment'].api_image(self._name, 'image', rec.id) if rec.image else '', 'type_s': json.dumps(rec._res_promotion_type()), @@ -44,7 +44,9 @@ class PromotionProgramLine(models.Model): 'package_limit_user_i': rec.package_limit_user, 'package_limit_trx_i': rec.package_limit_trx, 'price_f': rec.price, + 'product_ids': [x.product_id.id for x in rec.product_ids], 'products_s': json.dumps(products), + 'free_product_ids': [x.product_id.id for x in rec.free_product_ids], 'free_products_s': json.dumps(free_products) }) -- cgit v1.2.3 From a4a1461c3b6603c1a4943935ed45f1a3ea9b80ed Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 10 Oct 2023 10:41:47 +0700 Subject: Add program line get stock API --- indoteknik_api/controllers/api_v1/promotion.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index f84b8c1c..221f6e10 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -6,6 +6,28 @@ from datetime import datetime class Promotion(controller.Controller): prefix = '/api/v1/' + + @http.route(prefix + 'program-line//stock', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_promotion_stock(self, id): + program_line = request.env['promotion.program.line'].browse(int(id)) + if not program_line.id: + return self.response(code=400, description='program not found') + + user_data = self.verify_user_token() + + limit_qty = program_line._res_limit_qty() + remaining_qty = program_line._get_remaining_qty(user_data) + + percent_remaining = 0 + if limit_qty['all'] > 0: + percent_remaining = (limit_qty['all'] - remaining_qty['all']) / limit_qty['all'] * 100 + + return self.response({ + 'limit_qty': limit_qty, + 'remaining_qty': remaining_qty, + 'used_percentage': percent_remaining, + }) @http.route(prefix + 'promotion/', auth='public', methods=['GET']) -- cgit v1.2.3 From 6a87e59e7220bdfa78e98b23003ccc4ef41bd0ce Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 10 Oct 2023 10:42:30 +0700 Subject: Add program and program line constrains --- indoteknik_custom/models/solr/promotion_program.py | 7 +++++++ .../models/solr/promotion_program_line.py | 24 ++++++++++++---------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/indoteknik_custom/models/solr/promotion_program.py b/indoteknik_custom/models/solr/promotion_program.py index c288c165..0d417b3e 100644 --- a/indoteknik_custom/models/solr/promotion_program.py +++ b/indoteknik_custom/models/solr/promotion_program.py @@ -59,3 +59,10 @@ class PromotionProgram(models.Model): def write(self, vals): self._create_solr_queue('_sync_to_solr') return super(PromotionProgram, self).write(vals) + + @api.constrains('program_line') + def constrains_program_line(self): + for rec in self: + for line in rec.program_line: + line._create_solr_queue('_sync_to_solr') + diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py index e5f22e74..b0aeaa13 100644 --- a/indoteknik_custom/models/solr/promotion_program_line.py +++ b/indoteknik_custom/models/solr/promotion_program_line.py @@ -1,15 +1,16 @@ from odoo import models, api from typing import Type -import pysolr, json +import pysolr +import json class PromotionProgramLine(models.Model): _inherit = 'promotion.program.line' _solr_schema = 'promotion_program_lines' - + def solr(self) -> Type[pysolr.Solr]: return self.env['apache.solr'].connect(self._solr_schema) - + def _create_solr_queue(self, function_name: str): for rec in self: self.env['apache.solr.queue'].create_unique({ @@ -17,23 +18,23 @@ class PromotionProgramLine(models.Model): 'res_id': rec.id, 'function_name': function_name }) - + def _sync_to_solr(self): solr_model = self.env['apache.solr'] for rec in self: document = solr_model.get_doc(self._solr_schema, rec.id) - + products = [{ 'product_id': x.product_id.id, 'qty': x.qty } for x in rec.product_ids] - + free_products = [{ 'product_id': x.product_id.id, 'qty': x.qty } for x in rec.free_product_ids] - + document.update({ 'id': rec.id, 'program_id_i': rec.program_id.id, @@ -47,18 +48,19 @@ class PromotionProgramLine(models.Model): 'product_ids': [x.product_id.id for x in rec.product_ids], 'products_s': json.dumps(products), 'free_product_ids': [x.product_id.id for x in rec.free_product_ids], - 'free_products_s': json.dumps(free_products) + 'free_products_s': json.dumps(free_products), + 'total_qty_i': sum([x.qty for x in rec.product_ids] + [x.qty for x in rec.free_product_ids]), }) self.solr().add([document]) self.solr().commit() - + @api.model def create(self, vals): self._create_solr_queue('_sync_to_solr') return super(PromotionProgramLine, self).create(vals) - + def write(self, vals): self._create_solr_queue('_sync_to_solr') - return super(PromotionProgramLine, self).write(vals) \ No newline at end of file + return super(PromotionProgramLine, self).write(vals) -- cgit v1.2.3 From c1f7742c254898fa5981e8ca7d870ac42d3f8346 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 8 Dec 2023 14:58:52 +0700 Subject: Update document payload for promotion program lines SOLR --- indoteknik_custom/models/solr/promotion_program_line.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py index b0aeaa13..6e182324 100644 --- a/indoteknik_custom/models/solr/promotion_program_line.py +++ b/indoteknik_custom/models/solr/promotion_program_line.py @@ -35,12 +35,15 @@ class PromotionProgramLine(models.Model): 'qty': x.qty } for x in rec.free_product_ids] + promotion_type = rec._res_promotion_type() + document.update({ 'id': rec.id, 'program_id_i': rec.program_id.id, 'name_s': rec.name, 'image_s': self.env['ir.attachment'].api_image(self._name, 'image', rec.id) if rec.image else '', - 'type_s': json.dumps(rec._res_promotion_type()), + 'type_value_s': promotion_type['value'], + 'type_label_s': promotion_type['label'], 'package_limit_i': rec.package_limit, 'package_limit_user_i': rec.package_limit_user, 'package_limit_trx_i': rec.package_limit_trx, -- cgit v1.2.3 From ad127a4dc2bfb81d9c99ba78ab41a49eefeb0dd2 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 22 Dec 2023 11:20:45 +0700 Subject: update promotion program feature --- indoteknik_api/controllers/api_v1/cart.py | 21 +++++++++++++++------ .../models/promotion/promotion_program_line.py | 7 ++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index 8ef2c1c1..907c8288 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -36,18 +36,21 @@ class Cart(controller.Controller): def create_or_update_cart(self, user_id, **kw): # Convert input values to appropriate types user_id = int(user_id) - product_id = int(kw.get('product_id', 0)) - qty = int(kw.get('qty', 0)) - source = kw.get('source') - is_selected = kw.get('selected', False) + product_id = kw.get('product_id', 0) + product_id = False if product_id == 'null' or not product_id else int(product_id) + program_line_id = kw.get('program_line_id', False) program_line_id = False if program_line_id == 'null' or not program_line_id else int(program_line_id) + qty = int(kw.get('qty', 0)) + source = kw.get('source') + + is_selected = kw.get('selected', False) is_selected = is_selected in ('true', True) # Check required fields - if not user_id or not product_id or not qty: - return self.response(code=400, description='user_id, product_id and qty is required') + if not user_id: + return self.response(code=400, description='user_id is required') website_user_cart = request.env['website.user.cart'] @@ -97,9 +100,15 @@ class Cart(controller.Controller): def delete_cart_by_user_id(self, user_id, **kw): user_id = int(user_id) query = [('user_id', '=', user_id)] + + ids = kw.get('ids') + if ids: + query += [('id', 'in', [int(x) for x in ids.split(',')])] + product_ids = kw.get('product_ids') if product_ids: query += [('product_id', 'in', [int(x) for x in product_ids.split(',')])] + cart = request.env['website.user.cart'].search(query).unlink() return self.response(cart) diff --git a/indoteknik_custom/models/promotion/promotion_program_line.py b/indoteknik_custom/models/promotion/promotion_program_line.py index 34a0fbb2..d9095c75 100644 --- a/indoteknik_custom/models/promotion/promotion_program_line.py +++ b/indoteknik_custom/models/promotion/promotion_program_line.py @@ -96,7 +96,11 @@ class PromotionProgramLine(models.Model): weight = 0 if not any(x['package_weight'] == 0 for x in merged_products): weight = sum(x['package_weight'] for x in merged_products) - + + products_total = sum(x['price']['price_discount'] * x['qty'] for x in products) + free_products_total = sum(x['price']['price_discount'] * x['qty'] for x in free_products) + package_price = products_total + free_products_total + response = { 'id': self.id, 'name': self.name, @@ -106,6 +110,7 @@ class PromotionProgramLine(models.Model): 'limit_qty': limit_qty, 'remaining_qty': remaining_qty, 'used_percentage': percent_remaining, + 'package_price': package_price, 'price': { 'price': self.price, 'price_discount': self.price, -- cgit v1.2.3 From 717cb3b43c729e265603b3df61234c0b430742a7 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 4 Jan 2024 09:25:14 +0700 Subject: update promotion program feature --- .../models/promotion/promotion_program.py | 1 + .../models/promotion/promotion_program_line.py | 9 ++++----- indoteknik_custom/models/website_user_cart.py | 20 +++++++++++++++++--- .../views/promotion/promotion_program.xml | 1 + .../views/promotion/promotion_program_line.xml | 1 - 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/indoteknik_custom/models/promotion/promotion_program.py b/indoteknik_custom/models/promotion/promotion_program.py index 29aaa753..1a1ee6bf 100644 --- a/indoteknik_custom/models/promotion/promotion_program.py +++ b/indoteknik_custom/models/promotion/promotion_program.py @@ -6,6 +6,7 @@ class PromotionProgram(models.Model): name = fields.Char(string="Name") banner = fields.Binary(string="Banner") + image = fields.Binary(string="Image") icon = fields.Binary(string="Icon", help="Image 1:1 ratio") icon_top = fields.Binary(string="Icon Top", help="Icon ini ditampilkan sebagai atribut pada atas gambar di product card pada website") icon_bottom = fields.Binary(string="Icon Bottom", help="Icon ini ditampilkan sebagai atribut pada bawah gambar di product card pada website") diff --git a/indoteknik_custom/models/promotion/promotion_program_line.py b/indoteknik_custom/models/promotion/promotion_program_line.py index d9095c75..d77123ce 100644 --- a/indoteknik_custom/models/promotion/promotion_program_line.py +++ b/indoteknik_custom/models/promotion/promotion_program_line.py @@ -13,7 +13,6 @@ class PromotionProgramLine(models.Model): ("discount_loading", "Discount Loading"), ("merchandise", "Merchandise") ], 'Type') - image = fields.Binary(string="Image") package_limit = fields.Integer('Package limit') package_limit_user = fields.Integer('Package limit / user') @@ -96,15 +95,15 @@ class PromotionProgramLine(models.Model): weight = 0 if not any(x['package_weight'] == 0 for x in merged_products): weight = sum(x['package_weight'] for x in merged_products) - - products_total = sum(x['price']['price_discount'] * x['qty'] for x in products) - free_products_total = sum(x['price']['price_discount'] * x['qty'] for x in free_products) + + # Sum of products and free products in 1 package quantity + products_total = sum(x['price']['price_discount'] * x['qty'] / qty for x in products) + free_products_total = sum(x['price']['price_discount'] * x['qty'] / qty for x in free_products) package_price = products_total + free_products_total response = { 'id': self.id, 'name': self.name, - 'image': ir_attachment.api_image(self._name, 'image', self.id), 'remaining_time': self._get_remaining_time(), 'promotion_type': self._res_promotion_type(), 'limit_qty': limit_qty, diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index bbc14c88..eaa5f009 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -51,7 +51,9 @@ class WebsiteUserCart(models.Model): return res def get_products(self): - return [x.get_product() for x in self] + products = [x.get_product() for x in self] + + return products def get_product_by_user(self, user_id, selected=False, source=False): user_id = int(user_id) @@ -75,8 +77,20 @@ class WebsiteUserCart(models.Model): def get_user_checkout(self, user_id, voucher=False, source=False): products = self.get_product_by_user(user_id=user_id, selected=True, source=source) - total_purchase = sum(x['price']['price'] * x['quantity'] for x in products) - total_discount = sum((x['price']['price'] - x['price']['price_discount']) * x['quantity'] for x in products) + + total_purchase = 0 + total_discount = 0 + for product in products: + if product['cart_type'] == 'promotion': + price = product['package_price'] * product['quantity'] + else: + price = product['price']['price'] * product['quantity'] + + discount_price = price - product['price']['price_discount'] * product['quantity'] + + total_purchase += price + total_discount += discount_price + subtotal = total_purchase - total_discount discount_voucher = 0 if voucher: diff --git a/indoteknik_custom/views/promotion/promotion_program.xml b/indoteknik_custom/views/promotion/promotion_program.xml index f8432d8a..724f80c7 100644 --- a/indoteknik_custom/views/promotion/promotion_program.xml +++ b/indoteknik_custom/views/promotion/promotion_program.xml @@ -22,6 +22,7 @@ + diff --git a/indoteknik_custom/views/promotion/promotion_program_line.xml b/indoteknik_custom/views/promotion/promotion_program_line.xml index db6d5252..346a08c9 100644 --- a/indoteknik_custom/views/promotion/promotion_program_line.xml +++ b/indoteknik_custom/views/promotion/promotion_program_line.xml @@ -23,7 +23,6 @@ - -- cgit v1.2.3