diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-18 13:32:05 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-18 13:32:05 +0700 |
| commit | d1ff4bd35deac6c17a17e97f0904f67e113c5add (patch) | |
| tree | 16cc13d381b45bd0174f1ee8dd393b60f89aa8f4 | |
| parent | fe8c7bf1903242610d99381b5109506294648d10 (diff) | |
<miqdad> revisi, fetch item from bu out in tukar guling line
| -rw-r--r-- | indoteknik_custom/models/tukar_guling.py | 141 | ||||
| -rw-r--r-- | indoteknik_custom/views/tukar_guling.xml | 14 | ||||
| -rw-r--r-- | 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 @@ <data> <!-- Action --> <record id="action_pengajuan_tukar_guling" model="ir.actions.act_window"> - <field name="name">Pengajuan Tukar Guling SO</field> + <field name="name">Pengajuan Return SO</field> <field name="type">ir.actions.act_window</field> <field name="res_model">tukar.guling</field> <field name="view_mode">tree,form</field> @@ -11,14 +11,14 @@ <!-- Menu --> <menuitem id="menu_pengajuan_tukar_guling" - name="Pengajuan Tukar Guling SO" + name="Pengajuan Return SO" parent="sale.sale_order_menu" sequence="3" action="action_pengajuan_tukar_guling" /> <!-- Sequence --> <record id="seq_tukar_guling" model="ir.sequence"> - <field name="name">Pengajuan Tukar Guling SO</field> + <field name="name">Pengajuan Return SO</field> <field name="code">tukar.guling</field> <field name="prefix">PTG/</field> <field name="padding">5</field> @@ -34,7 +34,7 @@ <tree create="1" delete="1" default_order="create_date desc"> <field name="name"/> <field name="date"/> - <field name="out_num" string="BU/Out"/> + <field name="operations" string="Operations"/> <field name="ba_num" string="Nomor BA"/> <field name="return_type" string="Return Type"/> <field name="state" widget="badge" @@ -91,10 +91,10 @@ <field name="return_type"/> <!-- <field name="ort_num" readonly="1"/>--> <!-- <field name="srt_num" readonly="1"/>--> - <field name="out_num" string="BU/Out" + <field name="operations" string="Operations" attrs="{ - 'invisible': [('return_type', 'not in', ['revisi_so', 'credit_memo', 'tukar_guling'])], - 'required': [('return_type', 'in', ['revisi_so', 'credit_memo'])] + 'invisible': [('return_type', 'not in', ['revisi_so','tukar_guling'])], + 'required': [('return_type', 'in', ['revisi_so'])] }"/> <field name="origin" readonly="1"/> </group> 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 @@ <tree create="1" delete="1" default_order="create_date desc"> <field name="name"/> <field name="date"/> - <field name="out_num" string="BU/Out"/> + <field name="operations" string="BU/Out"/> <field name="ba_num" string="Nomor BA"/> <field name="return_type" string="Return Type"/> <field name="state" widget="badge" @@ -83,7 +83,7 @@ <group> <field name="date" string="Date" readonly="1"/> <field name="return_type"/> - <field name="out_num" string="BU/Out" + <field name="operations" string="BU/Out" attrs="{ 'invisible': [('return_type', 'not in', ['revisi_po', 'debit_memo', 'tukar_guling'])], 'required': [('return_type', 'in', ['revisi_po', 'debit_memo'])] |
