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/__manifest__.py | 3 + 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 ++++++++++++++++++ indoteknik_custom/security/ir.model.access.csv | 5 +- indoteknik_custom/views/promotion_program.xml | 63 ++++++++++++++++ .../views/promotion_program_free_item.xml | 45 +++++++++++ indoteknik_custom/views/promotion_program_line.xml | 86 ++++++++++++++++++++++ 9 files changed, 308 insertions(+), 1 deletion(-) 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 create mode 100644 indoteknik_custom/views/promotion_program.xml create mode 100644 indoteknik_custom/views/promotion_program_free_item.xml create mode 100644 indoteknik_custom/views/promotion_program_line.xml diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index c52e27b7..6386497b 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -74,6 +74,9 @@ 'views/procurement_monitoring_detail.xml', 'views/product_product.xml', 'views/brand_vendor.xml', + 'views/promotion_program.xml', + 'views/promotion_program_line.xml', + 'views/promotion_program_free_item.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 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 diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 39504393..3b35615f 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -48,4 +48,7 @@ access_apache_solr,access.apache.solr,model_apache_solr,,1,1,1,1 access_group_partner,access.group.partner,model_group_partner,,1,1,1,1 access_procurement_monitoring_detail,access.procurement.monitoring.detail,model_procurement_monitoring_detail,,1,1,1,1 access_rajaongkir_kurir,access.rajaongkir.kurir,model_rajaongkir_kurir,,1,1,1,1 -access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 \ No newline at end of file +access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 +access_promotion_program,access.promotion.program,model_promotion_program,,1,1,1,1 +access_promotion_program_line,access.promotion.program.line,model_promotion_program_line,,1,1,1,1 +access_promotion_program_free_item,access.promotion.program.free_item,model_promotion_program_free_item,,1,1,1,1 \ No newline at end of file diff --git a/indoteknik_custom/views/promotion_program.xml b/indoteknik_custom/views/promotion_program.xml new file mode 100644 index 00000000..e309cc29 --- /dev/null +++ b/indoteknik_custom/views/promotion_program.xml @@ -0,0 +1,63 @@ + + + Promotion Program Tree + promotion.program + + + + + + + + + + + + Promotion Program Form + promotion.program + +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + Promotion Program + ir.actions.act_window + promotion.program + tree,form + + + + + +
\ No newline at end of file diff --git a/indoteknik_custom/views/promotion_program_free_item.xml b/indoteknik_custom/views/promotion_program_free_item.xml new file mode 100644 index 00000000..c17a752d --- /dev/null +++ b/indoteknik_custom/views/promotion_program_free_item.xml @@ -0,0 +1,45 @@ + + + Promotion Program Free Item Tree + promotion.program.free_item + + + + + + + + + + Promotion Program Free Item Form + promotion.program.free_item + +
+ + + + + + + + + +
+
+
+ + + Promotion Program Free Item + ir.actions.act_window + promotion.program.free_item + tree,form + + + +
\ No newline at end of file diff --git a/indoteknik_custom/views/promotion_program_line.xml b/indoteknik_custom/views/promotion_program_line.xml new file mode 100644 index 00000000..60334d6b --- /dev/null +++ b/indoteknik_custom/views/promotion_program_line.xml @@ -0,0 +1,86 @@ + + + Promotion Program Line Tree + promotion.program.line + + + + + + + + + + + + + + + Promotion Program Line Form + promotion.program.line + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + Promotion Program Line + ir.actions.act_window + promotion.program.line + tree,form + + + +
\ No newline at end of file -- 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_api/controllers/api_v1/promotion.py | 66 +++++++++++++++++++++- indoteknik_custom/__manifest__.py | 1 + indoteknik_custom/models/__init__.py | 1 + indoteknik_custom/models/promotion_program.py | 9 ++- .../models/promotion_program_keyword.py | 8 +++ indoteknik_custom/models/promotion_program_line.py | 3 - indoteknik_custom/security/ir.model.access.csv | 3 +- indoteknik_custom/views/promotion_program.xml | 10 ++++ .../views/promotion_program_free_item.xml | 1 - .../views/promotion_program_keyword.xml | 44 +++++++++++++++ indoteknik_custom/views/promotion_program_line.xml | 1 - 11 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 indoteknik_custom/models/promotion_program_keyword.py create mode 100644 indoteknik_custom/views/promotion_program_keyword.xml diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index b137fe2e..5ee2acb1 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -1,7 +1,7 @@ from .. import controller from odoo import http from odoo.http import request -import ast +from datetime import datetime class Promotion(controller.Controller): @@ -26,4 +26,66 @@ class Promotion(controller.Controller): } return self.response(data) - \ No newline at end of file + + @http.route(prefix + 'promotion/home', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def v1_get_promotion_home(self): + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + programs = request.env['promotion.program'].search([ + ('start_time', '<=', current_time), + ('end_time', '>=', current_time), + ]) + if not programs: + return self.response(None) + + data = [] + for program in programs: + data_program = { + 'id': program.id, + 'name': program.name, + 'banner': request.env['ir.attachment'].api_image('promotion.program', 'banner', program.id), + 'icon': request.env['ir.attachment'].api_image('promotion.program', 'icon', program.id) + } + data.append(data_program) + + return self.response(data) + + @http.route(prefix + 'promotion/home/', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def v1_get_promotion_home_detail(self, id): + program_lines = request.env['promotion.program.line'].search([ + ('display_on_homepage', '=', True), + ('promotion_type', '=', 'specific_product'), + ('program_id', '=', int(id)) + ]) + pricelist = self.user_pricelist() + data = [] + for line in program_lines: + product = request.env['product.product'].v2_api_single_response(line.product_id, pricelist=pricelist) + product_template = line.product_id.product_tmpl_id + + product.update({ + 'id': product['parent']['id'], + 'image': product['parent']['image'], + 'name': product['parent']['name'], + 'variant_total': len(product_template.product_variant_ids), + 'lowest_price': product['price'], + 'stock_total': product['stock'], + 'icon': { + 'top': request.env['ir.attachment'].api_image('promotion.program', 'icon_top', line.program_id.id), + 'bottom': request.env['ir.attachment'].api_image('promotion.program', 'icon_bottom', line.program_id.id) + } + }) + price = product['lowest_price']['price'] + if line.discount_type == 'percentage': + product['lowest_price']['discount_percentage'] = line.discount_amount + product['lowest_price']['price_discount'] = price - (price * line.discount_amount / 100) + if line.discount_type == 'fixed_price': + product['lowest_price']['price_discount'] = line.discount_amount + product['lowest_price']['discount_percentage'] = (price - line.discount_amount) / price * 100 + + product.pop('parent', None) + product.pop('price', None) + product.pop('stock', None) + data.append(product) + return self.response(data) \ No newline at end of file diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 6386497b..c116ff0c 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -77,6 +77,7 @@ 'views/promotion_program.xml', 'views/promotion_program_line.xml', 'views/promotion_program_free_item.xml', + 'views/promotion_program_keyword.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 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 diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 3b35615f..f782046d 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -51,4 +51,5 @@ access_rajaongkir_kurir,access.rajaongkir.kurir,model_rajaongkir_kurir,,1,1,1,1 access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 access_promotion_program,access.promotion.program,model_promotion_program,,1,1,1,1 access_promotion_program_line,access.promotion.program.line,model_promotion_program_line,,1,1,1,1 -access_promotion_program_free_item,access.promotion.program.free_item,model_promotion_program_free_item,,1,1,1,1 \ No newline at end of file +access_promotion_program_free_item,access.promotion.program.free_item,model_promotion_program_free_item,,1,1,1,1 +access_promotion_program_keyword,access.promotion.program.keyword,model_promotion_program_keyword,,1,1,1,1 \ No newline at end of file diff --git a/indoteknik_custom/views/promotion_program.xml b/indoteknik_custom/views/promotion_program.xml index e309cc29..5dff80e6 100644 --- a/indoteknik_custom/views/promotion_program.xml +++ b/indoteknik_custom/views/promotion_program.xml @@ -21,6 +21,7 @@ + @@ -33,6 +34,15 @@ + + + + + + + + + diff --git a/indoteknik_custom/views/promotion_program_free_item.xml b/indoteknik_custom/views/promotion_program_free_item.xml index c17a752d..52d421fe 100644 --- a/indoteknik_custom/views/promotion_program_free_item.xml +++ b/indoteknik_custom/views/promotion_program_free_item.xml @@ -18,7 +18,6 @@ - diff --git a/indoteknik_custom/views/promotion_program_keyword.xml b/indoteknik_custom/views/promotion_program_keyword.xml new file mode 100644 index 00000000..fd279665 --- /dev/null +++ b/indoteknik_custom/views/promotion_program_keyword.xml @@ -0,0 +1,44 @@ + + + Promotion Program Keyword Tree + promotion.program.keyword + + + + + + + + + + Promotion Program Keyword Form + promotion.program.keyword + +
+ + + + + + + + +
+
+
+ + + Promotion Program Keyword + ir.actions.act_window + promotion.program.keyword + tree,form + + + +
\ No newline at end of file diff --git a/indoteknik_custom/views/promotion_program_line.xml b/indoteknik_custom/views/promotion_program_line.xml index 60334d6b..bb625a8f 100644 --- a/indoteknik_custom/views/promotion_program_line.xml +++ b/indoteknik_custom/views/promotion_program_line.xml @@ -23,7 +23,6 @@ - -- 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_api/controllers/api_v1/promotion.py | 52 +++++++++++++++++----- indoteknik_custom/models/ir_attachment.py | 5 +++ indoteknik_custom/models/promotion_program_line.py | 2 +- indoteknik_custom/views/promotion_program_line.xml | 6 +-- 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index 5ee2acb1..991a3eb9 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -6,7 +6,8 @@ from datetime import datetime class Promotion(controller.Controller): prefix = '/api/v1/' - + + @http.route(prefix + 'promotion/', auth='public', methods=['GET']) @controller.Controller.must_authorized() def get_promotion_by_id(self, **kw): @@ -14,19 +15,21 @@ class Promotion(controller.Controller): id = kw.get('id') if not id: return self.response(code=400, description='id is required') - + data = {} id = int(id) - coupon_program = request.env['coupon.program'].search([('id', '=', id)]) + coupon_program = request.env['coupon.program'].search( + [('id', '=', id)]) if coupon_program: data = { 'banner': base_url + 'api/image/coupon.program/x_studio_banner_promo/' + str(coupon_program.id) if coupon_program.x_studio_banner_promo else '', 'image': base_url + 'api/image/coupon.program/x_studio_image_promo/' + str(coupon_program.id) if coupon_program.x_studio_image_promo else '', 'name': coupon_program.name, } - + return self.response(data) - + + @http.route(prefix + 'promotion/home', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def v1_get_promotion_home(self): @@ -49,13 +52,14 @@ class Promotion(controller.Controller): data.append(data_program) return self.response(data) - + + @http.route(prefix + 'promotion/home/', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def v1_get_promotion_home_detail(self, id): program_lines = request.env['promotion.program.line'].search([ ('display_on_homepage', '=', True), - ('promotion_type', '=', 'specific_product'), + ('promotion_type', '=', 'special_price'), ('program_id', '=', int(id)) ]) pricelist = self.user_pricelist() @@ -82,10 +86,38 @@ class Promotion(controller.Controller): product['lowest_price']['price_discount'] = price - (price * line.discount_amount / 100) if line.discount_type == 'fixed_price': product['lowest_price']['price_discount'] = line.discount_amount - product['lowest_price']['discount_percentage'] = (price - line.discount_amount) / price * 100 - + product['lowest_price']['discount_percentage'] = round((price - line.discount_amount) / price * 100) + product.pop('parent', None) product.pop('price', None) product.pop('stock', None) data.append(product) - return self.response(data) \ No newline at end of file + return self.response(data) + + + @http.route(prefix + 'promotion/product/', auth='public', methods=['GET', 'OPTIONS']) + def v1_get_promotion_by_product_id(self, id): + id = int(id) + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + product = request.env['product.template'].search([('id', '=', id)]) + variant_ids = [variant.id for variant in product.product_variant_ids] + program_lines = request.env['promotion.program.line'].search([ + ('program_id.start_time', '<=', current_time), + ('program_id.end_time', '>=', current_time), + ('product_id.id', 'in', variant_ids) + ]) + + data = [] + ir_attachment = request.env['ir.attachment'] + for line in program_lines: + data.append({ + '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': line.limit_qty, + 'limit_qty_user': line.limit_qty_user, + 'limit_qty_transaction': line.limit_qty_transaction, + }) + return self.response(data) 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") diff --git a/indoteknik_custom/views/promotion_program_line.xml b/indoteknik_custom/views/promotion_program_line.xml index bb625a8f..e15bb0d7 100644 --- a/indoteknik_custom/views/promotion_program_line.xml +++ b/indoteknik_custom/views/promotion_program_line.xml @@ -34,11 +34,11 @@ -- 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_api/controllers/api_v1/cart.py | 36 +++++++++++++------------ indoteknik_api/controllers/api_v1/sale_order.py | 20 ++++++++++++++ indoteknik_custom/__manifest__.py | 3 --- indoteknik_custom/models/website_user_cart.py | 25 +++++++++++++++-- indoteknik_custom/security/ir.model.access.csv | 3 --- indoteknik_custom/views/website_user_cart.xml | 4 +++ 6 files changed, 66 insertions(+), 25 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index a8628432..0d54ecbc 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -5,32 +5,30 @@ from odoo.http import request class Cart(controller.Controller): prefix = '/api/v1/' + PREFIX_USER = prefix + 'user//' - @http.route(prefix + 'cart', auth='public', methods=['GET']) + @http.route(PREFIX_USER + 'cart', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() - def get_cart_by_user_id(self, **kw): - user_id = int(kw.get('user_id', 0)) + def get_cart_by_user_id(self, user_id, **kw): + user_id = int(user_id) limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) query = [('user_id', '=', user_id)] carts = request.env['website.user.cart'].search(query, limit=limit, offset=offset, order='create_date desc') data = { 'product_total': request.env['website.user.cart'].search_count(query), - 'products': [] + 'products': [cart.get_product() for cart in carts] } - for cart in carts: - product = request.env['product.product'].api_single_response(cart.product_id) - product['template_id'] = cart.product_id.product_tmpl_id.id - product['quantity'] = cart.qty - data['products'].append(product) return self.response(data) - @http.route(prefix + 'cart/create-or-update', auth='public', methods=['POST'], csrf=False) + @http.route(PREFIX_USER + 'cart/create-or-update', auth='public', methods=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() - def create_or_update_cart(self, **kw): - user_id = int(kw.get('user_id', 0)) + def create_or_update_cart(self, user_id, **kw): + user_id = int(user_id) product_id = int(kw.get('product_id', 0)) qty = int(kw.get('qty', 0)) + is_selected = int(kw.get('is_selected', False)) + program_line_id = int(kw.get('program_line_id', False)) 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') @@ -38,22 +36,26 @@ class Cart(controller.Controller): cart = request.env['website.user.cart'].search(query, limit=1) result = {} if cart: - cart.write({'qty': qty}) + data_to_update = {'qty': qty, 'is_selected': is_selected} + if program_line_id: + data_to_update['program_line_id'] = program_line_id + cart.write(data_to_update) result['id'] = cart.id else: create = request.env['website.user.cart'].create({ 'user_id': user_id, 'product_id': product_id, - 'qty': qty + 'qty': qty, + 'is_selected': is_selected }) result['id'] = create.id return self.response(result) - @http.route(prefix + 'cart', auth='public', methods=['DELETE'], csrf=False) + @http.route(PREFIX_USER + 'cart', auth='public', methods=['DELETE', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() - def delete_cart_by_user_id(self, **kw): - user_id = int(kw.get('user_id', 0)) + def delete_cart_by_user_id(self, user_id, **kw): + user_id = int(user_id) query = [('user_id', '=', user_id)] product_ids = kw.get('product_ids') if product_ids: diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 35361ba4..9df710ec 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -218,6 +218,26 @@ class SaleOrder(controller.Controller): data = sale_order.id return self.response(data) + @http.route(prefix + 'user//sale_order/checkout', auth='public', method=['GET', 'OPTIONS'], csrf=False) + @controller.Controller.must_authorized(private=True, private_key='user_id') + def get_user_checkout_so(self, user_id): + cart = request.env['website.user.cart'] + products = cart.get_product_by_user(user_id=user_id, selected=True) + total_purchase = sum(x['price']['price'] for x in products) + total_discount = sum((x['price']['price'] - x['price']['price_discount']) for x in products) + subtotal = total_purchase - total_discount + tax = round(subtotal * 0.11) + grand_total = subtotal + tax + result = { + 'total_purchase': total_purchase, + 'total_discount': total_discount, + 'subtotal': subtotal, + 'tax': tax, + 'grand_total': round(grand_total), + 'products': products + } + return self.response(result) + @http.route(PREFIX_PARTNER + 'sale_order/checkout', auth='public', method=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized(private=True, private_key='partner_id') def create_partner_sale_order(self, **kw): diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index f21fab0c..7b029a05 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -74,15 +74,12 @@ 'views/procurement_monitoring_detail.xml', 'views/product_product.xml', 'views/brand_vendor.xml', -<<<<<<< HEAD 'views/promotion_program.xml', 'views/promotion_program_line.xml', 'views/promotion_program_free_item.xml', 'views/promotion_program_keyword.xml', -======= 'views/requisition.xml', 'views/landedcost.xml', ->>>>>>> 24649f8e939484759ef34e5e68f251d951f63c02 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', 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 diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 3d23529f..c00f5b76 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -49,13 +49,10 @@ access_group_partner,access.group.partner,model_group_partner,,1,1,1,1 access_procurement_monitoring_detail,access.procurement.monitoring.detail,model_procurement_monitoring_detail,,1,1,1,1 access_rajaongkir_kurir,access.rajaongkir.kurir,model_rajaongkir_kurir,,1,1,1,1 access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 -<<<<<<< HEAD access_promotion_program,access.promotion.program,model_promotion_program,,1,1,1,1 access_promotion_program_line,access.promotion.program.line,model_promotion_program_line,,1,1,1,1 access_promotion_program_free_item,access.promotion.program.free_item,model_promotion_program_free_item,,1,1,1,1 access_promotion_program_keyword,access.promotion.program.keyword,model_promotion_program_keyword,,1,1,1,1 -======= access_requisition,access.requisition,model_requisition,,1,1,1,1 access_requisition_line,access.requisition.line,model_requisition_line,,1,1,1,1 access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1 ->>>>>>> 24649f8e939484759ef34e5e68f251d951f63c02 diff --git a/indoteknik_custom/views/website_user_cart.xml b/indoteknik_custom/views/website_user_cart.xml index 890d801c..fbd08acb 100755 --- a/indoteknik_custom/views/website_user_cart.xml +++ b/indoteknik_custom/views/website_user_cart.xml @@ -13,7 +13,9 @@ + + @@ -28,7 +30,9 @@ + +
-- cgit v1.2.3 From 12c821732b31ff68dec7e0a7a8390466b4181692 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 16 Jun 2023 11:08:21 +0700 Subject: Fix add to cart api --- indoteknik_api/controllers/api_v1/cart.py | 4 +++- indoteknik_api/controllers/api_v1/sale_order.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index 0d54ecbc..002b7442 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -27,9 +27,11 @@ class Cart(controller.Controller): user_id = int(user_id) product_id = int(kw.get('product_id', 0)) qty = int(kw.get('qty', 0)) - is_selected = int(kw.get('is_selected', False)) + is_selected = kw.get('selected', False) program_line_id = int(kw.get('program_line_id', False)) + if is_selected: + is_selected = True if is_selected == 'true' else False 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') query = [('user_id', '=', user_id), ('product_id', '=', product_id)] diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 9df710ec..89e96206 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -266,7 +266,7 @@ class SaleOrder(controller.Controller): parameters = { 'warehouse_id': 8, 'carrier_id': 1, - 'sales_tax_id': 21, + 'sales_tax_id': 23, 'pricelist_id': product_pricelist_default_discount_id, 'payment_term_id': 26, 'team_id': 2, -- cgit v1.2.3 From 09458dba5519f01eadf5f9ca4f22a30dad98d5c7 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Mon, 19 Jun 2023 15:13:31 +0700 Subject: Add get cart count API --- indoteknik_api/controllers/api_v1/cart.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index 002b7442..93d7b2f1 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -21,6 +21,14 @@ class Cart(controller.Controller): } return self.response(data) + @http.route(PREFIX_USER + 'cart/count', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_cart_count_by_user_id(self, user_id, **kw): + user_id = int(user_id) + query = [('user_id', '=', user_id)] + carts = request.env['website.user.cart'].search_count(query) + return self.response(carts) + @http.route(PREFIX_USER + 'cart/create-or-update', auth='public', methods=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() def create_or_update_cart(self, user_id, **kw): -- cgit v1.2.3 From 4e9a5a025012afe63133524eeea8987b9af9e050 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Mon, 19 Jun 2023 15:13:55 +0700 Subject: Add response on get user checkout data API --- indoteknik_api/controllers/api_v1/sale_order.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 89e96206..406ab577 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -223,17 +223,23 @@ class SaleOrder(controller.Controller): def get_user_checkout_so(self, user_id): cart = request.env['website.user.cart'] products = cart.get_product_by_user(user_id=user_id, selected=True) - total_purchase = sum(x['price']['price'] for x in products) - total_discount = sum((x['price']['price'] - x['price']['price_discount']) for x in products) + 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 self.response(result) -- 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 --- .../controllers/api_v1/product_variant.py | 12 +++++ indoteknik_api/controllers/api_v1/promotion.py | 27 ------------ indoteknik_custom/models/promotion_program_line.py | 51 ++++++++++++++++++++++ indoteknik_custom/models/sale_order.py | 1 + indoteknik_custom/views/promotion_program_line.xml | 15 ++++++- indoteknik_custom/views/sale_order.xml | 1 + 6 files changed, 79 insertions(+), 28 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product_variant.py b/indoteknik_api/controllers/api_v1/product_variant.py index 999ced6f..cec54fda 100644 --- a/indoteknik_api/controllers/api_v1/product_variant.py +++ b/indoteknik_api/controllers/api_v1/product_variant.py @@ -2,6 +2,7 @@ from .. import controller from odoo import http from odoo.http import request + class ProductVariant(controller.Controller): prefix = '/api/v1/' @@ -20,3 +21,14 @@ class ProductVariant(controller.Controller): return self.response(data) + @http.route(prefix + 'product_variant//promotions', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_product_variant_promotions(self, product_id): + product_id = int(product_id) + user_data = self.verify_user_token() + + program_line = request.env['promotion.program.line'] + program_lines = program_line.get_active_promotions(product_id) + program_lines = program_line.res_format(program_lines, user_data) + + return self.response(program_lines) diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index 991a3eb9..948681fd 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -94,30 +94,3 @@ class Promotion(controller.Controller): data.append(product) return self.response(data) - - @http.route(prefix + 'promotion/product/', auth='public', methods=['GET', 'OPTIONS']) - def v1_get_promotion_by_product_id(self, id): - id = int(id) - current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - product = request.env['product.template'].search([('id', '=', id)]) - variant_ids = [variant.id for variant in product.product_variant_ids] - program_lines = request.env['promotion.program.line'].search([ - ('program_id.start_time', '<=', current_time), - ('program_id.end_time', '>=', current_time), - ('product_id.id', 'in', variant_ids) - ]) - - data = [] - ir_attachment = request.env['ir.attachment'] - for line in program_lines: - data.append({ - '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': line.limit_qty, - 'limit_qty_user': line.limit_qty_user, - 'limit_qty_transaction': line.limit_qty_transaction, - }) - return self.response(data) 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: diff --git a/indoteknik_custom/views/promotion_program_line.xml b/indoteknik_custom/views/promotion_program_line.xml index e15bb0d7..5963d0dd 100644 --- a/indoteknik_custom/views/promotion_program_line.xml +++ b/indoteknik_custom/views/promotion_program_line.xml @@ -58,10 +58,23 @@ + + + + + + + + + +
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index ea13c954..83278ca8 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -60,6 +60,7 @@ "/> + -- 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(-) 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(-) 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 --- .../controllers/api_v1/product_variant.py | 3 +- indoteknik_api/controllers/api_v1/promotion.py | 9 +--- indoteknik_api/models/product_product.py | 60 ++++++++++------------ indoteknik_custom/models/promotion_program_line.py | 43 ++++++++++------ 4 files changed, 59 insertions(+), 56 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product_variant.py b/indoteknik_api/controllers/api_v1/product_variant.py index cec54fda..06ce5d3c 100644 --- a/indoteknik_api/controllers/api_v1/product_variant.py +++ b/indoteknik_api/controllers/api_v1/product_variant.py @@ -26,9 +26,10 @@ class ProductVariant(controller.Controller): def get_product_variant_promotions(self, product_id): product_id = int(product_id) user_data = self.verify_user_token() + pricelist = self.user_pricelist() program_line = request.env['promotion.program.line'] program_lines = program_line.get_active_promotions(product_id) - program_lines = program_line.res_format(program_lines, user_data) + program_lines = program_lines.res_format(user=user_data, pricelist=pricelist) return self.response(program_lines) diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index 948681fd..a3dbf0ba 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -73,20 +73,13 @@ class Promotion(controller.Controller): 'image': product['parent']['image'], 'name': product['parent']['name'], 'variant_total': len(product_template.product_variant_ids), - 'lowest_price': product['price'], + 'lowest_price': line.calculate_price(product['price']), 'stock_total': product['stock'], 'icon': { 'top': request.env['ir.attachment'].api_image('promotion.program', 'icon_top', line.program_id.id), 'bottom': request.env['ir.attachment'].api_image('promotion.program', 'icon_bottom', line.program_id.id) } }) - price = product['lowest_price']['price'] - if line.discount_type == 'percentage': - product['lowest_price']['discount_percentage'] = line.discount_amount - product['lowest_price']['price_discount'] = price - (price * line.discount_amount / 100) - if line.discount_type == 'fixed_price': - product['lowest_price']['price_discount'] = line.discount_amount - product['lowest_price']['discount_percentage'] = round((price - line.discount_amount) / price * 100) product.pop('parent', None) product.pop('price', None) diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 14fe68cb..9e218565 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -28,19 +28,38 @@ class ProductProduct(models.Model): return data def v2_api_single_response(self, product_product, pricelist=False): + product_template = product_product.product_tmpl_id + data = { + 'id': product_product.id, + 'parent': { + 'id': product_template.id, + 'name': product_template.name, + 'image': self.env['ir.attachment'].api_image('product.template', 'image_256', product_template.id), + }, + 'code': product_product.default_code or '', + 'name': product_product.display_name, + 'price': product_product.calculate_website_price(pricelist), + 'stock': product_product.qty_stock_vendor, + 'weight': product_product.weight, + 'attributes': [x.name for x in product_product.product_template_attribute_value_ids], + 'manufacture' : self.api_manufacture(product_product) + } + return data + + def calculate_website_price(self, 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 = product_product._get_website_disc(0) - price_discount = product_product._get_website_price_after_disc_and_tax() + discount_percentage = self._get_website_disc(0) + price_discount = self._get_website_price_after_disc_and_tax() price_tier = False pricelists = { - 'tier1': product_product._get_pricelist_tier1, - 'tier2': product_product._get_pricelist_tier2, - 'tier3': product_product._get_pricelist_tier3, + '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' @@ -54,34 +73,11 @@ class ProductProduct(models.Model): if price[discount_key] > 0: discount_percentage = price[discount_key] if price[price_key] > 0: price_discount = price[price_key] - flashsale = product_product._get_flashsale_price() - flashsale_price = flashsale['flashsale_price'] - flashsale_discount = flashsale['flashsale_discount'] - if flashsale_price > 0 and flashsale_price < price_discount: - price_discount = flashsale_price - discount_percentage = flashsale_discount - - product_template = product_product.product_tmpl_id - data = { - 'id': product_product.id, - 'parent': { - 'id': product_template.id, - 'name': product_template.name, - 'image': self.env['ir.attachment'].api_image('product.template', 'image_256', product_template.id), - }, - 'code': product_product.default_code or '', - 'name': product_product.display_name, - 'price': { - 'price': product_product._get_website_price_exclude_tax(), - 'discount_percentage': discount_percentage, - 'price_discount': price_discount - }, - 'stock': product_product.qty_stock_vendor, - 'weight': product_product.weight, - 'attributes': [x.name for x in product_product.product_template_attribute_value_ids], - 'manufacture' : self.api_manufacture(product_product) + return { + 'price': self._get_website_price_exclude_tax(), + 'discount_percentage': discount_percentage, + 'price_discount': price_discount } - return data def api_manufacture(self, product_template): if product_template.x_manufacture: 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_api/controllers/api_v1/cart.py | 7 ++++--- indoteknik_api/controllers/api_v1/product_variant.py | 3 +-- indoteknik_api/controllers/api_v1/promotion.py | 4 ++-- indoteknik_api/controllers/api_v2/product.py | 4 +--- indoteknik_api/controllers/api_v2/product_variant.py | 4 +--- indoteknik_api/controllers/controller.py | 1 + indoteknik_api/models/product_product.py | 8 +++++--- indoteknik_api/models/product_template.py | 6 ++---- indoteknik_custom/models/promotion_program_line.py | 12 ++++++++---- indoteknik_custom/models/website_user_cart.py | 14 +++++++++++--- 10 files changed, 36 insertions(+), 27 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index 93d7b2f1..035a40b7 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -10,14 +10,15 @@ class Cart(controller.Controller): @http.route(PREFIX_USER + 'cart', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_cart_by_user_id(self, user_id, **kw): + user_cart = request.env['website.user.cart'] user_id = int(user_id) limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) query = [('user_id', '=', user_id)] - carts = request.env['website.user.cart'].search(query, limit=limit, offset=offset, order='create_date desc') + carts = user_cart.search(query, limit=limit, offset=offset, order='create_date desc') data = { - 'product_total': request.env['website.user.cart'].search_count(query), - 'products': [cart.get_product() for cart in carts] + 'product_total': user_cart.search_count(query), + 'products': carts.get_products() } return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/product_variant.py b/indoteknik_api/controllers/api_v1/product_variant.py index 06ce5d3c..8de4669e 100644 --- a/indoteknik_api/controllers/api_v1/product_variant.py +++ b/indoteknik_api/controllers/api_v1/product_variant.py @@ -26,10 +26,9 @@ class ProductVariant(controller.Controller): def get_product_variant_promotions(self, product_id): product_id = int(product_id) user_data = self.verify_user_token() - pricelist = self.user_pricelist() program_line = request.env['promotion.program.line'] program_lines = program_line.get_active_promotions(product_id) - program_lines = program_lines.res_format(user=user_data, pricelist=pricelist) + program_lines = program_lines.res_format(user=user_data) return self.response(program_lines) diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index a3dbf0ba..68a23ef2 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -62,10 +62,10 @@ class Promotion(controller.Controller): ('promotion_type', '=', 'special_price'), ('program_id', '=', int(id)) ]) - pricelist = self.user_pricelist() + data = [] for line in program_lines: - product = request.env['product.product'].v2_api_single_response(line.product_id, pricelist=pricelist) + product = request.env['product.product'].v2_api_single_response(line.product_id) product_template = line.product_id.product_tmpl_id product.update({ diff --git a/indoteknik_api/controllers/api_v2/product.py b/indoteknik_api/controllers/api_v2/product.py index d9b43bda..19a97dec 100644 --- a/indoteknik_api/controllers/api_v2/product.py +++ b/indoteknik_api/controllers/api_v2/product.py @@ -12,12 +12,10 @@ class V2Product(controller.Controller): if not id: return self.response(code=400, description='id is required') - pricelist = self.user_pricelist() - data = [] id = [int(x) for x in id.split(',')] product_templates = request.env['product.template'].search([('id', 'in', id)]) if product_templates: - data = [request.env['product.template'].v2_api_single_response(x, pricelist=pricelist, with_detail='DEFAULT') for x in product_templates] + data = [request.env['product.template'].v2_api_single_response(x, with_detail='DEFAULT') for x in product_templates] return self.response(data) \ No newline at end of file diff --git a/indoteknik_api/controllers/api_v2/product_variant.py b/indoteknik_api/controllers/api_v2/product_variant.py index 8a5bbeb1..b74e4936 100644 --- a/indoteknik_api/controllers/api_v2/product_variant.py +++ b/indoteknik_api/controllers/api_v2/product_variant.py @@ -12,13 +12,11 @@ class V2ProductVariant(controller.Controller): if not id: return self.response(code=400, description='id is required') - pricelist = self.user_pricelist() - data = [] id = [int(x) for x in id.split(',')] product_products = request.env['product.product'].search([('id', 'in', id)]) if product_products: - data = [request.env['product.product'].v2_api_single_response(x, pricelist=pricelist) for x in product_products] + data = [request.env['product.product'].v2_api_single_response(x) for x in product_products] return self.response(data) diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 90bc50ed..a9ad2724 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -21,6 +21,7 @@ class Controller(http.Controller): def inner_wrapper(*args, **kwargs): self = args[0] auth = self.authenticate() + request.env.user_pricelist = self.user_pricelist() if not auth: return self.unauthorized_response() if private: diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 9e218565..1740f992 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -27,7 +27,7 @@ class ProductProduct(models.Model): } return data - def v2_api_single_response(self, product_product, pricelist=False): + def v2_api_single_response(self, product_product): product_template = product_product.product_tmpl_id data = { 'id': product_product.id, @@ -38,7 +38,7 @@ class ProductProduct(models.Model): }, 'code': product_product.default_code or '', 'name': product_product.display_name, - 'price': product_product.calculate_website_price(pricelist), + 'price': product_product.calculate_website_price(), 'stock': product_product.qty_stock_vendor, 'weight': product_product.weight, 'attributes': [x.name for x in product_product.product_template_attribute_value_ids], @@ -46,7 +46,9 @@ class ProductProduct(models.Model): } return data - def calculate_website_price(self, pricelist): + def calculate_website_price(self): + pricelist = 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')) diff --git a/indoteknik_api/models/product_template.py b/indoteknik_api/models/product_template.py index 1a345967..68ab79c2 100644 --- a/indoteknik_api/models/product_template.py +++ b/indoteknik_api/models/product_template.py @@ -51,9 +51,7 @@ class ProductTemplate(models.Model): data.update(data_with_detail) return data - def v2_api_single_response(self, product_template, pricelist=False, with_detail=''): - product_pricelist_default_discount_id = self.env['ir.config_parameter'].get_param('product.pricelist.default_discount_id') - product_pricelist_default_discount_id = int(product_pricelist_default_discount_id) + def v2_api_single_response(self, product_template, with_detail=''): data = { 'id': product_template.id, 'image': self.env['ir.attachment'].api_image('product.template', 'image_128', product_template.id), @@ -67,7 +65,7 @@ class ProductTemplate(models.Model): } if with_detail != '': - variants = [self.env['product.product'].v2_api_single_response(variant, pricelist=pricelist) for variant in product_template.product_variant_ids] + variants = [self.env['product.product'].v2_api_single_response(variant) for variant in product_template.product_variant_ids] lowest_price = variants[0]['price'] for variant in variants: if variant["price"]["price_discount"] < lowest_price["price_discount"]: 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(-) 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(-) 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(-) 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 41d0bc25d569901de38f77f0ba452e33630d01f0 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Thu, 13 Jul 2023 21:11:59 +0700 Subject: tracking history due extension --- indoteknik_custom/models/account_move.py | 56 ++++++++++++++++++++++ .../models/account_move_due_extension.py | 6 +++ indoteknik_custom/security/ir.model.access.csv | 3 +- indoteknik_custom/views/account_move.xml | 13 +++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 99439915..f479b4a9 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -1,6 +1,9 @@ from odoo import models, api, fields from odoo.exceptions import AccessError, UserError, ValidationError from datetime import timedelta, date +import logging + +_logger = logging.getLogger(__name__) class AccountMove(models.Model): @@ -15,6 +18,8 @@ class AccountMove(models.Model): shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur') due_extension = fields.Integer(string='Due Extension', default=0) new_due_date = fields.Date(string='New Due') + counter = fields.Integer(string="Counter", default=0) + due_line = fields.One2many('due.line', 'move_id', string='Due Extension Lines', auto_join=True) def unlink(self): res = super(AccountMove, self).unlink() @@ -102,3 +107,54 @@ class AccountMove(models.Model): add_days += line.days due_date = tukar_date + timedelta(days=add_days) invoice.invoice_date_due = due_date + + def generate_due_line(self): + partners = self.partner_id.get_child_ids() + + query = [ + ('due_line.invoice_id', '=', self.id), + ('due_line.day_to_due', '<', 0), + ('approval_status', '=', False), + ] + due = self.env['due.extension'].search(query) + count = 0 + + for line in due: + self.env['due.line'].create([{ + 'move_id': self.id, + 'due_id': line.id, + }]) + count += 1 + _logger.info("Due Extension Line generated %s" % count) + +class DueExtensionLine(models.Model): + _name = 'due.line' + _description = 'Due Extension Line' + _order = 'move_id, id' + + move_id = fields.Many2one('account.move', string='Acc Move Ref', required=True, ondelete='cascade', index=True, copy=False) + due_id = fields.Many2one('due.extension', string='Due Extension') + description = fields.Text(string='Description', compute="compute_description") + day_extension = fields.Char(string='Day Extension', compute="compute_day_extension") + approval_status = fields.Char(string='Status Approval', compute="compute_approval_status") + + def compute_description(self): + for line in self: + if line.due_id.description: + line.description = line.due_id.description + else: + line.description = '-' + + def compute_day_extension(self): + for line in self: + if line.due_id.day_extension: + line.day_extension = line.due_id.day_extension + else: + line.day_extension = '-' + + def compute_approval_status(self): + for line in self: + if line.due_id.approval_status: + line.approval_status = line.due_id.approval_status + else: + line.approval_status = '-' \ No newline at end of file diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py index 27c8577d..51d59e61 100644 --- a/indoteknik_custom/models/account_move_due_extension.py +++ b/indoteknik_custom/models/account_move_due_extension.py @@ -120,7 +120,13 @@ class DueExtension(models.Model): 'open_amt': invoice.amount_residual_signed }]) count += 1 + + invoice.generate_due_line() + + invoice.counter+=1 + _logger.info("Due Extension Line generated %s" % count) + def unlink(self): res = super(DueExtension, self).unlink() diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index df820053..33a13f40 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -53,4 +53,5 @@ access_rajaongkir_kurir,access.rajaongkir.kurir,model_rajaongkir_kurir,,1,1,1,1 access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 access_requisition,access.requisition,model_requisition,,1,1,1,1 access_requisition_line,access.requisition.line,model_requisition_line,,1,1,1,1 -access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1 \ No newline at end of file +access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1 +access_due_line,access.due.line,model_due_line,,1,1,1,1 \ No newline at end of file diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 7f7fb228..5aeff4ec 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -16,7 +16,20 @@ + + + + + + + + + + + + + -- cgit v1.2.3 From f53828b3df693a88ec7cfff8b323178f3550a9b2 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 14 Jul 2023 11:04:57 +0700 Subject: refactor tracking history due extension --- indoteknik_custom/models/account_move.py | 54 +--------------------- .../models/account_move_due_extension.py | 27 +++++++++-- indoteknik_custom/views/account_move.xml | 6 +-- 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index f479b4a9..7edeb0d9 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -19,7 +19,7 @@ class AccountMove(models.Model): due_extension = fields.Integer(string='Due Extension', default=0) new_due_date = fields.Date(string='New Due') counter = fields.Integer(string="Counter", default=0) - due_line = fields.One2many('due.line', 'move_id', string='Due Extension Lines', auto_join=True) + due_line = fields.One2many('due.extension.line', 'invoice_id', string='Due Extension Lines') def unlink(self): res = super(AccountMove, self).unlink() @@ -107,54 +107,4 @@ class AccountMove(models.Model): add_days += line.days due_date = tukar_date + timedelta(days=add_days) invoice.invoice_date_due = due_date - - def generate_due_line(self): - partners = self.partner_id.get_child_ids() - - query = [ - ('due_line.invoice_id', '=', self.id), - ('due_line.day_to_due', '<', 0), - ('approval_status', '=', False), - ] - due = self.env['due.extension'].search(query) - count = 0 - - for line in due: - self.env['due.line'].create([{ - 'move_id': self.id, - 'due_id': line.id, - }]) - count += 1 - _logger.info("Due Extension Line generated %s" % count) - -class DueExtensionLine(models.Model): - _name = 'due.line' - _description = 'Due Extension Line' - _order = 'move_id, id' - - move_id = fields.Many2one('account.move', string='Acc Move Ref', required=True, ondelete='cascade', index=True, copy=False) - due_id = fields.Many2one('due.extension', string='Due Extension') - description = fields.Text(string='Description', compute="compute_description") - day_extension = fields.Char(string='Day Extension', compute="compute_day_extension") - approval_status = fields.Char(string='Status Approval', compute="compute_approval_status") - - def compute_description(self): - for line in self: - if line.due_id.description: - line.description = line.due_id.description - else: - line.description = '-' - - def compute_day_extension(self): - for line in self: - if line.due_id.day_extension: - line.day_extension = line.due_id.day_extension - else: - line.day_extension = '-' - - def compute_approval_status(self): - for line in self: - if line.due_id.approval_status: - line.approval_status = line.due_id.approval_status - else: - line.approval_status = '-' \ No newline at end of file + \ No newline at end of file diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py index 51d59e61..18bb7599 100644 --- a/indoteknik_custom/models/account_move_due_extension.py +++ b/indoteknik_custom/models/account_move_due_extension.py @@ -120,9 +120,6 @@ class DueExtension(models.Model): 'open_amt': invoice.amount_residual_signed }]) count += 1 - - invoice.generate_due_line() - invoice.counter+=1 _logger.info("Due Extension Line generated %s" % count) @@ -141,6 +138,9 @@ class DueExtensionLine(models.Model): _order = 'due_id, id' due_id = fields.Many2one('due.extension', string='Due Ref', required=True, ondelete='cascade', index=True, copy=False) + due_description = fields.Text(string="Description", compute="_compute_due_description") + due_approval_status = fields.Char(string="Approval Status", compute="_compute_due_approval_status") + due_day_extension = fields.Char(string="Day Extension", compute="_compute_due_day_extension") partner_id = fields.Many2one('res.partner', string='Customer') invoice_id = fields.Many2one('account.move', string='Invoice') date_invoice = fields.Date(string='Invoice Date') @@ -151,6 +151,27 @@ class DueExtensionLine(models.Model): due_date = fields.Date(string='Due Date', compute="_compute_due_date") day_to_due = fields.Integer(string='Day To Due', compute="_compute_day_to_due") + def _compute_due_description(self): + for line in self: + if line.due_id.description: + line.due_description = line.due_id.description + else: + line.due_description = '-' + + def _compute_due_approval_status(self): + for line in self: + if line.due_id.approval_status: + line.due_approval_status = line.due_id.approval_status + else: + line.due_approval_status = '-' + + def _compute_due_day_extension(self): + for line in self: + if line.due_id.day_extension: + line.due_day_extension = line.due_id.day_extension + else: + line.due_day_extension = '-' + def _compute_day_to_due(self): for line in self: line.day_to_due = line.invoice_id.invoice_day_to_due diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 5aeff4ec..8cc8d723 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -23,9 +23,9 @@ - - - + + + -- cgit v1.2.3 From fca6864d2a5be42a185e8f2360f96cffcde75388 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Sat, 15 Jul 2023 09:11:08 +0700 Subject: fix bug due line invoice --- indoteknik_custom/security/ir.model.access.csv | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 33a13f40..df820053 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -53,5 +53,4 @@ access_rajaongkir_kurir,access.rajaongkir.kurir,model_rajaongkir_kurir,,1,1,1,1 access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 access_requisition,access.requisition,model_requisition,,1,1,1,1 access_requisition_line,access.requisition.line,model_requisition_line,,1,1,1,1 -access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1 -access_due_line,access.due.line,model_due_line,,1,1,1,1 \ No newline at end of file +access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1 \ No newline at end of file -- cgit v1.2.3 From 4170cd7bd55232de0a66880351421b054a97849b Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 17 Jul 2023 09:08:34 +0700 Subject: refactor tracking history due extension on invoice --- indoteknik_custom/models/account_move.py | 9 ++++++++- .../models/account_move_due_extension.py | 20 +++++++------------- indoteknik_custom/views/account_move.xml | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 7edeb0d9..bc6061ee 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -19,7 +19,14 @@ class AccountMove(models.Model): due_extension = fields.Integer(string='Due Extension', default=0) new_due_date = fields.Date(string='New Due') counter = fields.Integer(string="Counter", default=0) - due_line = fields.One2many('due.extension.line', 'invoice_id', string='Due Extension Lines') + due_line = fields.One2many('due.extension.line', 'invoice_id', compute='_compute_due_line', string='Due Extension Lines') + + def _compute_due_line(self): + for invoice in self: + invoice.due_line = self.env['due.extension.line'].search([ + ('invoice_id', '=', invoice.id), + ('due_id.approval_status', '=', 'approved') + ]) def unlink(self): res = super(AccountMove, self).unlink() diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py index 18bb7599..43207534 100644 --- a/indoteknik_custom/models/account_move_due_extension.py +++ b/indoteknik_custom/models/account_move_due_extension.py @@ -139,7 +139,10 @@ class DueExtensionLine(models.Model): due_id = fields.Many2one('due.extension', string='Due Ref', required=True, ondelete='cascade', index=True, copy=False) due_description = fields.Text(string="Description", compute="_compute_due_description") - due_approval_status = fields.Char(string="Approval Status", compute="_compute_due_approval_status") + due_approval_status = fields.Selection([ + ('pengajuan', 'Pengajuan'), + ('approved', 'Approved'), + ], string="Approval Status", compute="_compute_due_approval_status") due_day_extension = fields.Char(string="Day Extension", compute="_compute_due_day_extension") partner_id = fields.Many2one('res.partner', string='Customer') invoice_id = fields.Many2one('account.move', string='Invoice') @@ -153,24 +156,15 @@ class DueExtensionLine(models.Model): def _compute_due_description(self): for line in self: - if line.due_id.description: - line.due_description = line.due_id.description - else: - line.due_description = '-' + line.due_description = line.due_id.description def _compute_due_approval_status(self): for line in self: - if line.due_id.approval_status: - line.due_approval_status = line.due_id.approval_status - else: - line.due_approval_status = '-' + line.due_approval_status = line.due_id.approval_status def _compute_due_day_extension(self): for line in self: - if line.due_id.day_extension: - line.due_day_extension = line.due_id.day_extension - else: - line.due_day_extension = '-' + line.due_day_extension = line.due_id.day_extension def _compute_day_to_due(self): for line in self: diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 8cc8d723..a1d3eaaa 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -21,7 +21,7 @@ - + -- cgit v1.2.3 From cc4150ade5d8f6cea80ce4acf92907be0a3ed29a Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 10:31:56 +0700 Subject: refactor receipt bill --- indoteknik_custom/models/bill_receipt.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/indoteknik_custom/models/bill_receipt.py b/indoteknik_custom/models/bill_receipt.py index 806edc25..39d5f31b 100644 --- a/indoteknik_custom/models/bill_receipt.py +++ b/indoteknik_custom/models/bill_receipt.py @@ -11,24 +11,15 @@ class BillReceipt(models.Model): _rec_name = 'number' number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True) - vendor_id = fields.Many2one('res.partner', string="Vendor") - document_date = fields.Date(string="Document Date") + vendor_id = fields.Many2one('res.partner', string="Vendor", required=True) + document_date = fields.Date(string="Document Date", required=True) description = fields.Text(string='Description') validated = fields.Boolean(string="Validated", readonly=True) bill_line = fields.One2many('bill.receipt.line', 'bill_id', string='Bill Receipt Lines') - grand_total = fields.Float(string="Grand Total") - - def compute_amt_total_without_service(self): - for order in self: - sum_price_total = 0 - for line in order.order_line: - if line.product_id.type == 'product': - sum_price_total += line.price_total - order.amount_total_without_service = sum_price_total @api.model def create(self, vals): - vals['number'] = self.env['ir.sequence'].next_by_code('due.extension') or '0' + vals['number'] = self.env['ir.sequence'].next_by_code('bill.receipt') or '0' result = super(BillReceipt, self).create(vals) return result @@ -53,8 +44,8 @@ class BillReceiptLine(models.Model): _order = 'bill_id, id' bill_id = fields.Many2one('bill.receipt', string='Bill Receipt') - po_id = fields.Many2one('purchase.order', string='PO') sale_order_id = fields.Many2one('sale.order', string='Sale Order') + po_id = fields.Many2one('purchase.order', string='PO') user_id = fields.Many2one('res.users', string='Purchase Rep') payment_term_id = fields.Many2one('account.payment.term', string='Payment Terms') vendor_id = fields.Many2one('res.partner', string='Vendor') -- cgit v1.2.3 From 0aaf2d3af0e5096514f8b72850f6a3d2901cfc3e Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 11:56:33 +0700 Subject: refactor product real stock --- indoteknik_api/controllers/api_v1/product.py | 8 +++----- indoteknik_custom/models/product_sla.py | 9 +++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 8803bae3..8411ee25 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -18,11 +18,9 @@ class Product(controller.Controller): id = int(kw.get('id')) product = request.env['product.product'].search([('id', '=', id)], limit=1) product_sla = request.env['product.sla'].search([('product_variant_id', '=', id)], limit=1) + stock_vendor = request.env['stock.vendor'].search([('product_variant_id', '=', id)], limit=1) qty_available = product.qty_onhand_bandengan - qty_available -= 10 - if qty_available < 10: - qty_available = 0 qty = 0 sla_date = '-' @@ -33,8 +31,8 @@ class Product(controller.Controller): qty_altama = request.env['product.template'].get_stock_altama(product.default_code) qty_altama -= int(qty_altama * 0.1) qty_altama = math.ceil(float(qty_altama)) - qty = qty_altama - if qty_available > 10: + qty = qty_altama + if qty_available > 0: qty += qty_available sla_date = '1 Hari' elif qty_altama > 0: diff --git a/indoteknik_custom/models/product_sla.py b/indoteknik_custom/models/product_sla.py index f969502f..2e663d30 100644 --- a/indoteknik_custom/models/product_sla.py +++ b/indoteknik_custom/models/product_sla.py @@ -51,12 +51,9 @@ class ProductSla(models.Model): qty_available = 0 qty_available = product.qty_onhand_bandengan - qty_available -= 10 - if qty_available < 10: - qty_available = 0 - - if qty_available > 10: + + if qty_available > 0: self.sla = '1 Hari' query = [ @@ -80,7 +77,7 @@ class ProductSla(models.Model): rounded_leadtime = math.ceil(avg_leadtime) self.avg_leadtime = rounded_leadtime if rounded_leadtime >= 1 and rounded_leadtime <= 5: - self.sla = '3-6 Hari' + self.sla = '3-7 Hari' elif rounded_leadtime >= 6 and rounded_leadtime <= 10: self.sla = '4-12 Hari' elif rounded_leadtime >= 11: -- cgit v1.2.3 From 89c04f6748c4794018b34004472f08e3f41c8e43 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 13:31:55 +0700 Subject: add new fields on account move bills --- indoteknik_custom/models/account_move.py | 1 + indoteknik_custom/views/account_move.xml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index bc6061ee..33fb73b5 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -15,6 +15,7 @@ class AccountMove(models.Model): date_kirim_tukar_faktur = fields.Date(string='Kirim Faktur') resi_tukar_faktur = fields.Char(string='Resi Faktur') date_terima_tukar_faktur = fields.Date(string='Terima Faktur') + payment_schedule = fields.Date(string='Jadwal Pembayaran') shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur') due_extension = fields.Integer(string='Due Extension', default=0) new_due_date = fields.Date(string='New Due') diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index a1d3eaaa..0fd6b5b5 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -10,6 +10,9 @@ + + + -- cgit v1.2.3 From 9e0f8349ef5038bc3d7a3424ff5b6cfc0d1154ae Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 13:43:15 +0700 Subject: replace menu bill line --- indoteknik_custom/views/bill_receipt.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indoteknik_custom/views/bill_receipt.xml b/indoteknik_custom/views/bill_receipt.xml index cfc268b0..c73802c2 100644 --- a/indoteknik_custom/views/bill_receipt.xml +++ b/indoteknik_custom/views/bill_receipt.xml @@ -79,8 +79,8 @@ -- cgit v1.2.3 From e0102841e6e21c7b583f096914aa4ba1a28e1587 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 18 Jul 2023 14:00:34 +0700 Subject: Merge sale order voucher with promotion program --- indoteknik_api/controllers/api_v1/sale_order.py | 96 ++++++++++++------------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 7c38d47d..a2e28cda 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -262,16 +262,10 @@ class SaleOrder(controller.Controller): @controller.Controller.must_authorized(private=True, private_key='partner_id') def create_partner_sale_order(self, **kw): config = request.env['ir.config_parameter'] - product_pricelist_default_discount_id = int( - config.get_param('product.pricelist.default_discount_id')) - 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')) + product_pricelist_default_discount_id = int(config.get_param('product.pricelist.default_discount_id')) params = self.get_request_params(kw, { + 'user_id': ['number'], 'partner_id': ['number'], 'partner_shipping_id': ['required', 'number'], 'partner_invoice_id': ['required', 'number'], @@ -281,10 +275,9 @@ class SaleOrder(controller.Controller): 'type': [], 'delivery_amount': ['number', 'default:0'], 'carrier_id': [], - 'delivery_service_type': [], - 'voucher': [] + 'delivery_service_type': [] }) - + if not params['valid']: return self.response(code=400, description=params) @@ -316,51 +309,50 @@ class SaleOrder(controller.Controller): if params['value']['type'] == 'sale_order': parameters['approval_status'] = 'pengajuan1' sale_order = request.env['sale.order'].create([parameters]) - order_line = json.loads(params['value']['order_line']) parameters = [] - partner = request.env['res.partner'].browse( - params['value']['partner_id']) - partner_pricelist = partner.property_product_pricelist - for line in order_line: - product = request.env['product.product'].search( - [('id', '=', line['product_id'])], limit=1) - discount = product._get_website_disc(0) - - price_tier = False - pricelist = { - 'tier1': product._get_pricelist_tier1, - 'tier2': product._get_pricelist_tier2, - 'tier3': product._get_pricelist_tier3, - } - partner_pricelist_id = partner_pricelist.id if partner_pricelist else False - if partner_pricelist_id == product_pricelist_tier1: - price_tier = 'tier1' - if partner_pricelist_id == product_pricelist_tier2: - price_tier = 'tier2' - if partner_pricelist_id == product_pricelist_tier3: - price_tier = 'tier3' - - if price_tier: - price = pricelist[price_tier]() - discount_key = 'discount_%s' % price_tier - if price[discount_key] > 0: - discount = price[discount_key] - - flashsale = product._get_flashsale_price() - flashsale_discount = flashsale['flashsale_discount'] - if flashsale_discount > 0 and flashsale_discount > discount: - discount = flashsale_discount - - parameters.append({ + user_id = params['value']['user_id'] + user_cart = request.env['website.user.cart'] + products = user_cart.get_product_by_user(user_id=user_id, selected=True) + for product in products: + total_qty = product['quantity'] + price_unit = product['price']['price'] + price_discount =product['price']['discount_percentage'] + if product['program'] and product['program']['type']['value'] != 'special_price': + total_qty += sum(x['quantity'] for x in product['program']['items']) + price_unit = product['subtotal'] / total_qty + price_discount = 0 + + param = { 'company_id': 1, 'order_id': sale_order.id, - 'product_id': line['product_id'], - 'product_uom_qty': line['quantity'], - 'price_unit': product._get_website_price_exclude_tax(), - 'discount': discount - }) + 'price_unit': price_unit, + 'discount': price_discount + } + primary_product = { + **param, + 'product_id': product['id'], + 'product_uom_qty': product['quantity'] + } + if product['program']: + primary_product.update({ + 'program_line_id': product['program']['id'] + }) + parameters.append(primary_product) + + if not product['program']: + continue + + for item in product['program']['items']: + parameters.append({ + **param, + 'product_id': item['id'], + 'product_uom_qty': item['quantity'], + }) + + cart_ids = [x['cart_id'] for x in products] + user_cart.browse(cart_ids).unlink() request.env['sale.order.line'].create(parameters) amount_untaxed = sale_order.amount_untaxed @@ -380,7 +372,7 @@ class SaleOrder(controller.Controller): price = line.price_unit - voucher_discount_line line.price_unit = price line.amount_voucher_disc = voucher_discount_item * line.product_uom_qty - + return self.response({ 'id': sale_order.id, 'name': sale_order.name -- cgit v1.2.3 From d7148fd0267529c92fa07b0721461a6ef13c0890 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 14:36:36 +0700 Subject: add new field to tree --- indoteknik_custom/__manifest__.py | 1 + indoteknik_custom/views/account_bills.xml | 15 +++++++++++++++ indoteknik_custom/views/account_move.xml | 11 +++++++++++ 3 files changed, 27 insertions(+) create mode 100644 indoteknik_custom/views/account_bills.xml diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index f91b33d7..cd7c27d1 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -80,6 +80,7 @@ 'views/product_sla.xml', 'views/voucher.xml', 'views/bill_receipt.xml', + 'views/account_bills.xml', 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', diff --git a/indoteknik_custom/views/account_bills.xml b/indoteknik_custom/views/account_bills.xml new file mode 100644 index 00000000..cb624396 --- /dev/null +++ b/indoteknik_custom/views/account_bills.xml @@ -0,0 +1,15 @@ + + + + + Account Move + account.move + + + + + + + + + \ No newline at end of file diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 0fd6b5b5..18461d59 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -73,5 +73,16 @@ + + + Account Move + account.move + + + + + + + \ No newline at end of file -- cgit v1.2.3 From f953c7c5915e15bd499f374d49403ef2567e0071 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 16:37:47 +0700 Subject: refactor bill receipt --- indoteknik_custom/models/bill_receipt.py | 98 +++++++++++++++----------------- indoteknik_custom/views/bill_receipt.xml | 20 +++---- 2 files changed, 54 insertions(+), 64 deletions(-) diff --git a/indoteknik_custom/models/bill_receipt.py b/indoteknik_custom/models/bill_receipt.py index 39d5f31b..b3f7f0ae 100644 --- a/indoteknik_custom/models/bill_receipt.py +++ b/indoteknik_custom/models/bill_receipt.py @@ -11,8 +11,8 @@ class BillReceipt(models.Model): _rec_name = 'number' number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True) - vendor_id = fields.Many2one('res.partner', string="Vendor", required=True) - document_date = fields.Date(string="Document Date", required=True) + partner_id = fields.Many2one('res.partner', string="Vendor") + document_date = fields.Date(string="Document Date") description = fields.Text(string='Description') validated = fields.Boolean(string="Validated", readonly=True) bill_line = fields.One2many('bill.receipt.line', 'bill_id', string='Bill Receipt Lines') @@ -24,8 +24,41 @@ class BillReceipt(models.Model): return result def validate_button(self): - if not self.bill_line: - raise UserError('Bill receipt line masih kosong') + if self.validated: + raise UserError('Sudah di validate, tidak bisa digenerate ulang') + if self.bill_line: + raise UserError('Harus hapus semua line jika ingin generate ulang') + if self.partner_id.parent_id: + raise UserError('Harus pilih parent company') + + partners = [] + partners += self.partner_id.child_ids + partners.append(self.partner_id) + + for partner in partners: + query = [ + ('move_type', '=', 'in_invoice'), + ('state', '=', 'posted'), + ('payment_state', '=', 'not_paid'), + ('partner_id', '=', partner.id), + ('date_kirim_tukar_faktur', '=', False), + ] + invoices = self.env['account.move'].search(query, order='invoice_date') + count = 0 + for invoice in invoices: + self.env['bill.receipt.line'].create([{ + 'bill_id': self.id, + 'partner_id': invoice.partner_id.id, + 'invoice_id': invoice.id, + 'date_invoice': invoice.invoice_date, + 'efaktur_id': invoice.efaktur_id.id, + 'reference': invoice.ref, + 'total_amt': invoice.amount_total, + 'open_amt': invoice.amount_residual_signed, + 'due_date': invoice.invoice_date_due + }]) + count += 1 + _logger.info("Bill Receipt Line generated %s" % count) self.validated = True @@ -43,53 +76,12 @@ class BillReceiptLine(models.Model): _description = 'Bill Receipt Line' _order = 'bill_id, id' - bill_id = fields.Many2one('bill.receipt', string='Bill Receipt') - sale_order_id = fields.Many2one('sale.order', string='Sale Order') - po_id = fields.Many2one('purchase.order', string='PO') - user_id = fields.Many2one('res.users', string='Purchase Rep') - payment_term_id = fields.Many2one('account.payment.term', string='Payment Terms') - vendor_id = fields.Many2one('res.partner', string='Vendor') - date_approve = fields.Datetime(string='Confirmation Date') - date_planned = fields.Datetime(string='Receipt Date') - amount_untaxed = fields.Float(string='Untaxed Amount') - amount_total = fields.Float(string='Total') + bill_id = fields.Many2one('bill.receipt', string='Bill Ref', required=True, ondelete='cascade', index=True, copy=False) + partner_id = fields.Many2one('res.partner', string='Customer') + invoice_id = fields.Many2one('account.move', string='Invoice') + date_invoice = fields.Date(string='Invoice Date') + efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak') reference = fields.Char(string='Reference') - partner_ref = fields.Char(string='Vendor Reference') - - @api.onchange('po_id') - def onchange_partner_ref(self): - self.partner_ref = self.po_id.partner_ref - - @api.onchange('po_id') - def onchange_vendor_id(self): - self.vendor_id = self.po_id.partner_id - - @api.onchange('po_id') - def onchange_date_approve(self): - self.date_approve = self.po_id.date_approve - - @api.onchange('po_id') - def onchange_date_planned(self): - self.date_planned = self.po_id.date_planned - - @api.onchange('po_id') - def onchange_amount_untaxed(self): - self.amount_untaxed = self.po_id.amount_untaxed - - @api.onchange('po_id') - def onchange_user_id(self): - self.user_id = self.po_id.user_id - - @api.onchange('po_id') - def onchange_sale_order_id(self): - self.sale_order_id = self.po_id.sale_order_id - - @api.onchange('po_id') - def onchange_payment_term_id(self): - self.payment_term_id = self.po_id.payment_term_id - - @api.onchange('po_id') - def onchange_amount_total(self): - self.amount_total = self.po_id.amount_total - - + total_amt = fields.Float(string='Total Amount') + open_amt = fields.Float(string='Open Amount') + due_date = fields.Date(string='Due Date') \ No newline at end of file diff --git a/indoteknik_custom/views/bill_receipt.xml b/indoteknik_custom/views/bill_receipt.xml index c73802c2..138bd0a0 100644 --- a/indoteknik_custom/views/bill_receipt.xml +++ b/indoteknik_custom/views/bill_receipt.xml @@ -6,7 +6,7 @@ - + @@ -19,16 +19,14 @@ bill.receipt.line - - - - - - - + + + + - - + + + @@ -51,7 +49,7 @@ - + -- 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_api/controllers/api_v1/cart.py | 14 +++++++------ indoteknik_api/controllers/api_v1/promotion.py | 6 ++++-- indoteknik_api/controllers/api_v1/sale_order.py | 3 ++- indoteknik_api/models/product_product.py | 5 +++++ 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 +++++++++--- 8 files changed, 41 insertions(+), 37 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index 035a40b7..0265ec57 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -37,7 +37,8 @@ class Cart(controller.Controller): product_id = int(kw.get('product_id', 0)) qty = int(kw.get('qty', 0)) is_selected = kw.get('selected', False) - program_line_id = int(kw.get('program_line_id', False)) + 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) if is_selected: is_selected = True if is_selected == 'true' else False @@ -46,18 +47,19 @@ class Cart(controller.Controller): query = [('user_id', '=', user_id), ('product_id', '=', product_id)] cart = request.env['website.user.cart'].search(query, limit=1) result = {} + data_to_update = { + 'qty': qty, + 'is_selected': is_selected, + 'program_line_id': program_line_id + } if cart: - data_to_update = {'qty': qty, 'is_selected': is_selected} - if program_line_id: - data_to_update['program_line_id'] = program_line_id cart.write(data_to_update) result['id'] = cart.id else: create = request.env['website.user.cart'].create({ 'user_id': user_id, 'product_id': product_id, - 'qty': qty, - 'is_selected': is_selected + **data_to_update }) result['id'] = create.id diff --git a/indoteknik_api/controllers/api_v1/promotion.py b/indoteknik_api/controllers/api_v1/promotion.py index 68a23ef2..f84b8c1c 100644 --- a/indoteknik_api/controllers/api_v1/promotion.py +++ b/indoteknik_api/controllers/api_v1/promotion.py @@ -18,8 +18,7 @@ class Promotion(controller.Controller): data = {} id = int(id) - coupon_program = request.env['coupon.program'].search( - [('id', '=', id)]) + coupon_program = request.env['coupon.program'].search([('id', '=', id)]) if coupon_program: data = { 'banner': base_url + 'api/image/coupon.program/x_studio_banner_promo/' + str(coupon_program.id) if coupon_program.x_studio_banner_promo else '', @@ -37,7 +36,9 @@ class Promotion(controller.Controller): programs = request.env['promotion.program'].search([ ('start_time', '<=', current_time), ('end_time', '>=', current_time), + ('program_line.display_on_homepage', '=', True) ]) + if not programs: return self.response(None) @@ -85,5 +86,6 @@ class Promotion(controller.Controller): product.pop('price', None) product.pop('stock', None) data.append(product) + return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index a2e28cda..8135da33 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -275,7 +275,8 @@ class SaleOrder(controller.Controller): 'type': [], 'delivery_amount': ['number', 'default:0'], 'carrier_id': [], - 'delivery_service_type': [] + 'delivery_service_type': [], + 'voucher': [] }) if not params['valid']: diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 03742d69..334b58c5 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -48,6 +48,11 @@ class ProductProduct(models.Model): } return data + def has_active_program(self): + program_line = self.env['promotion.program.line'] + product_promotions = program_line.get_active_promotions(self.id) + return True if len(product_promotions) > 0 else False + def calculate_website_price(self): pricelist = self.env.user_pricelist 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 bf002b5e297db5f3021b63adf5b60cf00ff4cee8 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 18 Jul 2023 16:50:56 +0700 Subject: fix bug optional hide --- indoteknik_custom/__manifest__.py | 2 +- indoteknik_custom/views/account_bills.xml | 15 --------------- indoteknik_custom/views/account_move.xml | 11 ----------- 3 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 indoteknik_custom/views/account_bills.xml diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index cd7c27d1..b570810f 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -80,7 +80,7 @@ 'views/product_sla.xml', 'views/voucher.xml', 'views/bill_receipt.xml', - 'views/account_bills.xml', + # 'views/account_bills.xml', 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', diff --git a/indoteknik_custom/views/account_bills.xml b/indoteknik_custom/views/account_bills.xml deleted file mode 100644 index cb624396..00000000 --- a/indoteknik_custom/views/account_bills.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Account Move - account.move - - - - - - - - - \ No newline at end of file diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 18461d59..0fd6b5b5 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -73,16 +73,5 @@ - - - Account Move - account.move - - - - - - - \ No newline at end of file -- cgit v1.2.3 From 6f898864f5e825a560cc92f2e1f1973defafba51 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 20 Jul 2023 09:09:31 +0700 Subject: Update voucher api can apply to public voucher --- indoteknik_api/controllers/api_v1/voucher.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py index 0990a1a0..f948183e 100644 --- a/indoteknik_api/controllers/api_v1/voucher.py +++ b/indoteknik_api/controllers/api_v1/voucher.py @@ -2,6 +2,7 @@ from .. import controller from odoo import http from odoo.http import request + class Voucher(controller.Controller): prefix = '/api/v1/' @@ -9,14 +10,14 @@ class Voucher(controller.Controller): @controller.Controller.must_authorized() def get_vouchers(self, **kw): code = kw.get('code') - visibility = 'public' + visibility = ['public'] parameter = [] if code: - visibility = 'private' + visibility.append('private') parameter += [('code', '=', code)] - parameter += [('visibility', '=', visibility)] + parameter += [('visibility', 'in', visibility)] vouchers = request.env['voucher'].get_active_voucher(parameter) data = vouchers.res_format() return self.response(data) -- cgit v1.2.3 From 4ca27c7c265bfc84578b0f56524e9f3f2b0a6aad Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 20 Jul 2023 09:18:17 +0700 Subject: Add partner, amount voucher on voucher view --- indoteknik_custom/views/voucher.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml index cd42586e..17b6ffa0 100755 --- a/indoteknik_custom/views/voucher.xml +++ b/indoteknik_custom/views/voucher.xml @@ -66,6 +66,8 @@ + + -- cgit v1.2.3 From c7389ec4ab18ee7ad993f1ec4d29da9d677ee431 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 20 Jul 2023 09:18:55 +0700 Subject: Update voucher readonly on sale order --- indoteknik_custom/views/sale_order.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 7f4cc4ae..4570f43b 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -26,7 +26,7 @@ - + -- 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_api/controllers/api_v1/sale_order.py | 21 +-------------------- indoteknik_custom/models/website_user_cart.py | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 8135da33..29649315 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -236,26 +236,7 @@ class SaleOrder(controller.Controller): @controller.Controller.must_authorized(private=True, private_key='user_id') def get_user_checkout_so(self, user_id): cart = request.env['website.user.cart'] - products = cart.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 - } + result = cart.get_user_checkout(user_id) return self.response(result) @http.route(PREFIX_PARTNER + 'sale_order/checkout', auth='public', method=['POST', 'OPTIONS'], csrf=False) 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 ed231d1cfa4e78b8f98c5406f88c1f985c0225a7 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 20 Jul 2023 10:43:13 +0700 Subject: Add response on vouccher api - can apply - discount voucher - difference to apply --- indoteknik_api/controllers/api_v1/voucher.py | 36 ++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py index f948183e..5cdafba4 100644 --- a/indoteknik_api/controllers/api_v1/voucher.py +++ b/indoteknik_api/controllers/api_v1/voucher.py @@ -6,10 +6,12 @@ from odoo.http import request class Voucher(controller.Controller): prefix = '/api/v1/' - @http.route(prefix + 'voucher', auth='public', methods=['GET', 'OPTIONS']) - @controller.Controller.must_authorized() + @http.route(prefix + 'user//voucher', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized(private=True, private_key='user_id') def get_vouchers(self, **kw): + cart = request.env['website.user.cart'] code = kw.get('code') + user_id = kw.get('user_id') visibility = ['public'] parameter = [] @@ -19,5 +21,31 @@ class Voucher(controller.Controller): parameter += [('visibility', 'in', visibility)] vouchers = request.env['voucher'].get_active_voucher(parameter) - data = vouchers.res_format() - return self.response(data) + vouchers = vouchers.res_format() + checkout = cart.get_user_checkout(user_id) + + for voucher in vouchers: + subtotal = checkout['subtotal'] + min_purchase_amount = voucher['min_purchase_amount'] + max_discount_amount = voucher['max_discount_amount'] + discount_type = voucher['discount_type'] + discount_amount = voucher['discount_amount'] + can_apply = subtotal >= min_purchase_amount + difference_to_apply = 0 + if not can_apply: + difference_to_apply = min_purchase_amount - subtotal + + discount_voucher = 0 + if discount_type == 'fixed_price': + discount_voucher = discount_amount + if discount_type == 'percentage': + discount_voucher = subtotal * discount_amount / 100 + + if max_discount_amount > 0 and discount_voucher > max_discount_amount: + discount_voucher = max_discount_amount + + voucher['can_apply'] = can_apply + voucher['discount_voucher'] = discount_voucher + voucher['difference_to_apply'] = difference_to_apply + + return self.response(vouchers) -- 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_api/controllers/api_v1/sale_order.py | 6 ++++-- indoteknik_custom/models/website_user_cart.py | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 29649315..88a72755 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -234,9 +234,11 @@ class SaleOrder(controller.Controller): @http.route(prefix + 'user//sale_order/checkout', auth='public', method=['GET', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized(private=True, private_key='user_id') - def get_user_checkout_so(self, user_id): + def get_user_checkout_so(self, user_id, **kw): cart = request.env['website.user.cart'] - result = cart.get_user_checkout(user_id) + voucher_code = kw.get('voucher') + voucher = request.env['voucher'].search([('code', '=', voucher_code)], limit=1) + result = cart.get_user_checkout(user_id, voucher) return self.response(result) @http.route(PREFIX_PARTNER + 'sale_order/checkout', auth='public', method=['POST', 'OPTIONS'], csrf=False) 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 145b370e5b57206edd1b44400c9ed8a7a3d26c36 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Thu, 20 Jul 2023 17:56:34 +0700 Subject: update api product sla --- indoteknik_api/controllers/api_v1/product.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 8411ee25..96b0742a 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -13,31 +13,37 @@ class Product(controller.Controller): prefix = '/api/v1/' @http.route(prefix + 'product_variant//stock', auth='public', methods=['GET', 'OPTIONS']) - @controller.Controller.must_authorized() + # @controller.Controller.must_authorized() def get_product_template_stock_by_id(self, **kw): id = int(kw.get('id')) product = request.env['product.product'].search([('id', '=', id)], limit=1) product_sla = request.env['product.sla'].search([('product_variant_id', '=', id)], limit=1) stock_vendor = request.env['stock.vendor'].search([('product_variant_id', '=', id)], limit=1) - + qty_available = product.qty_onhand_bandengan qty = 0 sla_date = '-' + qty_vendor = stock_vendor.quantity + qty_vendor -= int(qty_vendor * 0.1) + qty_vendor = math.ceil(float(qty_vendor)) + total_excell = qty_vendor + is_altama_product = product.x_manufacture.id in [10,122,89] if is_altama_product: try: qty_altama = request.env['product.template'].get_stock_altama(product.default_code) qty_altama -= int(qty_altama * 0.1) qty_altama = math.ceil(float(qty_altama)) - qty = qty_altama + total_adem = qty_altama if qty_available > 0: - qty += qty_available + qty = qty_available + total_adem sla_date = '1 Hari' - elif qty_altama > 0: + elif qty_altama > 0 or qty_vendor > 0: + qty = total_adem if qty_altama > 0 else total_excell sla_date = '2-4 Hari' - else: + else: sla_date = 'Indent' except: print('error') -- cgit v1.2.3 From 22298c2cfdb7d3de1c7a2e85e21444847b65d4ff Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Thu, 20 Jul 2023 17:57:28 +0700 Subject: add must_authorized in api product sla --- indoteknik_api/controllers/api_v1/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 96b0742a..4795f1fb 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -13,7 +13,7 @@ class Product(controller.Controller): prefix = '/api/v1/' @http.route(prefix + 'product_variant//stock', auth='public', methods=['GET', 'OPTIONS']) - # @controller.Controller.must_authorized() + @controller.Controller.must_authorized() def get_product_template_stock_by_id(self, **kw): id = int(kw.get('id')) product = request.env['product.product'].search([('id', '=', id)], limit=1) -- cgit v1.2.3 From 81175e09c6fa406ee3269265a91ca859659ef7fe Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Thu, 20 Jul 2023 18:01:30 +0700 Subject: add total_excell to condition --- indoteknik_api/controllers/api_v1/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 4795f1fb..87747988 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -38,7 +38,7 @@ class Product(controller.Controller): qty_altama = math.ceil(float(qty_altama)) total_adem = qty_altama if qty_available > 0: - qty = qty_available + total_adem + qty = qty_available + total_adem + total_excell sla_date = '1 Hari' elif qty_altama > 0 or qty_vendor > 0: qty = total_adem if qty_altama > 0 else total_excell -- cgit v1.2.3 From 70c667cb341efa30f29626183bb5dc25654714de Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 21 Jul 2023 08:20:16 +0700 Subject: update stock vendor --- indoteknik_api/controllers/api_v1/product.py | 2 +- indoteknik_custom/models/stock_vendor.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 87747988..53ba7671 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -18,7 +18,7 @@ class Product(controller.Controller): id = int(kw.get('id')) product = request.env['product.product'].search([('id', '=', id)], limit=1) product_sla = request.env['product.sla'].search([('product_variant_id', '=', id)], limit=1) - stock_vendor = request.env['stock.vendor'].search([('product_variant_id', '=', id)], limit=1) + stock_vendor = self.env['stock.vendor'].get_stock_updated_last_7_days(id) qty_available = product.qty_onhand_bandengan diff --git a/indoteknik_custom/models/stock_vendor.py b/indoteknik_custom/models/stock_vendor.py index 1e5bce16..e72748c3 100755 --- a/indoteknik_custom/models/stock_vendor.py +++ b/indoteknik_custom/models/stock_vendor.py @@ -1,5 +1,6 @@ from odoo import fields, models, api import logging +from datetime import datetime, timedelta _logger = logging.getLogger(__name__) @@ -16,6 +17,17 @@ class StockVendor(models.Model): ('done', 'Done') ], string="Cache Reset") + @api.model + def get_stock_updated_last_7_days(self, id): + date_7_days_ago = datetime.now() - timedelta(days=7) + + stocks = self.search([ + ('product_variant_id', '=', id), + ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) + ], limit=1) + + return stocks + def cache_reset(self): stocks = self.env['stock.vendor'].search([ ('cache_reset_status', '=', 'reset'), -- cgit v1.2.3 From ce1c11b9be9274cf281a00cc340969f094a698be Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 21 Jul 2023 10:00:16 +0700 Subject: update receipt bill --- indoteknik_custom/models/bill_receipt.py | 98 ++++++++++++++++++++++---------- indoteknik_custom/views/bill_receipt.xml | 57 ++++++++++++++----- 2 files changed, 110 insertions(+), 45 deletions(-) diff --git a/indoteknik_custom/models/bill_receipt.py b/indoteknik_custom/models/bill_receipt.py index b3f7f0ae..5e03fdce 100644 --- a/indoteknik_custom/models/bill_receipt.py +++ b/indoteknik_custom/models/bill_receipt.py @@ -1,30 +1,68 @@ from odoo import models, api, fields from odoo.exceptions import AccessError, UserError, ValidationError -from datetime import timedelta, date +from datetime import timedelta import logging _logger = logging.getLogger(__name__) + class BillReceipt(models.Model): - _name = "bill.receipt" - _description = "Bill Receipt" - _rec_name = 'number' + _name = 'bill.receipt' + _description = 'Bill Receipt' + _order = 'bill_date desc, id desc' - number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True) - partner_id = fields.Many2one('res.partner', string="Vendor") - document_date = fields.Date(string="Document Date") - description = fields.Text(string='Description') - validated = fields.Boolean(string="Validated", readonly=True) - bill_line = fields.One2many('bill.receipt.line', 'bill_id', string='Bill Receipt Lines') + number = fields.Char(string='Document No', index=True, copy=False, readonly=True) + bill_date = fields.Date(string='Bill Date', required=True) + partner_id = fields.Many2one( + 'res.partner', string='Vendor', + required=True, change_default=True, index=True, tracking=1) + bill_line = fields.One2many('bill.receipt.line', 'bill_id', string='Bill Receipt Lines', auto_join=True) + # dunning_level = fields.Integer(string='Bill Level', default=30, help='30 hari sebelum jatuh tempo invoice') + date_kirim_tukar_faktur = fields.Date(string='Kirim Faktur') + resi_tukar_faktur = fields.Char(string='Resi Faktur') + date_terima_tukar_faktur = fields.Date(string='Terima Faktur') + shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur') + is_validated = fields.Boolean(string='Validated') + notification = fields.Char(string='Notification') - @api.model - def create(self, vals): - vals['number'] = self.env['ir.sequence'].next_by_code('bill.receipt') or '0' - result = super(BillReceipt, self).create(vals) - return result - - def validate_button(self): - if self.validated: + def copy_date_faktur(self): + if not self.is_validated: + raise UserError('Harus di validate dulu') + for line in self.bill_line: + invoice = line.invoice_id + if not invoice.date_kirim_tukar_faktur and self.date_kirim_tukar_faktur: + invoice.date_kirim_tukar_faktur = self.date_kirim_tukar_faktur + tukar_date = self.date_kirim_tukar_faktur + term = invoice.invoice_payment_term_id + add_days = 0 + for line in term.line_ids: + add_days += line.days + due_date = tukar_date + timedelta(days=add_days) + invoice.invoice_date_due = due_date + if not invoice.resi_tukar_faktur: + invoice.resi_tukar_faktur = self.resi_tukar_faktur + if not invoice.date_terima_tukar_faktur and self.date_terima_tukar_faktur: + invoice.date_terima_tukar_faktur = self.date_terima_tukar_faktur + tukar_date = self.date_terima_tukar_faktur + term = invoice.invoice_payment_term_id + add_days = 0 + for line in term.line_ids: + add_days += line.days + due_date = tukar_date + timedelta(days=add_days) + invoice.invoice_date_due = due_date + if not invoice.shipper_faktur_id: + invoice.shipper_faktur_id = self.shipper_faktur_id + self.notification = 'Berhasil copy tanggal terima faktur ke setiap invoice %s' % self.date_terima_tukar_faktur + + def validate_bill(self): + if not self.bill_line: + raise UserError('Bill Line masih kosong, generate dulu') + else: + self.is_validated = True + self.notification = 'Jangan lupa klik Copy Date jika sudah ada tanggal kirim / tanggal terima faktur' + + def generate_bill_line(self): + if self.is_validated: raise UserError('Sudah di validate, tidak bisa digenerate ulang') if self.bill_line: raise UserError('Harus hapus semua line jika ingin generate ulang') @@ -39,8 +77,8 @@ class BillReceipt(models.Model): query = [ ('move_type', '=', 'in_invoice'), ('state', '=', 'posted'), - ('payment_state', '=', 'not_paid'), ('partner_id', '=', partner.id), + ('payment_state', '=', 'not_paid'), ('date_kirim_tukar_faktur', '=', False), ] invoices = self.env['account.move'].search(query, order='invoice_date') @@ -58,19 +96,15 @@ class BillReceipt(models.Model): 'due_date': invoice.invoice_date_due }]) count += 1 - _logger.info("Bill Receipt Line generated %s" % count) - - self.validated = True + _logger.info("Bill Line generated %s" % count) + + @api.model + def create(self, vals): + vals['number'] = self.env['ir.sequence'].next_by_code('bill.receipt') or '0' + result = super(BillReceipt, self).create(vals) + return result - def cancel_button(self): - if not self.bill_line: - raise UserError('Bill receipt line masih kosong') - - if self.validated != True: - raise UserError('Document ini belum di validate') - self.validated = False - class BillReceiptLine(models.Model): _name = 'bill.receipt.line' _description = 'Bill Receipt Line' @@ -80,8 +114,10 @@ class BillReceiptLine(models.Model): partner_id = fields.Many2one('res.partner', string='Customer') invoice_id = fields.Many2one('account.move', string='Invoice') date_invoice = fields.Date(string='Invoice Date') + # due_date = fields.Date(string='Due Date') efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak') reference = fields.Char(string='Reference') total_amt = fields.Float(string='Total Amount') open_amt = fields.Float(string='Open Amount') - due_date = fields.Date(string='Due Date') \ No newline at end of file + due_date = fields.Date(string='Due Date') + diff --git a/indoteknik_custom/views/bill_receipt.xml b/indoteknik_custom/views/bill_receipt.xml index 138bd0a0..c9ab492a 100644 --- a/indoteknik_custom/views/bill_receipt.xml +++ b/indoteknik_custom/views/bill_receipt.xml @@ -6,10 +6,13 @@ + - - - + + + + + @@ -37,29 +40,41 @@
-
- - - + + + + - + + + + + - - + + @@ -67,16 +82,30 @@ + + bill.receipt.list.select + bill.receipt + + + + + + + + + + Bill Line ir.actions.act_window bill.receipt + tree,form Date: Fri, 21 Jul 2023 11:06:58 +0700 Subject: Update voucher use manufacture rules --- indoteknik_api/controllers/api_v1/voucher.py | 29 +++++++++++++++++++++++++--- indoteknik_custom/models/voucher.py | 18 ++++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py index 5cdafba4..96c52e1e 100644 --- a/indoteknik_api/controllers/api_v1/voucher.py +++ b/indoteknik_api/controllers/api_v1/voucher.py @@ -25,14 +25,36 @@ class Voucher(controller.Controller): checkout = cart.get_user_checkout(user_id) for voucher in vouchers: - subtotal = checkout['subtotal'] + apply_status = '' + products = checkout['products'] min_purchase_amount = voucher['min_purchase_amount'] max_discount_amount = voucher['max_discount_amount'] discount_type = voucher['discount_type'] discount_amount = voucher['discount_amount'] - can_apply = subtotal >= min_purchase_amount + can_apply = True difference_to_apply = 0 - if not can_apply: + + manufacture_ids = [x['id'] for x in voucher['manufactures']] + subtotal = 0 + has_match_manufacture = False + for product in products: + price = product['price']['price'] + price_discount = product['price']['price_discount'] + quantity = product['quantity'] + manufacture_id = product['manufacture']['id'] or False + + if len(manufacture_ids) == 0 or manufacture_id in manufacture_ids: + purchase_amt = price * quantity + discount_amt = (price - price_discount) * quantity + subtotal += purchase_amt - discount_amt + has_match_manufacture = True + + if not has_match_manufacture: + can_apply = False + apply_status = 'UM' + elif subtotal < min_purchase_amount: + can_apply = False + apply_status = 'MPA' difference_to_apply = min_purchase_amount - subtotal discount_voucher = 0 @@ -45,6 +67,7 @@ class Voucher(controller.Controller): discount_voucher = max_discount_amount voucher['can_apply'] = can_apply + voucher['apply_status'] = apply_status voucher['discount_voucher'] = discount_voucher voucher['difference_to_apply'] = difference_to_apply 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 8358754e6f258e1f3b9bf602ad45d9c83859b700 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 21 Jul 2023 11:07:06 +0700 Subject: Update voucher views --- indoteknik_custom/views/voucher.xml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml index 17b6ffa0..d79e73f6 100755 --- a/indoteknik_custom/views/voucher.xml +++ b/indoteknik_custom/views/voucher.xml @@ -28,15 +28,7 @@ - - - - - - - - @@ -60,8 +52,20 @@ + + + + + + + + + + -- 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_api/controllers/api_v1/voucher.py | 4 ++-- indoteknik_custom/models/voucher.py | 9 ++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py index 96c52e1e..454961da 100644 --- a/indoteknik_api/controllers/api_v1/voucher.py +++ b/indoteknik_api/controllers/api_v1/voucher.py @@ -34,7 +34,7 @@ class Voucher(controller.Controller): can_apply = True difference_to_apply = 0 - manufacture_ids = [x['id'] for x in voucher['manufactures']] + manufacture_ids = voucher['manufacture_ids'] subtotal = 0 has_match_manufacture = False for product in products: @@ -42,7 +42,7 @@ class Voucher(controller.Controller): price_discount = product['price']['price_discount'] quantity = product['quantity'] manufacture_id = product['manufacture']['id'] or False - + if len(manufacture_ids) == 0 or manufacture_id in manufacture_ids: purchase_amt = price * quantity discount_amt = (price - price_discount) * quantity 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 d157b2340a9c257d5f061b383ad8b909cc6d1ef7 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 21 Jul 2023 14:54:41 +0700 Subject: remove faktur pajak --- indoteknik_custom/models/bill_receipt.py | 3 --- indoteknik_custom/views/bill_receipt.xml | 1 - 2 files changed, 4 deletions(-) diff --git a/indoteknik_custom/models/bill_receipt.py b/indoteknik_custom/models/bill_receipt.py index 5e03fdce..76449c1f 100644 --- a/indoteknik_custom/models/bill_receipt.py +++ b/indoteknik_custom/models/bill_receipt.py @@ -89,7 +89,6 @@ class BillReceipt(models.Model): 'partner_id': invoice.partner_id.id, 'invoice_id': invoice.id, 'date_invoice': invoice.invoice_date, - 'efaktur_id': invoice.efaktur_id.id, 'reference': invoice.ref, 'total_amt': invoice.amount_total, 'open_amt': invoice.amount_residual_signed, @@ -114,8 +113,6 @@ class BillReceiptLine(models.Model): partner_id = fields.Many2one('res.partner', string='Customer') invoice_id = fields.Many2one('account.move', string='Invoice') date_invoice = fields.Date(string='Invoice Date') - # due_date = fields.Date(string='Due Date') - efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak') reference = fields.Char(string='Reference') total_amt = fields.Float(string='Total Amount') open_amt = fields.Float(string='Open Amount') diff --git a/indoteknik_custom/views/bill_receipt.xml b/indoteknik_custom/views/bill_receipt.xml index c9ab492a..15d82e7b 100644 --- a/indoteknik_custom/views/bill_receipt.xml +++ b/indoteknik_custom/views/bill_receipt.xml @@ -25,7 +25,6 @@ - -- cgit v1.2.3 From f4c02f0ca17c0c72314334c03417c2f54382dfa1 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 21 Jul 2023 15:20:08 +0700 Subject: fix condition --- indoteknik_api/controllers/api_v1/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 53ba7671..3667a787 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -44,7 +44,7 @@ class Product(controller.Controller): qty = total_adem if qty_altama > 0 else total_excell sla_date = '2-4 Hari' else: - sla_date = 'Indent' + sla_date = '3-7 Hari' except: print('error') else: -- cgit v1.2.3 From c758c2c63243a01e090a7640839b2dd7ce9476be Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 21 Jul 2023 16:33:22 +0700 Subject: Update contribute pro-rate on create sale order API --- indoteknik_api/controllers/api_v1/sale_order.py | 32 +++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 88a72755..6c878197 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -335,28 +335,36 @@ class SaleOrder(controller.Controller): 'product_uom_qty': item['quantity'], }) - cart_ids = [x['cart_id'] for x in products] - user_cart.browse(cart_ids).unlink() request.env['sale.order.line'].create(parameters) - amount_untaxed = sale_order.amount_untaxed - voucher = request.env['voucher'].search([ - ('code', '=', params['value']['voucher']) - ]) + voucher_code = params['value']['voucher'] + voucher = request.env['voucher'].search([('code', '=', voucher_code)]) if voucher: + amount_untaxed = 0 + manufacture_ids = [x.id for x in voucher.manufacture_ids] + for line in sale_order.order_line: + manufacture_id = line.product_id.x_manufacture.id or False + if len(manufacture_ids) == 0 or manufacture_id in manufacture_ids: + amount_untaxed += line.price_subtotal + voucher_discount = voucher.calculate_discount(amount_untaxed) sale_order.voucher_id = voucher.id sale_order.amount_voucher_disc = voucher_discount - total_qty = sum(line.product_uom_qty for line in sale_order.order_line) - voucher_discount_item = voucher_discount / total_qty for line in sale_order.order_line: + manufacture_id = line.product_id.x_manufacture.id or False + if len(manufacture_ids) > 0 and manufacture_id not in manufacture_ids: + continue + voucher_discount_line = line.price_subtotal / amount_untaxed * voucher_discount + line.amount_voucher_disc = voucher_discount_line + discount_decimal = line.discount / 100 - voucher_discount_line = voucher_discount_item / (1 - discount_decimal) - price = line.price_unit - voucher_discount_line - line.price_unit = price - line.amount_voucher_disc = voucher_discount_item * line.product_uom_qty + voucher_discount_item = voucher_discount_line / line.product_uom_qty + voucher_disc_before_line_disc = voucher_discount_item / (1 - discount_decimal) + line.price_unit -= voucher_disc_before_line_disc + cart_ids = [x['cart_id'] for x in products] + user_cart.browse(cart_ids).unlink() return self.response({ 'id': sale_order.id, 'name': sale_order.name -- 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_api/controllers/api_v1/voucher.py | 3 +++ indoteknik_custom/models/voucher.py | 6 ++++-- indoteknik_custom/views/voucher.xml | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py index 454961da..a6a88cad 100644 --- a/indoteknik_api/controllers/api_v1/voucher.py +++ b/indoteknik_api/controllers/api_v1/voucher.py @@ -18,6 +18,9 @@ class Voucher(controller.Controller): if code: visibility.append('private') parameter += [('code', '=', code)] + user_pricelist = request.env.user_pricelist + if user_pricelist: + parameter += [('excl_pricelist_ids', 'not in', [user_pricelist.id])] parameter += [('visibility', 'in', visibility)] vouchers = request.env['voucher'].get_active_voucher(parameter) 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 diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml index d79e73f6..c6741a8d 100755 --- a/indoteknik_custom/views/voucher.xml +++ b/indoteknik_custom/views/voucher.xml @@ -59,6 +59,7 @@ + -- cgit v1.2.3 From 2a1179b22cd1b8ee9e3e31c157821dbbeb66195f Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Sat, 22 Jul 2023 11:12:14 +0700 Subject: fix bug api product sla stock vendor --- indoteknik_api/controllers/api_v1/product.py | 6 ++++-- indoteknik_custom/models/stock_vendor.py | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 3667a787..587773ee 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -13,12 +13,14 @@ class Product(controller.Controller): prefix = '/api/v1/' @http.route(prefix + 'product_variant//stock', auth='public', methods=['GET', 'OPTIONS']) - @controller.Controller.must_authorized() + # @controller.Controller.must_authorized() def get_product_template_stock_by_id(self, **kw): id = int(kw.get('id')) product = request.env['product.product'].search([('id', '=', id)], limit=1) product_sla = request.env['product.sla'].search([('product_variant_id', '=', id)], limit=1) - stock_vendor = self.env['stock.vendor'].get_stock_updated_last_7_days(id) + stock_vendor = request.env['stock.vendor'].search([('product_variant_id', '=', id)], limit=1) + + stock_vendor = stock_vendor.get_stock_updated_last_7_days() qty_available = product.qty_onhand_bandengan diff --git a/indoteknik_custom/models/stock_vendor.py b/indoteknik_custom/models/stock_vendor.py index e72748c3..dcbeb399 100755 --- a/indoteknik_custom/models/stock_vendor.py +++ b/indoteknik_custom/models/stock_vendor.py @@ -17,12 +17,10 @@ class StockVendor(models.Model): ('done', 'Done') ], string="Cache Reset") - @api.model - def get_stock_updated_last_7_days(self, id): + def get_stock_updated_last_7_days(self): date_7_days_ago = datetime.now() - timedelta(days=7) stocks = self.search([ - ('product_variant_id', '=', id), ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) ], limit=1) -- cgit v1.2.3 From 968f63a411f8cc9e190a261123e47604ce54c2b2 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 24 Jul 2023 08:55:26 +0700 Subject: fix bug and refactor api product sla --- indoteknik_api/controllers/api_v1/product.py | 21 ++++++++++++--------- indoteknik_custom/models/product_template.py | 2 +- indoteknik_custom/models/stock_vendor.py | 9 --------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 587773ee..7ec6459b 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -13,32 +13,35 @@ class Product(controller.Controller): prefix = '/api/v1/' @http.route(prefix + 'product_variant//stock', auth='public', methods=['GET', 'OPTIONS']) - # @controller.Controller.must_authorized() + @controller.Controller.must_authorized() def get_product_template_stock_by_id(self, **kw): id = int(kw.get('id')) + date_7_days_ago = datetime.now() - timedelta(days=7) product = request.env['product.product'].search([('id', '=', id)], limit=1) product_sla = request.env['product.sla'].search([('product_variant_id', '=', id)], limit=1) - stock_vendor = request.env['stock.vendor'].search([('product_variant_id', '=', id)], limit=1) - - stock_vendor = stock_vendor.get_stock_updated_last_7_days() + stock_vendor = request.env['stock.vendor'].search([ + ('product_variant_id', '=', id), + ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) + ], limit=1) qty_available = product.qty_onhand_bandengan qty = 0 sla_date = '-' - - qty_vendor = stock_vendor.quantity - qty_vendor -= int(qty_vendor * 0.1) - qty_vendor = math.ceil(float(qty_vendor)) - total_excell = qty_vendor is_altama_product = product.x_manufacture.id in [10,122,89] if is_altama_product: try: + # Qty Altama qty_altama = request.env['product.template'].get_stock_altama(product.default_code) qty_altama -= int(qty_altama * 0.1) qty_altama = math.ceil(float(qty_altama)) total_adem = qty_altama + # Qty Stock Vendor + qty_vendor = stock_vendor.quantity + qty_vendor -= int(qty_vendor * 0.1) + qty_vendor = math.ceil(float(qty_vendor)) + total_excell = qty_vendor if qty_available > 0: qty = qty_available + total_adem + total_excell sla_date = '1 Hari' diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 1a83b702..7abdf1c1 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -221,7 +221,7 @@ class ProductTemplate(models.Model): datas = json.loads(response.text)['data'] qty = 0 for data in datas: - availability = int(data['availability']) # Mengonversi ke tipe data int + availability = float(data['availability']) # Mengonversi ke tipe data int qty += availability # Mengakumulasi qty dari setiap data return qty diff --git a/indoteknik_custom/models/stock_vendor.py b/indoteknik_custom/models/stock_vendor.py index dcbeb399..f214a5e1 100755 --- a/indoteknik_custom/models/stock_vendor.py +++ b/indoteknik_custom/models/stock_vendor.py @@ -17,15 +17,6 @@ class StockVendor(models.Model): ('done', 'Done') ], string="Cache Reset") - def get_stock_updated_last_7_days(self): - date_7_days_ago = datetime.now() - timedelta(days=7) - - stocks = self.search([ - ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) - ], limit=1) - - return stocks - def cache_reset(self): stocks = self.env['stock.vendor'].search([ ('cache_reset_status', '=', 'reset'), -- 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 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 From 4f743b1b2aa7001466404ebef0516fded12d674d Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 24 Jul 2023 13:41:07 +0700 Subject: invoice induk partner --- indoteknik_custom/models/sale_order.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 3d0dfc17..7b9d5704 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -242,6 +242,16 @@ class SaleOrder(models.Model): self.npwp = parent_id.npwp self.sppkp = parent_id.sppkp self.customer_type = parent_id.customer_type + + @api.onchange('partner_id') + def onchange_partner_id(self): + # INHERIT + result = super(SaleOrder, self).onchange_partner_id() + parent_id = self.partner_id.parent_id + parent_id = parent_id if parent_id else self.partner_id + + self.partner_invoice_id = parent_id + return result def _get_purchases(self): po_state = ['done', 'draft', 'purchase'] -- cgit v1.2.3 From 5b9e37d9a5f95e202be9fd0624e122c7aaacee4d Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Mon, 24 Jul 2023 13:46:24 +0700 Subject: Add parent_name on user api response --- indoteknik_api/models/res_users.py | 1 + 1 file changed, 1 insertion(+) diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index 69981e41..0fe9008b 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -20,6 +20,7 @@ class ResUsers(models.Model): data = { 'id': res_user.id, 'parent_id': res_user.parent_id.id or False, + 'parent_name': res_user.parent_id.name or False, 'partner_id': res_user.partner_id.id, 'name': res_user.name, 'email': res_user.login, -- cgit v1.2.3