summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indoteknik_api/controllers/api_v1/product.py102
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py29
-rw-r--r--indoteknik_api/models/sale_order.py16
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rwxr-xr-xindoteknik_custom/models/__init__.py1
-rwxr-xr-xindoteknik_custom/models/sale_order.py22
-rw-r--r--indoteknik_custom/models/sale_order_delay.py31
-rw-r--r--indoteknik_custom/models/stock_picking.py121
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/sale_order_delay.xml44
10 files changed, 258 insertions, 110 deletions
diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py
index a88c3368..7d6ebdb6 100644
--- a/indoteknik_api/controllers/api_v1/product.py
+++ b/indoteknik_api/controllers/api_v1/product.py
@@ -51,7 +51,7 @@ class Product(controller.Controller):
additional_days = request.env['sale.order'].get_days_until_next_business_day(start_date)
include_instant = True
- if(len(products) != len(product_ids)):
+ if(len(products) == len(product_ids)):
products_data_params = {product["id"] : product for product in product_data }
all_fast_products = all(
@@ -96,27 +96,40 @@ class Product(controller.Controller):
})
@http.route(prefix + 'product_variant/<id>/stock', auth='public', methods=['GET', 'OPTIONS'])
- @controller.Controller.must_authorized()
+ @controller.Controller.must_authorized()
def get_product_template_stock_by_id(self, **kw):
id = int(kw.get('id'))
date_7_days_ago = datetime.now() - timedelta(days=7)
- product = request.env['product.product'].search(
- [('id', '=', id)], limit=1)
- product_sla = request.env['product.sla'].search(
- [('product_variant_id', '=', id)], limit=1)
+ product_pruchase = request.env['purchase.pricelist'].search([
+ ('product_id', '=', id),
+ ('is_winner', '=', True)
+ ])
stock_vendor = request.env['stock.vendor'].search([
('product_variant_id', '=', id),
('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S"))
], limit=1)
+
+ product = product_pruchase.product_id
+
+ vendor_sla = request.env['vendor.sla'].search([('id_vendor', '=', product_pruchase.vendor_id.id)], limit=1)
+ slatime = 15
+ if vendor_sla:
+ if vendor_sla.unit == 'hari':
+ vendor_duration = vendor_sla.duration * 24 * 60
+ else :
+ vendor_duration = vendor_sla.duration * 60
+
+ estimation_sla = (1 * 24 * 60) + vendor_duration
+ estimation_sla_days = estimation_sla / (24 * 60)
+ slatime = math.ceil(estimation_sla_days)
qty_available = product.qty_free_bandengan
-
if qty_available < 1 :
qty_available = 0
qty = 0
- sla_date = '-'
+ sla_date = f'{slatime} Hari'
# Qty Stock Vendor
qty_vendor = stock_vendor.quantity
@@ -136,28 +149,89 @@ class Product(controller.Controller):
if qty_available > 0:
qty = qty_available + total_adem + total_excell
- sla_date = product_sla.sla or 1
+ sla_date = '1 Hari'
elif qty_altama > 0 or qty_vendor > 0:
qty = total_adem if qty_altama > 0 else total_excell
- sla_date = product_sla.sla
+ sla_date = f'{slatime} Hari'
else:
- sla_date = product_sla.sla
+ sla_date = f'{slatime} Hari'
except:
print('error')
else:
if qty_available > 0:
qty = qty_available
- sla_date = product_sla.sla or 'Indent'
+ sla_date = f'{slatime} Hari'
elif qty_vendor > 0:
qty = total_excell
- sla_date = '2-4 Hari'
+ sla_date = f'{slatime} Hari'
data = {
'qty': qty,
'sla_date': sla_date
}
- return self.response(data, headers=[('Cache-Control', 'max-age=600, private')])
+ return self.response(data, headers=[('Cache-Control', 'max-age=600, private')])
+ # def get_product_template_stock_by_id(self, **kw):
+ # id = int(kw.get('id'))
+ # date_7_days_ago = datetime.now() - timedelta(days=7)
+ # product = request.env['product.product'].search(
+ # [('id', '=', id)], limit=1)
+ # product_sla = request.env['product.sla'].search(
+ # [('product_variant_id', '=', id)], limit=1)
+ # stock_vendor = request.env['stock.vendor'].search([
+ # ('product_variant_id', '=', id),
+ # ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S"))
+ # ], limit=1)
+
+ # qty_available = product.qty_free_bandengan
+
+
+ # if qty_available < 1 :
+ # qty_available = 0
+
+ # qty = 0
+ # sla_date = '-'
+
+ # # Qty Stock Vendor
+ # qty_vendor = stock_vendor.quantity
+ # qty_vendor -= int(qty_vendor * 0.1)
+ # qty_vendor = math.ceil(float(qty_vendor))
+ # total_excell = qty_vendor
+
+ # is_altama_product = product.x_manufacture.id in [10, 122, 89]
+ # if is_altama_product:
+ # try:
+ # # Qty Altama
+ # qty_altama = request.env['product.template'].get_stock_altama(
+ # product.default_code)
+ # qty_altama -= int(qty_altama * 0.1)
+ # qty_altama = math.ceil(float(qty_altama))
+ # total_adem = qty_altama
+
+ # if qty_available > 0:
+ # qty = qty_available + total_adem + total_excell
+ # sla_date = product_sla.sla or 1
+ # elif qty_altama > 0 or qty_vendor > 0:
+ # qty = total_adem if qty_altama > 0 else total_excell
+ # sla_date = product_sla.sla
+ # else:
+ # sla_date = product_sla.sla
+ # except:
+ # print('error')
+ # else:
+ # if qty_available > 0:
+ # qty = qty_available
+ # sla_date = product_sla.sla or 'Indent'
+ # elif qty_vendor > 0:
+ # qty = total_excell
+ # sla_date = '2-4 Hari'
+
+ # data = {
+ # 'qty': qty,
+ # 'sla_date': sla_date
+ # }
+
+ # return self.response(data, headers=[('Cache-Control', 'max-age=600, private')])
@http.route(prefix + 'product_variant/<id>/qty_available', auth='public', methods=['GET', 'OPTIONS'])
@controller.Controller.must_authorized()
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
index 31706b99..e16af332 100644
--- a/indoteknik_api/controllers/api_v1/stock_picking.py
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -3,6 +3,7 @@ from odoo import http
from odoo.http import request
from pytz import timezone
from datetime import datetime
+import json
class StockPicking(controller.Controller):
@@ -101,7 +102,6 @@ class StockPicking(controller.Controller):
picking = picking_model.browse(id)
if not picking:
return self.response(None)
- hostori = picking.get_tracking_detail()
return self.response(picking.get_tracking_detail())
@http.route(prefix + 'stock-picking/<id>/tracking', auth='public', method=['GET', 'OPTIONS'])
@@ -141,13 +141,12 @@ class StockPicking(controller.Controller):
'name': picking_data.name
})
- @http.route(prefix + 'webhook/biteship', type='json', auth='public', methods=['POST'], csrf=False)
+ @http.route(prefix + 'webhook/biteship', auth='public', methods=['POST'], csrf=False)
def udpate_status_from_bitehsip(self, **kw):
try:
- if not request.jsonrequest:
- return "ok"
+ data = kw # Ambil data JSON dari request
- data = request.jsonrequest # Ambil data JSON dari request
+ print(data)
event = data.get('event')
# Handle Event Berdasarkan Jenisnya
@@ -158,27 +157,29 @@ class StockPicking(controller.Controller):
elif event == "order.waybill_id":
self.process_order_waybill(data)
- return {'success': True, 'message': f'Webhook {event} received'}
+ return self.response({'success': True})
except Exception as e:
- return {'success': False, 'message': str(e)}
+ return self.response({'success': False, 'message': str(e)})
def process_order_status(self, data):
picking_model = request.env['stock.picking'].sudo().search([('biteship_id', '=', data.get('order_id'))], limit=1)
- if data.get('status') == 'picked':
- picking_model.write({'driver_departure_date': datetime.utcnow()})
- elif data.get('status') == 'delivered':
- picking_model.write({'driver_arrival_date': datetime.utcnow()})
+ if picking_model :
+ if data.get('status') == 'picked':
+ result = picking_model.write({'driver_departure_date': datetime.utcnow()})
+ print(result)
+ elif data.get('status') == 'delivered':
+ picking_model.write({'driver_arrival_date': datetime.utcnow()})
def process_order_price(self, data):
- picking_model = request.env['stock.picking'].sudo().search([('biteship_id', '=', data.get('order_id'))], limit=1)
- order = request.env['sale.order'].sudo().search([('name', '=', picking_model.sale_id.name)], limit=1)
+ picking_model = request.env['stock.picking'].search([('biteship_id', '=', data.get('order_id'))], limit=1)
+ order = request.env['sale.order'].search([('name', '=', picking_model.sale_id.name)], limit=1)
if order:
order.write({
'delivery_amt': data.get('price')
})
def process_order_waybill(self, data):
- picking_model = request.env['stock.picking'].sudo().search([('biteship_id', '=', data.get('order_id'))], limit=1)
+ picking_model = request.env['stock.picking'].search([('biteship_id', '=', data.get('order_id'))], limit=1)
if picking_model:
picking_model.write({
'biteship_waybill_id': data.get('courier_waybill_id'),
diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py
index 727379c5..ce728f95 100644
--- a/indoteknik_api/models/sale_order.py
+++ b/indoteknik_api/models/sale_order.py
@@ -29,11 +29,23 @@ class SaleOrder(models.Model):
'pickings': []
}
for picking in sale_order.picking_ids:
+ picking_model = self.env['stock.picking'].sudo().search([('id', '=', picking.id)], limit=1)
+ if not picking_model:
+ continue
+ response = picking_model.get_tracking_detail()
+
data['pickings'].append({
+ 'waybill_number' : response['waybill_number'] or '',
+ 'delivered_date': response['delivered_date'],
+ 'delivery_order' : {
+ 'carrier' : response['delivery_order']['carrier'] or '',
+ 'service' : response['delivery_order']['service'] or ''
+ },
+ 'eta' : response['eta'],
'id': picking.id,
'name': picking.name,
- 'tracking_number': picking.delivery_tracking_no or '',
- 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False or picking.sj_return_date != False,
+ # 'tracking_number': picking.delivery_tracking_no or '',
+ # 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False or picking.sj_return_date != False,
})
if sale_order.state == 'cancel':
data['status'] = 'cancel'
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 8272efc4..dec0f26a 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -166,6 +166,7 @@
'views/coretax_faktur.xml',
'views/public_holiday.xml',
'views/stock_inventory.xml',
+ 'views/sale_order_delay.xml',
],
'demo': [],
'css': [],
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 08fa9803..605d1016 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -149,4 +149,5 @@ from . import sales_order_koli
from . import stock_backorder_confirmation
from . import account_payment_register
from . import stock_inventory
+from . import sale_order_delay
from . import approval_invoice_date
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 02d61387..3117a330 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -530,7 +530,7 @@ class SaleOrder(models.Model):
@api.depends('date_order', 'estimated_arrival_days', 'state', 'estimated_arrival_days_start')
def _compute_eta_date(self):
- current_date = datetime.now().date()
+ current_date = datetime.now()
for rec in self:
if rec.date_order and rec.state not in ['cancel'] and rec.estimated_arrival_days and rec.estimated_arrival_days_start:
rec.eta_date = current_date + timedelta(days=rec.estimated_arrival_days)
@@ -541,7 +541,19 @@ class SaleOrder(models.Model):
def get_days_until_next_business_day(self,start_date=None, *args, **kwargs):
- today = start_date or datetime.today().date()
+ now = start_date or datetime.now()
+
+ # Jika hanya diberikan tanggal (tanpa jam), asumsikan jam 00:00
+ if isinstance(now, datetime):
+ order_datetime = now
+ else:
+ order_datetime = datetime.combine(now, datetime.min.time())
+
+ today = order_datetime.date()
+
+ if order_datetime.time() > datetime.strptime("15:00", "%H:%M").time():
+ today += timedelta(days=1)
+
offset = 0 # Counter jumlah hari yang ditambahkan
holiday = self.env['hr.public.holiday']
@@ -602,13 +614,13 @@ class SaleOrder(models.Model):
rec.expected_ready_to_ship = False
return
- current_date = datetime.now().date()
+ current_date = datetime.now()
max_slatime = 1 # Default SLA jika tidak ada
slatime = self.calculate_sla_by_vendor(rec.order_line)
max_slatime = max(max_slatime, slatime['slatime'])
- sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1
+ sum_days = max_slatime + self.get_days_until_next_business_day(current_date)
if not rec.estimated_arrival_days:
rec.estimated_arrival_days = sum_days
@@ -631,7 +643,7 @@ class SaleOrder(models.Model):
max_slatime = 1 # Default SLA jika tidak ada
slatime = self.calculate_sla_by_vendor(rec.order_line)
max_slatime = max(max_slatime, slatime['slatime'])
- sum_days = max_slatime + self.get_days_until_next_business_day(current_date) - 1
+ sum_days = max_slatime + self.get_days_until_next_business_day(current_date)
eta_minimum = current_date + timedelta(days=sum_days)
if expected_date < eta_minimum:
diff --git a/indoteknik_custom/models/sale_order_delay.py b/indoteknik_custom/models/sale_order_delay.py
new file mode 100644
index 00000000..dfd94650
--- /dev/null
+++ b/indoteknik_custom/models/sale_order_delay.py
@@ -0,0 +1,31 @@
+from odoo import api, fields, models
+
+
+class SaleOrderDelay(models.Model):
+ _name = 'sale.order.delay'
+ _description = 'Sale Order Delay'
+ _primary_key = 'so_number'
+
+ so_number = fields.Char(string="SO Number", required=True)
+ days_delayed = fields.Integer(string="Day Delayed or Erly")
+ status = fields.Selection([
+ ('delayed', 'Delayed'),
+ ('on track', 'On Track'),
+ ('early', 'Early')
+ ], string='Status', required=True)
+
+ _sql_constraints = [
+ ('unique_so_number', 'unique(so_number)', 'SO Number must be unique!')
+ ]
+
+ def update_delay(self):
+ query = "SELECT check_so_delay();"
+ self.env.cr.execute(query)
+
+ @api.model
+ def create(self, vals):
+ return super(SaleOrderDelay, self).create(vals)
+
+ def write(self, vals):
+ return super(SaleOrderDelay, self).write(vals)
+ \ No newline at end of file
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 8f8ab54d..36129f00 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -242,9 +242,6 @@ class StockPicking(models.Model):
biteship_id = fields.Char(string="Biteship Respon ID")
biteship_tracking_id = fields.Char(string="Biteship Trackcking ID")
biteship_waybill_id = fields.Char(string="Biteship Waybill ID")
- # estimated_ready_ship_date = fields.Datetime(string='ET Ready to Ship', copy=False, related='sale_id.estimated_ready_ship_date')
- # countdown_hours = fields.Float(string='Countdown in Hours', compute='_callculate_sequance', default=False, store=False, compute_sudo=False)
- # countdown_ready_to_ship = fields.Char(string='Countdown Ready to Ship', compute='_callculate_sequance', store=False, compute_sudo=False)
final_seq = fields.Float(string='Remaining Time')
shipping_method_so_id = fields.Many2one('delivery.carrier', string='Shipping Method SO', related='sale_id.carrier_id')
state_packing = fields.Selection([('not_packing', 'Belum Packing'), ('packing_done', 'Sudah Packing')], string='Packing Status')
@@ -359,54 +356,6 @@ class StockPicking(models.Model):
def schduled_update_sequance(self):
query = "SELECT update_sequance_stock_picking();"
self.env.cr.execute(query)
-
-
- # @api.depends('estimated_ready_ship_date', 'state')
- # def _callculate_sequance(self):
- # for record in self:
- # try :
- # if record.estimated_ready_ship_date and record.state not in ('cancel', 'done'):
- # rts = record.estimated_ready_ship_date - waktu.now()
- # rts_days = rts.days
- # rts_hours = divmod(rts.seconds, 3600)
-
- # estimated_by_erts = rts.total_seconds() / 3600
-
- # record.countdown_ready_to_ship = f"{rts_days} days, {rts_hours} hours"
- # record.countdown_hours = estimated_by_erts
- # else:
- # record.countdown_hours = 999999999999
- # record.countdown_ready_to_ship = False
- # except Exception as e :
- # _logger.error(f"Error calculating sequance {record.id}: {str(e)}")
- # print(str(e))
- # return { 'error': str(e) }
-
-
- # @api.depends('estimated_ready_ship_date', 'state')
- # def _compute_countdown_hours(self):
- # for record in self:
- # if record.state in ('cancel', 'done') or not record.estimated_ready_ship_date:
- # # Gunakan nilai yang sangat besar sebagai placeholder
- # record.countdown_hours = 999999
- # else:
- # delta = record.estimated_ready_ship_date - waktu.now()
- # record.countdown_hours = delta.total_seconds() / 3600
-
- # @api.depends('estimated_ready_ship_date', 'state')
- # def _compute_countdown_ready_to_ship(self):
- # for record in self:
- # if record.state in ('cancel', 'done'):
- # record.countdown_ready_to_ship = False
- # else:
- # if record.estimated_ready_ship_date:
- # delta = record.estimated_ready_ship_date - waktu.now()
- # days = delta.days
- # hours, remainder = divmod(delta.seconds, 3600)
- # record.countdown_ready_to_ship = f"{days} days, {hours} hours"
- # record.countdown_hours = delta.total_seconds() / 3600
- # else:
- # record.countdown_ready_to_ship = False
def _compute_lalamove_image_html(self):
for record in self:
@@ -1471,28 +1420,42 @@ class StockPicking(models.Model):
self.ensure_one()
order = self.env['sale.order'].search([('name', '=', self.sale_id.name)], limit=1)
+
+ sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', order.name)], limit=1)
response = {
'delivery_order': {
'name': self.name,
- 'carrier': self.carrier_id.name or '',
- 'service' : order.delivery_service_type or '',
+ 'carrier': self.carrier_id.name or '-',
+ 'service' : order.delivery_service_type or '-',
'receiver_name': '',
'receiver_city': ''
},
+ 'delivered_date': self.driver_departure_date.strftime('%d %b %Y') if self.driver_departure_date != False else '-',
'delivered': False,
'status': self.shipping_status,
- 'waybill_number': self.delivery_tracking_no or '',
+ 'waybill_number': self.delivery_tracking_no or '-',
'delivery_status': None,
'eta': self.generate_eta_delivery(),
'is_biteship': True if self.biteship_id else False,
- 'manifests': self.get_manifests()
+ 'manifests': self.get_manifests(),
+ 'is_delay': True if sale_order_delay and sale_order_delay.status == 'delayed' else False
}
if self.biteship_id :
histori = self.get_manifest_biteship()
- eta_start = order.date_order + timedelta(days=order.estimated_arrival_days_start)
- eta_end = order.date_order + timedelta(days=order.estimated_arrival_days)
+ day_start = order.estimated_arrival_days_start
+ day_end = order.estimated_arrival_days
+ if sale_order_delay:
+ if sale_order_delay.status == 'delayed':
+ day_start = day_start + sale_order_delay.days_delayed
+ day_end = day_end + sale_order_delay.days_delayed
+ elif sale_order_delay.status == 'early':
+ day_start = day_start - sale_order_delay.days_delayed
+ day_end = day_end - sale_order_delay.days_delayed
+
+ eta_start = order.date_order + timedelta(days=day_start)
+ eta_end = order.date_order + timedelta(days=day_end)
formatted_eta = f"{eta_start.strftime('%d %b')} - {eta_end.strftime('%d %b %Y')}"
response['eta'] = formatted_eta
response['manifests'] = histori.get("manifests", [])
@@ -1519,7 +1482,6 @@ class StockPicking(models.Model):
"Content-Type": "application/json"
}
-
manifests = []
try:
@@ -1530,10 +1492,10 @@ class StockPicking(models.Model):
'confirmed' : 'Indoteknik telah melakukan permintaan pick-up',
'allocated' : 'Kurir akan melakukan pick-up pesanan',
'picking_up' : 'Kurir sedang dalam perjalanan menuju lokasi pick-up',
- 'picked' : 'Pesanan sudah di pick-up kurir '+result.get("courier", {}).get("name", ""),
+ 'picked' : 'Pesanan sudah di pick-up kurir '+result.get("courier", {}).get("company", ""),
'on_hold' : 'Pesanan ditahan sementara karena masalah pengiriman',
- 'dropping_off' : 'Kurir sudah ditugaskan dan pesanan akan segera diantar ke pembeli',
- 'delivered' : 'Pesanan telah sampai dan diterima oleh '+result.get("destination", {}).get("contact_name", "")
+ 'dropping_off' : 'Kurir sudah ditugaskan dan pesanan akan segera diantar ke pembeli',
+ 'delivered' : f'Pesanan telah sampai dan diterima oleh <span style="color:#DC2626;">{result.get("destination", {}).get("contact_name", "")}</span>'
}
if(result.get('success') == True):
history = result.get("history", [])
@@ -1551,7 +1513,10 @@ class StockPicking(models.Model):
"delivered": status
}
- return manifests
+ return {
+ "manifests": [],
+ "delivered": False
+ }
except Exception as e :
_logger.error(f"Error fetching Biteship order for picking {self.id}: {str(e)}")
return { 'error': str(e) }
@@ -1584,20 +1549,26 @@ class StockPicking(models.Model):
def generate_eta_delivery(self):
current_date = datetime.datetime.now()
- prepare_days = 3
- start_date = self.driver_departure_date or self.create_date
-
- ead = self.sale_id.estimated_arrival_days or 0
- if not self.driver_departure_date:
- ead += prepare_days
-
- ead_datetime = datetime.timedelta(days=ead)
- fastest_eta = start_date + ead_datetime
- if not self.driver_departure_date and fastest_eta < current_date:
- fastest_eta = current_date + ead_datetime
+ days_start = self.sale_id.estimated_arrival_days_start or self.sale_id.estimated_arrival_days
+ days_end = self.sale_id.estimated_arrival_days or (self.sale_id.estimated_arrival_days + 3)
+ start_date = self.sale_id.create_date + datetime.timedelta(days=days_start)
+ end_date = self.sale_id.create_date + datetime.timedelta(days=days_end)
+
+
+ add_day_start = 0
+ add_day_end = 0
+ sale_order_delay = self.env['sale.order.delay'].search([('so_number', '=', self.sale_id.name)], limit=1)
+ if sale_order_delay:
+ if sale_order_delay.status == 'delayed':
+ add_day_start = sale_order_delay.days_delayed
+ add_day_end = sale_order_delay.days_delayed
+ elif sale_order_delay.status == 'early':
+ add_day_start = -abs(sale_order_delay.days_delayed)
+ add_day_end = -abs(sale_order_delay.days_delayed)
+
+ fastest_eta = start_date +datetime.timedelta(days=add_day_start + add_day_start)
- longest_days = 3
- longest_eta = fastest_eta + datetime.timedelta(days=longest_days)
+ longest_eta = end_date + datetime.timedelta(days=add_day_end)
format_time = '%d %b %Y'
format_time_fastest = '%d %b' if fastest_eta.year == longest_eta.year else format_time
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 30088680..46ab4c1f 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -177,4 +177,5 @@ access_stock_inventory,access.stock.inventory,model_stock_inventory,,1,1,1,1
access_cancel_reason_order,cancel.reason.order,model_cancel_reason_order,,1,1,1,0
access_reject_reason_commision,reject.reason.commision,model_reject_reason_commision,,1,1,1,0
access_shipping_option,shipping.option,model_shipping_option,,1,1,1,1
+access_sale_order_delay,sale.order.delay,model_sale_order_delay,,1,1,1,1
access_production_purchase_match,access.production.purchase.match,model_production_purchase_match,,1,1,1,1
diff --git a/indoteknik_custom/views/sale_order_delay.xml b/indoteknik_custom/views/sale_order_delay.xml
new file mode 100644
index 00000000..b2aad8eb
--- /dev/null
+++ b/indoteknik_custom/views/sale_order_delay.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="view_sale_order_delay_tree" model="ir.ui.view">
+ <field name="name">sale.order.delay.tree</field>
+ <field name="model">sale.order.delay</field>
+ <field name="arch" type="xml">
+ <tree>
+ <field name="so_number" />
+ <field name="days_delayed" />
+ <field name="status" />
+ </tree>
+ </field>
+ </record>
+
+ <record id="sale_order_delay_action" model="ir.actions.act_window">
+ <field name="name">Sale Order Delay</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">sale.order.delay</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <record id="view_sale_order_delay_form" model="ir.ui.view">
+ <field name="name">sale.order.delay.form</field>
+ <field name="model">sale.order.delay</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <field name="so_number" />
+ <field name="days_delayed" />
+ <field name="status" />
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <menuitem id="menu_sale_order_delay"
+ name="Sale Order Delay"
+ action="sale_order_delay_action"
+ parent="sale.product_menu_catalog"
+ sequence="8"
+ />
+</odoo> \ No newline at end of file