summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIT Fixcomart <it@fixcomart.co.id>2023-09-29 02:32:56 +0000
committerIT Fixcomart <it@fixcomart.co.id>2023-09-29 02:32:56 +0000
commit78f205302c35cab2512971d64c8152aab2dcfa95 (patch)
tree72be75ad949fe9efaf7b55c8f7f5722225538b28
parent50b5bd7bd984ef108e8bd324440050a222d8262f (diff)
parent0bb47005022b33c79ecfb5924d41f35ce794c5fb (diff)
Merged in production (pull request #126)
Production
-rw-r--r--indoteknik_api/controllers/api_v1/cart.py13
-rw-r--r--indoteknik_api/models/product_product.py153
-rwxr-xr-xindoteknik_custom/__manifest__.py2
-rwxr-xr-xindoteknik_custom/models/__init__.py4
-rw-r--r--indoteknik_custom/models/price_group.py6
-rw-r--r--indoteknik_custom/models/product_attribute.py11
-rwxr-xr-xindoteknik_custom/models/product_template.py86
-rwxr-xr-xindoteknik_custom/models/purchase_order.py20
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py1
-rw-r--r--indoteknik_custom/models/quotation_so_multi_update.py22
-rwxr-xr-xindoteknik_custom/models/sale_order.py36
-rw-r--r--indoteknik_custom/models/sale_orders_multi_update.py22
-rw-r--r--indoteknik_custom/models/solr/__init__.py3
-rw-r--r--indoteknik_custom/models/solr/apache_solr.py4
-rw-r--r--indoteknik_custom/models/solr/product_product.py40
-rw-r--r--indoteknik_custom/models/solr/product_template.py76
-rw-r--r--indoteknik_custom/models/solr/x_banner_banner.py4
-rw-r--r--indoteknik_custom/models/solr/x_banner_category.py54
-rw-r--r--indoteknik_custom/models/solr/x_manufactures.py5
-rw-r--r--indoteknik_custom/models/stock_picking.py2
-rw-r--r--indoteknik_custom/models/users.py1
-rw-r--r--indoteknik_custom/models/voucher.py1
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv2
-rw-r--r--indoteknik_custom/views/account_move_line.xml1
-rw-r--r--indoteknik_custom/views/apache_solr_queue.xml2
-rw-r--r--indoteknik_custom/views/invoice_reklas.xml2
-rw-r--r--indoteknik_custom/views/price_group.xml6
-rwxr-xr-xindoteknik_custom/views/product_template.xml1
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml44
-rw-r--r--indoteknik_custom/views/quotation_so_multi_update.xml31
-rwxr-xr-xindoteknik_custom/views/sale_order.xml23
-rw-r--r--indoteknik_custom/views/sale_orders_multi_update.xml31
-rw-r--r--indoteknik_custom/views/users.xml1
-rwxr-xr-xindoteknik_custom/views/voucher.xml2
-rwxr-xr-xindoteknik_custom/views/x_banner_banner.xml2
-rwxr-xr-xindoteknik_custom/views/x_banner_category.xml9
36 files changed, 539 insertions, 184 deletions
diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py
index 2243ec0f..cb0f5a99 100644
--- a/indoteknik_api/controllers/api_v1/cart.py
+++ b/indoteknik_api/controllers/api_v1/cart.py
@@ -101,4 +101,17 @@ class Cart(controller.Controller):
query += [('product_id', 'in', [int(x) for x in product_ids.split(',')])]
cart = request.env['website.user.cart'].search(query).unlink()
return self.response(cart)
+
+ @http.route(PREFIX_USER + 'cart/select-all', auth='public', methods=['POST', 'OPTIONS'], csrf=False)
+ @controller.Controller.must_authorized(private=True, private_key='user_id')
+ def select_all_cart_by_user_id(self, user_id):
+ user_id = int(user_id)
+
+ website_user_cart = request.env['website.user.cart']
+ query = [('user_id', '=', user_id)]
+ website_user_cart.search(query).write({
+ 'is_selected': True
+ })
+
+ return self.response(True)
\ No newline at end of file
diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py
index 057b449c..78e32762 100644
--- a/indoteknik_api/models/product_product.py
+++ b/indoteknik_api/models/product_product.py
@@ -64,9 +64,9 @@ class ProductProduct(models.Model):
price_discount = self._get_website_price_after_disc_and_tax()
pricelists = {
- 'tier1': self._get_pricelist_tier1,
- 'tier2': self._get_pricelist_tier2,
- 'tier3': self._get_pricelist_tier3,
+ 'tier1': self._get_pricelist_tier(1),
+ 'tier2': self._get_pricelist_tier(2),
+ 'tier3': self._get_pricelist_tier(3),
}
price_tier = pricelist.get_tier_name()
@@ -122,33 +122,31 @@ class ProductProduct(models.Model):
retValue = math.floor(retValue)
return retValue
- def _get_website_price_exclude_tax(self):
- default_divide_tax = float(1.11)
- price_incl = self._get_website_price_include_tax()
- res = price_incl / default_divide_tax
- return math.floor(res)
-
- def _get_website_disc(self, partner_id):
- default_discount_id = int(4)
+ def _v2_get_website_price_include_tax(self):
+ default_pricelist_id = int(17022)
- # compile partner
- partner = self.env['res.partner'].search([('id', '=', partner_id)], limit=1)
-
- if partner:
- if not partner.parent_id: # it means this is a parent
- default_discount_id = partner.custom_pricelist_id
- else: # it means this is NOT parent
- default_discount_id = partner.parent_id.custom_pricelist_id
query = [
- ('pricelist_id.id', '=', default_discount_id),
+ ('pricelist_id.id', '=', default_pricelist_id),
('product_id.id', '=', self.id)
]
-
- pl_item2 = self.env['product.pricelist.item'].search(query, limit=1)
+ pl_item1 = self.env['product.pricelist.item'].search(query, limit=1)
- retValue = pl_item2.price_discount
+ retValue = pl_item1.fixed_price
+ retValue = math.floor(retValue)
return retValue
+ def _get_website_price_exclude_tax(self):
+ default_divide_tax = float(1.11)
+ price_incl = self._get_website_price_include_tax()
+ res = price_incl / default_divide_tax
+ return math.floor(res)
+
+ def _v2_get_website_price_exclude_tax(self):
+ default_divide_tax = float(1.11)
+ price_incl = self._v2_get_website_price_include_tax()
+ res = price_incl / default_divide_tax
+ return math.floor(res)
+
def _get_website_price_after_disc_and_tax(self):
default_divide_tax = float(1.11)
price_after_disc = self._get_website_price_after_disc()
@@ -156,6 +154,25 @@ class ProductProduct(models.Model):
res = math.ceil(res)
return res
+ def _v2_get_website_price_after_disc_and_tax(self):
+ default_divide_tax = float(1.11)
+ price_after_disc = self._v2_get_website_price_after_disc()
+ res = price_after_disc / default_divide_tax
+ res = math.ceil(res)
+ return res
+
+ def _get_website_tax(self):
+ default_percent_tax = float(11)
+ price_after_disc = self._get_website_price_after_disc_and_tax()
+ res = price_after_disc * default_percent_tax / 100
+ return math.floor(res)
+
+ def _v2_get_website_tax(self):
+ default_percent_tax = float(11)
+ price_after_disc = self._v2_get_website_price_after_disc_and_tax()
+ res = price_after_disc * default_percent_tax / 100
+ return math.floor(res)
+
def _get_website_price_after_disc(self):
discount = self._get_website_disc(0)
price_incl = self._get_website_price_include_tax()
@@ -166,75 +183,59 @@ class ProductProduct(models.Model):
res = price_incl
return math.floor(res)
- def _get_website_tax(self):
- default_percent_tax = float(11)
- price_after_disc = self._get_website_price_after_disc_and_tax()
- res = price_after_disc * default_percent_tax / 100
+ def _v2_get_website_price_after_disc(self):
+ discount = self._get_website_disc(0)
+ price_incl = self._v2_get_website_price_include_tax()
+ res = 0
+ if discount > 0:
+ res = price_incl - (price_incl * discount / 100)
+ else:
+ res = price_incl
return math.floor(res)
- def _get_pricelist_tier1(self):
- product_pricelist_tier1 = int(self.env['ir.config_parameter'].get_param('product.pricelist.tier1'))
- default_divide_tax = float(1.11)
- base_price = discount = price = 0
- pricelist_item = self.env['product.pricelist.item'].search([
- ('pricelist_id', '=', product_pricelist_tier1),
- ('product_id', '=', self.id)
- ], limit=1)
- if pricelist_item:
- # base_price = self._get_website_price_exclude_tax()
- base_price_incl = self._get_website_price_include_tax()
- discount = pricelist_item.price_discount
- price = base_price_incl - (base_price_incl * discount / 100)
- price = price / default_divide_tax
- price = math.floor(price)
- data = {
- # 'base_price_tier1': base_price or 0,
- 'discount_tier1': discount or 0,
- 'price_tier1': price or 0
- }
- return data
-
- def _get_pricelist_tier2(self):
- product_pricelist_tier2 = int(self.env['ir.config_parameter'].get_param('product.pricelist.tier2'))
- default_divide_tax = float(1.11)
- base_price = discount = price = 0
- pricelist_item = self.env['product.pricelist.item'].search([
- ('pricelist_id', '=', product_pricelist_tier2),
- ('product_id', '=', self.id)
- ], limit=1)
- if pricelist_item:
- # base_price = self._get_website_price_exclude_tax()
- base_price_incl = self._get_website_price_include_tax()
- discount = pricelist_item.price_discount
- price = base_price_incl - (base_price_incl * discount / 100)
- price = price / default_divide_tax
- price = math.floor(price)
- data = {
- # 'base_price_tier2': base_price or 0,
- 'discount_tier2': discount or 0,
- 'price_tier2': price or 0
- }
- return data
+ def _get_website_disc(self, partner_id):
+ default_discount_id = int(4)
+
+ # compile partner
+ partner = self.env['res.partner'].search([('id', '=', partner_id)], limit=1)
+
+ if partner:
+ if not partner.parent_id: # it means this is a parent
+ default_discount_id = partner.custom_pricelist_id
+ else: # it means this is NOT parent
+ default_discount_id = partner.parent_id.custom_pricelist_id
+ query = [
+ ('pricelist_id.id', '=', default_discount_id),
+ ('product_id.id', '=', self.id)
+ ]
+
+ pl_item2 = self.env['product.pricelist.item'].search(query, limit=1)
+
+ retValue = pl_item2.price_discount
+ return retValue
- def _get_pricelist_tier3(self):
- product_pricelist_tier3 = int(self.env['ir.config_parameter'].get_param('product.pricelist.tier3'))
+ def _get_pricelist_tier(self, tier_number):
+ config_param_name = f'product.pricelist.tier{tier_number}'
+ product_pricelist_tier = int(self.env['ir.config_parameter'].get_param(config_param_name))
default_divide_tax = float(1.11)
base_price = discount = price = 0
pricelist_item = self.env['product.pricelist.item'].search([
- ('pricelist_id', '=', product_pricelist_tier3),
+ ('pricelist_id', '=', int(product_pricelist_tier)),
('product_id', '=', self.id)
], limit=1)
if pricelist_item:
# base_price = self._get_website_price_exclude_tax()
base_price_incl = self._get_website_price_include_tax()
+ if tier_number in ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2']:
+ base_price_incl = self._v2_get_website_price_include_tax()
+
discount = pricelist_item.price_discount
price = base_price_incl - (base_price_incl * discount / 100)
price = price / default_divide_tax
price = math.floor(price)
data = {
- # 'base_price_tier3': base_price or 0,
- 'discount_tier3': discount or 0,
- 'price_tier3': price or 0
+ f'discount_tier{tier_number}': discount or 0,
+ f'price_tier{tier_number}': price or 0
}
return data
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 10878e32..48434845 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -95,6 +95,8 @@
'views/cost_centre.xml',
'views/account_account_views.xml',
'views/account_move_line.xml',
+ 'views/sale_orders_multi_update.xml',
+ 'views/quotation_so_multi_update.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 f51f95af..95defed6 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -86,4 +86,6 @@ from . import cost_centre
from . import account_account
from . import account_move_line
from . import stock_scheduler_compute
-from . import promotion \ No newline at end of file
+from . import promotion
+from . import sale_orders_multi_update
+from . import quotation_so_multi_update \ No newline at end of file
diff --git a/indoteknik_custom/models/price_group.py b/indoteknik_custom/models/price_group.py
index 50f0520f..2a1bbc91 100644
--- a/indoteknik_custom/models/price_group.py
+++ b/indoteknik_custom/models/price_group.py
@@ -15,6 +15,9 @@ class PriceGroup(models.Model):
group3 = fields.Float(string='Kelompok 3 (%)')
group4 = fields.Float(string='Kelompok 4 (%)')
group5 = fields.Float(string='Kelompok 5 (%)')
+ group6 = fields.Float(string='Kelompok 6 (%)')
+ group7 = fields.Float(string='Kelompok 7 (%)')
+ group8 = fields.Float(string='Kelompok 8 (%)')
class Manufacture(models.Model):
_inherit = 'x_manufactures'
@@ -25,4 +28,7 @@ class Manufacture(models.Model):
('group3', 'Kelompok 3'),
('group4', 'Kelompok 4'),
('group5', 'Kelompok 5'),
+ ('group6', 'Kelompok 6'),
+ ('group7', 'Kelompok 7'),
+ ('group8', 'Kelompok 8'),
], string='Pricing Group', copy=False)
diff --git a/indoteknik_custom/models/product_attribute.py b/indoteknik_custom/models/product_attribute.py
index 784ccd81..e3076805 100644
--- a/indoteknik_custom/models/product_attribute.py
+++ b/indoteknik_custom/models/product_attribute.py
@@ -5,11 +5,16 @@ import re
class ProductAttributeValue(models.Model):
_inherit = 'product.attribute.value'
+
@api.constrains('name')
def _validate_name(self):
- pattern = r'^[a-zA-Z0-9\[\]\(\)\.\s/%]+$'
+ rule_regex = self.env['ir.config_parameter'].sudo().get_param('product.product.rule_name_regex') or ''
+ pattern = rf'^{rule_regex}$'
if not re.match(pattern, self.name):
- pattern_suggest = r'[a-zA-Z0-9\[\]\(\)\.\s/%]+'
+ pattern_suggest = rf"{rule_regex}"
suggest = ''.join(re.findall(pattern_suggest, self.name))
- raise UserError(f'Nama hanya bisa menggunakan angka, huruf kecil, huruf besar, titik, kurung lengkung, kurung siku, garis miring. Contoh: {suggest}')
+ raise UserError(f'Contoh yang benar adalah {suggest}')
+
+
+
\ No newline at end of file
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 4c11dcef..d35188b4 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -1,5 +1,5 @@
from odoo import fields, models, api
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, date
from odoo.exceptions import UserError
import logging
import requests
@@ -52,11 +52,30 @@ class ProductTemplate(models.Model):
help='Centang jika ingin ditammpilkan di website sebagai segment Produk Baru')
seq_new_product = fields.Integer(string='Seq New Product', help='Urutan Sequence New Product')
is_edited = fields.Boolean(string='Is Edited')
+ publish = fields.Boolean(string='Publish', default=True)
+
+ @api.constrains('active')
+ def constrains_active_publish(self):
+ if not self.active or self.type != 'product':
+ self.publish = False
+ else:
+ self.publish = True
+
+ self._create_solr_queue('_sync_product_template_to_solr')
+
+ def day_product_to_edit(self):
+ day_products = []
+
+ for product in self:
+ day_product = (product.write_date - product.create_date).days
+ day_products.append(day_product)
+
+ return day_products
@api.constrains('name', 'default_code')
def _check_duplicate_product(self):
for product in self:
- if not self.env.user.is_purchasing_manager:
+ if not self.env.user.is_purchasing_manager and not self.env.user.is_editor_product:
domain = [('default_code', '!=', False)]
if product.product_variant_ids:
@@ -76,22 +95,21 @@ class ProductTemplate(models.Model):
if product.write_date == product.create_date:
message = "SKU atau Name yang Anda gunakan sudah digunakan di produk lain"
- else:
+ elif all(day_product > 0 for day_product in product.day_product_to_edit()):
domain = [('id', '=', product.id)]
message = "Hanya Pak Tyas yang dapat merubah data produk"
-
existing_purchase = self.search(domain, limit=1)
-
if existing_purchase:
raise UserError(message)
@api.constrains('name')
def _validate_name(self):
- pattern = r'^[a-zA-Z0-9\[\]\(\)\.\s/%-]+$'
+ rule_regex = self.env['ir.config_parameter'].sudo().get_param('product.product.rule_name_regex') or ''
+ pattern = rf'^{rule_regex}$'
if not re.match(pattern, self.name):
- pattern_suggest = r'[a-zA-Z0-9\[\]\(\)\.\s/%-]+'
+ pattern_suggest = rf"{rule_regex}"
suggest = ''.join(re.findall(pattern_suggest, self.name))
- raise UserError(f'Nama hanya bisa menggunakan angka, strip, huruf kecil, huruf besar, titik, kurung lengkung, kurung siku, garis miring. Contoh: {suggest}')
+ raise UserError(f'Contoh yang benar adalah {suggest}')
# def write(self, vals):
# if 'solr_flag' not in vals and self.solr_flag == 1:
@@ -175,13 +193,7 @@ class ProductTemplate(models.Model):
def _compute_web_price(self):
for template in self:
- # product = self.env['product.product'].search([('product_tmpl_id', '=', template.id)], limit=1)
-
- product_pricelist_item = self.env['product.pricelist.item'].search([
- ('pricelist_id', '=', 1),
- ('product_id', '=', template.product_variant_id.id)], limit=1)
- price = product_pricelist_item.fixed_price
- template.web_price = price
+ template.web_price = template.product_variant_ids[0].web_price
def _have_promotion_program(self):
for template in self:
@@ -324,10 +336,19 @@ class ProductProduct(models.Model):
sla_version = fields.Integer(string="SLA Version", default=0)
is_edited = fields.Boolean(string='Is Edited')
+ def day_product_to_edit(self):
+ day_products = []
+
+ for product in self:
+ day_product = (product.write_date - product.create_date).days
+ day_products.append(day_product)
+
+ return day_products
+
@api.constrains('name','default_code')
def _check_duplicate_product(self):
- if not self.env.user.is_purchasing_manager:
- for product in self:
+ for product in self:
+ if not self.env.user.is_purchasing_manager and not self.env.user.is_editor_product:
if product.write_date == product.create_date:
domain = [
('default_code', '!=', False),
@@ -340,25 +361,20 @@ class ProductProduct(models.Model):
existing_purchase = self.search(domain, limit=1)
if existing_purchase:
raise UserError(massage)
- else:
- domain = [
- ('id', '=', product.id),
- ('is_edited', '=', True),
- ]
+ elif all(day_product > 0 for day_product in product.day_product_to_edit()):
+ domain = [('id', '=', product.id)]
existing_purchase = self.search(domain)
if existing_purchase:
raise UserError('Hanya Pak Tyas Yang Dapat Merubah Data Product')
- if not existing_purchase:
- true = True
- self.is_edited = true
-
+
@api.constrains('name')
def _validate_name(self):
- pattern = r'^[a-zA-Z0-9\[\]\(\)\.\s/%-]+$'
+ rule_regex = self.env['ir.config_parameter'].sudo().get_param('product.product.rule_name_regex') or ''
+ pattern = rf'^{rule_regex}$'
if not re.match(pattern, self.name):
- pattern_suggest = r'[a-zA-Z0-9\[\]\(\)\.\s/%-]+'
+ pattern_suggest = rf"{rule_regex}"
suggest = ''.join(re.findall(pattern_suggest, self.name))
- raise UserError(f'Nama hanya bisa menggunakan angka, strip, huruf kecil, huruf besar, titik, kurung lengkung, kurung siku, garis miring. Contoh: {suggest}')
+ raise UserError(f'Contoh yang benar adalah {suggest}')
def _get_qty_incoming_bandengan(self):
for product in self:
@@ -389,8 +405,16 @@ class ProductProduct(models.Model):
def _compute_web_price(self):
for product in self:
- product_pricelist_item = self.env['product.pricelist.item'].search(
- [('pricelist_id', '=', 1), ('product_id', '=', product.id)], limit=1)
+ pricelist_id = self.env.context.get('pricelist')
+
+ domain = [('pricelist_id', '=', pricelist_id or 1), ('product_id', '=', product.id)]
+ product_pricelist_item = self.env['product.pricelist.item'].search(domain, limit=1)
+
+ if product_pricelist_item.base_pricelist_id:
+ base_pricelist_id = product_pricelist_item.base_pricelist_id.id
+ domain = [('pricelist_id', '=', base_pricelist_id), ('product_id', '=', product.id)]
+ product_pricelist_item = self.env['product.pricelist.item'].search(domain, limit=1)
+
product.web_price = product_pricelist_item.fixed_price
def _compute_stock_vendor(self):
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 3fb61955..8ad25228 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -46,6 +46,11 @@ class PurchaseOrder(models.Model):
summary_qty_receipt = fields.Float('Summary Qty Receipt', compute='_compute_summary_qty')
count_line_product = fields.Float('Total Item', compute='compute_count_line_product')
note_description = fields.Char(string='Note', help='bisa diisi sebagai informasi indent barang tertentu atau apapun')
+ has_active_invoice = fields.Boolean(string='Has Active Invoice', compute='_compute_has_active_invoice')
+
+ def _compute_has_active_invoice(self):
+ for order in self:
+ order.has_active_invoice = any(invoice.state != 'cancel' for invoice in order.invoice_ids)
def add_product_to_pricelist(self):
for line in self.order_line:
@@ -195,6 +200,7 @@ class PurchaseOrder(models.Model):
'product_qty': order_line.product_qty,
'qty_available_store': qty_available,
'suggest': suggest,
+ 'so_line_id': order_line.id,
}
self.order_line.create(values)
@@ -258,8 +264,6 @@ class PurchaseOrder(models.Model):
self.env['po.sync.price'].create([{
'order_line_id': line.id,
}])
-
-
def _send_mail(self):
output = io.BytesIO()
@@ -325,7 +329,7 @@ class PurchaseOrder(models.Model):
def re_calculate(self):
for line in self.order_line:
sale_order_line = self.env['sale.order.line'].search([
- ('product_id', '=', line.product_id.id),
+ ('id', '=', line.so_line_id.id),
('order_id', '=', line.order_id.sale_order_id.id)
], limit=1, order='price_reduce_taxexcl')
for so_line in sale_order_line:
@@ -340,9 +344,13 @@ class PurchaseOrder(models.Model):
def compute_total_margin(self):
sum_so_margin = sum_sales_price = sum_margin = 0
for line in self.order_line:
- sale_order_line = self.env['sale.order.line'].search(
- [('product_id', '=', line.product_id.id),
- ('order_id', '=', line.order_id.sale_order_id.id)], limit=1, order='price_reduce_taxexcl')
+ sale_order_line = line.so_line_id
+ if not sale_order_line:
+ sale_order_line = self.env['sale.order.line'].search([
+ ('product_id', '=', line.product_id.id),
+ ('order_id', '=', line.order_id.sale_order_id.id)
+ ], limit=1, order='price_reduce_taxexcl')
+
sum_so_margin += sale_order_line.item_margin
sales_price = sale_order_line.price_reduce_taxexcl * sale_order_line.product_uom_qty
if sale_order_line.order_id.shipping_cost_covered == 'indoteknik':
diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py
index 39aeba0f..95e85122 100755
--- a/indoteknik_custom/models/purchase_order_line.py
+++ b/indoteknik_custom/models/purchase_order_line.py
@@ -29,6 +29,7 @@ class PurchaseOrderLine(models.Model):
qty_available_store = fields.Float(string='Available')
suggest = fields.Char(string='Suggest')
price_vendor = fields.Float(string='Price Vendor', compute='compute_price_vendor')
+ so_line_id = fields.Many2one('sale.order.line', string='ID SO Line')
def compute_price_vendor(self):
for line in self:
diff --git a/indoteknik_custom/models/quotation_so_multi_update.py b/indoteknik_custom/models/quotation_so_multi_update.py
new file mode 100644
index 00000000..105b7963
--- /dev/null
+++ b/indoteknik_custom/models/quotation_so_multi_update.py
@@ -0,0 +1,22 @@
+from odoo import models, fields
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class QuotationSoMultiUpdate(models.TransientModel):
+ _name = 'quotation.so.multi_update'
+
+ def save_multi_update_quotation(self):
+ quotation_ids = self._context['quotation_ids']
+ sales = self.env['sale.order'].browse(quotation_ids)
+ sales.action_multi_update_state()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'Status berhasil diubah',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ } \ No newline at end of file
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 376b8e40..71163fa4 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -58,7 +58,7 @@ class SaleOrder(models.Model):
('partial_chargeback', 'Partial Chargeback'),
('authorize', 'Authorize'),
], tracking=True, string='Payment Status', help='Payment Gateway Status / Midtrans / Web, https://docs.midtrans.com/en/after-payment/status-cycle')
- date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ yang terakhir, tidak berpengaruh ke Accounting")
+ date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ yang terakhir, tidak berpengaruh ke Accounting", tracking=True)
payment_type = fields.Char(string='Payment Type', help='Jenis pembayaran dengan Midtrans')
gross_amount = fields.Float(string='Gross Amount', help='Jumlah pembayaran yang dilakukan dengan Midtrans')
notification = fields.Char(string='Notification', help='Dapat membantu error dari approval')
@@ -78,8 +78,41 @@ class SaleOrder(models.Model):
amount_voucher_disc = fields.Float(string='Voucher Discount')
source_id = fields.Many2one('utm.source', 'Source', domain="[('id', 'in', [32, 59, 60, 61])]")
estimated_arrival_days = fields.Integer('Estimated Arrival Days', default=0)
+ email = fields.Char(string='Email')
picking_iu_id = fields.Many2one('stock.picking', 'Picking IU')
+ @api.model
+ def action_multi_update_state(self):
+ for sale in self:
+ sale.update({
+ 'state': 'cancel',
+ })
+
+ if sale.state == 'cancel':
+ sale.update({
+ 'approval_status': False,
+ })
+
+ def open_form_multi_update_status(self):
+ action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_sale_orders_multi_update')
+ action['context'] = {
+ 'sale_ids': [x.id for x in self]
+ }
+ return action
+
+ def open_form_multi_update_state(self):
+ action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_quotation_so_multi_update')
+ action['context'] = {
+ 'quotation_ids': [x.id for x in self]
+ }
+ return action
+
+ def action_multi_update_invoice_status(self):
+ for sale in self:
+ sale.update({
+ 'invoice_status': 'invoiced',
+ })
+
def _compute_purchase_total(self):
for order in self:
total = 0
@@ -173,6 +206,7 @@ class SaleOrder(models.Model):
self.npwp = parent_id.npwp
self.sppkp = parent_id.sppkp
self.customer_type = parent_id.customer_type
+ self.email = parent_id.email
@api.onchange('partner_id')
def onchange_partner_id(self):
diff --git a/indoteknik_custom/models/sale_orders_multi_update.py b/indoteknik_custom/models/sale_orders_multi_update.py
new file mode 100644
index 00000000..95cfde21
--- /dev/null
+++ b/indoteknik_custom/models/sale_orders_multi_update.py
@@ -0,0 +1,22 @@
+from odoo import models, fields
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class SaleOrdersMultiUpdate(models.TransientModel):
+ _name = 'sale.orders.multi_update'
+
+ def save_multi_update_so(self):
+ sale_ids = self._context['sale_ids']
+ sales = self.env['sale.order'].browse(sale_ids)
+ sales.action_multi_update_invoice_status()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'Invoice Status berhasil diubah',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ } \ No newline at end of file
diff --git a/indoteknik_custom/models/solr/__init__.py b/indoteknik_custom/models/solr/__init__.py
index 16da73af..f2d13116 100644
--- a/indoteknik_custom/models/solr/__init__.py
+++ b/indoteknik_custom/models/solr/__init__.py
@@ -7,4 +7,5 @@ from . import product_template
from . import website_categories_homepage
from . import x_manufactures
from . import x_banner_banner
-from . import product_public_category \ No newline at end of file
+from . import product_public_category
+from . import x_banner_category \ No newline at end of file
diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py
index eb02cb57..5acfded8 100644
--- a/indoteknik_custom/models/solr/apache_solr.py
+++ b/indoteknik_custom/models/solr/apache_solr.py
@@ -213,6 +213,8 @@ class ApacheSolr(models.Model):
end_time = time.time()
_logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time))
+ return True
+
def _test_product_price(self, product_id=228178):
product = self.env['product.product'].search([('id', '=', product_id)], limit=1)
_logger.info('price incl tax: %s' % product._get_website_price_include_tax())
@@ -287,3 +289,5 @@ class ApacheSolr(models.Model):
_variants_solr.add(documents)
end_time = time.time()
_logger.info("[SYNC_VARIANTS_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time))
+
+ return False
diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py
index 93e26793..41af2d0e 100644
--- a/indoteknik_custom/models/solr/product_product.py
+++ b/indoteknik_custom/models/solr/product_product.py
@@ -31,8 +31,6 @@ class ProductProduct(models.Model):
solr_model = self.env['apache.solr']
for variant in self:
- if not variant.product_tmpl_id.active and variant.product_tmpl_id.type != 'product':
- continue
category_id = 0
category_name = ''
@@ -64,7 +62,8 @@ class ProductProduct(models.Model):
'search_rank_i': variant.product_tmpl_id.search_rank,
'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly,
'attributes': [x.name for x in variant.product_template_attribute_value_ids],
- 'has_product_info_b': True
+ 'has_product_info_b': True,
+ 'publish_b': variant.product_tmpl_id.publish,
})
self.solr().add(docs=[document], softCommit=True)
@@ -78,18 +77,18 @@ class ProductProduct(models.Model):
for variant in self:
price_excl_after_disc = price_excl = discount = tax = 0
- flashsale_data = tier1 = tier2 = tier3 = {}
+ flashsale_data = {}
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()
+ discount = variant._get_website_disc(0)
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()
+
+ price_excl_v2 = variant._v2_get_website_price_exclude_tax()
+ price_excl_after_disc_v2 = variant._v2_get_website_price_after_disc_and_tax()
+ tax_v2 = variant._v2_get_website_tax()
document = solr_model.get_doc('variants', variant.id)
document.update({
@@ -106,14 +105,23 @@ class ProductProduct(models.Model):
"discount_f": discount,
"price_discount_f": price_excl_after_disc,
"tax_f": tax,
- "discount_tier1_f": tier1.get('discount_tier1', 0),
- "price_tier1_f": tier1.get('price_tier1', 0),
- "discount_tier2_f": tier2.get('discount_tier2', 0),
- "price_tier2_f": tier2.get('price_tier2', 0),
- "discount_tier3_f": tier3.get('discount_tier3', 0),
- "price_tier3_f": tier3.get('price_tier3', 0),
- "has_price_info_b": True
+ "price_v2_f": price_excl_v2,
+ "price_discount_v2_f": price_excl_after_disc_v2,
+ "tax_v2_f": tax_v2,
})
+
+ for tier_number in [1, 2, 3, '1_v2', '2_v2', '3_v2', '4_v2', '5_v2']:
+ tier = variant._get_pricelist_tier(tier_number)
+ document.update({
+ f"discount_tier{tier_number}_f": tier.get(f'discount_tier{tier_number}', 0),
+ f"price_tier{tier_number}_f": tier.get(f'price_tier{tier_number}', 0),
+ })
+
+ # for tier_number in [1, 2, 3, '1_v2', '2_v2', '3_v2', '4_v2', '5_v2']:
+ # tier = tier_data[tier_number]
+
+ document.update({"has_price_info_b": True})
+
self.solr().add(docs=[document], softCommit=True)
variant.change_solr_data('Ada perubahan pada harga product')
diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py
index ea976359..b4782d1c 100644
--- a/indoteknik_custom/models/solr/product_template.py
+++ b/indoteknik_custom/models/solr/product_template.py
@@ -23,9 +23,21 @@ class ProductTemplate(models.Model):
'function_name': function_name
})
- @api.constrains('active')
- def _create_solr_queue_sync_active(self):
- self._create_solr_queue('_sync_active_template_solr')
+ @api.constrains('active', 'type')
+ def constrains_active(self):
+ for template in self:
+ template.publish = template.active and template.type == 'product'
+ self._create_solr_queue('_sync_product_template_to_solr')
+
+ @api.constrains('publish')
+ def constrains_publish(self):
+ for template in self:
+ if template.active and template.type == 'product':
+ continue
+ template.product_variant_ids.publish = template.publish
+ self._create_solr_queue('_sync_product_template_to_solr')
+
+ constrains_active._priority = 1
@api.constrains('name', 'default_code', 'weight', 'x_manufacture', 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920')
def _create_solr_queue_sync_product_template(self):
@@ -42,25 +54,10 @@ class ProductTemplate(models.Model):
product._create_solr_queue('_sync_price_to_solr')
product.solr_flag = 1
- def _sync_active_template_solr(self):
- for template in self:
- if not template.active or template.type != 'product':
- template._sync_delete_solr()
- else:
- template._sync_product_template_to_solr()
- template._sync_price_to_solr()
-
- products = self.env['product.product'].search(
- [('product_tmpl_id', '=', template.id), ('active', 'in', [True, False])])
- products._sync_variants_to_solr()
-
def _sync_product_template_to_solr(self):
solr_model = self.env['apache.solr']
for template in self:
- if not template.active or template.type != 'product':
- continue
-
variant_names = ', '.join([x.display_name or '' for x in template.product_variant_ids])
variant_codes = ', '.join([x.default_code or '' for x in template.product_variant_ids])
@@ -96,10 +93,15 @@ class ProductTemplate(models.Model):
"category_name": category_name,
"description_t": template.website_description or '',
'has_product_info_b': True,
+ 'publish_b': template.publish
})
self.solr().add(docs=[document], softCommit=True)
- template.product_variant_ids._sync_variants_to_solr()
+ products = self.env['product.product'].search([
+ ('product_tmpl_id', '=', template.id),
+ ('active', 'in', [True, False])
+ ])
+ products._sync_variants_to_solr()
self.change_solr_data('Perubahan pada data product')
if not document.get('has_price_info_b'):
@@ -110,6 +112,8 @@ class ProductTemplate(models.Model):
for template in self:
flashsale_data = {}
+ price_excl = price_excl_after_disc = discount = tax = 0
+ tier_data = {}
for variant in template.product_variant_ids:
variant_flashsale = variant._get_flashsale_price()
@@ -123,9 +127,10 @@ class ProductTemplate(models.Model):
price_excl_after_disc = variant._get_website_price_after_disc_and_tax()
discount = variant._get_website_disc(0)
tax = variant._get_website_tax()
- tier1 = variant._get_pricelist_tier1()
- tier2 = variant._get_pricelist_tier2()
- tier3 = variant._get_pricelist_tier3()
+
+ price_excl_v2 = variant._v2_get_website_price_exclude_tax()
+ price_excl_after_disc_v2 = variant._v2_get_website_price_after_disc_and_tax()
+ tax_v2 = variant._v2_get_website_tax()
document = solr_model.get_doc('product', template.id)
document.update({
@@ -142,28 +147,27 @@ class ProductTemplate(models.Model):
"discount_f": discount,
"price_discount_f": price_excl_after_disc,
"tax_f": tax,
- "discount_tier1_f": tier1.get('discount_tier1', 0),
- "price_tier1_f": tier1.get('price_tier1', 0),
- "discount_tier2_f": tier2.get('discount_tier2', 0),
- "price_tier2_f": tier2.get('price_tier2', 0),
- "discount_tier3_f": tier3.get('discount_tier3', 0),
- "price_tier3_f": tier3.get('price_tier3', 0),
- "has_price_info_b": True
+ "price_v2_f": price_excl_v2,
+ "price_discount_v2_f": price_excl_after_disc_v2,
+ "tax_v2_f": tax_v2,
})
+ for tier_number in [1, 2, 3, '1_v2', '2_v2', '3_v2', '4_v2', '5_v2']:
+ tier = variant._get_pricelist_tier(tier_number)
+ document.update({
+ f"discount_tier{tier_number}_f": tier.get(f'discount_tier{tier_number}', 0),
+ f"price_tier{tier_number}_f": tier.get(f'price_tier{tier_number}', 0),
+ })
+
+ document.update({"has_price_info_b": True})
+
self.solr().add(docs=[document], softCommit=True)
template.product_variant_ids._sync_price_to_solr()
template.change_solr_data('Ada perubahan pada harga product')
if not document.get('has_product_info_b'):
template._sync_product_template_to_solr()
-
- def _sync_delete_solr(self):
- for rec in self:
- self.solr().delete(rec.id)
- for variant in rec.product_variant_ids:
- variant._sync_delete_solr()
-
+
def solr_results(self, detail=False):
solr_model = self.env['apache.solr']
pricelist = self.env.user_pricelist
diff --git a/indoteknik_custom/models/solr/x_banner_banner.py b/indoteknik_custom/models/solr/x_banner_banner.py
index 5608a3d7..67739d47 100644
--- a/indoteknik_custom/models/solr/x_banner_banner.py
+++ b/indoteknik_custom/models/solr/x_banner_banner.py
@@ -46,8 +46,8 @@ class XBannerBanner(models.Model):
'background_color_s': banners.background_color or '',
'image_s': self.env['ir.attachment'].api_image('x_banner.banner', 'x_banner_image', banners.id),
'status_s': banners.x_status_banner or '',
- 'categories': banners.x_banner_category.id or '',
- 'manufactures': banners.x_relasi_manufacture.id or '',
+ 'category_id_i': banners.x_banner_category.id or '',
+ 'manufacture_id_i': banners.x_relasi_manufacture.id or '',
'group_by_week': banners.group_by_week or '',
})
self.solr().add([document])
diff --git a/indoteknik_custom/models/solr/x_banner_category.py b/indoteknik_custom/models/solr/x_banner_category.py
new file mode 100644
index 00000000..c73f6722
--- /dev/null
+++ b/indoteknik_custom/models/solr/x_banner_category.py
@@ -0,0 +1,54 @@
+from odoo import fields, models, api
+from datetime import datetime
+
+class XBannerCategory(models.Model):
+ _inherit = "x_banner.category"
+
+ last_update_solr = fields.Datetime(string='Last Update Solr')
+
+ def update_last_update_solr(self):
+ self.last_update_solr = datetime.utcnow()
+
+ def solr(self):
+ return self.env['apache.solr'].connect('banner_categories')
+
+ def _create_solr_queue(self, function_name):
+ for rec in self:
+ self.env['apache.solr.queue'].create_unique({
+ 'res_model': self._name,
+ 'res_id': rec.id,
+ 'function_name': function_name
+ })
+
+ @api.constrains('x_name', 'x_banner_subtitle', 'x_studio_field_KKVl4', 'banner_ids')
+ def _create_solr_queue_sync_banner_categories(self):
+ self._create_solr_queue('_sync_banner_categories_to_solr')
+
+ def action_sync_to_solr(self):
+ banner_ids = self.env.context.get('active_ids', [])
+ banners = self.search([('id', 'in', banner_ids)])
+ banners._create_solr_queue('_sync_banner_categories_to_solr')
+
+ def _sync_banner_categories_to_solr(self):
+ for banners in self:
+ document = {}
+ document.update({
+ 'id': banners.id,
+ 'display_name_s': banners.display_name,
+ 'name_s': banners.x_name,
+ 'banner_subtitle_s': banners.x_banner_subtitle or '',
+ 'x_studio_field_KKVl4_s': banners.x_studio_field_KKVl4 or '',
+ 'banners': [x.id for x in banners.banner_ids],
+ })
+ self.solr().add([document])
+ banners.update_last_update_solr()
+
+ self.solr().commit()
+
+ def unlink(self):
+ res = super(XBannerCategory, self).unlink()
+ for rec in self:
+ self.solr().delete(rec.id)
+ self.solr().optimize()
+ self.solr().commit()
+ return res \ No newline at end of file
diff --git a/indoteknik_custom/models/solr/x_manufactures.py b/indoteknik_custom/models/solr/x_manufactures.py
index c0c321e4..375b7708 100644
--- a/indoteknik_custom/models/solr/x_manufactures.py
+++ b/indoteknik_custom/models/solr/x_manufactures.py
@@ -44,10 +44,11 @@ class XManufactures(models.Model):
'sequence_i': brands.sequence or '',
'negara_asal_s': brands.x_negara_asal or '',
'short_desc_s': brands.x_short_desc or '',
+ 'level_s': brands.x_manufacture_level or '',
'image_s': self.env['ir.attachment'].api_image('x_manufactures', 'x_logo_manufacture', brands.id),
'produk_aksesoris_sparepart_s': brands.x_produk_aksesoris_sparepart or '',
- 'categories': [x.id for x in brands.category_ids],
- 'banners': [x.id for x in brands.x_manufactures_banners],
+ 'category_ids': [x.id for x in brands.category_ids],
+ 'banner_ids': [x.id for x in brands.x_manufactures_banners],
})
self.solr().add([document])
brands.update_last_update_solr()
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index e1564ca9..181f2a59 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -64,7 +64,7 @@ class StockPicking(models.Model):
('pengajuan1', 'Approval Finance'),
('approved', 'Approved'),
], string='Approval Return Status', readonly=True, copy=False, index=True, tracking=3, help="Approval Status untuk Return")
- date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ, tidak berpengaruh ke Accounting")
+ date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ, tidak berpengaruh ke Accounting", tracking=True)
note_logistic = fields.Selection([
('hold', 'Hold by Sales'),
('not_paid', 'Customer belum bayar'),
diff --git a/indoteknik_custom/models/users.py b/indoteknik_custom/models/users.py
index 14fcae98..b90c0097 100644
--- a/indoteknik_custom/models/users.py
+++ b/indoteknik_custom/models/users.py
@@ -10,6 +10,7 @@ class Users(models.Model):
is_leader = fields.Boolean(string='Leader', help='Berhak Approval SO Margin < 15 dan Approval PO')
is_accounting = fields.Boolean(string='Accounting', help='Berhak Approval Internal Use')
is_logistic_approver = fields.Boolean(string='Logistic Approver', help='Berhak Approval Penerimaan Barang')
+ is_editor_product = fields.Boolean(string='Editor Product', help='Berhak Mengedit Data Product')
def notify_internal_users(self, message, title):
users = self.search([('share', '=', False)])
diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py
index 4865db2f..8486fca0 100644
--- a/indoteknik_custom/models/voucher.py
+++ b/indoteknik_custom/models/voucher.py
@@ -218,6 +218,7 @@ class Voucher(models.Model):
tnc.append('<ol>')
tnc.append('<li>Voucher hanya berlaku apabila pembelian Pengguna sudah memenuhi syarat dan ketentuan yang tertera pada voucher</li>')
tnc.append(f'<li>Voucher berlaku {self._res_remaining_time()} lagi</li>')
+ tnc.append(f'<li>Voucher tidak bisa digunakan apabila terdapat produk flash sale</li>')
if len(self.voucher_line) > 0:
brand_names = ', '.join([x.manufacture_id.x_name for x in self.voucher_line])
tnc.append(f'<li>Voucher berlaku untuk produk dari brand {brand_names}</li>')
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index da92f81f..e362e546 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -76,3 +76,5 @@ access_apache_solr_queue,access.apache.solr.queue,model_apache_solr_queue,,1,1,1
access_cost_centre,access.cost.centre,model_cost_centre,,1,1,1,1
access_stock_scheduler_compute,access.stock.scheduler.compute,model_stock_scheduler_compute,,1,1,1,1
access_sale_order_promotion,access.sale.order.promotion,model_sale_order_promotion,,1,1,1,1
+access_sale_orders_multi_update,access.sale.orders.multi_update,model_sale_orders_multi_update,,1,1,1,1
+access_quotation_so_multi_update,access.quotation.so.multi_update,model_quotation_so_multi_update,,1,1,1,1 \ No newline at end of file
diff --git a/indoteknik_custom/views/account_move_line.xml b/indoteknik_custom/views/account_move_line.xml
index 5b5f73cd..02b936f1 100644
--- a/indoteknik_custom/views/account_move_line.xml
+++ b/indoteknik_custom/views/account_move_line.xml
@@ -11,6 +11,7 @@
</xpath>
<xpath expr="//page[@id='aml_tab']/field[@name='line_ids']/tree/field[@name='analytic_tag_ids']" position="attributes">
<attribute name="groups"/>
+ <attribute name="options">{'no_create': True}</attribute>
</xpath>
</field>
</record>
diff --git a/indoteknik_custom/views/apache_solr_queue.xml b/indoteknik_custom/views/apache_solr_queue.xml
index 56ab2713..3861fd20 100644
--- a/indoteknik_custom/views/apache_solr_queue.xml
+++ b/indoteknik_custom/views/apache_solr_queue.xml
@@ -3,7 +3,7 @@
<field name="name">apache.solr.queue.tree</field>
<field name="model">apache.solr.queue</field>
<field name="arch" type="xml">
- <tree editable="top" default_order="execute_date desc">
+ <tree editable="top" default_order="create_date desc">
<field name="display_name" readonly="1" />
<field name="res_model" readonly="1" />
<field name="res_id" readonly="1" />
diff --git a/indoteknik_custom/views/invoice_reklas.xml b/indoteknik_custom/views/invoice_reklas.xml
index e807dca5..a29139ad 100644
--- a/indoteknik_custom/views/invoice_reklas.xml
+++ b/indoteknik_custom/views/invoice_reklas.xml
@@ -10,7 +10,7 @@
</p>
<group>
<field name="reklas_type"/>
- <field name="reklas_id"/>
+ <field name="reklas_id" options="{'no_create': True}"/>
<field name="pay_amt"/>
</group>
<footer>
diff --git a/indoteknik_custom/views/price_group.xml b/indoteknik_custom/views/price_group.xml
index 7ee8d422..5db8756e 100644
--- a/indoteknik_custom/views/price_group.xml
+++ b/indoteknik_custom/views/price_group.xml
@@ -23,6 +23,9 @@
<field name="group3"/>
<field name="group4"/>
<field name="group5"/>
+ <field name="group6"/>
+ <field name="group7"/>
+ <field name="group8"/>
</tree>
</field>
</record>
@@ -42,6 +45,9 @@
<field name="group3"/>
<field name="group4"/>
<field name="group5"/>
+ <field name="group6"/>
+ <field name="group7"/>
+ <field name="group8"/>
</group>
</group>
</sheet>
diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml
index a3a23101..e09fee77 100755
--- a/indoteknik_custom/views/product_template.xml
+++ b/indoteknik_custom/views/product_template.xml
@@ -15,6 +15,7 @@
<field name="uom_po_id" position="after">
<field name="desc_update_solr" readonly="1" />
<field name="last_update_solr" readonly="1" />
+ <field name="publish" />
</field>
<page name="inventory" position="after">
<page string="Marketplace" name="marketplace">
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index 7d436c46..0ad76ae5 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -37,6 +37,7 @@
<field name="currency_id" position="after">
<field name="summary_qty_po"/>
<field name="count_line_product"/>
+ <field name="payment_term_id"/>
</field>
<field name="amount_total" position="after">
<field name="total_margin"/>
@@ -52,13 +53,19 @@
<field name="product_id" position="before">
<field name="line_no" attrs="{'readonly': 1}" optional="hide"/>
</field>
+ <field name="product_id" position="attributes">
+ <attribute name="options">{'no_create': True}</attribute>
+ </field>
<field name="product_qty" position="before">
- <field name="qty_available_store"/>
- <field name="suggest"/>
+ <field name="qty_available_store" readonly="1" />
+ <field name="suggest" readonly="1" />
</field>
<field name="price_unit" position="after">
<field name="price_vendor" attrs="{'readonly': 1}" optional="hide"/>
</field>
+ <field name="price_subtotal" position="after">
+ <field name="so_line_id" attrs="{'readonly': 1}" optional="hide"/>
+ </field>
<page name="purchase_delivery_invoice" position="after">
<page name="purchase_vendor_bills" string="Vendor Bills" groups="indoteknik_custom.technical_administrator">
<group>
@@ -69,11 +76,28 @@
<field name="fiscal_position_id" position="after">
<field name="note_description"/>
<field name="total_so_percent_margin"/>
-
+ <field name="has_active_invoice" invisible="1" />
+ </field>
+
+ <field name="order_line" position="attributes">
+ <attribute name="attrs">{'readonly': ['|', ('state', 'in', ['done', 'cancel']), ('has_active_invoice', '=', True)]}</attribute>
</field>
+
+ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_unit']" position="attributes">
+ <attribute name="attrs">{'readonly': [], 'required': True}</attribute>
+ </xpath>
+
+ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='taxes_id']" position="attributes">
+ <attribute name="attrs">{'readonly': []}</attribute>
+ </xpath>
+
+ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_qty']" position="attributes">
+ <attribute name="attrs">{'readonly': [], 'required': True}</attribute>
+ </xpath>
</field>
</record>
</data>
+
<data>
<record id="rfq_order_tree_view_inherit" model="ir.ui.view">
<field name="name">Purchase</field>
@@ -86,6 +110,7 @@
</field>
</record>
</data>
+
<data>
<record id="purchase_order_tree_view_inherit" model="ir.ui.view">
<field name="name">Purchase</field>
@@ -95,6 +120,19 @@
<field name="invoice_status" position="after">
<field name="po_status"/>
<field name="note_description" optional="hide"/>
+ <field name="sale_order_id" optional="hide"/>
+ </field>
+ </field>
+ </record>
+ </data>
+ <data>
+ <record id="purchase_order_search_inherit" model="ir.ui.view">
+ <field name="name">purchase.order.select.inherit</field>
+ <field name="model">purchase.order</field>
+ <field name="inherit_id" ref="purchase.purchase_order_view_search"/>
+ <field name="arch" type="xml">
+ <field name="name" position="after">
+ <field name="sale_order_id" string="Sale Order"/>
</field>
</field>
</record>
diff --git a/indoteknik_custom/views/quotation_so_multi_update.xml b/indoteknik_custom/views/quotation_so_multi_update.xml
new file mode 100644
index 00000000..d3d310d5
--- /dev/null
+++ b/indoteknik_custom/views/quotation_so_multi_update.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="view_quotation_so_multi_update_form" model="ir.ui.view">
+ <field name="name">Quotation Multi Update</field>
+ <field name="model">quotation.so.multi_update</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <span>Apakah Anda Yakin Ingin Mengubah Status Menjadi Cancel?</span>
+ </group>
+ </sheet>
+ <footer>
+ <button name="save_multi_update_quotation" string="Update" type="object" default_focus="1" class="oe_highlight"/>
+ <button string="Cancel" class="btn btn-secondary" special="cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_quotation_so_multi_update" model="ir.actions.act_window">
+ <field name="name">Quotation Multi Update</field>
+ <field name="res_model">quotation.so.multi_update</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_quotation_so_multi_update_form"/>
+ <field name="target">new</field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 04d4b854..bc098f18 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -45,6 +45,7 @@
<field name="customer_type" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-28'), ('create_date', '=', False)]}"/>
<field name="npwp" placeholder='99.999.999.9-999.999' attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-28'), ('create_date', '=', False)]}"/>
<field name="sppkp" attrs="{'invisible': [('customer_type','!=','pkp')], 'required': [('customer_type', '=', 'pkp')]}"/>
+ <field name="email" attrs="{'required': [('create_date', '&gt;', '2023-09-28')]}"/>
<field name="due_id" readonly="1"/>
<field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" attrs="{'required':[('create_date', '&gt;', '2023-09-10')]}"/>
</field>
@@ -61,7 +62,7 @@
</field>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']" position="attributes">
<attribute name="attrs">
- {'readonly': ['|', ('applied_voucher_id', '!=', False), ('state', 'in', ('done','cancel'))]}
+ {'readonly': [('state', 'in', ('done','cancel'))]}
</attribute>
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_unit']" position="attributes">
@@ -96,6 +97,9 @@
<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>
+ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']" position="attributes">
+ <attribute name="options">{'no_create': True}</attribute>
+ </xpath>
<field name="amount_total" position="after">
<field name="grand_total"/>
<label for="amount_voucher_disc" string="Voucher" />
@@ -182,5 +186,22 @@
</field>
</field>
</record>
+
+ <record id="sale_order_multi_update_ir_actions_server" model="ir.actions.server">
+ <field name="name">Mark As Cancel</field>
+ <field name="model_id" ref="sale.model_sale_order"/>
+ <field name="binding_model_id" ref="sale.model_sale_order"/>
+ <field name="binding_view_types">form,list</field>
+ <field name="state">code</field>
+ <field name="code">action = records.open_form_multi_update_state()</field>
+ </record>
+
+ <record id="sale_order_update_multi_actions_server" model="ir.actions.server">
+ <field name="name">Mark As Completed</field>
+ <field name="model_id" ref="sale.model_sale_order"/>
+ <field name="binding_model_id" ref="sale.model_sale_order"/>
+ <field name="state">code</field>
+ <field name="code">action = records.open_form_multi_update_status()</field>
+ </record>
</data>
</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/sale_orders_multi_update.xml b/indoteknik_custom/views/sale_orders_multi_update.xml
new file mode 100644
index 00000000..7f8d6a04
--- /dev/null
+++ b/indoteknik_custom/views/sale_orders_multi_update.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="view_sale_orders_multi_update_form" model="ir.ui.view">
+ <field name="name">Sale Orders Multi Update</field>
+ <field name="model">sale.orders.multi_update</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <span>Apakah Anda Yakin Ingin Mengubah Invoice Status?</span>
+ </group>
+ </sheet>
+ <footer>
+ <button name="save_multi_update_so" string="Multi Update" type="object" default_focus="1" class="oe_highlight"/>
+ <button string="Cancel" class="btn btn-secondary" special="cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_sale_orders_multi_update" model="ir.actions.act_window">
+ <field name="name">Sale Orders Multi Update</field>
+ <field name="res_model">sale.orders.multi_update</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_sale_orders_multi_update_form"/>
+ <field name="target">new</field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/users.xml b/indoteknik_custom/views/users.xml
index 25e7f90c..d67b4474 100644
--- a/indoteknik_custom/views/users.xml
+++ b/indoteknik_custom/views/users.xml
@@ -12,6 +12,7 @@
<field name="is_sales_manager"/>
<field name="is_leader"/>
<field name="is_logistic_approver"/>
+ <field name="is_editor_product"/>
</field>
</field>
</record>
diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml
index 97634d7d..a2f5557a 100755
--- a/indoteknik_custom/views/voucher.xml
+++ b/indoteknik_custom/views/voucher.xml
@@ -39,7 +39,7 @@
</group>
<group string="Discount Settings" attrs="{'invisible': [('apply_type', '!=', 'all')]}">
<field name="min_purchase_amount" widget="monetary" required="1" />
- <field name="discount_type" required="1" />
+ <field name="discount_type" attrs="{'invisible': [('apply_type','!=','all')], 'required': [('apply_type', '=', 'all')]}" />
<label for="max_discount_amount" string="Discount Amount" />
<div class="d-flex align-items-center">
diff --git a/indoteknik_custom/views/x_banner_banner.xml b/indoteknik_custom/views/x_banner_banner.xml
index be9ae951..c90e718b 100755
--- a/indoteknik_custom/views/x_banner_banner.xml
+++ b/indoteknik_custom/views/x_banner_banner.xml
@@ -31,7 +31,7 @@
<field name="x_status_banner" />
<field name="sequence" />
<field name="group_by_week" />
- <field name="last_update_solr" />
+ <field name="last_update_solr" readonly="1"/>
</group>
<group>
<field name="background_color" />
diff --git a/indoteknik_custom/views/x_banner_category.xml b/indoteknik_custom/views/x_banner_category.xml
index 45ad7940..11feb207 100755
--- a/indoteknik_custom/views/x_banner_category.xml
+++ b/indoteknik_custom/views/x_banner_category.xml
@@ -24,6 +24,7 @@
<field name="x_name"/>
<field name="x_banner_subtitle"/>
<field name="x_studio_field_KKVl4"/>
+ <field name="last_update_solr" readonly="1"/>
</group>
<group></group>
</group>
@@ -49,6 +50,14 @@
</field>
</record>
+ <record id="ir_actions_server_x_banner_category_sync_to_solr" model="ir.actions.server">
+ <field name="name">Sync to solr</field>
+ <field name="model_id" ref="indoteknik_custom.model_x_banner_category"/>
+ <field name="binding_model_id" ref="indoteknik_custom.model_x_banner_category"/>
+ <field name="state">code</field>
+ <field name="code">model.action_sync_to_solr()</field>
+ </record>
+
<menuitem
id="menu_banner_category"
name="Banner Category"