From 06a4478d69975b8a6eb3d228fa88708448b40a0e Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 31 May 2023 17:14:34 +0700 Subject: Promotion program feature --- indoteknik_custom/models/__init__.py | 3 + indoteknik_custom/models/promotion_program.py | 19 ++++++ .../models/promotion_program_free_item.py | 12 ++++ indoteknik_custom/models/promotion_program_line.py | 73 ++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 indoteknik_custom/models/promotion_program.py create mode 100644 indoteknik_custom/models/promotion_program_free_item.py create mode 100644 indoteknik_custom/models/promotion_program_line.py (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 18f46d34..42f011bf 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -15,6 +15,9 @@ from . import product_pricelist from . import product_public_category from . import product_spec from . import product_template +from . import promotion_program +from . import promotion_program_line +from . import promotion_program_free_item from . import purchase_order_line from . import purchase_order from . import purchase_outstanding diff --git a/indoteknik_custom/models/promotion_program.py b/indoteknik_custom/models/promotion_program.py new file mode 100644 index 00000000..7c264b65 --- /dev/null +++ b/indoteknik_custom/models/promotion_program.py @@ -0,0 +1,19 @@ +from odoo import fields, models + + +class PromotionProgram(models.Model): + _name = "promotion.program" + + name = fields.Char(string="Name") + banner = fields.Binary(string="Banner") + start_time = fields.Datetime(string="Start Time") + end_time = fields.Datetime(string="End Time") + applies_to = fields.Selection(selection=[ + ("all_user", "All User"), + ("login_user", "Login User") + ]) + program_line = fields.One2many( + comodel_name="promotion.program.line", inverse_name="program_id", string="Program Line") + + # TODO: Add search many2many tags input untuk ditampilkan ketika ada query search + # TODO: Add ribbon atas, ribbon bawah, image 1:1 \ No newline at end of file diff --git a/indoteknik_custom/models/promotion_program_free_item.py b/indoteknik_custom/models/promotion_program_free_item.py new file mode 100644 index 00000000..ddd97765 --- /dev/null +++ b/indoteknik_custom/models/promotion_program_free_item.py @@ -0,0 +1,12 @@ +from odoo import fields, models + + +class PromotionProgramFreeItem(models.Model): + _name = "promotion.program.free_item" + _rec_name = "product_id" + + product_id = fields.Many2one( + comodel_name="product.product", string="Product Variant") + qty = fields.Integer(string="Qty") + line_id = fields.Many2one( + comodel_name="promotion.program.line", string="Program Line") diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py new file mode 100644 index 00000000..3d314f76 --- /dev/null +++ b/indoteknik_custom/models/promotion_program_line.py @@ -0,0 +1,73 @@ +from odoo import fields, models, api + + +class PromotionProgramLine(models.Model): + _name = "promotion.program.line" + + name = fields.Char(string="Name") + image = fields.Binary(string="Image") + product_id = fields.Many2one( + comodel_name="product.product", string="Product Variant") + program_id = fields.Many2one( + comodel_name="promotion.program", string="Program") + discount_type = fields.Selection(selection=[ + ("percentage", "Percentage"), + ("fixed_price", "Fixed Price"), + ], string="Discount Type") + discount_amount = fields.Float(string="Discount Amount") + promotion_type = fields.Selection(selection=[ + ("specific_product", "Specific Product"), + ("bundling", "Bundling"), + ("discount_loading", "Discount Loading"), + ("merchandise", "Merchandise") + ], string="Promotion Type") + minimum_purchase_qty = fields.Integer( + string="Minimum Purchase Qty", help="Minimum Qty to applied discount loading") + applies_multiply = fields.Boolean( + string="Applies Multiply", help="Is applies multiply") + limit_qty = fields.Integer( + string="Limit Qty", help="Limit Qty product in promotion") + limit_qty_user = fields.Integer( + string="Limit Qty / User", help="Limit Qty per User") + limit_qty_transaction = fields.Integer( + string="Limit Qty / Transaction", help="Limit Qty per Transaction") + line_free_item = fields.One2many( + comodel_name="promotion.program.free_item", inverse_name="line_id", string="Line Free Item") + display_on_homepage = fields.Boolean(string="Display on Homepage") + + @api.onchange('product_id') + def _onchange_product_id(self): + if self.product_id and not self.name: + self.name = self.product_id.display_name + self._discount_loading_auto() + + @api.onchange('promotion_type') + def onchange_promotion_type(self): + self._discount_loading_auto() + + def _discount_loading_auto(self): + program_line = self + product = program_line.product_id + promotion_type = program_line.promotion_type + + if promotion_type != 'discount_loading' or not product: + return + + line = self.browse(self.ids) + line.product_id = self.product_id.id + line.promotion_type = self.promotion_type + + product_added = False + line_free_item = program_line.line_free_item + for line in line_free_item: + if line.product_id.id == product.id: + product_added = True + continue + line.unlink() + if not product_added: + data = {'product_id': product.id, + 'qty': 1, 'line_id': program_line.id} + line_free_item.create(data) + + # TODO: Add show on homepage boolean untuk priority specific product + # TODO: Discount loading otomatis membuat line dengan product_id yang sama dengan parent -- cgit v1.2.3 From db7481a490b87e3a1768112395bf096b93969562 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 7 Jun 2023 13:58:24 +0700 Subject: Add promotion program keyword and api homepage promotion --- indoteknik_custom/models/__init__.py | 1 + indoteknik_custom/models/promotion_program.py | 9 ++++++--- indoteknik_custom/models/promotion_program_keyword.py | 8 ++++++++ indoteknik_custom/models/promotion_program_line.py | 3 --- 4 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 indoteknik_custom/models/promotion_program_keyword.py (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 42f011bf..3123d608 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -18,6 +18,7 @@ from . import product_template from . import promotion_program from . import promotion_program_line from . import promotion_program_free_item +from . import promotion_program_keyword from . import purchase_order_line from . import purchase_order from . import purchase_outstanding diff --git a/indoteknik_custom/models/promotion_program.py b/indoteknik_custom/models/promotion_program.py index 7c264b65..bc7f2c49 100644 --- a/indoteknik_custom/models/promotion_program.py +++ b/indoteknik_custom/models/promotion_program.py @@ -6,6 +6,9 @@ class PromotionProgram(models.Model): name = fields.Char(string="Name") banner = fields.Binary(string="Banner") + 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") start_time = fields.Datetime(string="Start Time") end_time = fields.Datetime(string="End Time") applies_to = fields.Selection(selection=[ @@ -14,6 +17,6 @@ class PromotionProgram(models.Model): ]) program_line = fields.One2many( comodel_name="promotion.program.line", inverse_name="program_id", string="Program Line") - - # TODO: Add search many2many tags input untuk ditampilkan ketika ada query search - # TODO: Add ribbon atas, ribbon bawah, image 1:1 \ No newline at end of file + keywords = fields.One2many( + comodel_name="promotion.program.keyword", inverse_name="program_id", string="Keywords" + ) diff --git a/indoteknik_custom/models/promotion_program_keyword.py b/indoteknik_custom/models/promotion_program_keyword.py new file mode 100644 index 00000000..79b938e2 --- /dev/null +++ b/indoteknik_custom/models/promotion_program_keyword.py @@ -0,0 +1,8 @@ +from odoo import fields, models + + +class PromotionProgramKeyword(models.Model): + _name = "promotion.program.keyword" + + name = fields.Char(string="Keyword") + program_id = fields.Many2one(comodel_name="promotion.program") diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index 3d314f76..a8ee2c43 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -68,6 +68,3 @@ class PromotionProgramLine(models.Model): data = {'product_id': product.id, 'qty': 1, 'line_id': program_line.id} line_free_item.create(data) - - # TODO: Add show on homepage boolean untuk priority specific product - # TODO: Discount loading otomatis membuat line dengan product_id yang sama dengan parent -- cgit v1.2.3 From 1f2995a85428ac4335123bd33d48ae17d3c9f36f Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Mon, 12 Jun 2023 08:22:10 +0700 Subject: Update promotion program feature --- indoteknik_custom/models/ir_attachment.py | 5 +++++ indoteknik_custom/models/promotion_program_line.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/ir_attachment.py b/indoteknik_custom/models/ir_attachment.py index fd86ab1b..6417fa3f 100644 --- a/indoteknik_custom/models/ir_attachment.py +++ b/indoteknik_custom/models/ir_attachment.py @@ -22,4 +22,9 @@ class Attachment(models.Model): def api_image(self, model, field, id): base_url = self.env['ir.config_parameter'].get_param('web.base.url') is_found = self.is_found(model, field, id) + return base_url + 'api/image/' + model + '/' + field + '/' + str(id) if is_found else '' + + def api_image_local(self, model, field, id): + base_url = self.env['ir.config_parameter'].get_param('web.base.local_url') + is_found = self.is_found(model, field, id) return base_url + 'api/image/' + model + '/' + field + '/' + str(id) if is_found else '' \ No newline at end of file diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index a8ee2c43..b6c9a532 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -16,7 +16,7 @@ class PromotionProgramLine(models.Model): ], string="Discount Type") discount_amount = fields.Float(string="Discount Amount") promotion_type = fields.Selection(selection=[ - ("specific_product", "Specific Product"), + ("special_price", "Special Price"), ("bundling", "Bundling"), ("discount_loading", "Discount Loading"), ("merchandise", "Merchandise") -- cgit v1.2.3 From bc6bc85f455c4b8bc9f73b779b521faa5fcdcf96 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 15 Jun 2023 16:48:29 +0700 Subject: Update user cart model and API --- indoteknik_custom/models/website_user_cart.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index 8046469f..dcd9fa5a 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -5,6 +5,27 @@ class WebsiteUserCart(models.Model): _name = 'website.user.cart' _rec_name = 'user_id' - user_id = fields.Many2one('res.users', string='User', help="User ID yang terdaftar di table res.users") - product_id = fields.Many2one('product.product', string='Product', help="Product yang terdaftar di table product.product") + user_id = fields.Many2one('res.users', string='User') + product_id = fields.Many2one('product.product', string='Product') + program_line_id = fields.Many2one('promotion.program.line', string='Program', help="Apply program") qty = fields.Float(string='Quantity', digits='Product Unit of Measure') + is_selected = fields.Boolean(string='Selected?', digits='Is selected to process checkout') + + def get_product(self): + product_product = self.env['product.product'] + product = product_product.v2_api_single_response(self.product_id) + product['quantity'] = self.qty + product['subtotal'] = self.qty * product['price']['price_discount'] + product['selected'] = self.is_selected + return product + + def get_product_by_user(self, user_id, selected = False): + user_id = int(user_id) + parameters = [('user_id', '=', user_id)] + if selected: + parameters.append(('is_selected', '=', True)) + carts = self.search(parameters) + products = [] + for cart in carts: + products.append(cart.get_product()) + return products \ No newline at end of file -- cgit v1.2.3 From 329668e82ca9e4ebd2ee93d6670380abf6ed6377 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 22 Jun 2023 13:43:42 +0700 Subject: Add program line to order line relation, update remaining_qty response on get product promotion api, show order line on program line --- indoteknik_custom/models/promotion_program_line.py | 51 ++++++++++++++++++++++ indoteknik_custom/models/sale_order.py | 1 + 2 files changed, 52 insertions(+) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index b6c9a532..8d80bfb0 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -1,4 +1,5 @@ from odoo import fields, models, api +from datetime import datetime class PromotionProgramLine(models.Model): @@ -34,6 +35,7 @@ class PromotionProgramLine(models.Model): line_free_item = fields.One2many( comodel_name="promotion.program.free_item", inverse_name="line_id", string="Line Free Item") display_on_homepage = fields.Boolean(string="Display on Homepage") + order_line_ids = fields.One2many('sale.order.line', 'program_line_id') @api.onchange('product_id') def _onchange_product_id(self): @@ -68,3 +70,52 @@ class PromotionProgramLine(models.Model): data = {'product_id': product.id, 'qty': 1, 'line_id': program_line.id} line_free_item.create(data) + + def get_active_promotions(self, product_id): + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + return self.search([ + ('program_id.start_time', '<=', current_time), + ('program_id.end_time', '>=', current_time), + ('product_id', '=', product_id) + ]) + + def get_remaining_qty(self, line, user): + remaining_qty = { + 'all': line.limit_qty, + 'user': line.limit_qty_user, + 'transaction': line.limit_qty_transaction + } + for order in line.order_line_ids: + parent_order = order.order_id + if parent_order.state != 'cancel': + remaining_qty['all'] -= order.product_uom_qty + if parent_order.partner_id.id == user['partner_id']: + remaining_qty['user'] -= order.product_uom_qty + + if remaining_qty['all'] < remaining_qty['user']: + remaining_qty['user'] = remaining_qty['all'] + if remaining_qty['user'] < remaining_qty['transaction']: + remaining_qty['transaction'] = remaining_qty['user'] + + return remaining_qty + + def res_format(self, lines, user): + ir_attachment = self.env['ir.attachment'] + data = [] + for line in lines: + data.append({ + 'id': line.id, + 'name': line.name, + 'image': ir_attachment.api_image('promotion.program.line', 'image', line.id), + 'type': line.promotion_type, + 'minimum_purchase_qty': line.minimum_purchase_qty, + 'applies_multiply': line.applies_multiply, + 'limit_qty': { + 'all': line.limit_qty, + 'user': line.limit_qty_user, + 'transaction': line.limit_qty_transaction, + }, + 'remaining_qty': self.get_remaining_qty(line, user), + }) + return data + diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index cbc6a60a..f8826fab 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -459,6 +459,7 @@ class SaleOrderLine(models.Model): delivery_amt_line = fields.Float('DeliveryAmtLine', compute='compute_delivery_amt_line') fee_third_party_line = fields.Float('FeeThirdPartyLine', compute='compute_fee_third_party_line', default=0) line_no = fields.Integer('No', default=0, copy=False) + program_line_id = fields.Many2one('promotion.program.line', 'Program Line') def compute_item_margin(self): for line in self: -- cgit v1.2.3 From 751a3684ebf54521daa2edc9f62fca8131c9d653 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 22 Jun 2023 14:32:14 +0700 Subject: Add type value, label and remaining_time on program --- indoteknik_custom/models/promotion_program_line.py | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index 8d80bfb0..e6f2f0ea 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -79,17 +79,17 @@ class PromotionProgramLine(models.Model): ('product_id', '=', product_id) ]) - def get_remaining_qty(self, line, user): + def _get_remaining_qty(self, user): remaining_qty = { - 'all': line.limit_qty, - 'user': line.limit_qty_user, - 'transaction': line.limit_qty_transaction + 'all': self.limit_qty, + 'user': self.limit_qty_user, + 'transaction': self.limit_qty_transaction } - for order in line.order_line_ids: + for order in self.order_line_ids: parent_order = order.order_id if parent_order.state != 'cancel': remaining_qty['all'] -= order.product_uom_qty - if parent_order.partner_id.id == user['partner_id']: + if user and parent_order.partner_id.id == user['partner_id']: remaining_qty['user'] -= order.product_uom_qty if remaining_qty['all'] < remaining_qty['user']: @@ -99,6 +99,10 @@ class PromotionProgramLine(models.Model): return remaining_qty + def _get_remaining_time(self): + calculate_time = self.program_id.end_time - datetime.now() + return round(calculate_time.total_seconds()) + def res_format(self, lines, user): ir_attachment = self.env['ir.attachment'] data = [] @@ -107,15 +111,19 @@ class PromotionProgramLine(models.Model): 'id': line.id, 'name': line.name, 'image': ir_attachment.api_image('promotion.program.line', 'image', line.id), - 'type': line.promotion_type, + 'type': { + 'value': line.promotion_type, + 'label': dict(self._fields['promotion_type'].selection).get(line.promotion_type) + }, 'minimum_purchase_qty': line.minimum_purchase_qty, 'applies_multiply': line.applies_multiply, + 'remaining_time': line._get_remaining_time(), 'limit_qty': { 'all': line.limit_qty, 'user': line.limit_qty_user, 'transaction': line.limit_qty_transaction, }, - 'remaining_qty': self.get_remaining_qty(line, user), + 'remaining_qty': line._get_remaining_qty(user), }) return data -- cgit v1.2.3 From ae998f145e4f8b4a0939a97c02e70564ef758e73 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 22 Jun 2023 16:00:25 +0700 Subject: Refactor get promotion by product API --- indoteknik_custom/models/promotion_program_line.py | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index e6f2f0ea..3e419ef9 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -103,6 +103,19 @@ class PromotionProgramLine(models.Model): calculate_time = self.program_id.end_time - datetime.now() return round(calculate_time.total_seconds()) + def _res_limit_qty(self): + return { + 'all': self.limit_qty, + 'user': self.limit_qty_user, + 'transaction': self.limit_qty_transaction, + } + + def _res_promotion_type(self): + return { + 'value': self.promotion_type, + 'label': dict(self._fields['promotion_type'].selection).get(self.promotion_type) + } + def res_format(self, lines, user): ir_attachment = self.env['ir.attachment'] data = [] @@ -111,18 +124,11 @@ class PromotionProgramLine(models.Model): 'id': line.id, 'name': line.name, 'image': ir_attachment.api_image('promotion.program.line', 'image', line.id), - 'type': { - 'value': line.promotion_type, - 'label': dict(self._fields['promotion_type'].selection).get(line.promotion_type) - }, 'minimum_purchase_qty': line.minimum_purchase_qty, 'applies_multiply': line.applies_multiply, 'remaining_time': line._get_remaining_time(), - 'limit_qty': { - 'all': line.limit_qty, - 'user': line.limit_qty_user, - 'transaction': line.limit_qty_transaction, - }, + 'type': line._res_promotion_type(), + 'limit_qty': line._res_limit_qty(), 'remaining_qty': line._get_remaining_qty(user), }) return data -- cgit v1.2.3 From 23014336a1fe1fe5ef54fad30cf6c3d9cc59b2d8 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 23 Jun 2023 11:20:52 +0700 Subject: Update response price di product promotion API, Membuat fungsi calculate price promotion, Refactor promotion homepage, Refactor fungsi calculate product price --- indoteknik_custom/models/promotion_program_line.py | 43 ++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index 3e419ef9..c888f01a 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -71,6 +71,16 @@ class PromotionProgramLine(models.Model): 'qty': 1, 'line_id': program_line.id} line_free_item.create(data) + def calculate_price(self, price): + initial_price = price['price'] + if self.discount_type == 'percentage': + price['discount_percentage'] = self.discount_amount + price['price_discount'] = initial_price - (initial_price * self.discount_amount / 100) + elif self.discount_type == 'fixed_price': + price['price_discount'] = self.discount_amount + price['discount_percentage'] = round((initial_price - self.discount_amount) / initial_price * 100) + return price + def get_active_promotions(self, product_id): current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') return self.search([ @@ -116,20 +126,23 @@ class PromotionProgramLine(models.Model): 'label': dict(self._fields['promotion_type'].selection).get(self.promotion_type) } - def res_format(self, lines, user): + def format(self, user = None, pricelist = False): ir_attachment = self.env['ir.attachment'] - data = [] - for line in lines: - data.append({ - 'id': line.id, - 'name': line.name, - 'image': ir_attachment.api_image('promotion.program.line', 'image', line.id), - 'minimum_purchase_qty': line.minimum_purchase_qty, - 'applies_multiply': line.applies_multiply, - 'remaining_time': line._get_remaining_time(), - 'type': line._res_promotion_type(), - 'limit_qty': line._res_limit_qty(), - 'remaining_qty': line._get_remaining_qty(user), - }) + product_price = self.product_id.calculate_website_price(pricelist=pricelist) + return { + 'id': self.id, + 'name': self.name, + 'image': ir_attachment.api_image('promotion.program.line', 'image', self.id), + 'minimum_purchase_qty': self.minimum_purchase_qty, + 'applies_multiply': self.applies_multiply, + 'remaining_time': self._get_remaining_time(), + 'type': self._res_promotion_type(), + 'limit_qty': self._res_limit_qty(), + 'remaining_qty': self._get_remaining_qty(user), + 'price': self.calculate_price(price=product_price) + } + + def res_format(self, user, pricelist): + data = [x.format(user, pricelist=pricelist) for x in self] return data - + -- cgit v1.2.3 From 3ed54712ca9856f3be937f8325db030d0796532e Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 23 Jun 2023 14:19:38 +0700 Subject: Refactor pricelist on product price --- indoteknik_custom/models/promotion_program_line.py | 12 ++++++++---- indoteknik_custom/models/website_user_cart.py | 14 +++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index c888f01a..55331aea 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -126,9 +126,9 @@ class PromotionProgramLine(models.Model): 'label': dict(self._fields['promotion_type'].selection).get(self.promotion_type) } - def format(self, user = None, pricelist = False): + def format(self, user = None): ir_attachment = self.env['ir.attachment'] - product_price = self.product_id.calculate_website_price(pricelist=pricelist) + product_price = self.product_id.calculate_website_price() return { 'id': self.id, 'name': self.name, @@ -142,7 +142,11 @@ class PromotionProgramLine(models.Model): 'price': self.calculate_price(price=product_price) } - def res_format(self, user, pricelist): - data = [x.format(user, pricelist=pricelist) for x in self] + def res_format(self, user): + data = [x.format(user) for x in self] + return data + + def res_format_cart(self, user): + data = self.format(user) return data diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index dcd9fa5a..388151ab 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -12,12 +12,22 @@ class WebsiteUserCart(models.Model): is_selected = fields.Boolean(string='Selected?', digits='Is selected to process checkout') def get_product(self): + user_data = { + 'partner_id': self.user_id.partner_id.id, + 'user_id': self.user_id.id + } product_product = self.env['product.product'] product = product_product.v2_api_single_response(self.product_id) product['quantity'] = self.qty product['subtotal'] = self.qty * product['price']['price_discount'] product['selected'] = self.is_selected + product['program'] = None + if self.program_line_id: + product['program'] = self.program_line_id.res_format_cart(user_data) return product + + def get_products(self): + return [x.get_product() for x in self] def get_product_by_user(self, user_id, selected = False): user_id = int(user_id) @@ -25,7 +35,5 @@ class WebsiteUserCart(models.Model): if selected: parameters.append(('is_selected', '=', True)) carts = self.search(parameters) - products = [] - for cart in carts: - products.append(cart.get_product()) + products = carts.get_products() return products \ No newline at end of file -- cgit v1.2.3 From 80da0a90852cc589f5e2f10cc1b7df1c48ddb0b2 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 23 Jun 2023 16:48:08 +0700 Subject: Add used percentage on program line response --- indoteknik_custom/models/promotion_program_line.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index 55331aea..e300a5d1 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -129,6 +129,9 @@ class PromotionProgramLine(models.Model): def format(self, user = None): ir_attachment = self.env['ir.attachment'] product_price = self.product_id.calculate_website_price() + limit_qty = self._res_limit_qty() + remaining_qty = self._get_remaining_qty(user) + percent_remaining = (remaining_qty['all'] - limit_qty['all']) / remaining_qty['all'] return { 'id': self.id, 'name': self.name, @@ -137,8 +140,9 @@ class PromotionProgramLine(models.Model): 'applies_multiply': self.applies_multiply, 'remaining_time': self._get_remaining_time(), 'type': self._res_promotion_type(), - 'limit_qty': self._res_limit_qty(), - 'remaining_qty': self._get_remaining_qty(user), + 'limit_qty': limit_qty, + 'remaining_qty': remaining_qty, + 'percent_remaining': percent_remaining, 'price': self.calculate_price(price=product_price) } -- cgit v1.2.3 From 6fbfc93c2297bfa4dcf870ec4d57017d602a5f27 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 23 Jun 2023 16:55:42 +0700 Subject: Fix used_percentage on program line response --- indoteknik_custom/models/promotion_program_line.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index e300a5d1..3ab9b2c0 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -131,7 +131,7 @@ class PromotionProgramLine(models.Model): product_price = self.product_id.calculate_website_price() limit_qty = self._res_limit_qty() remaining_qty = self._get_remaining_qty(user) - percent_remaining = (remaining_qty['all'] - limit_qty['all']) / remaining_qty['all'] + percent_remaining = (limit_qty['all'] - remaining_qty['all']) / limit_qty['all'] * 100 return { 'id': self.id, 'name': self.name, @@ -142,7 +142,7 @@ class PromotionProgramLine(models.Model): 'type': self._res_promotion_type(), 'limit_qty': limit_qty, 'remaining_qty': remaining_qty, - 'percent_remaining': percent_remaining, + 'used_percentage': percent_remaining, 'price': self.calculate_price(price=product_price) } -- cgit v1.2.3 From d418bd8dd84b91b9dc031819cfa9a2446e77acd2 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sat, 24 Jun 2023 11:22:54 +0700 Subject: Fixing percent remaining on program line --- indoteknik_custom/models/promotion_program_line.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index 3ab9b2c0..7aaff4c4 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -131,7 +131,9 @@ class PromotionProgramLine(models.Model): product_price = self.product_id.calculate_website_price() limit_qty = self._res_limit_qty() remaining_qty = self._get_remaining_qty(user) - percent_remaining = (limit_qty['all'] - remaining_qty['all']) / limit_qty['all'] * 100 + percent_remaining = 0 + if limit_qty['all'] > 0: + percent_remaining = (limit_qty['all'] - remaining_qty['all']) / limit_qty['all'] * 100 return { 'id': self.id, 'name': self.name, -- cgit v1.2.3 From d5319d565a4b40cc6fe5b7fa8f9abc507f09e752 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 14 Jul 2023 17:02:27 +0700 Subject: Add amount voucher on sale order and update api --- indoteknik_custom/models/sale_order.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index e54b9ae2..1bdc0cb6 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -87,6 +87,7 @@ class SaleOrder(models.Model): npwp = fields.Char(string="NPWP") purchase_total = fields.Monetary(string='Purchase Total', compute='_compute_purchase_total') voucher_id = fields.Many2one(comodel_name='voucher', string='Voucher') + amount_voucher_disc = fields.Float(string='Voucher Discount') def _compute_purchase_total(self): for order in self: @@ -586,6 +587,7 @@ class SaleOrderLine(models.Model): line_no = fields.Integer('No', default=0, copy=False) note_procurement = fields.Char(string='Note', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring") vendor_subtotal = fields.Float(string='Vendor Subtotal', compute="_compute_vendor_subtotal") + amount_voucher_disc = fields.Float(string='Voucher Discount') def _compute_vendor_subtotal(self): for line in self: -- cgit v1.2.3 From d966917a5ba95074b6773f49fcb2c3c924296029 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 18 Jul 2023 16:38:29 +0700 Subject: Fix lost merge voucher with promotion program --- indoteknik_custom/models/promotion_program.py | 7 ++----- .../models/promotion_program_free_item.py | 6 ++---- indoteknik_custom/models/promotion_program_line.py | 24 ++++++++-------------- indoteknik_custom/models/website_user_cart.py | 13 +++++++++--- 4 files changed, 22 insertions(+), 28 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/promotion_program.py b/indoteknik_custom/models/promotion_program.py index bc7f2c49..e60f48e1 100644 --- a/indoteknik_custom/models/promotion_program.py +++ b/indoteknik_custom/models/promotion_program.py @@ -15,8 +15,5 @@ class PromotionProgram(models.Model): ("all_user", "All User"), ("login_user", "Login User") ]) - program_line = fields.One2many( - comodel_name="promotion.program.line", inverse_name="program_id", string="Program Line") - keywords = fields.One2many( - comodel_name="promotion.program.keyword", inverse_name="program_id", string="Keywords" - ) + program_line = fields.One2many(comodel_name="promotion.program.line", inverse_name="program_id", string="Program Line") + keywords = fields.One2many(comodel_name="promotion.program.keyword", inverse_name="program_id", string="Keywords") diff --git a/indoteknik_custom/models/promotion_program_free_item.py b/indoteknik_custom/models/promotion_program_free_item.py index ddd97765..705456dd 100644 --- a/indoteknik_custom/models/promotion_program_free_item.py +++ b/indoteknik_custom/models/promotion_program_free_item.py @@ -5,8 +5,6 @@ class PromotionProgramFreeItem(models.Model): _name = "promotion.program.free_item" _rec_name = "product_id" - product_id = fields.Many2one( - comodel_name="product.product", string="Product Variant") + product_id = fields.Many2one(comodel_name="product.product", string="Product Variant") qty = fields.Integer(string="Qty") - line_id = fields.Many2one( - comodel_name="promotion.program.line", string="Program Line") + line_id = fields.Many2one(comodel_name="promotion.program.line", string="Program Line") diff --git a/indoteknik_custom/models/promotion_program_line.py b/indoteknik_custom/models/promotion_program_line.py index 7aaff4c4..077f7e12 100644 --- a/indoteknik_custom/models/promotion_program_line.py +++ b/indoteknik_custom/models/promotion_program_line.py @@ -7,10 +7,8 @@ class PromotionProgramLine(models.Model): name = fields.Char(string="Name") image = fields.Binary(string="Image") - product_id = fields.Many2one( - comodel_name="product.product", string="Product Variant") - program_id = fields.Many2one( - comodel_name="promotion.program", string="Program") + product_id = fields.Many2one(comodel_name="product.product", string="Product Variant") + program_id = fields.Many2one(comodel_name="promotion.program", string="Program") discount_type = fields.Selection(selection=[ ("percentage", "Percentage"), ("fixed_price", "Fixed Price"), @@ -22,18 +20,12 @@ class PromotionProgramLine(models.Model): ("discount_loading", "Discount Loading"), ("merchandise", "Merchandise") ], string="Promotion Type") - minimum_purchase_qty = fields.Integer( - string="Minimum Purchase Qty", help="Minimum Qty to applied discount loading") - applies_multiply = fields.Boolean( - string="Applies Multiply", help="Is applies multiply") - limit_qty = fields.Integer( - string="Limit Qty", help="Limit Qty product in promotion") - limit_qty_user = fields.Integer( - string="Limit Qty / User", help="Limit Qty per User") - limit_qty_transaction = fields.Integer( - string="Limit Qty / Transaction", help="Limit Qty per Transaction") - line_free_item = fields.One2many( - comodel_name="promotion.program.free_item", inverse_name="line_id", string="Line Free Item") + minimum_purchase_qty = fields.Integer(string="Minimum Purchase Qty", help="Minimum Qty to applied discount loading") + applies_multiply = fields.Boolean(string="Applies Multiply", help="Is applies multiply") + limit_qty = fields.Integer(string="Limit Qty", help="Limit Qty product in promotion") + limit_qty_user = fields.Integer(string="Limit Qty / User", help="Limit Qty per User") + limit_qty_transaction = fields.Integer(string="Limit Qty / Transaction", help="Limit Qty per Transaction") + line_free_item = fields.One2many(comodel_name="promotion.program.free_item", inverse_name="line_id", string="Line Free Item") display_on_homepage = fields.Boolean(string="Display on Homepage") order_line_ids = fields.One2many('sale.order.line', 'program_line_id') diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index 388151ab..a8cde228 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -16,14 +16,21 @@ class WebsiteUserCart(models.Model): 'partner_id': self.user_id.partner_id.id, 'user_id': self.user_id.id } - product_product = self.env['product.product'] - product = product_product.v2_api_single_response(self.product_id) + product = self.product_id.v2_api_single_response(self.product_id) + product['cart_id'] = self.id product['quantity'] = self.qty product['subtotal'] = self.qty * product['price']['price_discount'] product['selected'] = self.is_selected product['program'] = None + product['can_buy'] = True if self.program_line_id: - product['program'] = self.program_line_id.res_format_cart(user_data) + product['program'] = self.program_line_id.res_format_cart(user=user_data, quantity=self.qty) + + if product['program']: + if self.qty < product['program']['minimum_purchase_qty'] or self.qty > product['program']['remaining_qty']['transaction']: + product['can_buy'] = False + product['price'] = product['program']['price'] + return product def get_products(self): -- cgit v1.2.3 From 7b76facc6b7fdbff83a98a1b3251f1d3dad48937 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 20 Jul 2023 10:42:32 +0700 Subject: Add get_user_checkout on user cart --- indoteknik_custom/models/website_user_cart.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index a8cde228..802dbd37 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -43,4 +43,27 @@ class WebsiteUserCart(models.Model): parameters.append(('is_selected', '=', True)) carts = self.search(parameters) products = carts.get_products() - return products \ No newline at end of file + return products + + def get_user_checkout(self, user_id): + products = self.get_product_by_user(user_id=user_id, selected=True) + 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) + subtotal = total_purchase - total_discount + tax = round(subtotal * 0.11) + grand_total = subtotal + tax + total_weight = sum(x['weight'] * x['quantity'] for x in products) + result = { + 'total_purchase': total_purchase, + 'total_discount': total_discount, + 'subtotal': subtotal, + 'tax': tax, + 'grand_total': round(grand_total), + 'total_weight': { + 'kg': total_weight, + 'g': total_weight * 1000 + }, + 'has_product_without_weight': any(not product.get('weight') or product.get('weight') == 0 for product in products), + 'products': products + } + return result \ No newline at end of file -- cgit v1.2.3 From 3c9ef63acb42298d948ee86407d9a5ca67004246 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 20 Jul 2023 11:20:21 +0700 Subject: Add discount_voucher on get checkout data API --- indoteknik_custom/models/website_user_cart.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index 802dbd37..29bf4291 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -45,17 +45,22 @@ class WebsiteUserCart(models.Model): products = carts.get_products() return products - def get_user_checkout(self, user_id): + def get_user_checkout(self, user_id, voucher=False): products = self.get_product_by_user(user_id=user_id, selected=True) 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) subtotal = total_purchase - total_discount + discount_voucher = 0 + if voucher: + discount_voucher = voucher.calculate_discount(subtotal) + subtotal -= discount_voucher tax = round(subtotal * 0.11) grand_total = subtotal + tax total_weight = sum(x['weight'] * x['quantity'] for x in products) result = { 'total_purchase': total_purchase, 'total_discount': total_discount, + 'discount_voucher': discount_voucher, 'subtotal': subtotal, 'tax': tax, 'grand_total': round(grand_total), -- cgit v1.2.3 From da2389775171d288b96958651a45f07865a2e014 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 21 Jul 2023 11:06:58 +0700 Subject: Update voucher use manufacture rules --- indoteknik_custom/models/voucher.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py index b327df6d..1cdf88c4 100644 --- a/indoteknik_custom/models/voucher.py +++ b/indoteknik_custom/models/voucher.py @@ -1,5 +1,6 @@ -from odoo import models, fields +from odoo import models, fields, api from datetime import datetime, timedelta +from odoo.exceptions import ValidationError class Voucher(models.Model): @@ -37,6 +38,14 @@ class Voucher(models.Model): min_purchase_amount = fields.Integer(string='Min. Purchase Amount', help='Nominal minimum untuk dapat menggunakan voucher. Isi 0 jika tidak ada minimum purchase amount') max_discount_amount = fields.Integer(string='Max. Discount Amount', help='Max nominal terhadap persentase diskon') order_ids = fields.One2many('sale.order', 'voucher_id', string='Order') + limit = fields.Integer(string='Limit', help='Voucher limit by sale order. Masukan 0 untuk tanpa limit') + manufacture_ids = fields.Many2many('x_manufactures', string='Brands', help='Voucher appplied only for brand') + + @api.constrains('description') + def _check_description_length(self): + for record in self: + if len(record.description) > 120: + raise ValidationError('Description cannot exceed 120 characters') def _compute_display_name(self): for voucher in self: @@ -50,6 +59,12 @@ class Voucher(models.Model): ir_attachment = self.env['ir.attachment'] discount_type = self.discount_type max_discount_amount = self.max_discount_amount if discount_type == 'percentage' else 0 + manufactures = [] + for manufacture in self.manufacture_ids: + manufactures.append({ + 'id': manufacture.id, + 'name': manufacture.x_name, + }) data = { 'id': self.id, 'image': ir_attachment.api_image('voucher', 'image', self.id), @@ -61,6 +76,7 @@ class Voucher(models.Model): 'remaining_time': self._res_remaining_time(), 'min_purchase_amount': self.min_purchase_amount, 'max_discount_amount': max_discount_amount, + 'manufactures': manufactures } return data -- cgit v1.2.3 From f58e8b41012f692b7995026b9869d7c07763b250 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 21 Jul 2023 11:20:34 +0700 Subject: Update voucher manufacture response --- indoteknik_custom/models/voucher.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py index 1cdf88c4..839a5d47 100644 --- a/indoteknik_custom/models/voucher.py +++ b/indoteknik_custom/models/voucher.py @@ -59,12 +59,6 @@ class Voucher(models.Model): ir_attachment = self.env['ir.attachment'] discount_type = self.discount_type max_discount_amount = self.max_discount_amount if discount_type == 'percentage' else 0 - manufactures = [] - for manufacture in self.manufacture_ids: - manufactures.append({ - 'id': manufacture.id, - 'name': manufacture.x_name, - }) data = { 'id': self.id, 'image': ir_attachment.api_image('voucher', 'image', self.id), @@ -76,7 +70,8 @@ class Voucher(models.Model): 'remaining_time': self._res_remaining_time(), 'min_purchase_amount': self.min_purchase_amount, 'max_discount_amount': max_discount_amount, - 'manufactures': manufactures + 'manufacture_names': ", ".join([x.x_name for x in self.manufacture_ids]), + 'manufacture_ids': [x.id for x in self.manufacture_ids] } return data -- cgit v1.2.3 From bc0c9e782140d82dc2147afb4a049c37141b081a Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 21 Jul 2023 17:03:15 +0700 Subject: Add exclude voucher pricelist API --- indoteknik_custom/models/voucher.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py index 839a5d47..b3a55499 100644 --- a/indoteknik_custom/models/voucher.py +++ b/indoteknik_custom/models/voucher.py @@ -40,11 +40,12 @@ class Voucher(models.Model): order_ids = fields.One2many('sale.order', 'voucher_id', string='Order') limit = fields.Integer(string='Limit', help='Voucher limit by sale order. Masukan 0 untuk tanpa limit') manufacture_ids = fields.Many2many('x_manufactures', string='Brands', help='Voucher appplied only for brand') + excl_pricelist_ids = fields.Many2many('product.pricelist', string='Excluded Pricelists', help='Hide voucher from selected exclude pricelist') @api.constrains('description') def _check_description_length(self): for record in self: - if len(record.description) > 120: + if record.description and len(record.description) > 120: raise ValidationError('Description cannot exceed 120 characters') def _compute_display_name(self): @@ -71,7 +72,8 @@ class Voucher(models.Model): 'min_purchase_amount': self.min_purchase_amount, 'max_discount_amount': max_discount_amount, 'manufacture_names': ", ".join([x.x_name for x in self.manufacture_ids]), - 'manufacture_ids': [x.id for x in self.manufacture_ids] + 'manufacture_ids': [x.id for x in self.manufacture_ids], + 'excl_pricelist_ids': [x.id for x in self.excl_pricelist_ids], } return data -- cgit v1.2.3 From 30909e82d7ff1f3cac4700e284f80552a0d38523 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Mon, 24 Jul 2023 10:30:22 +0700 Subject: Delete unused model --- indoteknik_custom/models/typesense_client.py | 150 --------------------------- 1 file changed, 150 deletions(-) delete mode 100644 indoteknik_custom/models/typesense_client.py (limited to 'indoteknik_custom/models') diff --git a/indoteknik_custom/models/typesense_client.py b/indoteknik_custom/models/typesense_client.py deleted file mode 100644 index fccd04e3..00000000 --- a/indoteknik_custom/models/typesense_client.py +++ /dev/null @@ -1,150 +0,0 @@ -from odoo import models -import typesense -import logging -import time - - -_logger = logging.getLogger(__name__) -_typesense = typesense.Client({ - 'nodes': [{ - 'host': 'localhost', - 'port': '9090', - 'protocol': 'http' - }], - 'api_key': 'WKWKdwakdjopwakfoij21321fkdmvaskamd' -}) - -class Typesense(models.Model): - _name = 'typesense.client' - - def _check_collection(self, name): - collections = _typesense.collections.retrieve() - for collection in collections: - if collection['name'] == name: - return True - return False - - def _init_collection(self, name): - is_exist = self._check_collection(name) - if is_exist: - return False - - schema = { - "name": name, - "fields": [ - {"name": ".*", "type": "auto" }, - {"name": ".*_facet", "type": "auto", "facet": True } - ] - } - _typesense.collections.create(schema) - return True - - def _indexing_product(self, limit=500): - start_time = time.time() - self._init_collection('products') - - query = ["&", "&", ("type", "=", "product"), ("active", "=", True), "|", ("solr_flag", "=", 0), ("solr_flag", "=", 2)] - product_templates = self.env['product.template'].search(query, limit=limit) - - counter = 0 - documents = [] - for product_template in product_templates: - counter += 1 - template_time = time.time() - document = self._map_product_document(product_template) - documents.append(document) - product_template.solr_flag = 1 - _logger.info('[SYNC_PRODUCT_TO_TYPESENSE] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) - _logger.info('[SYNC_PRODUCT_TO_TYPESENSE] Success add to typesense product %s' % product_template.id) - - _typesense.collections['products'].documents.import_(documents, {'action': 'upsert'}) - 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 _map_product_document(self, product_template): - price_excl_after_disc = price_excl = discount = tax = 0 - variants_name = variants_code = '' - flashsale_data = tier1 = tier2 = tier3 = {} - if product_template.product_variant_count > 1: - for variant in product_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 = product_template.display_name - price_excl = product_template.product_variant_id._get_website_price_exclude_tax() - discount = product_template.product_variant_id._get_website_disc(0) - price_excl_after_disc = product_template.product_variant_id._get_website_price_after_disc_and_tax() - tax = product_template.product_variant_id._get_website_tax() - flashsale_data = product_template.product_variant_id._get_flashsale_price() - tier1 = product_template.product_variant_id._get_pricelist_tier1() - tier2 = product_template.product_variant_id._get_pricelist_tier2() - tier3 = product_template.product_variant_id._get_pricelist_tier3() - - category_id = '' - category_name = '' - for category in product_template.public_categ_ids: - category_id = category.id - category_name = category.name - - document = { - 'id': str(product_template.id), - 'display_name': product_template.display_name, - 'name': product_template.name, - 'default_code': product_template.default_code or '', - 'product_rating': product_template.virtual_rating, - 'product_id': product_template.id, - 'image': self.env['ir.attachment'].api_image('product.template', 'image_512', product_template.id), - 'price': price_excl, - 'discount': discount, - 'price_discount': price_excl_after_disc, - 'tax': tax, - 'variant_total': product_template.product_variant_count, - 'stock_total': product_template.qty_stock_vendor, - 'weight': product_template.weight, - 'manufacture_id': product_template.x_manufacture.id or 0, - 'manufacture_name': product_template.x_manufacture.x_name or '', - 'manufacture_name': product_template.x_manufacture.x_name or '', - 'image_promotion_1': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', product_template.x_manufacture.id), - 'image_promotion_2': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', product_template.x_manufacture.id), - 'category_id': category_id or 0, - 'category_name': category_name or '', - 'category_name': category_name or '', - 'variants_name_t': variants_name, - 'variants_code_t': variants_code, - 'search_rank': product_template.search_rank, - 'search_rank_weekly': product_template.search_rank_weekly, - 'flashsale_id': flashsale_data['flashsale_id'] or 0, - 'flashsale_name': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price': flashsale_data['flashsale_price'] or 0, - 'discount_tier1': tier1['discount_tier1'] or 0, - 'price_tier1': tier1['price_tier1'] or 0, - 'discount_tier2': tier2['discount_tier2'] or 0, - 'price_tier2': tier2['price_tier2'] or 0, - 'discount_tier3': tier3['discount_tier3'] or 0, - 'price_tier3': tier3['price_tier3'] or 0 - } - - return document - - -- cgit v1.2.3