summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2024-02-28 14:07:47 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2024-02-28 14:07:47 +0700
commit00b6739e4f4228c1cc66de0ef63312bc633ae21f (patch)
tree85f8fc83d4030878893599abb2a949e5d478e3e7
parent0738a192409687790c16c757f85fe440cb1f377d (diff)
parent46a7cc5601ceab2a7a6cdf4d74e0fa26ce13ab8a (diff)
Merge branch 'production' into purchasing-job
-rw-r--r--indoteknik_api/controllers/__init__.py1
-rw-r--r--indoteknik_api/controllers/api_v1/cart.py42
-rw-r--r--indoteknik_api/controllers/api_v1/voucher.py29
-rw-r--r--indoteknik_api/controllers/controller.py22
-rw-r--r--indoteknik_api/controllers/export.py46
-rw-r--r--indoteknik_api/models/product_pricelist.py2
-rw-r--r--indoteknik_api/models/product_product.py9
-rwxr-xr-xindoteknik_custom/__manifest__.py5
-rwxr-xr-xindoteknik_custom/models/__init__.py3
-rw-r--r--indoteknik_custom/models/account_move.py2
-rw-r--r--indoteknik_custom/models/base_import_import.py9
-rw-r--r--indoteknik_custom/models/commision.py19
-rw-r--r--indoteknik_custom/models/cust_commision.py25
-rw-r--r--indoteknik_custom/models/logbook_sj.py45
-rwxr-xr-xindoteknik_custom/models/product_template.py67
-rw-r--r--indoteknik_custom/models/promotion/__init__.py3
-rw-r--r--indoteknik_custom/models/promotion/promotion_free_product.py4
-rw-r--r--indoteknik_custom/models/promotion/promotion_monitoring.py45
-rw-r--r--indoteknik_custom/models/promotion/promotion_product.py4
-rw-r--r--indoteknik_custom/models/promotion/promotion_program_line.py9
-rwxr-xr-xindoteknik_custom/models/purchase_pricelist.py2
-rw-r--r--indoteknik_custom/models/report_logbook_sj.py50
-rw-r--r--indoteknik_custom/models/report_stock_forecasted.py45
-rwxr-xr-xindoteknik_custom/models/res_users.py17
-rw-r--r--indoteknik_custom/models/role_permission/__init__.py1
-rw-r--r--indoteknik_custom/models/role_permission/ir_model_access.py9
-rwxr-xr-xindoteknik_custom/models/sale_order.py1
-rw-r--r--indoteknik_custom/models/sale_order_line.py36
-rw-r--r--indoteknik_custom/models/solr/apache_solr_queue.py17
-rw-r--r--indoteknik_custom/models/solr/product_product.py10
-rw-r--r--indoteknik_custom/models/solr/promotion_program_line.py16
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv6
-rw-r--r--indoteknik_custom/views/apache_solr_queue.xml7
-rw-r--r--indoteknik_custom/views/cust_commision.xml44
-rw-r--r--indoteknik_custom/views/customer_commision.xml18
-rw-r--r--indoteknik_custom/views/ir_sequence.xml10
-rw-r--r--indoteknik_custom/views/promotion/promotion_monitoring.xml64
-rw-r--r--indoteknik_custom/views/promotion/promotion_product.xml45
-rw-r--r--indoteknik_custom/views/promotion/promotion_program_line.xml17
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml2
-rw-r--r--indoteknik_custom/views/report_logbook_sj.xml28
-rw-r--r--indoteknik_custom/views/role_permission/ir_model_access.xml16
-rw-r--r--indoteknik_custom/views/role_permission/res_groups.xml45
-rwxr-xr-xindoteknik_custom/views/sale_order.xml6
44 files changed, 742 insertions, 161 deletions
diff --git a/indoteknik_api/controllers/__init__.py b/indoteknik_api/controllers/__init__.py
index 237f4135..34bba89f 100644
--- a/indoteknik_api/controllers/__init__.py
+++ b/indoteknik_api/controllers/__init__.py
@@ -1,4 +1,5 @@
from . import controller
+from . import export
from . import api_v1
from . import api_v2
from . import api_v3 \ No newline at end of file
diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py
index 907c8288..f472a9b0 100644
--- a/indoteknik_api/controllers/api_v1/cart.py
+++ b/indoteknik_api/controllers/api_v1/cart.py
@@ -44,6 +44,7 @@ class Cart(controller.Controller):
qty = int(kw.get('qty', 0))
source = kw.get('source')
+ qty_append = kw.get('qty_append', False)
is_selected = kw.get('selected', False)
is_selected = is_selected in ('true', True)
@@ -52,6 +53,9 @@ class Cart(controller.Controller):
if not user_id:
return self.response(code=400, description='user_id is required')
+ if not product_id and not program_line_id:
+ return self.response(code=400, description='product_id or program_line_id is required')
+
website_user_cart = request.env['website.user.cart']
# Remove previous 'buy' entries for the user
@@ -68,32 +72,36 @@ class Cart(controller.Controller):
cart = website_user_cart.search(query, limit=1)
data_to_update = {
+ 'user_id': user_id,
'qty': qty,
'is_selected': is_selected,
'program_line_id': program_line_id,
- 'product_id': product_id
+ 'product_id': product_id,
+ 'source': source or False
}
+
+ if isinstance(qty_append, str) and qty_append.lower() == "true" and cart:
+ data_to_update['qty'] += cart.qty
- if program_line_id:
- data_to_update['product_id'] = False
-
- if source:
- data_to_update['source'] = source
-
- result = {}
if cart:
- # Update existing cart entry
cart.write(data_to_update)
- result['id'] = cart.id
else:
- # Create a new cart entry if it doesn't exist
- create = website_user_cart.create({
- 'user_id': user_id,
- **data_to_update
- })
- result['id'] = create.id
+ cart = website_user_cart.create(data_to_update)
- return self.response(result)
+ return self.response({
+ 'id': cart.id,
+ 'product': {
+ 'id': cart.product_id.id,
+ 'name': cart.product_id.name
+ } if cart.product_id else None,
+ 'program_line': {
+ 'id': cart.program_line_id.id,
+ 'name': cart.program_line_id.name
+ } if cart.program_line_id else None,
+ 'qty': cart.qty,
+ 'is_selected': cart.is_selected,
+ 'source': cart.source
+ })
@http.route(PREFIX_USER + 'cart', auth='public', methods=['DELETE', 'OPTIONS'], csrf=False)
@controller.Controller.must_authorized()
diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py
index 3c056ecd..53f118ec 100644
--- a/indoteknik_api/controllers/api_v1/voucher.py
+++ b/indoteknik_api/controllers/api_v1/voucher.py
@@ -1,31 +1,39 @@
-from .. import controller
+from bs4 import BeautifulSoup
from odoo import http
from odoo.http import request
-from bs4 import BeautifulSoup
+
+from .. import controller
class Voucher(controller.Controller):
- prefix = '/api/v1/'
+ PREFIX_API = '/api/v1/'
+
+ @http.route(PREFIX_API + 'voucher', auth='public', methods=['GET', 'OPTIONS'])
+ @controller.Controller.must_authorized()
+ def get_vouchers(self, **kw):
+ vouchers = request.env['voucher'].get_active_voucher([('visibility', 'in', ['public'])])
+ vouchers = vouchers.res_format()
+ return self.response(vouchers)
- @http.route(prefix + 'user/<user_id>/voucher', auth='public', methods=['GET', 'OPTIONS'])
+ @http.route(PREFIX_API + 'user/<user_id>/voucher', auth='public', methods=['GET', 'OPTIONS'])
@controller.Controller.must_authorized(private=True, private_key='user_id')
- def get_vouchers(self, **kw):
+ def get_vouchers_by_user_id(self, **kw):
cart = request.env['website.user.cart']
code = kw.get('code')
user_id = int(kw.get('user_id', 0))
source = kw.get('source')
visibility = ['public']
- parameter = []
+ domain = []
if code:
visibility.append('private')
- parameter += [('code', '=', code)]
+ domain += [('code', '=', code)]
user_pricelist = request.env.context.get('user_pricelist')
if user_pricelist:
- parameter += [('excl_pricelist_ids', 'not in', [user_pricelist.id])]
+ domain += [('excl_pricelist_ids', 'not in', [user_pricelist.id])]
- parameter += [('visibility', 'in', visibility)]
- vouchers = request.env['voucher'].get_active_voucher(parameter)
+ domain += [('visibility', 'in', visibility)]
+ vouchers = request.env['voucher'].get_active_voucher(domain)
checkout = cart.get_user_checkout(user_id, source=source)
products = checkout['products']
@@ -35,6 +43,7 @@ class Voucher(controller.Controller):
order_line = []
for product in products:
+ if product['cart_type'] == 'promotion': continue
order_line.append({
'product_id': request.env['product.product'].browse(product['id']),
'price': product['price']['price'],
diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py
index 50e86b68..c4f323fe 100644
--- a/indoteknik_api/controllers/controller.py
+++ b/indoteknik_api/controllers/controller.py
@@ -193,8 +193,11 @@ class Controller(http.Controller):
if model_name in ['product.template']:
version = '1' if field in ['image_256', 'image_512', 'image_1024', 'image_1920'] else '2'
ratio = kw.get('ratio', '')
+ variant = kw.get('variant', False)
+
image = model['image_256'] or ''
- image = self.add_watermark_to_image(image, ratio, version)
+ if not variant:
+ image = self.add_watermark_to_image(image, ratio, version)
response_headers = [
('Content-Type', 'image/jpg'),
@@ -210,7 +213,12 @@ class Controller(http.Controller):
def add_watermark_to_image(self, image, ratio, version = '1'):
if not image: return ''
- logo_path = get_module_resource('indoteknik_api', 'static', 'src', 'images', 'logo-indoteknik-gray.png')
+ LOGO_FILENAME = {
+ '1': 'logo-indoteknik-gray.png',
+ '2': 'logo-indoteknik.png'
+ }
+
+ logo_path = get_module_resource('indoteknik_api', 'static', 'src', 'images', LOGO_FILENAME.get(version))
logo_img = Image.open(logo_path).convert('RGBA')
img_data = io.BytesIO(base64.b64decode(image))
@@ -238,13 +246,15 @@ class Controller(http.Controller):
logo_footer_img = Image.open(logo__footer_path).convert('RGBA')
logo_footer_img.thumbnail((img_width, img_height // 1))
logo_footer_w, logo_footer_h = logo_footer_img.size
- new_img.paste(logo_footer_img, (0, img_height - logo_footer_h - 20), logo_footer_img)
+ new_img.paste(logo_footer_img, (0, img_height - logo_footer_h), logo_footer_img)
+
+ logo_img_w = img_width // 1.8
+ logo_img_h = img_height // 1.8
logo_img.thumbnail((logo_img_w, logo_img_h))
- if version == '1':
- # Add watermark
- new_img.paste(logo_img, (12, 10), logo_img)
+ # Add watermark
+ new_img.paste(logo_img, (12, 10), logo_img)
buffered = io.BytesIO()
new_img.save(buffered, format="PNG")
diff --git a/indoteknik_api/controllers/export.py b/indoteknik_api/controllers/export.py
new file mode 100644
index 00000000..c29c82c7
--- /dev/null
+++ b/indoteknik_api/controllers/export.py
@@ -0,0 +1,46 @@
+import json
+
+from odoo.tools import pycompat
+from odoo.exceptions import Warning
+from odoo import http
+from odoo.http import request
+from odoo.addons.web.controllers.main import ExportFormat, GroupExportXlsxWriter, ExportXlsxWriter, serialize_exception, clean_action
+
+class Export(ExportFormat, http.Controller):
+ @http.route('/web/export/xlsx', type='http', auth="public", csrf=False)
+ @serialize_exception
+ def export_xlsx(self, data, token, **kw):
+ data_obj = json.loads(data)
+ model = data_obj['model']
+ can_export = request.env.user.check_access(model, 'export')
+
+ if not can_export:
+ raise Warning('You are not allowed to export')
+
+ return self.base(data, token)
+
+ @property
+ def content_type(self):
+ return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+
+ def filename(self, base):
+ return base + '.xlsx'
+
+ def from_group_data(self, fields, groups):
+ with GroupExportXlsxWriter(fields, groups.count) as xlsx_writer:
+ x, y = 1, 0
+ for group_name, group in groups.children.items():
+ x, y = xlsx_writer.write_group(x, y, group_name, group)
+
+ return xlsx_writer.value
+
+ def from_data(self, fields, rows):
+ with ExportXlsxWriter(fields, len(rows)) as xlsx_writer:
+ for row_index, row in enumerate(rows):
+ for cell_index, cell_value in enumerate(row):
+ if isinstance(cell_value, (list, tuple)):
+ cell_value = pycompat.to_text(cell_value)
+ xlsx_writer.write_cell(row_index + 1, cell_index, cell_value)
+
+ return xlsx_writer.value
+ \ No newline at end of file
diff --git a/indoteknik_api/models/product_pricelist.py b/indoteknik_api/models/product_pricelist.py
index f05fa82d..0d4247c8 100644
--- a/indoteknik_api/models/product_pricelist.py
+++ b/indoteknik_api/models/product_pricelist.py
@@ -92,7 +92,7 @@ class ProductPricelist(models.Model):
('is_flash_sale', '=', True),
('start_date', '<=', current_time),
('end_date', '>=', current_time)
- ], limit=1)
+ ], limit=1, order='start_date asc')
return pricelist
def is_flash_sale_product(self, product_id: int):
diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py
index 1db58d8e..3ecad627 100644
--- a/indoteknik_api/models/product_product.py
+++ b/indoteknik_api/models/product_product.py
@@ -278,12 +278,19 @@ class ProductProduct(models.Model):
discount = 0
price_flashsale = 0
+ default_divide_tax = float(1.11)
+ default_tax = float(11)
if item.price_discount > 0:
discount = item.price_discount
price_flashsale = base_price - (base_price * discount // 100)
+ price_flashsale = price_flashsale / default_divide_tax
elif item.fixed_price > 0:
price_flashsale = item.fixed_price # ask darren for include or exclude
- discount = (base_price - price_flashsale) // base_price * 100
+ price_flashsale = price_flashsale + (price_flashsale * default_tax / 100)
+ discount = (base_price - price_flashsale) * 100 / base_price
+ discount = (math.ceil(discount*100)/100)
+ price_flashsale = item.fixed_price
+ # price_flashsale = price_flashsale / default_divide_tax # darren must fill the fixed price with price exclude
if price_for == 'odoo':
base_price = self._v2_get_website_price_exclude_tax()
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 333596a3..fe6955fd 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -77,6 +77,8 @@
'views/brand_vendor.xml',
'views/promotion/promotion_program.xml',
'views/promotion/promotion_program_line.xml',
+ 'views/promotion/promotion_product.xml',
+ 'views/promotion/promotion_monitoring.xml',
'views/requisition.xml',
'views/landedcost.xml',
'views/product_sla.xml',
@@ -113,6 +115,9 @@
'views/po_multi_cancel.xml',
'views/logbook_sj.xml',
'views/report_logbook_sj.xml',
+ 'views/role_permission/ir_model_access.xml',
+ 'views/role_permission/res_groups.xml',
+ 'views/cust_commision.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 720a4f91..9d8b9bea 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -106,3 +106,6 @@ from . import stock_quant
from . import po_multi_cancel
from . import logbook_sj
from . import report_logbook_sj
+from . import role_permission
+from . import cust_commision
+from . import report_stock_forecasted
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index a9db212f..7eb65e9f 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -122,7 +122,7 @@ class AccountMove(models.Model):
sum_qty_invoice = sum_qty_order = 0
for line in purchase_order.order_line:
sum_qty_invoice += line.qty_invoiced
- sum_qty_order += line.product_uom_qty
+ sum_qty_order += line.product_qty
if sum_qty_invoice > sum_qty_order:
raise UserError('Error Qty Invoice akan lebih besar dari Qty Order jika lanjut Posting')
diff --git a/indoteknik_custom/models/base_import_import.py b/indoteknik_custom/models/base_import_import.py
index 6a100cb8..01e02a4a 100644
--- a/indoteknik_custom/models/base_import_import.py
+++ b/indoteknik_custom/models/base_import_import.py
@@ -56,7 +56,10 @@ class Import(models.TransientModel):
raise UserError(message)
def do(self, fields, columns, options, dryrun=False):
- enable_import = self._check_enable_import()
- if not enable_import:
- self._unable_import_notif()
+ model = self.res_model
+ can_import = self.env.user.check_access(model, 'import')
+
+ if not can_import:
+ raise UserError('You are not allowed to import')
+
return super(Import, self).do(fields, columns, options, dryrun)
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index 955d1634..094aa66e 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -156,7 +156,17 @@ class CustomerCommision(models.Model):
# add status for type of commision, fee, rebate / cashback
# include child or not?
- @api.constrains('commision_percent')
+ @api.constrains('partner_ids')
+ def _onchange_partner_ids(self):
+ commision = self.env['cust.commision'].search([
+ ('partner_id', 'in', [rec.id for rec in self.partner_ids]),
+ ])
+
+ if commision:
+ max_commision = max(commision.mapped('commision_percent'))
+ self.commision_percent = max_commision
+
+ @api.constrains('commision_percent', 'partner_ids')
def _onchange_commision_percent(self):
print('masuk onchange commision percent')
if self.commision_amt == 0:
@@ -165,8 +175,8 @@ class CustomerCommision(models.Model):
@api.constrains('commision_amt')
def _onchange_commision_amt(self):
print('masuk onchange commision amt')
- if self.commision_percent == 0:
- self.commision_percent = (self.commision_amt / self.total_dpp * 100)
+ if self.total_dpp > 0:
+ self.commision_percent = (self.commision_amt / self.total_dpp) * 100
def _compute_total_dpp(self):
for data in self:
@@ -208,6 +218,9 @@ class CustomerCommision(models.Model):
else:
self._generate_customer_commision_rebate()
+ self._onchange_commision_percent()
+ self._onchange_commision_amt()
+
def _generate_customer_commision_rebate(self):
for rec in self:
# partners = rec.partner_ids.child_ids + rec.partner_ids
diff --git a/indoteknik_custom/models/cust_commision.py b/indoteknik_custom/models/cust_commision.py
new file mode 100644
index 00000000..eeb255cd
--- /dev/null
+++ b/indoteknik_custom/models/cust_commision.py
@@ -0,0 +1,25 @@
+from odoo import models, api, fields
+from odoo.exceptions import UserError
+from datetime import datetime
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class CustCommision(models.Model):
+ _name = 'cust.commision'
+ _order = 'id desc'
+
+ partner_id = fields.Many2one('res.partner', String='Customer', required=True)
+ commision_percent = fields.Float(string='Commision %', tracking=3)
+
+ @api.constrains('partner_id')
+ def _check_partner_id(self):
+ for rec in self:
+ duplicate_partner = self.search([
+ ('partner_id', '=', rec.partner_id.id),
+ ('id', '!=', rec.id)
+ ])
+ if duplicate_partner:
+ raise UserError('Partner already exists')
+ \ No newline at end of file
diff --git a/indoteknik_custom/models/logbook_sj.py b/indoteknik_custom/models/logbook_sj.py
index 567f1ae3..bf4acd14 100644
--- a/indoteknik_custom/models/logbook_sj.py
+++ b/indoteknik_custom/models/logbook_sj.py
@@ -18,31 +18,27 @@ class LogbookSJ(models.TransientModel):
current_time = datetime.utcnow()
report_logbook_ids = []
+ parameters_header = {
+ 'date': current_time,
+ }
+
+ report_logbook = self.env['report.logbook.sj'].create([parameters_header])
for line in logbook_line:
- nomor_sj = line.name
- picking = self.env['stock.picking'].search([
- ('picking_code', '=', nomor_sj),
- ])
- parameters_header = {
- 'name': nomor_sj,
- 'date': current_time,
- 'name_picking': picking.name,
- 'partner_id': picking.partner_id.id,
+ picking = self.env['stock.picking'].search([('picking_code', '=', line.name)], limit=1)
+ stock = picking
+
+ data = {
+ 'picking_id': stock.id,
+ 'name': stock.name,
+ 'driver_id': stock.driver_id.id,
+ 'departure_date': stock.driver_departure_date,
+ 'arrival_date': stock.driver_arrival_date,
+ 'carrier_id': stock.carrier_id.id,
+ 'tracking_no': stock.delivery_tracking_no,
+ 'partner_id': stock.partner_id.id,
+ 'report_logbook_sj_id': report_logbook.id
}
-
- report_logbook = self.env['report.logbook.sj'].create([parameters_header])
-
-
- for stock in picking.move_line_ids_without_package:
- data = {
- 'product_id': stock.product_id.id,
- 'location_id': stock.location_id.id,
- 'product_uom_qty': stock.product_uom_qty,
- 'qty_done': stock.qty_done,
- 'product_uom_id': stock.product_uom_id.id,
- 'report_logbook_sj_id': report_logbook.id
- }
- self.env['report.logbook.sj.line'].create([data])
+ self.env['report.logbook.sj.line'].create([data])
report_logbook_ids.append(report_logbook.id)
line.unlink()
@@ -68,6 +64,7 @@ class LogbookSJLine(models.TransientModel):
tracking_no = fields.Char(string='Tracking No')
logbook_sj_id = fields.Many2one('logbook.sj', string='Logbook SJ')
partner_id = fields.Many2one('res.partner', string='Customer')
+ picking_id = fields.Many2one('res.partner', string='Customer')
@api.onchange('name')
def onchange_name(self):
@@ -94,6 +91,8 @@ class LogbookSJLine(models.TransientModel):
self.partner_id = picking.partner_id
+ self.picking_id = picking.id
+
delivery_type = self.get_delivery_type(picking.driver_departure_date, picking.driver_arrival_date)
if delivery_type != 'departure':
self.departure_date = picking.driver_departure_date.astimezone(timezone('Asia/Jakarta')).strftime('%Y-%m-%d %H:%M:%S')
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index d2fa793a..4bab2cad 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -74,34 +74,27 @@ class ProductTemplate(models.Model):
@api.constrains('name', 'default_code')
def _check_duplicate_product(self):
for product in self:
- if self.env.user.is_purchasing_manager or self.env.user.is_editor_product or self.env.user.id in [1, 25]:
- continue
-
- domain = [('default_code', '!=', False)]
+ variants = product.product_variant_ids
+ names = [x.name for x in variants] if variants else [product.name]
+ default_codes = [x.default_code for x in variants] if variants else [product.default_code]
- if product.product_variant_ids:
- domain.extend([
- '|',
- ('name', 'in', [variants.name for variants in product.product_variant_ids]),
- ('default_code', 'in', [variants.default_code for variants in product.product_variant_ids])
- ])
- else:
- domain.extend([
- '|',
- ('name', 'in', [product.name]),
- ('default_code', 'in', [product.default_code])
- ])
+ domain = [
+ ('default_code', '!=', False),
+ ('id', '!=', product.id),
+ '|',
+ ('name', 'in', names),
+ ('default_code', 'in', default_codes)
+ ]
+
+ product_exist = self.search(domain, limit=1)
+ if len(product_exist) > 0:
+ raise UserError('Name atau Internal Reference sudah digunakan pada produk lain')
- domain.append(('id', '!=', product.id))
+ if self.env.user.is_purchasing_manager or self.env.user.is_editor_product or self.env.user.id in [1, 25]:
+ continue
- if product.write_date == product.create_date:
- message = "SKU atau Name yang Anda gunakan sudah digunakan di produk lain"
- elif all(day_product > 0 for day_product in product.day_product_to_edit()):
- domain = [('id', '=', product.id)]
- message = "Anda tidak berhak merubah data produk ini"
- existing_purchase = self.search(domain, limit=1)
- if existing_purchase:
- raise UserError(message)
+ if sum(product.day_product_to_edit()) > 0:
+ raise UserError('Produk ini tidak dapat diubah')
@api.constrains('name')
def _validate_name(self):
@@ -382,30 +375,6 @@ class ProductProduct(models.Model):
day_products.append(day_product)
return day_products
-
- @api.constrains('name','default_code')
- def _check_duplicate_product(self):
- for product in self:
- if self.env.user.is_purchasing_manager or self.env.user.is_editor_product or self.env.user.id in [1, 25]:
- continue
-
- if product.write_date == product.create_date:
- domain = [
- ('default_code', '!=', False),
- '|',
- ('name', 'in', [template.name for template in product.product_tmpl_id] or [product.name]),
- ('default_code', 'in', [template.default_code for template in product.product_tmpl_id] or [product.default_code])]
-
- domain.append(('id', '!=', product.id))
- massage="SKU atau Name yang anda pakai sudah digunakan di product lain"
- existing_purchase = self.search(domain, limit=1)
- if existing_purchase:
- raise UserError(massage)
- 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('Anda tidak berhak merubah data product ini')
@api.constrains('name')
def _validate_name(self):
diff --git a/indoteknik_custom/models/promotion/__init__.py b/indoteknik_custom/models/promotion/__init__.py
index 1e15d714..82628d31 100644
--- a/indoteknik_custom/models/promotion/__init__.py
+++ b/indoteknik_custom/models/promotion/__init__.py
@@ -5,4 +5,5 @@ from . import promotion_free_product
from . import sale_order_promotion
from . import sale_order_line
from . import sale_order
-from . import promotion_keyword \ No newline at end of file
+from . import promotion_keyword
+from . import promotion_monitoring \ No newline at end of file
diff --git a/indoteknik_custom/models/promotion/promotion_free_product.py b/indoteknik_custom/models/promotion/promotion_free_product.py
index c5055562..e91d5137 100644
--- a/indoteknik_custom/models/promotion/promotion_free_product.py
+++ b/indoteknik_custom/models/promotion/promotion_free_product.py
@@ -17,6 +17,10 @@ class PromotionFreeProduct(models.Model):
weight = rec.product_id.weight or 0
result.append({
'id': rec.product_id.id,
+ 'parent': {
+ 'id': rec.product_id.product_tmpl_id.id,
+ 'name': rec.product_id.product_tmpl_id.name,
+ },
'image': ir_attachment.api_image('product.template', 'image_256', rec.product_id.product_tmpl_id.id),
'display_name': rec.product_id.display_name,
'name': rec.product_id.name,
diff --git a/indoteknik_custom/models/promotion/promotion_monitoring.py b/indoteknik_custom/models/promotion/promotion_monitoring.py
new file mode 100644
index 00000000..9df0825d
--- /dev/null
+++ b/indoteknik_custom/models/promotion/promotion_monitoring.py
@@ -0,0 +1,45 @@
+from odoo import fields, models, tools
+
+
+class PromotionMonitoring(models.Model):
+ _name = "promotion.monitoring"
+ _auto = False
+ _rec_name = "product_id"
+
+ product_id = fields.Many2one(comodel_name="product.product", string="Product")
+ manufacture_id = fields.Many2one(comodel_name="x_manufactures", string="Manufacture", related="product_id.x_manufacture")
+ price = fields.Float(string="Price", help="Computed Price di Product Pricelist (Tier 1 New)")
+ has_promo = fields.Boolean(string="Has Promo")
+ count_active = fields.Integer(string="Count Active")
+ count_inactive = fields.Integer(string="Count Inactive")
+
+ def init(self):
+ tools.drop_view_if_exists(self.env.cr, self._table)
+ sql = {
+ 'count_active': "COUNT(CASE WHEN ppl.active = True THEN ppl.id ELSE NULL END)",
+ 'count_inactive': "COUNT(CASE WHEN ppl.active = False THEN ppl.id ELSE NULL END)"
+ }
+ self.env.cr.execute("""
+ CREATE OR REPLACE VIEW {table} AS (
+ SELECT
+ p.id as id,
+ p.id as product_id,
+ ppi.computed_price as price,
+ ({count_active} > 0) as has_promo,
+ {count_active} as count_active,
+ {count_inactive} as count_inactive
+ FROM product_product p
+ LEFT JOIN product_template pt ON pt.id = p.product_tmpl_id
+ LEFT JOIN promotion_product pp ON pp.product_id = p.id
+ LEFT JOIN promotion_program_line ppl ON ppl.id = pp.program_line_id
+ LEFT JOIN product_pricelist_item ppi ON ppi.product_id = p.id
+ WHERE p.active = True
+ AND pt.sale_ok = True
+ AND ppi.pricelist_id = 17023
+ GROUP BY p.id, ppi.id
+ )
+ """.format(
+ table=self._table,
+ count_active=sql['count_active'],
+ count_inactive=sql['count_inactive']
+ )) \ No newline at end of file
diff --git a/indoteknik_custom/models/promotion/promotion_product.py b/indoteknik_custom/models/promotion/promotion_product.py
index 2fad0f0d..ae26e888 100644
--- a/indoteknik_custom/models/promotion/promotion_product.py
+++ b/indoteknik_custom/models/promotion/promotion_product.py
@@ -17,6 +17,10 @@ class PromotionProduct(models.Model):
weight = rec.product_id.weight or 0
result.append({
'id': rec.product_id.id,
+ 'parent': {
+ 'id': rec.product_id.product_tmpl_id.id,
+ 'name': rec.product_id.product_tmpl_id.name,
+ },
'image': ir_attachment.api_image('product.template', 'image_256', rec.product_id.product_tmpl_id.id),
'display_name': rec.product_id.display_name,
'name': rec.product_id.name,
diff --git a/indoteknik_custom/models/promotion/promotion_program_line.py b/indoteknik_custom/models/promotion/promotion_program_line.py
index 18a7e184..cb231889 100644
--- a/indoteknik_custom/models/promotion/promotion_program_line.py
+++ b/indoteknik_custom/models/promotion/promotion_program_line.py
@@ -30,6 +30,8 @@ class PromotionProgramLine(models.Model):
discount_amount = fields.Float('Discount Amount')
order_promotion_ids = fields.One2many('sale.order.promotion', 'program_line_id', 'Promotions')
+ active = fields.Boolean(string="Active", default=True)
+ solr_flag = fields.Integer(string="Solr Flag", default=1)
def get_active_promotions(self, product_id):
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@@ -74,6 +76,9 @@ class PromotionProgramLine(models.Model):
}
def _get_remaining_time(self):
+ if not self.program_id.end_time:
+ return 0
+
calculate_time = self.program_id.end_time - datetime.now()
return round(calculate_time.total_seconds())
@@ -93,9 +98,7 @@ class PromotionProgramLine(models.Model):
free_products = self.free_product_ids.formats(purchase_qty=qty)
merged_products = products + free_products
- weight = 0
- if not any(x['package_weight'] == 0 for x in merged_products):
- weight = sum(x['package_weight'] for x in merged_products)
+ weight = sum(x['package_weight'] for x in merged_products)
# Sum of products and free products in 1 package quantity
products_total = sum(x['price']['price_discount'] * x['qty'] / qty for x in products)
diff --git a/indoteknik_custom/models/purchase_pricelist.py b/indoteknik_custom/models/purchase_pricelist.py
index 67b22e4c..d9c9a51d 100755
--- a/indoteknik_custom/models/purchase_pricelist.py
+++ b/indoteknik_custom/models/purchase_pricelist.py
@@ -17,7 +17,7 @@ class PurchasePricelist(models.Model):
count_trx_po = fields.Integer(string='Count Trx Product')
count_trx_po_vendor = fields.Integer(string='Count Trx Vendor')
taxes_product_id = fields.Many2one('account.tax', string='Taxes Human', domain=[('type_tax_use', '=', 'purchase')])
- taxes_system_id = fields.Many2one('account.tax', string='Taxes System', readonly=True)
+ taxes_system_id = fields.Many2one('account.tax', string='Taxes System')
include_price = fields.Float(string='Final Price', readonly=True)
@api.depends('product_id', 'vendor_id')
def _compute_name(self):
diff --git a/indoteknik_custom/models/report_logbook_sj.py b/indoteknik_custom/models/report_logbook_sj.py
index d2008608..5ff56c9a 100644
--- a/indoteknik_custom/models/report_logbook_sj.py
+++ b/indoteknik_custom/models/report_logbook_sj.py
@@ -6,29 +6,59 @@ from datetime import datetime
class ReportLogbookSJ(models.Model):
_name = 'report.logbook.sj'
- name = fields.Char(string='Nomor SJ', default='Logbook SJ')
- date = fields.Datetime(string='Date')
- name_picking = fields.Char(string='Picking Name')
- partner_id = fields.Many2one('res.partner', string='Customer')
+ name = fields.Char(string='Name', default='Logbook SJ')
+ date = fields.Datetime(string='Date Created')
+ date_approve = fields.Datetime(string='Date Approve')
approve_by_finance = fields.Boolean(string='Approve By Finance')
+ approve_by = fields.Many2one(comodel_name='res.users', string='Approve By')
report_logbook_sj_line = fields.One2many(
comodel_name='report.logbook.sj.line',
inverse_name='report_logbook_sj_id',
string='Logbook SJ Line'
)
+ state = fields.Selection(
+ [('belum_terima', 'Belum Terima'),
+ ('terima_sebagian', 'Terima Sebagian'),
+ ('terima_semua', 'Sudah di terima semua'),
+ ],
+ default='terima_semua',
+ string='Status',
+ tracking=True
+ )
+
+ @api.model
+ def create(self, vals):
+ vals['name'] = self.env['ir.sequence'].next_by_code('report.logbook.sj') or '0'
+ result = super(ReportLogbookSJ, self).create(vals)
+ return result
def approve(self):
+ current_time = datetime.utcnow()
if self.env.user.is_accounting:
self.approve_by_finance = True
+ self.date_approve = current_time
+ self.approve_by = self.env.user.id
+ if any(line.not_exist for line in self.report_logbook_sj_line):
+ if all(line.not_exist for line in self.report_logbook_sj_line):
+ self.state = 'belum_terima'
+ else:
+ self.state = 'terima_sebagian'
+ else:
+ self.state = 'terima_semua'
else:
raise UserError('Hanya Accounting yang bisa Approve')
class ReportLogbookSJLine(models.Model):
_name = 'report.logbook.sj.line'
- product_id = fields.Many2one(comodel_name='product.product', string='Product')
- location_id = fields.Many2one(comodel_name='stock.location', string='From')
- product_uom_qty = fields.Float(string='Reserved')
- qty_done = fields.Float(string='Done')
- product_uom_id = fields.Many2one('uom.uom', string='Unit of Measure')
- report_logbook_sj_id = fields.Many2one('report.logbook.sj', string='Logbook SJ') \ No newline at end of file
+ name = fields.Char(string='SJ Number')
+ driver_id = fields.Many2one(comodel_name='res.users', string='Driver')
+ departure_date = fields.Char(string='Departure Date')
+ arrival_date = fields.Char(string='Arrival Date')
+ carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method')
+ tracking_no = fields.Char(string='Tracking No')
+ logbook_sj_id = fields.Many2one('report.logbook.sj', string='Logbook SJ') # Corrected model name
+ partner_id = fields.Many2one('res.partner', string='Customer')
+ picking_id = fields.Many2one('stock.picking', string='Picking')
+ report_logbook_sj_id = fields.Many2one('report.logbook.sj', string='Logbook SJ')
+ not_exist = fields.Boolean(string='Not Exist')
diff --git a/indoteknik_custom/models/report_stock_forecasted.py b/indoteknik_custom/models/report_stock_forecasted.py
new file mode 100644
index 00000000..48a17095
--- /dev/null
+++ b/indoteknik_custom/models/report_stock_forecasted.py
@@ -0,0 +1,45 @@
+from odoo import api, models
+
+class ReplenishmentReport(models.AbstractModel):
+ _inherit = 'report.stock.report_product_product_replenishment'
+
+ @api.model
+ def _get_report_lines(self, product_template_ids, product_variant_ids, wh_location_ids):
+ lines = super(ReplenishmentReport, self)._get_report_lines(product_template_ids, product_variant_ids, wh_location_ids)
+
+ result_dict = {}
+
+ for line in lines:
+ product_id = line.get('product', {}).get('id')
+ query = [('product_id', '=', product_id)]
+ document_out = line.get('document_out')
+ order_id = document_out.id if document_out else None
+
+ if order_id:
+ result = self._calculate_result(line)
+ result_dict.setdefault(order_id, []).append(result)
+
+ for order_id, results in result_dict.items():
+ sale_order_lines = self.env['sale.order.line'].search([('order_id', '=', order_id)])
+
+ concatenated_result = ' ,'.join(results)
+
+ for sale_order_line in sale_order_lines:
+ sale_order_line.reserved_from = concatenated_result
+
+ return lines
+
+ def _calculate_result(self, line):
+ if line['document_in']:
+ return str(line["document_in"].name)
+ elif line['reservation'] and not line['document_in']:
+ return 'Reserved from stock'
+ elif line['replenishment_filled']:
+ if line['document_out']:
+ return 'Inventory On Hand'
+ else:
+ return 'Free Stock'
+ else:
+ return 'Not Available'
+
+
diff --git a/indoteknik_custom/models/res_users.py b/indoteknik_custom/models/res_users.py
index 09321fc6..33f64ce3 100755
--- a/indoteknik_custom/models/res_users.py
+++ b/indoteknik_custom/models/res_users.py
@@ -39,3 +39,20 @@ class ResUsers(models.Model):
if not vouchers: return None
return ', '.join(x.code for x in vouchers)
return None
+
+ def check_access(self, model, mode):
+ assert mode in ('read', 'write', 'create', 'unlink', 'import', 'export'), 'Invalid access mode'
+
+ self._cr.execute("""
+ SELECT MAX(CASE WHEN perm_{mode} THEN 1 ELSE 0 END)
+ FROM ir_model_access a
+ JOIN ir_model m ON (m.id = a.model_id)
+ JOIN res_groups_users_rel gu ON (gu.gid = a.group_id)
+ WHERE m.model = %s
+ AND gu.uid = %s
+ AND a.active IS TRUE
+ """.format(mode=mode), (model, self._uid,))
+ r = self._cr.fetchone()[0]
+
+ return bool(r)
+
diff --git a/indoteknik_custom/models/role_permission/__init__.py b/indoteknik_custom/models/role_permission/__init__.py
new file mode 100644
index 00000000..da36bc1e
--- /dev/null
+++ b/indoteknik_custom/models/role_permission/__init__.py
@@ -0,0 +1 @@
+from . import ir_model_access \ No newline at end of file
diff --git a/indoteknik_custom/models/role_permission/ir_model_access.py b/indoteknik_custom/models/role_permission/ir_model_access.py
new file mode 100644
index 00000000..c77e9b79
--- /dev/null
+++ b/indoteknik_custom/models/role_permission/ir_model_access.py
@@ -0,0 +1,9 @@
+from odoo import fields, models
+
+
+class IrModelAccess(models.Model):
+ _inherit = 'ir.model.access'
+
+ perm_import = fields.Boolean(string='Import Access')
+ perm_export = fields.Boolean(string='Export Access')
+ \ No newline at end of file
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 362ca574..8b789976 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -453,6 +453,7 @@ class SaleOrder(models.Model):
order.approval_status = 'approved'
order._set_sppkp_npwp_contact()
order.calculate_line_no()
+ # order.order_line.get_reserved_from()
res = super(SaleOrder, self).action_confirm()
return res
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index 62f4a6b4..a140468c 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -29,6 +29,32 @@ class SaleOrderLine(models.Model):
vendor_subtotal = fields.Float(string='Vendor Subtotal', compute="_compute_vendor_subtotal")
amount_voucher_disc = fields.Float(string='Voucher Discount')
qty_reserved = fields.Float(string='Qty Reserved', compute='_compute_qty_reserved')
+ reserved_from = fields.Char(string='Reserved From', copy=False)
+
+ # def get_reserved_from(self):
+ # for line in self:
+ # current_stock = self.env['stock.quant'].search([
+ # ('product_id', '=', line.product_id.id),
+ # ('location_id', '=', line.order_id.warehouse_id.lot_stock_id.id)
+ # ])
+
+ # po_stock = self.env['purchase.order.line'].search([
+ # ('product_id', '=', line.product_id.id),
+ # ('order_id.sale_order_id', '=', line.order_id.id),
+ # ('state', '=', 'done')
+ # ])
+
+ # available_quantity = current_stock.available_quantity if current_stock else 0
+ # product_qty = po_stock.product_qty if po_stock else 0
+
+ # if available_quantity >= line.product_uom_qty:
+ # line.reserved_from = 'From Stock'
+ # elif product_qty >= line.product_uom_qty:
+ # line.reserved_from = 'From PO'
+ # elif (available_quantity + product_qty) >= line.product_uom_qty:
+ # line.reserved_from = 'From Stock and PO'
+ # else:
+ # line.reserved_from = None
def _compute_qty_reserved(self):
for line in self:
@@ -41,6 +67,16 @@ class SaleOrderLine(models.Model):
reserved_qty = sum(move.product_uom_qty for move in stock_moves)
line.qty_reserved = reserved_qty
+ if reserved_qty > 0:
+ line._compute_reserved_from()
+
+
+ def _compute_reserved_from(self):
+ for line in self:
+ # continue
+ report_stock_forecasted = self.env['report.stock.report_product_product_replenishment']
+ report_stock_forecasted._get_report_data(False, [line.product_id.id])
+
def _compute_vendor_subtotal(self):
for line in self:
if line.purchase_price > 0 and line.product_uom_qty > 0:
diff --git a/indoteknik_custom/models/solr/apache_solr_queue.py b/indoteknik_custom/models/solr/apache_solr_queue.py
index 07274295..1b51538f 100644
--- a/indoteknik_custom/models/solr/apache_solr_queue.py
+++ b/indoteknik_custom/models/solr/apache_solr_queue.py
@@ -18,6 +18,7 @@ class ApacheSolrQueue(models.Model):
('not_found', 'Record not found')
], 'Execute Status')
execute_date = fields.Datetime('Execute Date')
+ description = fields.Text('Description')
def _compute_display_name(self):
for rec in self:
@@ -38,6 +39,16 @@ class ApacheSolrQueue(models.Model):
if elapsed_time > max_exec_time:
break
rec.execute_queue()
+
+ def open_target_record(self):
+ return {
+ 'name': '',
+ 'view_mode': 'form',
+ 'res_model': self.res_model,
+ 'target': 'current',
+ 'type': 'ir.actions.act_window',
+ 'res_id': self.res_id
+ }
def execute_queue(self):
for rec in self:
@@ -48,7 +59,8 @@ class ApacheSolrQueue(models.Model):
_logger.info(f'Execute Queue: {res_model}.{function_name}() -> {res_id}')
domain = [('id', '=', res_id)]
- if res_model in ['product.template']:
+ model_incl_archive = ['product.template', 'promotion.program.line']
+ if res_model in model_incl_archive:
domain.append(('active', 'in', [True, False]))
model_instance = self.env[res_model].search(domain)
@@ -57,7 +69,8 @@ class ApacheSolrQueue(models.Model):
rec.execute_status = 'success'
else:
rec.execute_status = 'not_found'
- except:
+ except Exception as e:
+ rec.description = e
rec.execute_status = 'failed'
rec.execute_date = datetime.utcnow()
self.env.cr.commit()
diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py
index ac41dbff..c14f6b98 100644
--- a/indoteknik_custom/models/solr/product_product.py
+++ b/indoteknik_custom/models/solr/product_product.py
@@ -49,12 +49,6 @@ class ProductProduct(models.Model):
document = solr_model.get_doc('variants', variant.id)
- image = ''
- if variant.image_256:
- image = ir_attachment.api_image('product.product', 'image_256', variant.id)
- else:
- image = ir_attachment.api_image('product.template', 'image_256', variant.product_tmpl_id.id)
-
document.update({
'id': variant.id,
'display_name_s': variant.display_name,
@@ -63,9 +57,9 @@ class ProductProduct(models.Model):
'product_rating_f': variant.product_tmpl_id.virtual_rating,
'product_id_i': variant.id,
'template_id_i': variant.product_tmpl_id.id,
- "image_s": image,
+ 'image_s': ir_attachment.api_image('product.template', 'image_256', variant.product_tmpl_id.id),
'stock_total_f': variant.qty_stock_vendor,
- 'weight_f': variant.product_tmpl_id.weight,
+ 'weight_f': variant.weight,
'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0,
'manufacture_name_s': variant.product_tmpl_id.x_manufacture.x_name or '',
'manufacture_name': variant.product_tmpl_id.x_manufacture.x_name or '',
diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py
index 6e182324..9cd226fb 100644
--- a/indoteknik_custom/models/solr/promotion_program_line.py
+++ b/indoteknik_custom/models/solr/promotion_program_line.py
@@ -39,9 +39,8 @@ class PromotionProgramLine(models.Model):
document.update({
'id': rec.id,
- 'program_id_i': rec.program_id.id,
+ 'program_id_i': rec.program_id.id or 0,
'name_s': rec.name,
- 'image_s': self.env['ir.attachment'].api_image(self._name, 'image', rec.id) if rec.image else '',
'type_value_s': promotion_type['value'],
'type_label_s': promotion_type['label'],
'package_limit_i': rec.package_limit,
@@ -53,10 +52,9 @@ class PromotionProgramLine(models.Model):
'free_product_ids': [x.product_id.id for x in rec.free_product_ids],
'free_products_s': json.dumps(free_products),
'total_qty_i': sum([x.qty for x in rec.product_ids] + [x.qty for x in rec.free_product_ids]),
+ 'active_b': rec.active
})
-
self.solr().add([document])
-
self.solr().commit()
@api.model
@@ -67,3 +65,13 @@ class PromotionProgramLine(models.Model):
def write(self, vals):
self._create_solr_queue('_sync_to_solr')
return super(PromotionProgramLine, self).write(vals)
+
+ def solr_flag_to_queue(self, limit=500):
+ domain = [
+ ('solr_flag', '=', 2),
+ ('active', 'in', [True, False])
+ ]
+ records = self.search(domain, limit=limit)
+ for record in records:
+ record._create_solr_queue('_sync_to_solr')
+ record.solr_flag = 1
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index a8888b64..3ef1aa35 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -52,10 +52,11 @@ access_procurement_monitoring_detail,access.procurement.monitoring.detail,model_
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_line,access.promotion.program.line,model_promotion_program_line,,1,1,1,0
access_promotion_product,access.promotion.product,model_promotion_product,,1,1,1,1
access_promotion_free_product,access.promotion.free_product,model_promotion_free_product,,1,1,1,1
access_promotion_keyword,access.promotion.keyword,model_promotion_keyword,,1,1,1,1
+access_promotion_monitoring,access.promotion.monitoring,model_promotion_monitoring,,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
@@ -103,3 +104,6 @@ access_logbook_sj,access.logbook.sj,model_logbook_sj,,1,1,1,1
access_logbook_sj_line,access.logbook.sj.line,model_logbook_sj_line,,1,1,1,1
access_report_logbook_sj,access.report.logbook.sj,model_report_logbook_sj,,1,1,1,1
access_report_logbook_sj_line,access.report.logbook.sj.line,model_report_logbook_sj_line,,1,1,1,1
+access_report_logbook_sj_line,access.report.logbook.sj.line,model_report_logbook_sj_line,,1,1,1,1
+access_cust_commision,access.cust.commision,model_cust_commision,,1,1,1,1
+access_report_stock_report_product_product_replenishment,access.report.stock.report_product_product_replenishment,model_report_stock_report_product_product_replenishment,,1,1,1,1
diff --git a/indoteknik_custom/views/apache_solr_queue.xml b/indoteknik_custom/views/apache_solr_queue.xml
index 13869b4c..4c145b9f 100644
--- a/indoteknik_custom/views/apache_solr_queue.xml
+++ b/indoteknik_custom/views/apache_solr_queue.xml
@@ -4,11 +4,16 @@
<field name="model">apache.solr.queue</field>
<field name="arch" type="xml">
<tree editable="top" default_order="create_date desc">
+ <button type="object" name="open_target_record" string="" icon="fa-external-link" />
+ <field name="id" readonly="1" />
<field name="display_name" readonly="1" />
<field name="res_model" readonly="1" />
<field name="res_id" readonly="1" />
<field name="function_name" readonly="1" />
- <field name="execute_status" widget="badge" readonly="1"
+ <field
+ name="execute_status"
+ widget="badge"
+ readonly="1"
decoration-danger="execute_status == 'failed'"
decoration-success="execute_status == 'success'"
decoration-primary="execute_status == 'not_found'"
diff --git a/indoteknik_custom/views/cust_commision.xml b/indoteknik_custom/views/cust_commision.xml
new file mode 100644
index 00000000..dfa4adfb
--- /dev/null
+++ b/indoteknik_custom/views/cust_commision.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <record id="cust_commision_tree" model="ir.ui.view">
+ <field name="name">cust.commision.tree</field>
+ <field name="model">cust.commision</field>
+ <field name="arch" type="xml">
+ <tree editable="bottom">
+ <field name="partner_id"/>
+ <field name="commision_percent"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="cust_commision_form" model="ir.ui.view">
+ <field name="name">cust.commision.form</field>
+ <field name="model">cust.commision</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet string="Commision">
+ <group>
+ <group>
+ <field name="partner_id"/>
+ <field name="commision_percent"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="cust_commision_action" model="ir.actions.act_window">
+ <field name="name">Commision</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">cust.commision</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem id="menu_cust_commision_sales"
+ name="Commision"
+ action="cust_commision_action"
+ parent="sale.product_menu_catalog"
+ sequence="101"
+ />
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml
index 88fe1cf1..600ad192 100644
--- a/indoteknik_custom/views/customer_commision.xml
+++ b/indoteknik_custom/views/customer_commision.xml
@@ -8,9 +8,9 @@
<field name="number"/>
<field name="date_from"/>
<field name="date_to"/>
- <field name="partner_ids"/>
- <field name="description"/>
- <field name="notification" readonly="1"/>
+ <field name="partner_ids" widget="many2many_tags"/>
+ <field name="commision_percent"/>
+ <field name="commision_amt" readonly="1"/>
<field name="status" readonly="1"/>
</tree>
</field>
@@ -90,10 +90,22 @@
</field>
</record>
+ <record id="view_customer_commision_filter" model="ir.ui.view">
+ <field name="name">customer.commision.list.select</field>
+ <field name="model">customer.commision</field>
+ <field name="priority" eval="15"/>
+ <field name="arch" type="xml">
+ <search string="Search Customer Commision">
+ <field name="partner_ids"/>
+ </search>
+ </field>
+ </record>
+
<record id="customer_commision_action" model="ir.actions.act_window">
<field name="name">Customer Commision</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">customer.commision</field>
+ <field name="search_view_id" ref="view_customer_commision_filter"/>
<field name="view_mode">tree,form</field>
</record>
diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml
index f276275d..d52f55ca 100644
--- a/indoteknik_custom/views/ir_sequence.xml
+++ b/indoteknik_custom/views/ir_sequence.xml
@@ -10,6 +10,16 @@
<field name="number_next">1</field>
<field name="number_increment">1</field>
</record>
+
+ <record id="sequence_logbook_sj" model="ir.sequence">
+ <field name="name">Logbook SJ</field>
+ <field name="code">report.logbook.sj</field>
+ <field name="active">TRUE</field>
+ <field name="prefix">LSJ/%(year)s/</field>
+ <field name="padding">5</field>
+ <field name="number_next">1</field>
+ <field name="number_increment">1</field>
+ </record>
<record id="sequence_stock_picking_code" model="ir.sequence">
<field name="name">Stock Picking Code</field>
diff --git a/indoteknik_custom/views/promotion/promotion_monitoring.xml b/indoteknik_custom/views/promotion/promotion_monitoring.xml
new file mode 100644
index 00000000..88325c52
--- /dev/null
+++ b/indoteknik_custom/views/promotion/promotion_monitoring.xml
@@ -0,0 +1,64 @@
+<odoo>
+ <record id="promotion_monitoring_tree" model="ir.ui.view">
+ <field name="name">Promotion Monitoring Tree</field>
+ <field name="model">promotion.monitoring</field>
+ <field name="arch" type="xml">
+ <tree create="0">
+ <field name="product_id" />
+ <field name="manufacture_id" />
+ <field name="price" />
+ <field name="has_promo" />
+ <field name="count_active" />
+ <field name="count_inactive" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="promotion_monitoring_form" model="ir.ui.view">
+ <field name="name">Promotion Monitoring Form</field>
+ <field name="model">promotion.monitoring</field>
+ <field name="arch" type="xml">
+ <form create="0" edit="0">
+ <sheet>
+ <group>
+ <group>
+ <field name="product_id" />
+ <field name="manufacture_id" />
+ <field name="price" />
+ <field name="has_promo" />
+ <field name="count_active" />
+ <field name="count_inactive" />
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="promotion_monitoring_view_search" model="ir.ui.view">
+ <field name="name">promotion.monitoring.search</field>
+ <field name="model">promotion.monitoring</field>
+ <field name="mode">primary</field>
+ <field name="arch" type="xml">
+ <search string="Search">
+ <field name="product_id" />
+ <field name="manufacture_id" />
+ </search>
+ </field>
+ </record>
+
+ <record id="promotion_monitoring_action" model="ir.actions.act_window">
+ <field name="name">Promotion Monitoring</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">promotion.monitoring</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_promotion_monitoring"
+ name="Monitoring"
+ parent="indoteknik_custom.menu_promotion_program_parent"
+ sequence="3"
+ action="promotion_monitoring_action"
+ />
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/promotion/promotion_product.xml b/indoteknik_custom/views/promotion/promotion_product.xml
new file mode 100644
index 00000000..eac42a45
--- /dev/null
+++ b/indoteknik_custom/views/promotion/promotion_product.xml
@@ -0,0 +1,45 @@
+<odoo>
+ <record id="promotion_product_tree" model="ir.ui.view">
+ <field name="name">Promotion Product Tree</field>
+ <field name="model">promotion.product</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="product_id" />
+ <field name="qty" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="promotion_product_form" model="ir.ui.view">
+ <field name="name">Promotion Product Form</field>
+ <field name="model">promotion.product</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <group>
+ <field name="program_line_id" />
+ <field name="product_id" />
+ <field name="qty" />
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="promotion_product_action" model="ir.actions.act_window">
+ <field name="name">Promotion Product</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">promotion.product</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem
+ id="menu_promotion_product"
+ name="Product"
+ parent="indoteknik_custom.menu_promotion_program_parent"
+ sequence="3"
+ action="promotion_product_action"
+ />
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/promotion/promotion_program_line.xml b/indoteknik_custom/views/promotion/promotion_program_line.xml
index 346a08c9..025ea35a 100644
--- a/indoteknik_custom/views/promotion/promotion_program_line.xml
+++ b/indoteknik_custom/views/promotion/promotion_program_line.xml
@@ -22,7 +22,9 @@
<group>
<group>
<field name="name" />
+ <field name="program_id" />
<field name="promotion_type" />
+ <field name="active" readonly="1" />
</group>
<group>
<field name="package_limit" />
@@ -70,4 +72,19 @@
sequence="2"
action="promotion_program_line_action"
/>
+
+ <data noupdate="1">
+ <record id="cron_program_line_solr_flag_solr" model="ir.cron">
+ <field name="name">Program Line: Solr Flag to Queue</field>
+ <field name="interval_number">1</field>
+ <field name="interval_type">hours</field>
+ <field name="numbercall">-1</field>
+ <field name="doall" eval="False"/>
+ <field name="model_id" ref="model_promotion_program_line"/>
+ <field name="code">model.solr_flag_to_queue()</field>
+ <field name="state">code</field>
+ <field name="priority">55</field>
+ <field name="active">True</field>
+ </record>
+ </data>
</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index 3f7ca5a7..baff620c 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -102,7 +102,7 @@
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_qty']" position="attributes">
- <attribute name="attrs">{'readonly': [('is_edit_product_qty', '=', False)], 'required': True}</attribute>
+ <attribute name="attrs">{'required': True}</attribute>
</xpath>
<xpath expr="//form/sheet/notebook/page[@name='purchase_delivery_invoice']" position="before">
diff --git a/indoteknik_custom/views/report_logbook_sj.xml b/indoteknik_custom/views/report_logbook_sj.xml
index 52e00d17..ea58aefd 100644
--- a/indoteknik_custom/views/report_logbook_sj.xml
+++ b/indoteknik_custom/views/report_logbook_sj.xml
@@ -6,10 +6,11 @@
<field name="arch" type="xml">
<tree create="0">
<field name="name"/>
+ <field name="approve_by"/>
<field name="date"/>
- <field name="name_picking"/>
+ <field name="date_approve"/>
<field name="approve_by_finance"/>
- <field name="partner_id"/>
+ <field name="state"/>
</tree>
</field>
</record>
@@ -18,12 +19,16 @@
<field name="name">report.logbook.sj.line.tree</field>
<field name="model">report.logbook.sj.line</field>
<field name="arch" type="xml">
- <tree>
- <field name="product_id"/>
- <field name="location_id"/>
- <field name="product_uom_qty"/>
- <field name="qty_done"/>
- <field name="product_uom_id"/>
+ <tree editable="bottom">
+ <field name="name"/>
+ <field name="driver_id"/>
+ <field name="departure_date"/>
+ <field name="arrival_date"/>
+ <field name="carrier_id"/>
+ <field name="tracking_no"/>
+ <field name="partner_id"/>
+ <field name="picking_id"/>
+ <field name="not_exist"/>
</tree>
</field>
</record>
@@ -35,7 +40,7 @@
<form>
<header>
<button name="approve"
- string="Approve"
+ string="Validate"
type="object"
/>
</header>
@@ -45,11 +50,12 @@
<group>
<field name="name" readonly="1"/>
<field name="date" readonly="1"/>
+ <field name="date_approve" readonly="1"/>
</group>
<group>
- <field name="name_picking" readonly="1"/>
- <field name="partner_id" readonly="1"/>
<field name="approve_by_finance" readonly="1"/>
+ <field name="state" readonly="1"/>
+ <field name="approve_by" readonly="1"/>
</group>
</group>
<notebook>
diff --git a/indoteknik_custom/views/role_permission/ir_model_access.xml b/indoteknik_custom/views/role_permission/ir_model_access.xml
new file mode 100644
index 00000000..0c74d5e2
--- /dev/null
+++ b/indoteknik_custom/views/role_permission/ir_model_access.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="ir_model_access_tree_view_inherit" model="ir.ui.view">
+ <field name="name">Access Rights</field>
+ <field name="model">ir.model.access</field>
+ <field name="inherit_id" ref="base.ir_access_view_tree_edition"/>
+ <field name="arch" type="xml">
+ <field name="perm_unlink" position="after">
+ <field name="perm_import"/>
+ <field name="perm_export"/>
+ </field>
+ </field>
+ </record>
+ </data>
+</odoo>
diff --git a/indoteknik_custom/views/role_permission/res_groups.xml b/indoteknik_custom/views/role_permission/res_groups.xml
new file mode 100644
index 00000000..910469fd
--- /dev/null
+++ b/indoteknik_custom/views/role_permission/res_groups.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record model="ir.module.category" id="module_category_roles">
+ <field name="name">Roles</field>
+ <field name="sequence">70</field>
+ <field name="visible" eval="0" />
+ </record>
+
+ <record id="group_role_it" model="res.groups">
+ <field name="name">IT</field>
+ <field name="category_id" ref="module_category_roles" />
+ </record>
+
+ <record id="group_role_fat" model="res.groups">
+ <field name="name">FAT</field>
+ <field name="category_id" ref="module_category_roles" />
+ </record>
+
+ <record id="group_role_sales" model="res.groups">
+ <field name="name">Sales</field>
+ <field name="category_id" ref="module_category_roles" />
+ </record>
+
+ <record id="group_role_marketing" model="res.groups">
+ <field name="name">Marketing</field>
+ <field name="category_id" ref="module_category_roles" />
+ </record>
+
+ <record id="group_role_purchasing" model="res.groups">
+ <field name="name">Purchasing</field>
+ <field name="category_id" ref="module_category_roles" />
+ </record>
+
+ <record id="group_role_logistic" model="res.groups">
+ <field name="name">Logistic</field>
+ <field name="category_id" ref="module_category_roles" />
+ </record>
+
+ <record id="group_role_merchandiser" model="res.groups">
+ <field name="name">Merchandiser</field>
+ <field name="category_id" ref="module_category_roles" />
+ </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 02dba7d5..aa508443 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -109,11 +109,15 @@
<field name="line_no" readonly="1" optional="hide"/>
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='qty_delivered']" position="before">
- <field name="qty_reserved" readonly="1"/>
+ <field name="qty_reserved" invisible="1"/>
+ <field name="reserved_from" 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>
+ <!-- <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='tax_id']" position="attributes">
+ <attribute name="required">1</attribute>
+ </xpath> -->
<field name="amount_total" position="after">
<field name="grand_total"/>
<label for="amount_voucher_disc" string="Voucher" />