summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIndoteknik . <it@fixcomart.co.id>2025-07-31 09:51:55 +0700
committerIndoteknik . <it@fixcomart.co.id>2025-07-31 09:51:55 +0700
commit145d15ceaf462f0b3533c441287a66410b7d12e6 (patch)
tree136490542c166282883533d59427a3afed094b0d
parent60b037c72887d20e8cebd7f4a2439c546d16960b (diff)
parentd6bdde8fe63ff15ce8f3fee6bc5e8ae903fc78ce (diff)
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into reminder-tempo-v2
-rwxr-xr-xindoteknik_custom/models/purchase_order.py146
-rwxr-xr-xindoteknik_custom/models/sale_order.py7
-rw-r--r--indoteknik_custom/models/stock_picking.py10
-rw-r--r--indoteknik_custom/models/tukar_guling.py87
-rw-r--r--indoteknik_custom/models/tukar_guling_po.py43
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv1
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml43
-rwxr-xr-xindoteknik_custom/views/sale_order.xml1
-rw-r--r--indoteknik_custom/views/stock_picking.xml4
-rw-r--r--indoteknik_custom/views/tukar_guling.xml5
-rw-r--r--indoteknik_custom/views/tukar_guling_po.xml3
11 files changed, 298 insertions, 52 deletions
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 45134939..27aca0d1 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -92,6 +92,11 @@ class PurchaseOrder(models.Model):
is_cab_visible = fields.Boolean(string='Tampilkan Tombol CAB', compute='_compute_is_cab_visible')
+ reason_change_date_planned = fields.Selection([
+ ('delay', 'Delay By Vendor'),
+ ('urgent', 'Urgent Delivery'),
+ ], string='Reason Change Date Planned', tracking=True)
+
# picking_ids = fields.One2many('stock.picking', 'purchase_id', string='Pickings')
bu_related_count = fields.Integer(
@@ -100,9 +105,68 @@ class PurchaseOrder(models.Model):
)
manufacturing_id = fields.Many2one('mrp.production', string='Manufacturing Orders')
+ complete_bu_in_count = fields.Integer(
+ string="Complete BU In Count",
+ compute='_compute_complete_bu_in_count'
+ )
+
+ def _compute_complete_bu_in_count(self):
+ for order in self:
+ if order.state not in ['done', 'cancel']:
+ order.complete_bu_in_count = 1
+ else:
+ relevant_pickings = order.picking_ids.filtered(
+ lambda p: p.state != 'done'
+ and p.state != 'cancel'
+ and p.picking_type_code == 'incoming'
+ and p.origin == order.name
+ and p.name.startswith('BU/IN')
+ )
+ order.complete_bu_in_count = len(relevant_pickings)
+
def _has_vcm(self):
if self.id:
self.vcm_id = self.env['tukar.guling.po'].search([('origin', '=', self.name)], limit=1)
+
+ @api.depends('order_line.date_planned')
+ def _compute_date_planned(self):
+ """ date_planned = the earliest date_planned across all order lines. """
+ for order in self:
+ order.date_planned = False
+
+ @api.constrains('date_planned')
+ def constrains_date_planned(self):
+ for rec in self:
+ if not self.env.user.has_group('indoteknik_custom.group_role_purchasing'):
+ raise ValidationError("Hanya dapat diisi oleh Purchasing")
+
+ base_bu = self.env['stock.picking'].search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'ilike', rec.name),
+ ('group_id', '=', rec.group_id.id),
+ ('state', 'not in', ['cancel','done'])
+ ])
+
+ for bu in base_bu:
+ bu.write({
+ 'scheduled_date': rec.date_planned,
+ 'reason_change_date_planned': rec.reason_change_date_planned
+ })
+
+ rec.sync_date_planned_to_so()
+
+ def sync_date_planned_to_so(self):
+ for line in self.order_sales_match_line:
+ other_sales_match = self.env['purchase.order.sales.match'].search([
+ # ('product_id', '=', line.product_id.id),
+ ('sale_id', '=', line.sale_id.id),
+ # ('sale_line_id', '=', line.sale_line_id.id)
+ ])
+
+ dates = [d for d in other_sales_match.mapped('purchase_order_id.date_planned') if d]
+ if dates:
+ date_planned = max(dates)
+ line.sale_id.write({'et_products': date_planned, 'reason_change_date_planned': line.purchase_order_id.reason_change_date_planned})
@api.depends('name')
def _compute_bu_related_count(self):
@@ -677,13 +741,6 @@ class PurchaseOrder(models.Model):
for order in self:
order.has_active_invoice = any(invoice.state != 'cancel' for invoice in order.invoice_ids)
- # def _compute_has_active_invoice(self):
- # for order in self:
- # related_invoices = order.invoice_ids.filtered(
- # lambda inv: inv.purchase_order_id.id == order.id and inv.move_type == 'in_invoice' and inv.state != 'cancel'
- # )
- # order.has_active_invoice = bool(related_invoices)
-
def add_product_to_pricelist(self):
i = 0
for line in self.order_line:
@@ -766,16 +823,16 @@ class PurchaseOrder(models.Model):
"""
purchase_pricelist.message_post(body=message, subtype_id=self.env.ref("mail.mt_note").id)
- def _compute_date_planned(self):
- for order in self:
- if order.date_approve:
- leadtime = order.partner_id.leadtime
- current_time = order.date_approve
- delta_time = current_time + timedelta(days=leadtime)
- delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
- order.date_planned = delta_time
- else:
- order.date_planned = False
+ # def _compute_date_planned(self):
+ # for order in self:
+ # if order.date_approve:
+ # leadtime = order.partner_id.leadtime
+ # current_time = order.date_approve
+ # delta_time = current_time + timedelta(days=leadtime)
+ # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
+ # order.date_planned = delta_time
+ # else:
+ # order.date_planned = False
def action_create_invoice(self):
res = super(PurchaseOrder, self).action_create_invoice()
@@ -959,6 +1016,9 @@ class PurchaseOrder(models.Model):
if self.amount_untaxed >= 50000000 and not self.env.user.id == 21:
raise UserError("Hanya Rafly Hanggara yang bisa approve")
+
+ if not self.date_planned:
+ raise UserError("Receipt Date harus diisi")
if self.total_percent_margin < self.total_so_percent_margin:
self.env.user.notify_danger(
@@ -975,7 +1035,7 @@ class PurchaseOrder(models.Model):
# )
if not self.from_apo:
- if (not self.matches_so or not self.sale_order_id) and not self.env.user.is_purchasing_manager and not self.env.user.is_leader and not self.manufacturing_id:
+ if not self.matches_so and not self.env.user.is_purchasing_manager and not self.env.user.is_leader:
raise UserError("Tidak ada link dengan SO, harus di confirm oleh Purchasing Manager")
send_email = False
@@ -1010,10 +1070,10 @@ class PurchaseOrder(models.Model):
self.approve_by = self.env.user.id
# override date planned added with two days
- leadtime = self.partner_id.leadtime
- delta_time = current_time + timedelta(days=leadtime)
- delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
- self.date_planned = delta_time
+ # leadtime = self.partner_id.leadtime
+ # delta_time = current_time + timedelta(days=leadtime)
+ # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S')
+ # self.date_planned = delta_time
self.date_deadline_ref_date_planned()
self.unlink_purchasing_job_state()
@@ -1391,6 +1451,20 @@ class PurchaseOrder(models.Model):
# Tambahkan pemanggilan method untuk handle pricelist system update
self._handle_pricelist_system_update(vals)
return res
+
+ def action_open_change_date_wizard(self):
+ self.ensure_one()
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'change.date.planned.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {
+ 'default_purchase_id': self.id,
+ 'default_new_date_planned': self.date_planned,
+ }
+ }
+
def _handle_pricelist_system_update(self, vals):
if 'order_line' in vals or any(key in vals for key in ['state', 'approval_status']):
@@ -1479,4 +1553,32 @@ class PurchaseOrderUnlockWizard(models.TransientModel):
order.approval_status_unlock = 'pengajuanFinance'
return {'type': 'ir.actions.act_window_close'}
+class ChangeDatePlannedWizard(models.TransientModel):
+ _name = 'change.date.planned.wizard'
+ _description = 'Change Date Planned Wizard'
+
+ purchase_id = fields.Many2one('purchase.order', string="Purchase Order", required=True)
+ new_date_planned = fields.Datetime(string="New Date Planned") # <- harus DTTM biar match
+ old_date_planned = fields.Datetime(string="Current Planned Date", related='purchase_id.date_planned', readonly=True)
+ reason = fields.Selection([
+ ('delay', 'Delay By Vendor'),
+ ('urgent', 'Urgent Delivery'),
+ ], string='Reason')
+ date_changed = fields.Boolean(string="Date Changed", compute="_compute_date_changed")
+
+ @api.depends('old_date_planned', 'new_date_planned')
+ def _compute_date_changed(self):
+ for rec in self:
+ rec.date_changed = (
+ rec.old_date_planned and rec.new_date_planned and
+ rec.old_date_planned != rec.new_date_planned
+ )
+
+ def confirm_change(self):
+ self.purchase_id.write({
+ 'date_planned': self.new_date_planned,
+ 'reason_change_date_planned': self.reason,
+ })
+
+
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 7be0e8ff..4e36a9fb 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -350,7 +350,7 @@ class SaleOrder(models.Model):
date_unhold = fields.Datetime(string='Date Unhold', tracking=True, readonly=True, help='Waktu ketika SO di Unhold'
)
- et_products = fields.Datetime(string='ET Products', compute='_compute_et_products', help="Leadtime produk berdasarkan SLA vendor, tanpa logistik.")
+ et_products = fields.Datetime(string='ET Products', help="Leadtime produk berdasarkan SLA vendor, tanpa logistik.", tracking=True)
eta_date_reserved = fields.Datetime(
string="Date Reserved",
@@ -381,6 +381,11 @@ class SaleOrder(models.Model):
if self.id:
self.ccm_id = self.env['tukar.guling'].search([('origin', 'ilike', self.name)], limit=1)
+ reason_change_date_planned = fields.Selection([
+ ('delay', 'Delay By Vendor'),
+ ('urgent', 'Urgent Delivery'),
+ ], string='Reason Change Date Planned', tracking=True)
+
@api.depends('order_line.product_id', 'date_order')
def _compute_et_products(self):
jakarta = pytz.timezone("Asia/Jakarta")
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 3e152f10..825368de 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -303,6 +303,10 @@ class StockPicking(models.Model):
approval_invoice_date_id = fields.Many2one('approval.invoice.date', string='Approval Invoice Date')
last_update_date_doc_kirim = fields.Datetime(string='Last Update Tanggal Kirim', copy=False)
update_date_doc_kirim_add = fields.Boolean(string='Update Tanggal Kirim Lewat ADD')
+ reason_change_date_planned = fields.Selection([
+ ('delay', 'Delay By Vendor'),
+ ('urgent', 'Urgent Delivery'),
+ ], string='Reason Change Date Planned', tracking=True)
def _get_kgx_awb_number(self):
"""Menggabungkan name dan origin untuk membuat AWB Number"""
@@ -1380,6 +1384,12 @@ class StockPicking(models.Model):
self.send_mail_bills()
if 'BU/PUT' in self.name:
self.automatic_reserve_product()
+
+ if self.tukar_guling_id:
+ self.tukar_guling_id.update_state()
+ elif self.tukar_guling_po_id:
+ self.tukar_guling_po_id.update_state()
+
return res
def automatic_reserve_product(self):
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py
index 396e4db4..5411b17c 100644
--- a/indoteknik_custom/models/tukar_guling.py
+++ b/indoteknik_custom/models/tukar_guling.py
@@ -5,7 +5,8 @@ from datetime import datetime
_logger = logging.getLogger(__name__)
-#TODO
+
+# TODO
# 1. tracking status dokumen BU [X]
# 2. ganti nama dokumen
# 3. Tracking ketika create dokumen [X]
@@ -20,7 +21,7 @@ class TukarGuling(models.Model):
_order = 'date desc, id desc'
_rec_name = 'name'
_inherit = ['mail.thread', 'mail.activity.mixin']
-
+
partner_id = fields.Many2one('res.partner', string='Customer', readonly=True)
origin = fields.Char(string='Origin SO')
if_so = fields.Boolean('Is SO', default=True)
@@ -62,6 +63,7 @@ class TukarGuling(models.Model):
('approval_sales', ' Approval Sales'),
('approval_finance', 'Approval Finance'),
('approval_logistic', 'Approval Logistic'),
+ ('approved', 'Waiting for Operations'),
('done', 'Done'),
('cancel', 'Canceled')
], default='draft', tracking=True, required=True)
@@ -98,7 +100,7 @@ class TukarGuling(models.Model):
@api.onchange('operations')
def _onchange_operations(self):
"""Auto-populate lines ketika operations dipilih"""
- if self.operations.picking_type_id.id not in [29,30]:
+ if self.operations.picking_type_id.id not in [29, 30]:
raise UserError("❌ Picking type harus BU/OUT atau BU/PICK")
for rec in self:
if rec.operations and rec.operations.picking_type_id.id == 30:
@@ -217,7 +219,6 @@ class TukarGuling(models.Model):
self.origin = False
-
def action_populate_lines(self):
"""Manual button untuk populate lines - sebagai alternatif"""
self.ensure_one()
@@ -257,7 +258,7 @@ class TukarGuling(models.Model):
def _check_product_lines(self):
"""Constraint: Product lines harus ada jika state bukan draft"""
for record in self:
- if record.state in ('approval_sales', 'approval_logistic', 'approval_finance',
+ if record.state in ('approval_sales', 'approval_logistic', 'approval_finance', 'approved',
'done') and not record.line_ids:
raise ValidationError("Product lines harus diisi sebelum submit atau approve!")
@@ -345,7 +346,7 @@ class TukarGuling(models.Model):
def write(self, vals):
self.ensure_one()
- if self.operations.picking_type_id.id not in [29,30]:
+ if self.operations.picking_type_id.id not in [29, 30]:
raise UserError("❌ Picking type harus BU/OUT atau BU/PICK")
self._check_invoice_on_revisi_so()
operasi = self.operations.picking_type_id.id
@@ -376,10 +377,10 @@ class TukarGuling(models.Model):
# if self.state == 'done':
# raise UserError ("Tidak Boleh delete ketika sudahh done")
for record in self:
- if record.state == 'done':
+ if record.state == 'approved' or record.state == 'done':
raise UserError(
- "Tidak bisa hapus pengajuan jika sudah done, set ke draft terlebih dahulu jika ingin menghapus")
- ongoing_bu = self.picking_ids.filtered(lambda p: p.state != 'done')
+ "Tidak bisa hapus pengajuan jika sudah Approved, set ke draft terlebih dahulu jika ingin menghapus")
+ ongoing_bu = self.picking_ids.filtered(lambda p: p.state != 'approved')
for picking in ongoing_bu:
picking.action_cancel()
return super(TukarGuling, self).unlink()
@@ -461,6 +462,47 @@ class TukarGuling(models.Model):
raise UserError("Submit hanya bisa dilakukan dari Draft.")
self.state = 'approval_sales'
+ def update_state(self):
+ # OUT tukar guling
+ if self.operations.picking_type_id.id == 29 and self.return_type == 'tukar_guling':
+ total_out = self.env['stock.picking'].search_count([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 29),
+ ])
+ done_out = self.env['stock.picking'].search_count([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 29),
+ ('state', '=', 'done'),
+ ])
+ if self.state == 'approved' and total_out > 0 and done_out == total_out:
+ self.state = 'done'
+
+ # OUT revisi SO
+ elif self.operations.picking_type_id.id == 29 and self.return_type == 'revisi_so':
+ total_ort = self.env['stock.picking'].search_count([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 74),
+ ])
+ done_ort = self.env['stock.picking'].search_count([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 74),
+ ('state', '=', 'done'),
+ ])
+ if self.state == 'approved' and total_ort > 0 and done_ort == total_ort:
+ self.state = 'done'
+
+ # PICK revisi SO
+ elif self.operations.picking_type_id.id == 30 and self.return_type == 'revisi_so':
+ done_ort = self.env['stock.picking'].search([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 74),
+ ('state', '=', 'done'),
+ ])
+ if self.state == 'approved' and done_ort:
+ self.state = 'done'
+ else:
+ raise UserError("Tidak bisa menentukan jenis retur.")
+
def action_approve(self):
self.ensure_one()
self._validate_product_lines()
@@ -510,7 +552,7 @@ class TukarGuling(models.Model):
elif rec.state == 'approval_logistic':
if not rec.env.user.has_group('indoteknik_custom.group_role_logistic'):
raise UserError("Hanya Logistic Manager yang boleh approve tahap ini.")
- rec.state = 'done'
+ rec.state = 'approved'
rec._create_pickings()
rec.date_logistic = now
@@ -606,7 +648,8 @@ class TukarGuling(models.Model):
### ======== ORT dari BU/PICK =========
ort_pickings = []
is_retur_from_bu_pick = record.operations.picking_type_id.id == 30
- picks_to_return = [record.operations] if is_retur_from_bu_pick else mapping_koli.mapped('pick_id') or line.product_uom_qty
+ picks_to_return = [record.operations] if is_retur_from_bu_pick else mapping_koli.mapped(
+ 'pick_id') or line.product_uom_qty
for pick in picks_to_return:
ort_return_lines = []
@@ -622,7 +665,8 @@ class TukarGuling(models.Model):
'quantity': line.product_uom_qty,
'move_id': move.id,
}))
- _logger.info(f"📟 ORT (BU/PICK langsung) | {pick.name} | {line.product_id.display_name} | qty={line.product_uom_qty}")
+ _logger.info(
+ f"📟 ORT (BU/PICK langsung) | {pick.name} | {line.product_id.display_name} | qty={line.product_uom_qty}")
else:
# Ambil dari mapping koli
for mk in mapping_koli.filtered(lambda m: m.pick_id == pick):
@@ -635,7 +679,8 @@ class TukarGuling(models.Model):
'quantity': mk.qty_return,
'move_id': move.id,
}))
- _logger.info(f"📟 ORT (mapping koli) | {pick.name} | {mk.product_id.display_name} | qty={mk.qty_return}")
+ _logger.info(
+ f"📟 ORT (mapping koli) | {pick.name} | {mk.product_id.display_name} | qty={mk.qty_return}")
if ort_return_lines:
ort_wizard = self.env['stock.return.picking'].with_context({
@@ -817,18 +862,17 @@ class StockPicking(models.Model):
message = _(
"📦 <b>%s</b> Validated by <b>%s</b> Status Changed <b>%s</b> at <b>%s</b>."
) % (
- picking.name,
- # picking.picking_type_id.name,
- picking.env.user.name,
- picking.state,
- fields.Datetime.now().strftime("%d/%m/%Y %H:%M")
- )
+ picking.name,
+ # picking.picking_type_id.name,
+ picking.env.user.name,
+ picking.state,
+ fields.Datetime.now().strftime("%d/%m/%Y %H:%M")
+ )
picking.tukar_guling_id.message_post(body=message)
return res
-
class TukarGulingMappingKoli(models.Model):
_name = 'tukar.guling.mapping.koli'
_description = 'Mapping Koli di Tukar Guling'
@@ -839,6 +883,7 @@ class TukarGulingMappingKoli(models.Model):
qty_done = fields.Float(string='Qty Done BU PICK')
qty_return = fields.Float(string='Qty diretur')
sequence = fields.Integer(string='Sequence', default=10)
+
@api.constrains('qty_return')
def _check_qty_return_editable(self):
for rec in self:
@@ -849,4 +894,4 @@ class TukarGulingMappingKoli(models.Model):
for rec in self:
if rec.tukar_guling_id and rec.tukar_guling_id.state not in ['draft', 'cancel']:
raise UserError("Tidak bisa menghapus Mapping Koli karena status Tukar Guling bukan Draft atau Cancel.")
- return super(TukarGulingMappingKoli, self).unlink() \ No newline at end of file
+ return super(TukarGulingMappingKoli, self).unlink()
diff --git a/indoteknik_custom/models/tukar_guling_po.py b/indoteknik_custom/models/tukar_guling_po.py
index 11377bc4..23ca1923 100644
--- a/indoteknik_custom/models/tukar_guling_po.py
+++ b/indoteknik_custom/models/tukar_guling_po.py
@@ -49,6 +49,7 @@ class TukarGulingPO(models.Model):
('approval_purchase', 'Approval Purchasing'),
('approval_finance', 'Approval Finance'),
('approval_logistic', 'Approval Logistic'),
+ ('approved', 'Waiting for Operations'),
('done', 'Done'),
('cancel', 'Cancel'),
], string='Status', default='draft', tracking=3)
@@ -311,7 +312,7 @@ class TukarGulingPO(models.Model):
def unlink(self):
for record in self:
- if record.state == 'done':
+ if record.state == 'done' or record.state == 'approved':
raise UserError("Tidak bisa hapus pengajuan jika sudah done, set ke draft terlebih dahulu")
ongoing_bu = self.po_picking_ids.filtered(lambda p: p.state != 'done')
for picking in ongoing_bu:
@@ -412,12 +413,50 @@ class TukarGulingPO(models.Model):
elif rec.state == 'approval_logistic':
if not rec.env.user.has_group('indoteknik_custom.group_role_logistic'):
raise UserError("Hanya Logistic Manager yang boleh approve tahap ini.")
- rec.state = 'done'
+ rec.state = 'approved'
rec._create_pickings()
rec.date_logistic = now
else:
raise UserError("Status ini tidak bisa di-approve.")
+ def update_stae(self):
+ # bu input rev po
+ if self.operations.picking_type_id.id == 28 and self.return_type == 'revisi_po':
+ prt = self.env['stock.picking'].search([
+ ('tukar_guling_po_id', '=', self.id),
+ ('state', '=', 'done'),
+ ('picking_type_id.id', '=', 76)
+ ])
+ if self.state == 'aproved' and prt:
+ self.state = 'done'
+ # bu put rev po
+ elif self.operations.picking_type_id.id == 75 and self.return_type == 'revisi_po':
+ total_prt = self.env['stock.picking'].search_count([
+ ('tukar_guling_po_id', '=', self.id),
+ ('picking_type_id.id', '=', 76)
+ ])
+ prt = self.env['stock.picking'].search_count([
+ ('tukar_guling_po_id', '=', self.id),
+ ('state', '=', 'done'),
+ ('picking_type_id.id', '=', 76)
+ ])
+ if self.state == 'aproved' and total_prt > 0 and prt == total_prt:
+ self.state = 'done'
+ # bu put tukar guling
+ elif self.operations.picking_type_id.id == 75 and self.return_type == 'tukar_guling':
+ total_put = self.env['stock.picking'].search_count([
+ ('tukar_guling_po_id', '=', self.id),
+ ('picking_type_id.id', '=', 75)
+ ])
+ put = self.env['stock.picking'].search_count([
+ ('tukar_guling_po_id', '=', self.id),
+ ('state', '=', 'done'),
+ ('picking_type_id.id', '=', 75)
+ ])
+ if self.state == 'aproved' and total_put > 0 and put == total_put:
+ self.state = 'done'
+
+
def action_cancel(self):
self.ensure_one()
# if self.state == 'done':
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 015b257c..9b43bf2a 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -161,6 +161,7 @@ access_konfirm_koli,access.konfirm.koli,model_konfirm_koli,,1,1,1,1
access_stock_immediate_transfer,access.stock.immediate.transfer,model_stock_immediate_transfer,,1,1,1,1
access_coretax_faktur,access.coretax.faktur,model_coretax_faktur,,1,1,1,1
access_purchase_order_unlock_wizard,access.purchase.order.unlock.wizard,model_purchase_order_unlock_wizard,,1,1,1,1
+access_change_date_planned_wizard,access.change.date.planned.wizard,model_change_date_planned_wizard,,1,1,1,1
access_sales_order_koli,access.sales.order.koli,model_sales_order_koli,,1,1,1,1
access_stock_backorder_confirmation,access.stock.backorder.confirmation,model_stock_backorder_confirmation,,1,1,1,1
access_warning_modal_wizard,access.warning.modal.wizard,model_warning_modal_wizard,,1,1,1,1
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index ff223125..fedcb4f9 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -75,11 +75,13 @@
</field>
<field name="partner_id" position="after">
<field name="purchase_order_count"/>
+ <field name="complete_bu_in_count" invisible="1"/>
</field>
<field name="incoterm_id" position="after">
<field name="amount_total_without_service"/>
<field name="delivery_amt"/>
<field name="approve_by"/>
+ <field name="reason_change_date_planned"/>
</field>
<field name="currency_id" position="after">
<field name="summary_qty_po"/>
@@ -106,9 +108,16 @@
<field name="product_id" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
</field>
- <field name="date_planned" position="attributes">
- <attribute name="invisible">1</attribute>
- </field>
+ <xpath expr="//field[@name='date_planned']" position="replace">
+ <field name="date_planned" readonly="1"/>
+ </xpath>
+ <xpath expr="//field[@name='date_planned']" position="after">
+ <button name="action_open_change_date_wizard"
+ type="object"
+ string="Change Receipt Date"
+ class="btn-primary"
+ attrs="{'invisible': ['|', ('state', '=', 'cancel'), ('complete_bu_in_count', '=', 0)]}"/>
+ </xpath>
<field name="product_qty" position="before">
<field name="is_edit_product_qty" readonly="1" optional="hide"/>
<field name="qty_onhand" readonly="1" optional="hide"/>
@@ -225,6 +234,34 @@
</data>
<data>
+ <record id="view_change_date_planned_wizard_form" model="ir.ui.view">
+ <field name="name">change.date.planned.wizard.form</field>
+ <field name="model">change.date.planned.wizard</field>
+ <field name="arch" type="xml">
+ <form string="Change Date Planned">
+ <group>
+ <field name="purchase_id" readonly="1"/>
+ <field name="old_date_planned" readonly="1"/>
+ <field name="date_changed" invisible="1"/>
+ <field name="new_date_planned"/>
+ <field name="reason"
+ attrs="{
+ 'invisible': ['|', ('old_date_planned', '=', False), ('date_changed', '=', False)],
+ 'required': [('date_changed', '=', True)]
+ }"/>
+ </group>
+
+ <footer>
+ <button name="confirm_change" type="object" string="Confirm" class="btn-primary"/>
+ <button string="Cancel" class="btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+ </data>
+
+
+ <data>
<record id="rfq_order_tree_view_inherit" model="ir.ui.view">
<field name="name">Purchase</field>
<field name="model">purchase.order</field>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index d75120b7..e8f41ca3 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -172,6 +172,7 @@
<xpath expr="//page[@name='other_information']/group/group[@name='sale_reporting']" position="after">
<group string="ETA">
<field name="et_products"/>
+ <field name="reason_change_date_planned" readonly="1"/>
<field name="eta_date_reserved"/>
<field name="expected_ready_to_ship"/>
<field name="eta_date_start"/>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index f9200dfa..b3f0ce9f 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -129,6 +129,9 @@
<field name="date_done" position="after">
<field name="arrival_time"/>
</field>
+ <field name="scheduled_date" position="attributes">
+ <attribute name="readonly">1</attribute>
+ </field>
<field name="origin" position="after">
<!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>-->
<field name="state_approve_md" widget="badge"/>
@@ -165,6 +168,7 @@
<field name="approval_receipt_status"/>
<field name="approval_return_status"/>
<field name="so_lama"/>
+ <field name="reason_change_date_planned" readonly="1"/>
</field>
<field name="product_id" position="before">
<field name="line_no" attrs="{'readonly': 1}" optional="hide"/>
diff --git a/indoteknik_custom/views/tukar_guling.xml b/indoteknik_custom/views/tukar_guling.xml
index fa3db0d2..c23995d3 100644
--- a/indoteknik_custom/views/tukar_guling.xml
+++ b/indoteknik_custom/views/tukar_guling.xml
@@ -29,6 +29,7 @@
<field name="return_type" string="Return Type"/>
<field name="state" widget="badge"
decoration-info="state in ('draft', 'approval_sales', 'approval_finance','approval_logistic')"
+ decoration-warning="state == 'approved'"
decoration-success="state == 'done'"
decoration-muted="state == 'cancel'"
/>
@@ -58,7 +59,7 @@
class="btn-secondary"
attrs="{'invisible': [('state', '!=', 'cancel')]}"/>
<field name="state" widget="statusbar" readonly="1"
- statusbar_visible="draft,approval_sales,approval_logistic,approval_finance,done"/>
+ statusbar_visible="draft,approval_sales,approval_logistic,approval_finance,approved,done"/>
</header>
<sheet>
<div class="oe_button_box">
@@ -66,7 +67,7 @@
type="object"
class="oe_stat_button"
icon="fa-truck"
- attrs="{'invisible': [('picking_ids', '=', False), ('state', 'in', ['draft', 'approval_sales', 'approval_logistic', 'approval_finance'])]}">
+ attrs="{'invisible': [('picking_ids', '=', False), ('state', 'in', ['draft', 'approval_sales', 'approval_logistic', 'approval_finance', 'approved', 'done', 'cancel'])]}">
<field name="picking_ids" widget="statinfo" string="Delivery"/>
</button>
</div>
diff --git a/indoteknik_custom/views/tukar_guling_po.xml b/indoteknik_custom/views/tukar_guling_po.xml
index 26c0a0d4..accf7dbc 100644
--- a/indoteknik_custom/views/tukar_guling_po.xml
+++ b/indoteknik_custom/views/tukar_guling_po.xml
@@ -29,6 +29,7 @@
<field name="return_type" string="Return Type"/>
<field name="state" widget="badge"
decoration-info="state in ('draft', 'approval_purchase', 'approval_finance','approval_logistic')"
+ decoration-warning="state == 'approved'"
decoration-success="state == 'done'"
decoration-muted="state == 'cancel'"
/>
@@ -60,7 +61,7 @@
attrs="{'invisible': [('state', '!=', 'cancel')]}"
confirm="Are you sure you want to reset this record to draft?"/>
<field name="state" widget="statusbar" readonly="1"
- statusbar_visible="draft,approval_purchase,approval_logistic,approval_finance,done"/>
+ statusbar_visible="draft,approval_purchase,approval_logistic,approval_finance,approved,done"/>
</header>
<sheet>
<div class="oe_button_box">