summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-09-06 13:59:28 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-09-06 13:59:28 +0700
commit4986c63d2a6bd8e2feadbd2403a211b0b0cf405f (patch)
treeb80d2d415b887a7ab66c9d55d5a4857d34142bea
parentea48748650d1abe7b9c09f961eaa3762750e21be (diff)
parente07379886024a313695a56ebdd072bfd87b6626a (diff)
Merge branch 'production' into feature/voucher-group
-rw-r--r--indoteknik_api/controllers/api_v1/__init__.py3
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py12
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py81
-rw-r--r--indoteknik_api/models/sale_order.py8
-rwxr-xr-xindoteknik_custom/__manifest__.py3
-rwxr-xr-xindoteknik_custom/models/__init__.py3
-rw-r--r--indoteknik_custom/models/account_account.py8
-rw-r--r--indoteknik_custom/models/account_move.py2
-rw-r--r--indoteknik_custom/models/account_move_line.py24
-rw-r--r--indoteknik_custom/models/cost_centre.py11
-rw-r--r--indoteknik_custom/models/product_pricelist.py10
-rwxr-xr-xindoteknik_custom/models/product_template.py62
-rwxr-xr-xindoteknik_custom/models/purchase_pricelist.py15
-rwxr-xr-xindoteknik_custom/models/sale_order.py1
-rw-r--r--indoteknik_custom/models/solr/product_pricelist_item.py32
-rw-r--r--indoteknik_custom/models/solr/product_template.py42
-rw-r--r--indoteknik_custom/models/stock_picking.py101
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rw-r--r--indoteknik_custom/views/account_account_views.xml15
-rw-r--r--indoteknik_custom/views/account_move_line.xml18
-rw-r--r--indoteknik_custom/views/cost_centre.xml41
-rwxr-xr-xindoteknik_custom/views/sale_order.xml1
22 files changed, 432 insertions, 62 deletions
diff --git a/indoteknik_api/controllers/api_v1/__init__.py b/indoteknik_api/controllers/api_v1/__init__.py
index 65bcf926..36fcbd53 100644
--- a/indoteknik_api/controllers/api_v1/__init__.py
+++ b/indoteknik_api/controllers/api_v1/__init__.py
@@ -25,4 +25,5 @@ from . import content
from . import midtrans
from . import wati
from . import courier
-from . import voucher \ No newline at end of file
+from . import voucher
+from . import stock_picking \ No newline at end of file
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index ccecb55f..adc89f66 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -97,12 +97,8 @@ class SaleOrder(controller.Controller):
if not params['valid']:
return self.response(code=400, description=params)
- partner_child_ids = self.get_partner_child_ids(
- params['value']['partner_id'])
- domain = [
- ('id', '=', params['value']['id']),
- ('partner_id', 'in', partner_child_ids)
- ]
+ partner_child_ids = self.get_partner_child_ids(params['value']['partner_id'])
+ domain = [('id', '=', params['value']['id']), ('partner_id', 'in', partner_child_ids)]
data = {}
sale_order = request.env['sale.order'].search(domain)
if sale_order:
@@ -262,7 +258,8 @@ class SaleOrder(controller.Controller):
'carrier_id': [],
'delivery_service_type': [],
'voucher': [],
- 'source': []
+ 'source': [],
+ 'estimated_arrival_days': ['number', 'default:0']
})
if not params['valid']:
@@ -287,6 +284,7 @@ class SaleOrder(controller.Controller):
'partner_purchase_order_name': params['value']['po_number'],
'partner_purchase_order_file': params['value']['po_file'],
'delivery_amt': params['value']['delivery_amount'],
+ 'estimated_arrival_days': params['value']['estimated_arrival_days'],
'shipping_cost_covered': 'customer',
'shipping_paid_by': 'customer',
'carrier_id': params['value']['carrier_id'],
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
new file mode 100644
index 00000000..e0a60c98
--- /dev/null
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -0,0 +1,81 @@
+from .. import controller
+from odoo import http
+from odoo.http import request
+
+
+class StockPicking(controller.Controller):
+ prefix = '/api/v1/'
+ PREFIX_PARTNER = prefix + 'partner/<partner_id>/'
+
+ @http.route(PREFIX_PARTNER + 'stock-picking', auth='public', method=['GET', 'OPTIONS'])
+ @controller.Controller.must_authorized(private=True, private_key='partner_id')
+ def get_partner_stock_picking(self, **kw):
+ get_params = self.get_request_params(kw, {
+ 'partner_id': ['number'],
+ 'q': [],
+ 'limit': ['default:0', 'number'],
+ 'offset': ['default:0', 'number']
+ })
+
+ if not get_params['valid']:
+ return self.response(code=400, description=get_params)
+
+ params = get_params['value']
+ partner_id = params['partner_id']
+ limit = params['limit']
+ offset = params['offset']
+
+ child_ids = request.env['res.partner'].browse(partner_id).get_child_ids()
+
+ picking_model = request.env['stock.picking']
+ default_domain = [('partner_id', 'in', child_ids), ('sale_id', '!=', False), ('origin', 'ilike', 'SO%'), ('state', '!=', 'cancel')]
+
+ domain = default_domain
+ if params['q']:
+ query_like = '%' + params['q'].replace(' ', '%') + '%'
+ domain += ['|', '|', ('name', 'ilike', query_like), ('sale_id.client_order_ref', 'ilike', query_like), ('delivery_tracking_no', 'ilike', query_like)]
+
+ stock_pickings = picking_model.search(domain, offset=offset, limit=limit, order='create_date desc')
+ res_pickings = []
+ for picking in stock_pickings:
+ manifests = picking.get_manifests()
+ res_pickings.append({
+ 'id': picking.id,
+ 'name': picking.name,
+ 'date': self.time_to_str(picking.create_date, '%d/%m/%Y'),
+ 'tracking_number': picking.delivery_tracking_no or '',
+ 'sale_order': {
+ 'id': picking.sale_id.id,
+ 'name': picking.sale_id.name,
+ 'client_order_ref': picking.sale_id.client_order_ref or ''
+ },
+ 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False,
+ 'carrier_name': picking.carrier_id.name or '',
+ 'last_manifest': next(iter(manifests), None)
+ })
+
+ pending_count = picking_model.search_count(default_domain + [('driver_departure_date', '=', False), ('driver_arrival_date', '=', False)])
+ shipment_count = picking_model.search_count(default_domain + [('driver_departure_date', '!=', False), ('driver_arrival_date', '=', False)])
+ completed_count = picking_model.search_count(default_domain + [('driver_departure_date', '!=', False), ('driver_arrival_date', '!=', False)])
+
+ return self.response({
+ 'summary': {
+ 'pending_count': pending_count,
+ 'shipment_count': shipment_count,
+ 'completed_count': completed_count
+ },
+ 'picking_total': picking_model.search_count(default_domain),
+ 'pickings': res_pickings
+ })
+
+ @http.route(PREFIX_PARTNER + 'stock-picking/<id>/tracking', auth='public', method=['GET', 'OPTIONS'])
+ @controller.Controller.must_authorized(private=True, private_key='partner_id')
+ def get_partner_stock_picking_detail_tracking(self, **kw):
+ id = int(kw.get('id', 0))
+ picking_model = request.env['stock.picking']
+
+ picking = picking_model.browse(id)
+ if not picking:
+ return self.response(None)
+
+ return self.response(picking.get_tracking_detail())
diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py
index 9661a0ba..85bf5015 100644
--- a/indoteknik_api/models/sale_order.py
+++ b/indoteknik_api/models/sale_order.py
@@ -18,7 +18,15 @@ class SaleOrder(models.Model):
'invoice_count': sale_order.invoice_count,
'status': 'draft',
'date_order': self.env['rest.api'].datetime_to_str(sale_order.date_order, '%d/%m/%Y %H:%M:%S'),
+ 'pickings': []
}
+ for picking in sale_order.picking_ids:
+ data['pickings'].append({
+ 'id': picking.id,
+ 'name': picking.name,
+ 'tracking_number': picking.delivery_tracking_no or '',
+ 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False,
+ })
if sale_order.state == 'cancel':
data['status'] = 'cancel'
if sale_order.state in ['draft', 'sent']:
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 0d38a7d7..e1be8910 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -93,6 +93,9 @@
'views/price_group.xml',
'views/mrp_production.xml',
'views/apache_solr_queue.xml',
+ 'views/cost_centre.xml',
+ 'views/account_account_views.xml',
+ 'views/account_move_line.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 55d1807c..ee5a3a87 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -86,3 +86,6 @@ from . import base_import_import
from . import product_attribute
from . import mrp_production
from . import solr
+from . import cost_centre
+from . import account_account
+from . import account_move_line
diff --git a/indoteknik_custom/models/account_account.py b/indoteknik_custom/models/account_account.py
new file mode 100644
index 00000000..d8ac3204
--- /dev/null
+++ b/indoteknik_custom/models/account_account.py
@@ -0,0 +1,8 @@
+from odoo import fields, models, api, _
+
+class AccountAccount(models.Model):
+ _inherit = 'account.account'
+
+ cost_centre_id = fields.Many2one('cost.centre', string='Cost Centre')
+ analytic_tag_ids = fields.Many2many("account.analytic.tag",
+ string="Analytic Tags") \ No newline at end of file
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 9e7266b1..18025b32 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -20,6 +20,8 @@ class AccountMove(models.Model):
due_extension = fields.Integer(string='Due Extension', default=0)
new_due_date = fields.Date(string='New Due')
counter = fields.Integer(string="Counter", default=0)
+ cost_centre_id = fields.Many2one('cost.centre', string='Cost Centre')
+ analytic_account_ids = fields.Many2many('account.analytic.account', string='Analytic Account')
due_line = fields.One2many('due.extension.line', 'invoice_id', compute='_compute_due_line', string='Due Extension Lines')
def _compute_due_line(self):
diff --git a/indoteknik_custom/models/account_move_line.py b/indoteknik_custom/models/account_move_line.py
new file mode 100644
index 00000000..a4b25109
--- /dev/null
+++ b/indoteknik_custom/models/account_move_line.py
@@ -0,0 +1,24 @@
+from odoo import models, api, fields
+
+
+class AccountMoveLine(models.Model):
+ _inherit = "account.move.line"
+
+ cost_centre_id = fields.Many2one('cost.centre', string='Cost Centre')
+ is_required = fields.Boolean(string='Is Required', compute='_compute_is_required')
+ analytic_account_ids = fields.Many2many('account.analytic.account', string='Analytic Account')
+
+ @api.onchange('account_id')
+ def _onchange_account_id(self):
+ for account in self:
+ analytic_account = account.account_id.analytic_tag_ids
+ account.analytic_tag_ids = analytic_account
+
+ @api.onchange('account_id')
+ def _compute_is_required(self):
+ for account in self:
+ if account.account_id.code and account.account_id.code[0] in ['6', '7']:
+ account.is_required = True
+ else:
+ account.is_required = False
+
diff --git a/indoteknik_custom/models/cost_centre.py b/indoteknik_custom/models/cost_centre.py
new file mode 100644
index 00000000..eaf518d5
--- /dev/null
+++ b/indoteknik_custom/models/cost_centre.py
@@ -0,0 +1,11 @@
+from odoo import fields, models, api
+from datetime import datetime, timedelta
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class CostCentre(models.Model):
+ _name = 'cost.centre'
+ name = fields.Char(string="Name")
+ description = fields.Text(string="Description")
diff --git a/indoteknik_custom/models/product_pricelist.py b/indoteknik_custom/models/product_pricelist.py
index b0adcef7..026977f8 100644
--- a/indoteknik_custom/models/product_pricelist.py
+++ b/indoteknik_custom/models/product_pricelist.py
@@ -41,12 +41,4 @@ class ProductPricelistItem(models.Model):
manufacture_id = fields.Many2one('x_manufactures', string='Manufacture')
- def action_sync_to_solr(self):
- active_ids = self.env.context.get('active_ids', [])
-
- for pricelist_item_id in active_ids:
- pricelist = self.env['product.pricelist.item'].browse(pricelist_item_id)
-
- templates = self.env['product.template'].search([('id', 'in', [pricelist.product_id.product_tmpl_id.id])])
-
- templates._create_solr_queue('_sync_product_template_to_solr')
+ \ No newline at end of file
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 019d229c..8daa0b7a 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -51,7 +51,40 @@ class ProductTemplate(models.Model):
is_new_product = fields.Boolean(string='Produk Baru',
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')
+ @api.constrains('name', 'default_code')
+ def _check_duplicate_product(self):
+ for product in self:
+ if not self.env.user.is_purchasing_manager:
+ domain = [('default_code', '!=', False)]
+
+ 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.append(('id', '!=', product.id))
+
+ if product.write_date == product.create_date:
+ message = "SKU atau Name yang Anda gunakan sudah digunakan di produk lain"
+ else:
+ 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/%-]+$'
@@ -289,6 +322,35 @@ class ProductProduct(models.Model):
qty_onhand_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_onhand_bandengan')
qty_incoming_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_incoming_bandengan')
sla_version = fields.Integer(string="SLA Version", default=0)
+ is_edited = fields.Boolean(string='Is Edited')
+
+ @api.constrains('name','default_code')
+ def _check_duplicate_product(self):
+ if not self.env.user.is_purchasing_manager:
+ for product in self:
+ 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)
+ else:
+ domain = [
+ ('id', '=', product.id),
+ ('is_edited', '=', True),
+ ]
+ 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):
diff --git a/indoteknik_custom/models/purchase_pricelist.py b/indoteknik_custom/models/purchase_pricelist.py
index 419ca8e0..6a8a4650 100755
--- a/indoteknik_custom/models/purchase_pricelist.py
+++ b/indoteknik_custom/models/purchase_pricelist.py
@@ -27,3 +27,18 @@ class PurchasePricelist(models.Model):
self.system_last_update = current_time
else:
self.human_last_update = current_time
+
+ @api.constrains('vendor_id', 'product_id','human_last_update','write_date')
+ def _check_duplicate_purchase_pricelist(self):
+ for price in self:
+ domain = [
+ ('product_id', '=', price.product_id.id),
+ ('vendor_id', '=', price.vendor_id.id)
+ ]
+
+ domain.append(('id', '!=', price.id))
+ massage="Product dan vendor yang anda gunakan sudah ada di purchase pricelist"
+ existing_purchase = self.search(domain, limit=1)
+ if existing_purchase:
+ raise UserError(massage)
+ \ No newline at end of file
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index f8c97258..85ef3ad8 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -77,6 +77,7 @@ class SaleOrder(models.Model):
applied_voucher_id = fields.Many2one(comodel_name='voucher', string='Applied Voucher', copy=False)
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)
def _compute_purchase_total(self):
for order in self:
diff --git a/indoteknik_custom/models/solr/product_pricelist_item.py b/indoteknik_custom/models/solr/product_pricelist_item.py
index 6ab2f588..3be8c4c0 100644
--- a/indoteknik_custom/models/solr/product_pricelist_item.py
+++ b/indoteknik_custom/models/solr/product_pricelist_item.py
@@ -6,25 +6,15 @@ class ProductPricelistItem(models.Model):
@api.constrains('applied_on', 'product_id', 'base', 'base_pricelist_id', 'price_discount')
def _constrains_related_solr_field(self):
- self.update_template_solr()
- self.update_variant_solr()
+ for rec in self:
+ rec.product_id.product_tmpl_id._create_solr_queue('_sync_price_to_solr')
- def update_template_solr(self):
- updated_template_ids = []
- for rec in self:
- template = rec.product_id.product_tmpl_id
- if template.id in updated_template_ids:
- continue
-
- template._sync_price_to_solr()
- updated_template_ids.append(template.id)
-
- def update_variant_solr(self):
- updated_product_ids = []
- for rec in self:
- product = rec.product_id
- if product.id in updated_product_ids:
- continue
-
- product._sync_price_to_solr()
- updated_product_ids.append(product.id) \ No newline at end of file
+ def action_sync_to_solr(self):
+ active_ids = self.env.context.get('active_ids', [])
+
+ for pricelist_item_id in active_ids:
+ pricelist = self.env['product.pricelist.item'].browse(pricelist_item_id)
+
+ templates = self.env['product.template'].search([('id', 'in', [pricelist.product_id.product_tmpl_id.id])])
+
+ templates._create_solr_queue('_sync_price_to_solr')
diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py
index 6ae0bec2..9950c93a 100644
--- a/indoteknik_custom/models/solr/product_template.py
+++ b/indoteknik_custom/models/solr/product_template.py
@@ -104,32 +104,25 @@ class ProductTemplate(models.Model):
solr = self.solr()
for template in self:
- price_excl_after_disc = price_excl = discount = tax = 0
- flashsale_data = tier1 = tier2 = tier3 = {}
-
+ document = solr_model.get_doc('product', template.id)
+ flashsale_data = {}
+
for variant in template.product_variant_ids:
- if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc:
- price_excl = variant._get_website_price_exclude_tax()
- price_excl_after_disc = variant._get_website_price_after_disc_and_tax()
- discount = variant._get_website_disc(0)
- tax = variant._get_website_tax()
- flashsale_data = variant._get_flashsale_price()
- # add price tiering for base price, discount, and price after discount (tier 1 - 3)
- tier1 = variant._get_pricelist_tier1()
- tier2 = variant._get_pricelist_tier2()
- tier3 = variant._get_pricelist_tier3()
-
- if template.product_variant_count == 1:
- price_excl = template.product_variant_id._get_website_price_exclude_tax()
- discount = template.product_variant_id._get_website_disc(0)
- price_excl_after_disc = template.product_variant_id._get_website_price_after_disc_and_tax()
- tax = template.product_variant_id._get_website_tax()
- flashsale_data = template.product_variant_id._get_flashsale_price()
- tier1 = template.product_variant_id._get_pricelist_tier1()
- tier2 = template.product_variant_id._get_pricelist_tier2()
- tier3 = template.product_variant_id._get_pricelist_tier3()
+ variant_flashsale = variant._get_flashsale_price()
+ variant_flashsale_price = variant_flashsale.get('flashsale_price', 0)
+ flashsale_data_price = flashsale_data.get('flashsale_price', 0)
+
+ if flashsale_data_price == 0 or (variant_flashsale_price != 0 and variant_flashsale_price < flashsale_data_price):
+ flashsale_data = variant_flashsale
+
+ 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()
+ tier1 = variant._get_pricelist_tier1()
+ tier2 = variant._get_pricelist_tier2()
+ tier3 = variant._get_pricelist_tier3()
- document = solr_model.get_doc('product', template.id)
document.update({
'id': template.id,
'flashsale_id_i': flashsale_data.get('flashsale_id', 0),
@@ -151,6 +144,7 @@ class ProductTemplate(models.Model):
'has_price_info_b': True
})
self.solr().add([document])
+ 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'):
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 1ffb9aef..8e8c1e79 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -2,6 +2,7 @@ from odoo import fields, models, api, _
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.tools.float_utils import float_is_zero
from itertools import groupby
+import pytz, datetime
class StockPicking(models.Model):
@@ -354,3 +355,103 @@ class StockPicking(models.Model):
picking.delivery_status = "Diterima Ekspedisi"
else:
picking.delivery_status = "Diterima Konsumen"
+
+ def create_manifest_data(self, description, object):
+ datetime_str = ''
+ if isinstance(object, datetime.datetime):
+ jakarta_timezone = pytz.timezone('Asia/Jakarta')
+ datetime_str = object.replace(tzinfo=pytz.utc).astimezone(jakarta_timezone).strftime('%Y-%m-%d %H:%M:%S')
+ return {
+ 'description': description,
+ 'datetime': datetime_str
+ }
+
+ def get_manifests(self):
+ if self.waybill_id and len(self.waybill_id.manifest_ids) > 0:
+ return [self.create_manifest_data(x.description, x.datetime) for x in self.waybill_id.manifest_ids]
+
+ status_mapping = {
+ 'pickup': {
+ 'arrival': 'Sudah diambil',
+ 'departure': 'Siap diambil',
+ 'prepare': 'Sedang disiapkan'
+ },
+ 'delivery': {
+ 'arrival': 'Sudah sampai',
+ 'departure': 'Sedang dikirim',
+ 'prepare': 'Menunggu pickup',
+ }
+ }
+
+ status_key = 'delivery'
+ if self.carrier_id.id == 32:
+ status_key = 'pickup'
+
+ manifest_datas = []
+ departure_date = self.driver_departure_date
+ arrival_date = self.driver_arrival_date
+ status = status_mapping.get(status_key)
+
+ if not status:
+ return manifest_datas
+
+ if arrival_date:
+ manifest_datas.append(self.create_manifest_data(status['arrival'], arrival_date))
+ if departure_date:
+ manifest_datas.append(self.create_manifest_data(status['departure'], departure_date))
+ manifest_datas.append(self.create_manifest_data(status['prepare'], self.create_date))
+
+ return manifest_datas
+
+ def get_tracking_detail(self):
+ self.ensure_one()
+
+ response = {
+ 'delivery_order': {
+ 'name': self.name,
+ 'carrier': self.carrier_id.name or '',
+ 'receiver_name': '',
+ 'receiver_city': ''
+ },
+ 'delivered': False,
+ 'waybill_number': self.delivery_tracking_no or '',
+ 'delivery_status': None,
+ 'eta': self.generate_eta_delivery(),
+ 'manifests': self.get_manifests()
+ }
+
+ if not self.waybill_id or len(self.waybill_id.manifest_ids) == 0:
+ response['delivered'] = self.driver_arrival_date != False
+ return response
+
+ response['delivery_order']['receiver_name'] = self.waybill_id.receiver_name
+ response['delivery_order']['receiver_city'] = self.waybill_id.receiver_city
+ response['delivery_status'] = self.waybill_id._get_history('delivery_status')
+ response['delivered'] = self.waybill_id.delivered
+
+ return response
+
+ 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
+
+ longest_days = 3
+ longest_eta = fastest_eta + datetime.timedelta(days=longest_days)
+
+ format_time = '%d %b %Y'
+ format_time_fastest = '%d %b' if fastest_eta.year == longest_eta.year else format_time
+
+ formatted_fastest_eta = fastest_eta.strftime(format_time_fastest)
+ formatted_longest_eta = longest_eta.strftime(format_time)
+
+ return f'{formatted_fastest_eta} - {formatted_longest_eta}'
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 67ab4de5..0e4fda51 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -72,3 +72,4 @@ access_po_sync_price,access.po.sync.price,model_po_sync_price,,1,1,1,1
access_product_attribute_value,access.product.attribute.value,model_product_attribute_value,,1,1,1,1
access_mrp_production,access.mrp.production,model_mrp_production,,1,1,1,1
access_apache_solr_queue,access.apache.solr.queue,model_apache_solr_queue,,1,1,1,1
+access_cost_centre,access.cost.centre,model_cost_centre,,1,1,1,1
diff --git a/indoteknik_custom/views/account_account_views.xml b/indoteknik_custom/views/account_account_views.xml
new file mode 100644
index 00000000..875d5a6b
--- /dev/null
+++ b/indoteknik_custom/views/account_account_views.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="account_account_view_inherit" model="ir.ui.view">
+ <field name="name">account.account.list</field>
+ <field name="model">account.account</field>
+ <field name="inherit_id" ref="account.view_account_list"/>
+ <field name="arch" type="xml">
+ <field name="currency_id" position="after">
+ <field name="analytic_tag_ids" optional="show" widget="many2many_tags"/>
+ </field>
+ </field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/account_move_line.xml b/indoteknik_custom/views/account_move_line.xml
new file mode 100644
index 00000000..5b5f73cd
--- /dev/null
+++ b/indoteknik_custom/views/account_move_line.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="view_move_form_inherit" model="ir.ui.view">
+ <field name="name">account.move.form.inherit</field>
+ <field name="model">account.move</field>
+ <field name="inherit_id" ref="account.view_move_form"/>
+ <field name="arch" type="xml">
+ <xpath expr="//page[@id='aml_tab']/field[@name='line_ids']/tree/field[@name='currency_id']" position="before">
+ <field name="is_required" invisible="1"/>
+ </xpath>
+ <xpath expr="//page[@id='aml_tab']/field[@name='line_ids']/tree/field[@name='analytic_tag_ids']" position="attributes">
+ <attribute name="groups"/>
+ </xpath>
+ </field>
+ </record>
+ </data>
+</odoo>
diff --git a/indoteknik_custom/views/cost_centre.xml b/indoteknik_custom/views/cost_centre.xml
new file mode 100644
index 00000000..3e4d2736
--- /dev/null
+++ b/indoteknik_custom/views/cost_centre.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <record id="cost_centre_tree" model="ir.ui.view">
+ <field name="name">cost.centre.tree</field>
+ <field name="model">cost.centre</field>
+ <field name="arch" type="xml">
+ <tree editable="top">
+ <field name="name"/>
+ <field name="description"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="cost_centre_form" model="ir.ui.view">
+ <field name="name">cost.centre.form</field>
+ <field name="model">cost.centre</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet string="Cost Centre">
+ <group>
+ <group>
+ <field name="name" required="1"/>
+ <field name="description"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="cost_centre_action" model="ir.actions.act_window">
+ <field name="name">Cost Centre</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">cost.centre</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem name="Cost Centre" action="cost_centre_action"
+ id="menu_cost_centre"
+ parent="account.menu_finance_entries" sequence="112"/>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index bbfc9e3b..d37b5d1e 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -108,6 +108,7 @@
</field>
<field name="effective_date" position="after">
<field name="carrier_id"/>
+ <field name="estimated_arrival_days"/>
</field>
<page name="customer_signature" position="after">