From d1ff4bd35deac6c17a17e97f0904f67e113c5add Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 18 Jun 2025 13:32:05 +0700 Subject: revisi, fetch item from bu out in tukar guling line --- indoteknik_custom/models/tukar_guling.py | 141 ++++++++++++++++++++++------ indoteknik_custom/views/tukar_guling.xml | 14 +-- indoteknik_custom/views/tukar_guling_po.xml | 4 +- 3 files changed, 122 insertions(+), 37 deletions(-) diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py index 7ed6e10f..a5724104 100644 --- a/indoteknik_custom/models/tukar_guling.py +++ b/indoteknik_custom/models/tukar_guling.py @@ -4,6 +4,7 @@ import logging _logger = logging.getLogger(__name__) + class TukarGuling(models.Model): _name = 'tukar.guling' _description = 'Tukar Guling' @@ -21,14 +22,13 @@ class TukarGuling(models.Model): ) name = fields.Char('Number', required=True, copy=False, readonly=True, default='New') date = fields.Datetime('Date', default=fields.Datetime.now, required=True) - out_num = fields.Many2one('stock.picking', 'Nomor BU/Out', - domain=[('picking_type_id.code', '=', 'outgoing')]) + operations = fields.Many2one('stock.picking', 'Operations', + domain=[('picking_type_id.code', '=', 'outgoing')], help='Nomor BU/Out atau BU/Pick') ba_num = fields.Text('Nomor BA') notes = fields.Text('Notes') return_type = fields.Selection(String='Return Type', selection=[ - ('tukar_guling', 'Tukar Guling'), # -> barang yang sama - ('revisi_so', 'Revisi SO'), # -> ganti barang ? - ('credit_memo', 'Credit Memo')]) # -> dijadiin credit memo + ('tukar_guling', 'Tukar Guling'), # -> barang yang sama + ('revisi_so', 'Revisi SO')]) state = fields.Selection(string='Status', selection=[ ('draft', 'Draft'), ('approval_sales', ' Approval Sales'), @@ -40,24 +40,108 @@ class TukarGuling(models.Model): line_ids = fields.One2many('tukar.guling.line', 'tukar_guling_id', string='Product Lines') - @api.constrains('return_type', 'out_num') + @api.onchange('operations') + def _onchange_operations(self): + """Auto-populate lines ketika operations dipilih""" + if self.operations: + # Clear existing lines + self.line_ids = [(5, 0, 0)] + + # Set origin dari operations + if self.operations.origin: + self.origin = self.operations.origin + + # Auto-populate lines dari move_ids operations + lines_data = [] + sequence = 10 + + # Untuk Odoo 14, gunakan move_ids_without_package atau move_lines + moves_to_check = [] + + # 1. move_ids_without_package (standard di Odoo 14) + if hasattr(self.operations, 'move_ids_without_package') and self.operations.move_ids_without_package: + moves_to_check = self.operations.move_ids_without_package + # 2. move_lines (backup untuk versi lama) + elif hasattr(self.operations, 'move_lines') and self.operations.move_lines: + moves_to_check = self.operations.move_lines + + # Debug logging + _logger = logging.getLogger(__name__) + _logger.info(f"BU/OUT: {self.operations.name}, State: {self.operations.state}") + _logger.info(f"Total moves found: {len(moves_to_check)}") + + for move in moves_to_check: + _logger.info( + f"Move: {move.name}, Product: {move.product_id.name if move.product_id else 'No Product'}, Qty: {move.product_uom_qty}, State: {move.state}") + + # Ambil semua move yang ada quantity + if move.product_id and move.product_uom_qty > 0: + lines_data.append((0, 0, { + 'sequence': sequence, + 'product_id': move.product_id.id, + 'product_uom_qty': move.product_uom_qty, + 'product_uom': move.product_uom.id, + 'name': move.name or move.product_id.display_name, + })) + sequence += 10 + + if lines_data: + self.line_ids = lines_data + _logger.info(f"Created {len(lines_data)} lines") + else: + _logger.info("No lines created - no valid moves found") + else: + # Clear lines jika operations dikosongkan + self.line_ids = [(5, 0, 0)] + self.origin = False + + def action_populate_lines(self): + """Manual button untuk populate lines - sebagai alternatif""" + self.ensure_one() + if not self.operations: + raise UserError("Pilih BU/OUT terlebih dahulu!") + + # Clear existing lines + self.line_ids = [(5, 0, 0)] + + lines_data = [] + sequence = 10 + + # Ambil semua stock moves dari operations + for move in self.operations.move_ids: + if move.product_uom_qty > 0: + lines_data.append((0, 0, { + 'sequence': sequence, + 'product_id': move.product_id.id, + 'product_uom_qty': move.product_uom_qty, + 'product_uom': move.product_uom.id, + 'name': move.name or move.product_id.display_name, + })) + sequence += 10 + + if lines_data: + self.line_ids = lines_data + else: + raise UserError("Tidak ditemukan barang di BU/OUT yang dipilih!") + + @api.constrains('return_type', 'operations') def _check_required_bu_fields(self): for record in self: - if record.return_type in ['revisi_so', 'credit_memo', 'tukar_guling'] and not record.out_num: + if record.return_type in ['revisi_so', 'tukar_guling'] and not record.operations: raise ValidationError("BU/Out harus diisi!") @api.constrains('line_ids', 'state') 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', 'done') and not record.line_ids: + if record.state in ('approval_sales', 'approval_logistic', 'approval_finance', + 'done') and not record.line_ids: raise ValidationError("Product lines harus diisi sebelum submit atau approve!") def _validate_product_lines(self): """Helper method untuk validasi product lines""" self.ensure_one() - # Check ada product lines if not self.line_ids: raise UserError("Belum ada product lines yang ditambahkan!") @@ -78,9 +162,9 @@ class TukarGuling(models.Model): def create(self, vals): if not vals.get('name') or vals['name'] == 'New': vals['name'] = self.env['ir.sequence'].next_by_code('tukar.guling') or 'New' - # Auto-fill origin from out_num - if not vals.get('origin') and vals.get('out_num'): - picking = self.env['stock.picking'].browse(vals['out_num']) + # Auto-fill origin from operations + if not vals.get('origin') and vals.get('operations'): + picking = self.env['stock.picking'].browse(vals['operations']) if picking.origin: vals['origin'] = picking.origin return super(TukarGuling, self).create(vals) @@ -109,8 +193,8 @@ class TukarGuling(models.Model): return new_record def write(self, vals): - if 'out_num' in vals and not vals.get('origin'): - picking = self.env['stock.picking'].browse(vals['out_num']) + if 'operations' in vals and not vals.get('origin'): + picking = self.env['stock.picking'].browse(vals['operations']) if picking.origin: vals['origin'] = picking.origin @@ -145,7 +229,7 @@ class TukarGuling(models.Model): def action_approve(self): self.ensure_one() - if not self.out_num: + if not self.operations: raise UserError("BU/Out harus diisi!") if not self.return_type: @@ -170,6 +254,7 @@ class TukarGuling(models.Model): rec._create_pickings() else: raise UserError("Status ini tidak bisa di-approve.") + def action_cancel(self): self.ensure_one() # if self.state == 'done': @@ -177,10 +262,10 @@ class TukarGuling(models.Model): self.state = 'cancel' def _create_pickings(self): - if not self.out_num: + if not self.operations: raise UserError("BU/Out harus diisi terlebih dahulu.") - origin_so = self.out_num.origin + origin_so = self.operations.origin if not origin_so: raise UserError("BU/OUT tidak memiliki origin (SO), tidak bisa cari BU/PICK.") @@ -206,15 +291,15 @@ class TukarGuling(models.Model): # Lokasi location_dest_id = srt_type.default_location_dest_id.id location_dest_id_ort = ort_type.default_location_dest_id.id - location_customer = self.out_num.location_dest_id + location_customer = self.operations.location_dest_id - # 1. BU/SRT: retur dari out_num + # 1. BU/SRT: retur dari operations srt_picking = Picking.create({ - 'partner_id': self.out_num.partner_id.id, + 'partner_id': self.operations.partner_id.id, 'picking_type_id': srt_type.id, 'location_id': location_customer.id, 'location_dest_id': location_dest_id, - 'origin': f"Retur {self.out_num.name}", + 'origin': f"Retur {self.operations.name}", 'tukar_guling_id': self.id, 'group_id': group_id, 'move_ids_without_package': [ @@ -232,7 +317,7 @@ class TukarGuling(models.Model): srt_picking.action_confirm() # 2. Cari BU/PICK dari SO yang sama - origin_so = self.out_num.origin + origin_so = self.operations.origin if not origin_so: raise UserError("BU/OUT tidak memiliki origin (SO), tidak bisa cari BU/PICK.") @@ -246,7 +331,7 @@ class TukarGuling(models.Model): # 3. BU/ORT: retur dari BU/PICK ort_picking = Picking.create({ - 'partner_id': self.out_num.partner_id.id, + 'partner_id': self.operations.partner_id.id, 'picking_type_id': ort_type.id, 'location_id': location_dest_id, 'location_dest_id': location_dest_id_ort, @@ -266,7 +351,7 @@ class TukarGuling(models.Model): ] }) ort_picking.action_confirm() - + ort_picking.action_assign() class TukarGulingPO(models.Model): _name = 'tukar.guling.po' @@ -274,7 +359,7 @@ class TukarGulingPO(models.Model): name = fields.Char('Number', required=True, copy=False, readonly=True, default='New') date = fields.Datetime('Date', default=fields.Datetime.now, required=True) - out_num = fields.Many2one('stock.picking', 'Nomor BU/Out', + operations = fields.Many2one('stock.picking', 'Nomor BU/Out', domain=[('picking_type_id.code', '=', 'outgoing')]) ba_num = fields.Text('Nomor BA') notes = fields.Text('Notes') @@ -296,10 +381,10 @@ class TukarGulingPO(models.Model): ('debit_memo', 'Debit Memo'), ], string='Return Type', required=True) - @api.constrains('return_type', 'out_num') + @api.constrains('return_type', 'operations') def _check_required_bu_fields(self): for record in self: - if record.return_type in ['tukar_guling', 'revisi_po', 'debit_memo'] and not record.out_num: + if record.return_type in ['tukar_guling', 'revisi_po', 'debit_memo'] and not record.operations: raise ValidationError("BU/Out harus diisi!") @api.constrains('line_ids', 'state') @@ -369,7 +454,7 @@ class TukarGulingPO(models.Model): def action_approve(self): self.ensure_one() - if not self.out_num: + if not self.operations: raise UserError("BU/Out harus diisi!") if not self.return_type: diff --git a/indoteknik_custom/views/tukar_guling.xml b/indoteknik_custom/views/tukar_guling.xml index 9f8a6ff6..c775c301 100644 --- a/indoteknik_custom/views/tukar_guling.xml +++ b/indoteknik_custom/views/tukar_guling.xml @@ -3,7 +3,7 @@ - Pengajuan Tukar Guling SO + Pengajuan Return SO ir.actions.act_window tukar.guling tree,form @@ -11,14 +11,14 @@ - Pengajuan Tukar Guling SO + Pengajuan Return SO tukar.guling PTG/ 5 @@ -34,7 +34,7 @@ - + - diff --git a/indoteknik_custom/views/tukar_guling_po.xml b/indoteknik_custom/views/tukar_guling_po.xml index 3ad269ee..76d85904 100644 --- a/indoteknik_custom/views/tukar_guling_po.xml +++ b/indoteknik_custom/views/tukar_guling_po.xml @@ -36,7 +36,7 @@ - + -