diff options
Diffstat (limited to 'indoteknik_custom/models/purchase_order.py')
| -rwxr-xr-x | indoteknik_custom/models/purchase_order.py | 168 |
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") |
