summaryrefslogtreecommitdiff
path: root/indoteknik_custom/models/purchase_order.py
diff options
context:
space:
mode:
Diffstat (limited to 'indoteknik_custom/models/purchase_order.py')
-rwxr-xr-xindoteknik_custom/models/purchase_order.py168
1 files changed, 152 insertions, 16 deletions
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index cbfd4acd..45134939 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -17,6 +17,7 @@ _logger = logging.getLogger(__name__)
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
+ vcm_id = fields.Many2one('tukar.guling.po', string='Doc VCM', readonly=True, compute='_has_vcm', copy=False)
order_sales_match_line = fields.One2many('purchase.order.sales.match', 'purchase_order_id', string='Sales Match Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True)
sale_order_id = fields.Many2one('sale.order', string='Sale Order')
procurement_status = fields.Char(string='Procurement Status', compute='get_procurement_status', readonly=True)
@@ -65,7 +66,7 @@ class PurchaseOrder(models.Model):
sale_order = fields.Char(string='Sale Order')
matches_so = fields.Many2many('sale.order', string='Matches SO', compute='_compute_matches_so')
is_create_uangmuka = fields.Boolean(string='Uang Muka?')
- move_id = fields.Many2one('account.move', string='Account Move')
+ move_id = fields.Many2one('account.move', string='Journal Entries Uang Muka', domain=[('move_type', '=', 'entry')])
logbook_bill_id = fields.Many2one('report.logbook.bill', string='Logbook Bill')
status_printed = fields.Selection([
('not_printed', 'Belum Print'),
@@ -89,6 +90,112 @@ class PurchaseOrder(models.Model):
store_name = fields.Char(string='Nama Toko')
purchase_order_count = fields.Integer('Purchase Order Count', related='partner_id.purchase_order_count')
+ is_cab_visible = fields.Boolean(string='Tampilkan Tombol CAB', compute='_compute_is_cab_visible')
+
+ # picking_ids = fields.One2many('stock.picking', 'purchase_id', string='Pickings')
+
+ bu_related_count = fields.Integer(
+ string="BU Related Count",
+ compute='_compute_bu_related_count'
+ )
+ manufacturing_id = fields.Many2one('mrp.production', string='Manufacturing Orders')
+
+ def _has_vcm(self):
+ if self.id:
+ self.vcm_id = self.env['tukar.guling.po'].search([('origin', '=', self.name)], limit=1)
+
+ @api.depends('name')
+ def _compute_bu_related_count(self):
+ StockPicking = self.env['stock.picking']
+ for order in self:
+ if not order.name:
+ order.bu_related_count = 0
+ continue
+
+ # Ambil semua BU awal dari PO
+ base_bu = StockPicking.search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'ilike', order.name)
+ ])
+
+ all_bu = base_bu
+ seen_names = set(base_bu.mapped('name'))
+
+ # Loop rekursif untuk mencari seluruh return BU
+ while True:
+ next_bu = StockPicking.search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'in', ['Return of %s' % name for name in seen_names])
+ ])
+ next_names = set(next_bu.mapped('name'))
+
+ if not next_names - seen_names:
+ break
+
+ all_bu |= next_bu
+ seen_names |= next_names
+
+ order.bu_related_count = len(all_bu)
+
+
+ def action_view_related_bu(self):
+ self.ensure_one()
+
+ StockPicking = self.env['stock.picking']
+
+ # Step 1: cari semua BU pertama (PUT, INT) yang berasal dari PO ini
+ base_bu = StockPicking.search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'ilike', self.name)
+ ])
+
+ all_bu = base_bu
+ seen_names = set(base_bu.mapped('name'))
+
+ # Step 2: Loop rekursif cari BU dengan origin 'Return of {name}'
+ while True:
+ next_bu = StockPicking.search([
+ ('name', 'ilike', 'BU/'),
+ ('origin', 'in', ['Return of %s' % name for name in seen_names])
+ ])
+ next_names = set(next_bu.mapped('name'))
+
+ if not next_names - seen_names:
+ break
+
+ all_bu |= next_bu
+ seen_names |= next_names
+
+ return {
+ 'name': 'Related BU (INT/PRT/PUT/VRT)',
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'stock.picking',
+ 'view_mode': 'tree,form',
+ 'target': 'current',
+ 'domain': [('id', 'in', list(all_bu.ids))],
+ }
+
+
+ @api.depends('move_id.state')
+ def _compute_is_cab_visible(self):
+ for order in self:
+ move = order.move_id
+ order.is_cab_visible = bool(move and move.state == 'posted')
+
+ def action_view_journal_uangmuka(self):
+ self.ensure_one()
+ if not self.move_id:
+ raise UserError("Journal Uang Muka belum tersedia.")
+
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Journal Entry',
+ 'res_model': 'account.move',
+ 'res_id': self.move_id.id,
+ 'view_mode': 'form',
+ 'target': 'current',
+ }
+
# cek payment term
def _check_payment_term(self):
_logger.info("Check Payment Term Terpanggil")
@@ -430,6 +537,18 @@ class PurchaseOrder(models.Model):
'company_id': self.company_id.id,
'payment_schedule': payment_schedule
}
+
+ receipt = self.env['stock.picking'].search([
+ ('purchase_id', '=', self.id),
+ ('state', '=', 'done'),
+ ('picking_type_code', '=', 'incoming'),
+ ('date_done', '!=', False)
+ ], order='date_done desc', limit=1)
+
+ if receipt:
+ invoice_vals['invoice_date'] = receipt.date_done
+ invoice_vals['date'] = receipt.date_done
+
return invoice_vals
def _compute_matches_so(self):
@@ -558,6 +677,13 @@ 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:
@@ -808,16 +934,20 @@ class PurchaseOrder(models.Model):
# test = line.product_uom_qty
# test2 = line.product_id.plafon_qty
# test3 = test2 + line.product_uom_qty
- if line.product_uom_qty > line.product_id.plafon_qty + line.product_uom_qty and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
- raise UserError('Product '+line.product_id.name+' melebihi plafon, harus Approval MD')
+ if line.product_uom_qty > line.product_id.plafon_qty + line.product_uom_qty and not self.env.user.id == 21:
+ raise UserError('Product '+line.product_id.name+' melebihi plafon, harus Approval Rafly')
def check_different_vendor_so_po(self):
vendor_po = self.partner_id.id
for line in self.order_line:
if not line.so_line_id:
continue
- if line.so_line_id.vendor_id.id != vendor_po and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
- raise UserError("Produk "+line.product_id.name+" memiliki vendor berbeda dengan SO (Vendor PO: "+str(self.partner_id.name)+", Vendor SO: "+str(line.so_line_id.vendor_id.name)+")")
+ if line.so_line_id.vendor_id.id != vendor_po:
+ self.env.user.notify_danger(
+ title='WARNING!!!',
+ message="Produk "+line.product_id.name+" memiliki vendor berbeda dengan SO (Vendor PO: "+str(self.partner_id.name)+", Vendor SO: "+str(line.so_line_id.vendor_id.name)+")",
+ sticky=True
+ )
def button_confirm(self):
# self._check_payment_term() # check payment term
@@ -830,23 +960,23 @@ 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 self.total_percent_margin < self.total_so_percent_margin and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
+ if self.total_percent_margin < self.total_so_percent_margin:
self.env.user.notify_danger(
title='WARNING!!!',
message='Beda Margin dengan Sale Order',
sticky=True
)
- if len(self.order_sales_match_line) == 0 and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
- self.env.user.notify_danger(
- title='WARNING!!!',
- message='Tidak ada matches SO',
- sticky=True
- )
+ # if len(self.order_sales_match_line) == 0 and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
+ # self.env.user.notify_danger(
+ # title='WARNING!!!',
+ # message='Tidak ada matches SO',
+ # sticky=True
+ # )
if not self.from_apo:
- if not self.matches_so and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser') and not self.env.user.is_leader:
- raise UserError("Tidak ada link dengan SO, harus approval Merchandise")
+ 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:
+ raise UserError("Tidak ada link dengan SO, harus di confirm oleh Purchasing Manager")
send_email = False
if not self.not_update_purchasepricelist:
@@ -891,6 +1021,12 @@ class PurchaseOrder(models.Model):
if self.product_bom_id:
self._remove_product_bom()
+ # Tambahan: redirect ke BU hanya untuk single PO yang berhasil dikonfirmasi
+ _logger.info("Jumlah PO: %s | State: %s", len(self), self.state)
+ if len(self) == 1:
+ _logger.info("Redirecting ke BU")
+ return self.action_view_related_bu()
+
return res
def _remove_product_bom(self):
@@ -912,7 +1048,7 @@ class PurchaseOrder(models.Model):
for line in self.order_line:
if line.taxes_id != reference_taxes:
- raise UserError("PPN harus sama untuk semua baris pada line.")
+ raise UserError(f"PPN harus sama untuk semua baris pada line {line.product_id.name}")
def check_data_vendor(self):
vendor = self.partner_id
@@ -998,7 +1134,7 @@ class PurchaseOrder(models.Model):
self.approval_status_unlock = 'approvedFinance'
else:
raise UserError("Bisa langsung Confirm, menunggu persetujuan Finance jika ingin unlock PO")
- elif self.env.user.is_leader or self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
+ elif self.env.user.is_leader or self.env.user.has_group('indoteknik_custom.group_role_purchasing'):
raise UserError("Bisa langsung Confirm")
elif self.total_percent_margin == self.total_so_percent_margin and self.matches_so and not greater_than_plafon and not different_vendor_message:
raise UserError("Bisa langsung Confirm")