diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-16 14:38:40 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-16 14:38:40 +0700 |
| commit | a0e90200638e26ad06d1caaf2d91d0aeea3ba19d (patch) | |
| tree | 34adea34676cc913273ae3a4c87845ef5df204db /indoteknik_custom/models | |
| parent | 0b6109930666039ed8e12569b6a9de7cbb4ea216 (diff) | |
<miqdad> add tukar guling PO and move from inventory
Diffstat (limited to 'indoteknik_custom/models')
| -rw-r--r-- | indoteknik_custom/models/tukar_guling.py | 211 |
1 files changed, 146 insertions, 65 deletions
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py index f8cbec0a..95aa7cd6 100644 --- a/indoteknik_custom/models/tukar_guling.py +++ b/indoteknik_custom/models/tukar_guling.py @@ -12,66 +12,34 @@ class TukarGuling(models.Model): 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')]) - in_num = fields.Many2one('stock.picking', 'Nomor BU/In', domain=[('picking_type_id.code', '=', 'incoming')]) 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 ? - ('revisi_po', 'Revisi PO'), - ('credit_memo', 'Credit Memo'), # -> dijadiin credit memo - ('debit_memo', 'Debit Memo')]) + ('credit_memo', 'Credit Memo')]) # -> dijadiin credit memo state = fields.Selection(string='Status', selection=[ ('draft', 'Draft'), - ('waiting', 'Waiting for Approval'), + ('approval_sales', ' Approval Sales'), + ('approval_logistic', 'Approval Logistic'), + ('approval_finance', 'Approval Finance'), ('done', 'Done'), ('cancel', 'Canceled') ], default='draft', tracking=True, required=True) line_ids = fields.One2many('tukar.guling.line', 'tukar_guling_id', string='Product Lines') - @api.onchange('return_type') - def _onchange_return_type(self): - in_domain = [] - out_domain = [] - - if self.return_type in ['debit_memo', 'revisi_po']: - # Hanya tampilkan BU In - in_domain = [('picking_type_id.code', '=', 'incoming')] - out_domain = [('id', '=', False)] # Kosongkan BU Out - elif self.return_type in ['revisi_so', 'credit_memo']: - # Hanya tampilkan BU Out - in_domain = [('id', '=', False)] # Kosongkan BU In - out_domain = [('picking_type_id.code', '=', 'outgoing')] - elif self.return_type == 'tukar_guling': - # Boleh pilih keduanya - in_domain = [('picking_type_id.code', '=', 'incoming')] - out_domain = [('picking_type_id.code', '=', 'outgoing')] - - return { - 'domain': { - 'in_num': in_domain, - 'out_num': out_domain, - } - } - - @api.constrains('return_type', 'in_num', 'out_num') + @api.constrains('return_type', 'out_num') def _check_required_bu_fields(self): for record in self: - if record.return_type in ['debit_memo', 'revisi_po'] and not record.in_num: - raise ValidationError("BU/In harus diisi untuk return type Debit Memo atau Revisi PO.") - - if record.return_type in ['revisi_so', 'credit_memo'] and not record.out_num: - raise ValidationError("BU/Out harus diisi untuk return type Revisi SO atau Credit Memo.") - - if record.return_type == 'tukar_guling' and not (record.in_num or record.out_num): - raise ValidationError("Untuk Tukar Guling, minimal isi salah satu, BU/In atau BU/Out.") + if record.return_type in ['revisi_so', 'credit_memo', 'tukar_guling'] and not record.out_num: + 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 ('waiting', '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): @@ -95,29 +63,29 @@ class TukarGuling(models.Model): return True - @api.model_create_multi - def create(self, vals_list): - for vals in vals_list: - if vals.get('name', 'New') == 'New': - vals['name'] = self.env['ir.sequence'].next_by_code('tukar.guling') or 'PTG/00001' - return super(TukarGuling, self).create(vals_list) + @api.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' + return super(TukarGuling, self).create(vals) def copy(self, default=None): - """Override copy untuk custom behavior saat duplicate""" if default is None: default = {} - # Reset fields penting saat duplicate + if 'name' not in default: + default.update({ + 'name': self.env['ir.sequence'].next_by_code(self._name) or 'New', + }) + default.update({ - 'name': 'New', 'state': 'draft', 'date': fields.Datetime.now(), }) - # Copy record dengan default values new_record = super(TukarGuling, self).copy(default) - # Re-sequence line items record baru + # Re-sequence lines if new_record.line_ids: for i, line in enumerate(new_record.line_ids): line.sequence = (i + 1) * 10 @@ -134,40 +102,153 @@ class TukarGuling(models.Model): def action_submit(self): self.ensure_one() - # cek bu out sudah diisi atau blm + + if self.state != 'draft': + raise UserError("Submit hanya bisa dilakukan dari Draft.") + self.state = 'approval_sales' + + def action_approve(self): + self.ensure_one() + if not self.out_num: raise UserError("BU/Out harus diisi!") - # cek return type - # if not self.return_type: - # raise UserError("Return Type harus diisi!") + if not self.return_type: + raise UserError("Return Type harus diisi!") + + # Cek hak akses berdasarkan state + if self.state == 'approval_sales': + if not self.env.user.has_group('indoteknik_custom.group_sales_manager'): + raise UserError("Hanya Sales Manager yang boleh approve tahap ini.") + self.state = 'approval_logistic' + + elif self.state == 'approval_logistic': + if not self.env.user.has_group('indoteknik_custom.group_logistic'): + raise UserError("Hanya Logistic Manager yang boleh approve tahap ini.") + self.state = 'approval_finance' + + elif self.state == 'approval_finance': + if not self.env.user.has_group('indoteknik_custom.group_finance'): + raise UserError("Hanya Finance Manager yang boleh approve tahap ini.") + self.state = 'done' + + else: + raise UserError("Status ini tidak bisa di-approve.") + def action_cancel(self): + self.ensure_one() + # if self.state == 'done': + # raise UserError("Tidak bisa cancel jika sudah done") + self.state = 'cancel' + +class TukarGulingPO(models.Model): + _name = 'tukar.guling.po' + _inherit = 'tukar.guling' + _description = 'Tukar Guling PO' + + # tukar_guling_id = fields.Many2one( + # 'tukar.guling', required=True, ondelete='cascade', string='Tukar Guling Ref' + # ) + + return_type = fields.Selection([ + ('tukar_guling', 'Tukar Guling'), + ('revisi_po', 'Revisi PO'), + ('debit_memo', 'Debit Memo'), + ], string='Return Type', required=True) + + @api.constrains('return_type', 'out_num') + 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: + 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: + 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!") + + # Check product sudah diisi + empty_lines = self.line_ids.filtered(lambda line: not line.product_id) + if empty_lines: + raise UserError("Ada product lines yang belum diisi productnya!") + + # Check quantity > 0 + zero_qty_lines = self.line_ids.filtered(lambda line: line.product_uom_qty <= 0) + if zero_qty_lines: + raise UserError("Quantity product tidak boleh kosong atau 0!") + return True + + @api.model + def create(self, vals): + if not vals.get('name') or vals['name'] in ('New', False): + vals['name'] = self.env['ir.sequence'].next_by_code('tukar.guling.po') or 'New' + return super(TukarGulingPO, self).create(vals) + def copy(self, default=None): + if default is None: + default = {} + + # Generate sequence satu-satunya di sini + default['name'] = self.env['ir.sequence'].next_by_code('tukar.guling.po') or 'New' + default['state'] = 'draft' + default['date'] = fields.Datetime.now() + + new_record = super(TukarGulingPO, self).copy(default) + + # Re-sequence lines + if new_record.line_ids: + for i, line in enumerate(new_record.line_ids): + line.sequence = (i + 1) * 10 + + return new_record + + def action_draft(self): + """Reset to draft state""" + for record in self: + if record.state == 'cancel': + record.write({'state': 'draft'}) + else: + raise UserError("Hanya record yang di-cancel yang bisa dikembalikan ke draft") + + def action_submit(self): + self.ensure_one() if self.state != 'draft': - raise UserError("Hanya status Draft saja yang bisa di submit") - self.state = 'waiting' + raise UserError("Submit hanya bisa dilakukan dari Draft.") + self.state = 'approval_sales' def action_approve(self): self.ensure_one() - # cek bu out sudah diisi atau blm if not self.out_num: raise UserError("BU/Out harus diisi!") - # cek return type if not self.return_type: raise UserError("Return Type harus diisi!") - if self.state != 'waiting': - raise UserError("Hanya status Waiting saja yang bisa di approve") - self.state = 'done' + if self.state == 'approval_sales': + self.state = 'approval_logistic' + elif self.state == 'approval_logistic': + self.state = 'approval_finance' + elif self.state == 'approval_finance': + self.state = 'done' + else: + raise UserError("Status ini tidak bisa di-approve.") def action_cancel(self): self.ensure_one() - if self.state == 'done': - raise UserError("Tidak bisa cancel jika sudah done") + # if self.state == 'done': + # raise UserError("Tidak bisa cancel jika sudah done") self.state = 'cancel' - class TukarGulingLine(models.Model): _name = 'tukar.guling.line' _description = 'Tukar Guling Line' |
