summaryrefslogtreecommitdiff
path: root/indoteknik_custom
diff options
context:
space:
mode:
authorIT Fixcomart <it@fixcomart.co.id>2023-07-24 03:31:59 +0000
committerIT Fixcomart <it@fixcomart.co.id>2023-07-24 03:31:59 +0000
commitc1ac22304b557b9982b5fb79d23d29b6faf48090 (patch)
treea1e6db531a5bf19994374e895d5d8a8c9abf1ffa /indoteknik_custom
parent6966c00bf2ef2bd9c2261d9363ac6b463a7766dd (diff)
parent30909e82d7ff1f3cac4700e284f80552a0d38523 (diff)
Merged in feature/voucher-cart (pull request #65)
Feature/voucher cart
Diffstat (limited to 'indoteknik_custom')
-rwxr-xr-xindoteknik_custom/__manifest__.py4
-rwxr-xr-xindoteknik_custom/models/__init__.py4
-rw-r--r--indoteknik_custom/models/ir_attachment.py5
-rw-r--r--indoteknik_custom/models/promotion_program.py19
-rw-r--r--indoteknik_custom/models/promotion_program_free_item.py10
-rw-r--r--indoteknik_custom/models/promotion_program_keyword.py8
-rw-r--r--indoteknik_custom/models/promotion_program_line.py150
-rwxr-xr-xindoteknik_custom/models/sale_order.py3
-rw-r--r--indoteknik_custom/models/voucher.py15
-rw-r--r--indoteknik_custom/models/website_user_cart.py68
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv4
-rw-r--r--indoteknik_custom/views/promotion_program.xml73
-rw-r--r--indoteknik_custom/views/promotion_program_free_item.xml44
-rw-r--r--indoteknik_custom/views/promotion_program_keyword.xml44
-rw-r--r--indoteknik_custom/views/promotion_program_line.xml98
-rwxr-xr-xindoteknik_custom/views/sale_order.xml9
-rwxr-xr-xindoteknik_custom/views/voucher.xml23
-rwxr-xr-xindoteknik_custom/views/website_user_cart.xml4
18 files changed, 573 insertions, 12 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index b570810f..ead47bd3 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -75,6 +75,10 @@
'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',
+ 'views/promotion_program_keyword.xml',
'views/requisition.xml',
'views/landedcost.xml',
'views/product_sla.xml',
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 8b3296a5..929fc8ba 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -15,6 +15,10 @@ 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 promotion_program_keyword
from . import purchase_order_line
from . import purchase_order
from . import purchase_outstanding
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.py b/indoteknik_custom/models/promotion_program.py
new file mode 100644
index 00000000..e60f48e1
--- /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")
+ 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=[
+ ("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")
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..705456dd
--- /dev/null
+++ b/indoteknik_custom/models/promotion_program_free_item.py
@@ -0,0 +1,10 @@
+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_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
new file mode 100644
index 00000000..077f7e12
--- /dev/null
+++ b/indoteknik_custom/models/promotion_program_line.py
@@ -0,0 +1,150 @@
+from odoo import fields, models, api
+from datetime import datetime
+
+
+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=[
+ ("special_price", "Special Price"),
+ ("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")
+ order_line_ids = fields.One2many('sale.order.line', 'program_line_id')
+
+ @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)
+
+ 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([
+ ('program_id.start_time', '<=', current_time),
+ ('program_id.end_time', '>=', current_time),
+ ('product_id', '=', product_id)
+ ])
+
+ def _get_remaining_qty(self, user):
+ remaining_qty = {
+ 'all': self.limit_qty,
+ 'user': self.limit_qty_user,
+ 'transaction': self.limit_qty_transaction
+ }
+ 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 user and 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 _get_remaining_time(self):
+ 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 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 = 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,
+ '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': limit_qty,
+ 'remaining_qty': remaining_qty,
+ 'used_percentage': percent_remaining,
+ 'price': self.calculate_price(price=product_price)
+ }
+
+ 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/sale_order.py b/indoteknik_custom/models/sale_order.py
index 3d0dfc17..deea64a1 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -88,6 +88,7 @@ class SaleOrder(models.Model):
npwp = fields.Char(string="NPWP")
purchase_total = fields.Monetary(string='Purchase Total', compute='_compute_purchase_total')
voucher_id = fields.Many2one(comodel_name='voucher', string='Voucher')
+ amount_voucher_disc = fields.Float(string='Voucher Discount')
def _compute_purchase_total(self):
for order in self:
@@ -589,6 +590,8 @@ class SaleOrderLine(models.Model):
line_no = fields.Integer('No', default=0, copy=False)
note_procurement = fields.Char(string='Note', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring")
vendor_subtotal = fields.Float(string='Vendor Subtotal', compute="_compute_vendor_subtotal")
+ amount_voucher_disc = fields.Float(string='Voucher Discount')
+ program_line_id = fields.Many2one('promotion.program.line', 'Program Line')
def _compute_vendor_subtotal(self):
for line in self:
diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py
index b327df6d..b3a55499 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,15 @@ 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')
+ 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 record.description and len(record.description) > 120:
+ raise ValidationError('Description cannot exceed 120 characters')
def _compute_display_name(self):
for voucher in self:
@@ -61,6 +71,9 @@ class Voucher(models.Model):
'remaining_time': self._res_remaining_time(),
'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],
+ 'excl_pricelist_ids': [x.id for x in self.excl_pricelist_ids],
}
return data
diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py
index 8046469f..29bf4291 100644
--- a/indoteknik_custom/models/website_user_cart.py
+++ b/indoteknik_custom/models/website_user_cart.py
@@ -5,6 +5,70 @@ 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):
+ user_data = {
+ 'partner_id': self.user_id.partner_id.id,
+ 'user_id': self.user_id.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=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):
+ return [x.get_product() for x in self]
+
+ 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 = carts.get_products()
+ return products
+
+ 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),
+ '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
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 379c4c8e..f115da56 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -51,6 +51,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
+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
diff --git a/indoteknik_custom/views/promotion_program.xml b/indoteknik_custom/views/promotion_program.xml
new file mode 100644
index 00000000..5dff80e6
--- /dev/null
+++ b/indoteknik_custom/views/promotion_program.xml
@@ -0,0 +1,73 @@
+<odoo>
+ <record id="promotion_program_tree" model="ir.ui.view">
+ <field name="name">Promotion Program Tree</field>
+ <field name="model">promotion.program</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="name" />
+ <field name="start_time" />
+ <field name="end_time" />
+ <field name="applies_to" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="promotion_program_form" model="ir.ui.view">
+ <field name="name">Promotion Program Form</field>
+ <field name="model">promotion.program</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="name" />
+ <field name="keywords" widget="many2many_tags" />
+ <field name="banner" widget="image" height="160" />
+ </group>
+ <group>
+ <field name="start_time" />
+ <field name="end_time" />
+ <field name="applies_to" />
+ </group>
+ </group>
+ <notebook>
+ <page string="Program Lines" name="program_lines">
+ <field name="program_line" />
+ </page>
+ <page string="Image Properties" name="image_properties">
+ <group>
+ <group>
+ <field name="icon" widget="image" height="120" />
+ <field name="icon_top" widget="image" height="80" />
+ <field name="icon_bottom" widget="image" height="80" />
+ </group>
+ </group>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="promotion_program_action" model="ir.actions.act_window">
+ <field name="name">Promotion Program</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">promotion.program</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_promotion_program_parent"
+ name="Promotion Program"
+ parent="website.menu_website_configuration"
+ sequence="7"
+ />
+
+ <menuitem
+ id="menu_promotion_program"
+ name="Program"
+ parent="indoteknik_custom.menu_promotion_program_parent"
+ sequence="1"
+ action="promotion_program_action"
+ />
+</odoo> \ 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..52d421fe
--- /dev/null
+++ b/indoteknik_custom/views/promotion_program_free_item.xml
@@ -0,0 +1,44 @@
+<odoo>
+ <record id="promotion_program_free_item_tree" model="ir.ui.view">
+ <field name="name">Promotion Program Free Item Tree</field>
+ <field name="model">promotion.program.free_item</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="product_id" />
+ <field name="qty" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="promotion_program_free_item_form" model="ir.ui.view">
+ <field name="name">Promotion Program Free Item Form</field>
+ <field name="model">promotion.program.free_item</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="product_id" />
+ <field name="qty" />
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="promotion_program_free_item_action" model="ir.actions.act_window">
+ <field name="name">Promotion Program Free Item</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">promotion.program.free_item</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_promotion_program_free_item"
+ name="Program Free Item"
+ parent="indoteknik_custom.menu_promotion_program_parent"
+ sequence="3"
+ action="promotion_program_free_item_action"
+ />
+</odoo> \ No newline at end of file
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 @@
+<odoo>
+ <record id="promotion_program_keyword_tree" model="ir.ui.view">
+ <field name="name">Promotion Program Keyword Tree</field>
+ <field name="model">promotion.program.keyword</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="name" />
+ <field name="program_id" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="promotion_program_keyword_form" model="ir.ui.view">
+ <field name="name">Promotion Program Keyword Form</field>
+ <field name="model">promotion.program.keyword</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="name" />
+ <field name="program_id" />
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="promotion_program_keyword_action" model="ir.actions.act_window">
+ <field name="name">Promotion Program Keyword</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">promotion.program.keyword</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_promotion_program_keyword"
+ name="Program Keyword"
+ parent="indoteknik_custom.menu_promotion_program_parent"
+ sequence="4"
+ action="promotion_program_keyword_action"
+ />
+</odoo> \ 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..5963d0dd
--- /dev/null
+++ b/indoteknik_custom/views/promotion_program_line.xml
@@ -0,0 +1,98 @@
+<odoo>
+ <record id="promotion_program_line_tree" model="ir.ui.view">
+ <field name="name">Promotion Program Line Tree</field>
+ <field name="model">promotion.program.line</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="name" />
+ <field name="promotion_type" />
+ <field name="limit_qty" />
+ <field name="limit_qty_user" />
+ <field name="limit_qty_transaction" />
+ <field name="line_free_item" />
+ <field name="display_on_homepage" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="promotion_program_line_form" model="ir.ui.view">
+ <field name="name">Promotion Program Line Form</field>
+ <field name="model">promotion.program.line</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="name" />
+ <field name="promotion_type"/>
+ <field name="product_id" />
+ <field name="image" widget="image" height="160" />
+ </group>
+ <group>
+ <field name="limit_qty" />
+ <field name="limit_qty_user" />
+ <field name="limit_qty_transaction" />
+ <field
+ name="discount_type"
+ attrs="{'invisible': [('promotion_type', '!=', 'special_price')]}"
+ />
+ <field
+ name="discount_amount"
+ attrs="{'invisible': [('promotion_type', '!=', 'special_price')]}"
+ />
+ <field
+ name="minimum_purchase_qty"
+ attrs="{'invisible': [('promotion_type', 'not in', ['discount_loading', 'bundling', 'merchandise'])]}"
+ />
+ <field
+ name="applies_multiply"
+ attrs="{'invisible': [('promotion_type', 'not in', ['discount_loading', 'bundling', 'merchandise'])]}"
+ />
+ <field
+ name="display_on_homepage"
+ attrs="{'invisible': [('promotion_type', '!=', 'special_price')]}"
+ />
+ </group>
+ </group>
+ <notebook>
+ <page
+ string="Line Free Item"
+ name="line_free_items"
+ attrs="{'invisible': [('promotion_type', '=', 'special_price')]}"
+ >
+ <field name="line_free_item" />
+ </page>
+ <page
+ string="Order Line"
+ name="order_line"
+ >
+ <field name="order_line_ids" readonly="1">
+ <tree>
+ <field name="order_id" />
+ <field name="name" />
+ <field name="product_id" />
+ <field name="product_uom_qty" />
+ </tree>
+ </field>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="promotion_program_line_action" model="ir.actions.act_window">
+ <field name="name">Promotion Program Line</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">promotion.program.line</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_promotion_program_line"
+ name="Program Line"
+ parent="indoteknik_custom.menu_promotion_program_parent"
+ sequence="2"
+ action="promotion_program_line_action"
+ />
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index b55fefff..4570f43b 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -26,7 +26,7 @@
<field name="delivery_amt"/>
<field name="fee_third_party"/>
<field name="total_percent_margin"/>
- <field name="voucher_id" />
+ <field name="voucher_id" readonly="1" />
</field>
<field name="analytic_account_id" position="after">
<field name="customer_type" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-28'), ('create_date', '=', False)]}"/>
@@ -71,12 +71,19 @@
<field name="item_percent_margin"/>
<field name="note_procurement" optional="hide"/>
<field name="vendor_subtotal" optional="hide"/>
+ <field name="amount_voucher_disc" string="Voucher" optional="hide"/>
+ <field name="program_line_id" optional="1" />
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']" position="before">
<field name="line_no" readonly="1" optional="hide"/>
</xpath>
<field name="amount_total" position="after">
<field name="grand_total"/>
+ <label for="amount_voucher_disc" string="Voucher" />
+ <div>
+ <field class="mb-0" name="amount_voucher_disc" string="Voucher"/>
+ <div class="text-right mb-2"><small>*Hanya informasi</small></div>
+ </div>
<field name="total_margin"/>
<field name="total_percent_margin"/>
</field>
diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml
index cd42586e..c6741a8d 100755
--- a/indoteknik_custom/views/voucher.xml
+++ b/indoteknik_custom/views/voucher.xml
@@ -28,15 +28,7 @@
<group>
<field name="image" widget="image" width="120"/>
<field name="name" required="1" />
- <field name="description" placeholder="Insert short description..." />
- </group>
- <group string="Rules">
- <field name="code" required="1" />
- <field name="visibility" required="1" />
- <field name="start_time" required="1"/>
- <field name="end_time" required="1"/>
</group>
- <group></group>
<group string="Discount Settings">
<field name="min_purchase_amount" widget="monetary" required="1" />
<field name="discount_type" required="1" />
@@ -60,12 +52,27 @@
<field name="max_discount_amount" widget="monetary" required="1" attrs="{'invisible': [('discount_type', '!=', 'percentage')]}"/>
</group>
+ <group string="Rules">
+ <field name="code" required="1" />
+ <field name="visibility" required="1" />
+ <field name="start_time" required="1"/>
+ <field name="end_time" required="1"/>
+ <field name="limit" required="1"/>
+ <field name="manufacture_ids" widget="many2many_tags"/>
+ <field name="excl_pricelist_ids" widget="many2many_tags"/>
+ </group>
</group>
<notebook>
+ <page name="description" string="Description">
+ <label for="description" string="Max 120 characters:" class="font-weight-normal mb-2 oe_edit_only"/>
+ <field name="description" placeholder="Insert short description..." />
+ </page>
<page name="order_page" string="Orders">
<field name="order_ids" readonly="1">
<tree>
<field name="name" />
+ <field name="partner_id" />
+ <field name="amount_voucher_disc" />
<field name="amount_total" />
</tree>
</field>
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 @@
<tree>
<field name="user_id"/>
<field name="product_id"/>
+ <field name="program_line_id"/>
<field name="qty"/>
+ <field name="is_selected"/>
</tree>
</field>
</record>
@@ -28,7 +30,9 @@
<group>
<field name="user_id"/>
<field name="product_id"/>
+ <field name="program_line_id" domain="[('product_id', '=', product_id)]"/>
<field name="qty"/>
+ <field name="is_selected"/>
</group>
<group></group>
</group>