diff options
| author | Indoteknik . <it@fixcomart.co.id> | 2025-08-09 14:45:48 +0700 |
|---|---|---|
| committer | Indoteknik . <it@fixcomart.co.id> | 2025-08-09 14:45:48 +0700 |
| commit | 979ffc90fffe2f09788016376d71a940a28f8fed (patch) | |
| tree | a5408296eb204a0a5066578664ed0acb13174f27 /indoteknik_custom/models/tukar_guling.py | |
| parent | 33621956bdb9d807b480eda44ce7f2152f508695 (diff) | |
| parent | df5ff0fc9bcd45c19b74288d8e5cfee018ba5bdd (diff) | |
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into pum-v2
Diffstat (limited to 'indoteknik_custom/models/tukar_guling.py')
| -rw-r--r-- | indoteknik_custom/models/tukar_guling.py | 348 |
1 files changed, 249 insertions, 99 deletions
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py index 43bc156e..6aedb70e 100644 --- a/indoteknik_custom/models/tukar_guling.py +++ b/indoteknik_custom/models/tukar_guling.py @@ -5,7 +5,8 @@ from datetime import datetime _logger = logging.getLogger(__name__) -#TODO + +# TODO # 1. tracking status dokumen BU [X] # 2. ganti nama dokumen # 3. Tracking ketika create dokumen [X] @@ -20,7 +21,7 @@ class TukarGuling(models.Model): _order = 'date desc, id desc' _rec_name = 'name' _inherit = ['mail.thread', 'mail.activity.mixin'] - + partner_id = fields.Many2one('res.partner', string='Customer', readonly=True) origin = fields.Char(string='Origin SO') if_so = fields.Boolean('Is SO', default=True) @@ -31,7 +32,7 @@ class TukarGuling(models.Model): 'tukar_guling_id', string='Transfers' ) - # origin_so = fields.Many2one('sale.order', string='Origin SO') + origin_so = fields.Many2one('sale.order', string='Origin SO', compute='_compute_origin_so') name = fields.Char('Number', required=True, copy=False, readonly=True, default='New') date = fields.Datetime('Date', default=fields.Datetime.now, required=True) operations = fields.Many2one( @@ -62,6 +63,7 @@ class TukarGuling(models.Model): ('approval_sales', ' Approval Sales'), ('approval_finance', 'Approval Finance'), ('approval_logistic', 'Approval Logistic'), + ('approved', 'Waiting for Operations'), ('done', 'Done'), ('cancel', 'Canceled') ], default='draft', tracking=True, required=True) @@ -72,6 +74,47 @@ class TukarGuling(models.Model): date_sales = fields.Datetime('Approved Date Sales', tracking=3, readonly=True) date_logistic = fields.Datetime('Approved Date Logistic', tracking=3, readonly=True) + val_inv_opt = fields.Selection([ + ('tanpa_cancel', 'Tanpa Cancel Invoice'), + ('cancel_invoice', 'Cancel Invoice'), + ], tracking=3, string='Invoice Option') + + is_has_invoice = fields.Boolean('Has Invoice?', compute='_compute_is_has_invoice', readonly=True, default=False) + + invoice_id = fields.Many2many('account.move', string='Invoice Ref', readonly=True) + + @api.depends('origin', 'operations') + def _compute_origin_so(self): + for rec in self: + rec.origin_so = False + origin_str = rec.origin or rec.operations.origin + if origin_str: + so = self.env['sale.order'].search([('name', '=', origin_str)], limit=1) + rec.origin_so = so.id if so else False + + @api.depends('origin') + def _compute_is_has_invoice(self): + for rec in self: + invoices = self.env['account.move'].search([ + ('invoice_origin', 'ilike', rec.origin), + ('move_type', '=', 'out_invoice'), # hanya invoice + ('state', 'not in', ['draft', 'cancel']) + ]) + if invoices: + rec.is_has_invoice = True + rec.invoice_id = invoices + else: + rec.is_has_invoice = False + + def set_opt(self): + if not self.val_inv_opt and self.is_has_invoice == True: + raise UserError("Kalau sudah ada invoice Return Invoice Option harus diisi!") + for rec in self: + if rec.val_inv_opt == 'cancel_invoice' and self.is_has_invoice == True: + raise UserError("Tidak bisa mengubah Return karena sudah ada invoice dan belum di cancel.") + elif rec.val_inv_opt == 'tanpa_cancel' and self.is_has_invoice == True: + continue + # @api.onchange('operations') # def get_partner_id(self): # if self.operations and self.operations.partner_id and self.operations.partner_id.name: @@ -98,7 +141,7 @@ class TukarGuling(models.Model): @api.onchange('operations') def _onchange_operations(self): """Auto-populate lines ketika operations dipilih""" - if self.operations.picking_type_id.id not in [29,30]: + if self.operations.picking_type_id.id not in [29, 30]: raise UserError("❌ Picking type harus BU/OUT atau BU/PICK") for rec in self: if rec.operations and rec.operations.picking_type_id.id == 30: @@ -110,8 +153,6 @@ class TukarGuling(models.Model): if self.line_ids and from_return_picking: # Hanya update origin, jangan ubah lines - if self.operations.origin: - self.origin = self.operations.origin _logger.info("📌 Menggunakan product lines dari return wizard, tidak populate ulang.") # 🚀 Tapi tetap populate mapping koli jika BU/OUT @@ -143,6 +184,7 @@ class TukarGuling(models.Model): # Set origin dari operations if self.operations.origin: self.origin = self.operations.origin + self.origin_so = self.operations.group_id.id # Auto-populate lines dari move_ids operations lines_data = [] @@ -217,7 +259,6 @@ class TukarGuling(models.Model): self.origin = False - def action_populate_lines(self): """Manual button untuk populate lines - sebagai alternatif""" self.ensure_one() @@ -257,7 +298,7 @@ class TukarGuling(models.Model): 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', + if record.state in ('approval_sales', 'approval_logistic', 'approval_finance', 'approved', 'done') and not record.line_ids: raise ValidationError("Product lines harus diisi sebelum submit atau approve!") @@ -281,36 +322,38 @@ class TukarGuling(models.Model): return True - def _is_already_returned(self, picking): - return self.env['stock.picking'].search_count([ - ('origin', '=', 'Return of %s' % picking.name), - ('state', '!=', 'cancel') - ]) > 0 + # def _is_already_returned(self, picking): + # return self.env['stock.picking'].search_count([ + # ('origin', '=', 'Return of %s' % picking.name), + # ('state', '!=', 'cancel') + # ]) > 0 + + # def _check_invoice_on_revisi_so(self): + # for record in self: + # if record.return_type == 'revisi_so' and record.origin: + # invoices = self.env['account.move'].search([ + # ('invoice_origin', 'ilike', record.origin), + # ('state', 'not in', ['draft', 'cancel']) + # ]) + # if invoices: + # raise ValidationError( + # _("Tidak bisa memilih Return Type 'Revisi SO' karena dokumen %s sudah dibuat invoice.") % record.origin + # ) - @api.constrains('return_type', 'operations') - def _check_invoice_on_revisi_so(self): - for record in self: - if record.return_type == 'revisi_so' and record.origin: - invoices = self.env['account.move'].search([ - ('invoice_origin', 'ilike', record.origin), - ('state', 'not in', ['draft', 'cancel']) - ]) - if invoices: - raise ValidationError( - _("Tidak bisa memilih Return Type 'Revisi SO' karena dokumen %s sudah dibuat invoice.") % record.origin - ) @api.model def create(self, vals): - # Generate sequence number if not vals.get('name') or vals['name'] == 'New': vals['name'] = self.env['ir.sequence'].next_by_code('tukar.guling') - # Auto-fill origin from operations - if not vals.get('origin') and vals.get('operations'): + if vals.get('operations'): picking = self.env['stock.picking'].browse(vals['operations']) if picking.origin: vals['origin'] = picking.origin + # Find matching SO + so = self.env['sale.order'].search([('name', '=', picking.origin)], limit=1) + if so: + vals['origin_so'] = so.id if picking.partner_id: vals['partner_id'] = picking.partner_id.id @@ -318,6 +361,10 @@ class TukarGuling(models.Model): res.message_post(body=_("CCM Created By %s") % self.env.user.name) return res + res = super(TukarGuling, self).create(vals) + res.message_post(body=_("CCM Created By %s") % self.env.user.name) + return res + def copy(self, default=None): if default is None: default = {} @@ -345,9 +392,9 @@ class TukarGuling(models.Model): def write(self, vals): self.ensure_one() - if self.operations.picking_type_id.id not in [29,30]: + if self.operations.picking_type_id.id not in [29, 30]: raise UserError("❌ Picking type harus BU/OUT atau BU/PICK") - self._check_invoice_on_revisi_so() + # self._check_invoice_on_revisi_so() operasi = self.operations.picking_type_id.id tipe = self.return_type pp = vals.get('return_type', tipe) @@ -376,24 +423,33 @@ class TukarGuling(models.Model): # if self.state == 'done': # raise UserError ("Tidak Boleh delete ketika sudahh done") for record in self: - if record.state == 'done': + if record.state == 'approved' or record.state == 'done': raise UserError( - "Tidak bisa hapus pengajuan jika sudah done, set ke draft terlebih dahulu jika ingin menghapus") - ongoing_bu = self.picking_ids.filtered(lambda p: p.state != 'done') + "Tidak bisa hapus pengajuan jika sudah Approved, set ke draft terlebih dahulu jika ingin menghapus") + ongoing_bu = self.picking_ids.filtered(lambda p: p.state != 'approved') for picking in ongoing_bu: picking.action_cancel() return super(TukarGuling, self).unlink() def action_view_picking(self): self.ensure_one() - action = self.env.ref('stock.action_picking_tree_all').read()[0] - pickings = self.picking_ids - if len(pickings) > 1: - action['domain'] = [('id', 'in', pickings.ids)] - elif pickings: - action['views'] = [(self.env.ref('stock.view_picking_form').id, 'form')] - action['res_id'] = pickings.id - return action + + # picking_origin = f"Return of {self.operations.name}" + returs = self.env['stock.picking'].search([ + ('tukar_guling_id', '=', self.id), + ]) + + if not returs: + raise UserError("Doc Retrun Not Found") + + return { + 'type': 'ir.actions.act_window', + 'name': 'Delivery Pengajuan Retur SO', + 'res_model': 'stock.picking', + 'view_mode': 'tree,form', + 'domain': [('id', 'in', returs.ids)], + 'target': 'current', + } def action_draft(self): """Reset to draft state""" @@ -434,40 +490,100 @@ class TukarGuling(models.Model): linked_bu_out = picking.linked_manual_bu_out if linked_bu_out and linked_bu_out.state == 'done': raise UserError("❌ Tidak bisa retur BU/PICK karena BU/OUT suda Done!") - if self._is_already_returned(self.operations): - raise UserError("BU ini sudah pernah diretur oleh dokumen lain.") + # if self._is_already_returned(self.operations): + # raise UserError("BU ini sudah pernah diretur oleh dokumen lain.") if self.operations.picking_type_id.id == 29: - for line in self.line_ids: - mapping_lines = self.mapping_koli_ids.filtered(lambda x: x.product_id == line.product_id) - total_qty = sum(l.qty_return for l in mapping_lines) - if total_qty != line.product_uom_qty: - raise UserError( - _("Qty di Koli tidak sesuai dengan qty retur untuk produk %s") % line.product_id.display_name) - - self._check_invoice_on_revisi_so() + # Cek apakah ada BU/PICK di origin + origin = self.operations.origin + has_bu_pick = self.env['stock.picking'].search_count([ + ('origin', '=', origin), + ('picking_type_id', '=', 30), + ('state', '!=', 'cancel') + ]) > 0 + + if has_bu_pick: + for line in self.line_ids: + mapping_lines = self.mapping_koli_ids.filtered(lambda x: x.product_id == line.product_id) + total_qty = sum(l.qty_return for l in mapping_lines) + if total_qty != line.product_uom_qty: + raise UserError( + _("Qty di Koli tidak sesuai dengan qty retur untuk produk %s") % line.product_id.display_name + ) + # self._check_invoice_on_revisi_so() self._validate_product_lines() if self.state != 'draft': raise UserError("Submit hanya bisa dilakukan dari Draft.") self.state = 'approval_sales' + def update_doc_state(self): + # OUT tukar guling + if self.operations.picking_type_id.id == 29 and self.return_type == 'tukar_guling': + total_out = self.env['stock.picking'].search_count([ + ('tukar_guling_id', '=', self.id), + ('picking_type_id', '=', 29), + ]) + done_out = self.env['stock.picking'].search_count([ + ('tukar_guling_id', '=', self.id), + ('picking_type_id', '=', 29), + ('state', '=', 'done'), + ]) + if self.state == 'approved' and total_out > 0 and done_out == total_out: + self.state = 'done' + + # OUT revisi SO + elif self.operations.picking_type_id.id == 29 and self.return_type == 'revisi_so': + total_ort = self.env['stock.picking'].search_count([ + ('tukar_guling_id', '=', self.id), + ('picking_type_id', '=', 74), + ]) + done_ort = self.env['stock.picking'].search_count([ + ('tukar_guling_id', '=', self.id), + ('picking_type_id', '=', 74), + ('state', '=', 'done'), + ]) + if self.state == 'approved' and total_ort > 0 and done_ort == total_ort: + self.state = 'done' + + # PICK revisi SO + elif self.operations.picking_type_id.id == 30 and self.return_type == 'revisi_so': + done_ort = self.env['stock.picking'].search([ + ('tukar_guling_id', '=', self.id), + ('picking_type_id', '=', 74), + ('state', '=', 'done'), + ]) + if self.state == 'approved' and done_ort: + self.state = 'done' + else: + raise UserError("Tidak bisa menentukan jenis retur.") + def action_approve(self): self.ensure_one() self._validate_product_lines() - self._check_invoice_on_revisi_so() + # self._check_invoice_on_revisi_so() self._check_not_allow_tukar_guling_on_bu_pick() operasi = self.operations.picking_type_id.id tipe = self.return_type if self.operations.picking_type_id.id == 29: - for line in self.line_ids: - mapping_lines = self.mapping_koli_ids.filtered(lambda x: x.product_id == line.product_id) - total_qty = sum(l.qty_return for l in mapping_lines) - if total_qty != line.product_uom_qty: - raise UserError( - _("Qty di Koli tidak sesuai dengan qty retur untuk produk %s") % line.product_id.display_name) + # Cek apakah ada BU/PICK di origin + origin = self.operations.origin + has_bu_pick = self.env['stock.picking'].search_count([ + ('origin', '=', origin), + ('picking_type_id', '=', 30), + ('state', '!=', 'cancel') + ]) > 0 + + if has_bu_pick: + for line in self.line_ids: + mapping_lines = self.mapping_koli_ids.filtered(lambda x: x.product_id == line.product_id) + total_qty = sum(l.qty_return for l in mapping_lines) + if total_qty != line.product_uom_qty: + raise UserError( + _("Qty di Koli tidak sesuai dengan qty retur untuk produk %s") % line.product_id.display_name + ) if operasi == 30 and self.operations.linked_manual_bu_out.state == 'done': raise UserError("❌ Tidak bisa retur BU/PICK karena BU/OUT sudah done") @@ -495,13 +611,15 @@ class TukarGuling(models.Model): elif rec.state == 'approval_finance': if not rec.env.user.has_group('indoteknik_custom.group_role_fat'): raise UserError("Hanya Finance Manager yang boleh approve tahap ini.") + # rec._check_invoice_on_revisi_so() + rec.set_opt() rec.state = 'approval_logistic' rec.date_finance = now elif rec.state == 'approval_logistic': if not rec.env.user.has_group('indoteknik_custom.group_role_logistic'): raise UserError("Hanya Logistic Manager yang boleh approve tahap ini.") - rec.state = 'done' + rec.state = 'approved' rec._create_pickings() rec.date_logistic = now @@ -533,6 +651,23 @@ class TukarGuling(models.Model): def _create_pickings(self): _logger.info("🛠 Starting _create_pickings()") + + def _force_locations(picking, from_loc, to_loc): + picking.write({ + 'location_id': from_loc, + 'location_dest_id': to_loc, + }) + for move in picking.move_lines: + move.write({ + 'location_id': from_loc, + 'location_dest_id': to_loc, + }) + for move_line in move.move_line_ids: + move_line.write({ + 'location_id': from_loc, + 'location_dest_id': to_loc, + }) + for record in self: if not record.operations: raise UserError("BU/OUT dari field operations tidak ditemukan.") @@ -555,36 +690,53 @@ class TukarGuling(models.Model): ### ======== SRT dari BU/OUT ========= srt_return_lines = [] - for prod in mapping_koli.mapped('product_id'): - qty_total = sum(mk.qty_return for mk in mapping_koli.filtered(lambda m: m.product_id == prod)) - move = bu_out.move_lines.filtered(lambda m: m.product_id == prod) - if not move: - raise UserError(f"Move BU/OUT tidak ditemukan untuk produk {prod.display_name}") - srt_return_lines.append((0, 0, { - 'product_id': prod.id, - 'quantity': qty_total, - 'move_id': move.id, - })) - _logger.info(f"📟 SRT line: {prod.display_name} | qty={qty_total}") + if mapping_koli: + for prod in mapping_koli.mapped('product_id'): + qty_total = sum(mk.qty_return for mk in mapping_koli.filtered(lambda m: m.product_id == prod)) + move = bu_out.move_lines.filtered(lambda m: m.product_id == prod) + if not move: + raise UserError(f"Move BU/OUT tidak ditemukan untuk produk {prod.display_name}") + srt_return_lines.append((0, 0, { + 'product_id': prod.id, + 'quantity': qty_total, + 'move_id': move.id, + })) + _logger.info(f"📟 SRT line: {prod.display_name} | qty={qty_total}") + + elif not mapping_koli: + for line in record.line_ids: + move = bu_out.move_lines.filtered(lambda m: m.product_id == line.product_id) + if not move: + raise UserError(f"Move BU/OUT tidak ditemukan untuk produk {line.product_id.display_name}") + srt_return_lines.append((0, 0, { + 'product_id': line.product_id.id, + 'quantity': line.product_uom_qty, + 'move_id': move.id, + })) + _logger.info( + f"📟 SRT line (fallback line_ids): {line.product_id.display_name} | qty={line.product_uom_qty}") srt_picking = None if srt_return_lines: + # Tentukan tujuan lokasi berdasarkan ada/tidaknya mapping_koli + dest_location_id = BU_OUTPUT_LOCATION_ID if mapping_koli else BU_STOCK_LOCATION_ID + srt_wizard = self.env['stock.return.picking'].with_context({ 'active_id': bu_out.id, 'default_location_id': PARTNER_LOCATION_ID, - 'default_location_dest_id': BU_OUTPUT_LOCATION_ID, + 'default_location_dest_id': dest_location_id, 'from_ui': False, }).create({ 'picking_id': bu_out.id, 'location_id': PARTNER_LOCATION_ID, - 'original_location_id': BU_OUTPUT_LOCATION_ID, 'product_return_moves': srt_return_lines }) + srt_vals = srt_wizard.create_returns() srt_picking = self.env['stock.picking'].browse(srt_vals['res_id']) + _force_locations(srt_picking, PARTNER_LOCATION_ID, dest_location_id) + srt_picking.write({ - 'location_id': PARTNER_LOCATION_ID, - 'location_dest_id': BU_OUTPUT_LOCATION_ID, 'group_id': bu_out.group_id.id, 'tukar_guling_id': record.id, 'sale_order': record.origin @@ -597,12 +749,11 @@ class TukarGuling(models.Model): ### ======== ORT dari BU/PICK ========= ort_pickings = [] is_retur_from_bu_pick = record.operations.picking_type_id.id == 30 - picks_to_return = [record.operations] if is_retur_from_bu_pick else mapping_koli.mapped('pick_id') or line.product_uom_qty + picks_to_return = [record.operations] if is_retur_from_bu_pick else mapping_koli.mapped('pick_id') for pick in picks_to_return: ort_return_lines = [] if is_retur_from_bu_pick: - # Ambil dari tukar.guling.line for line in record.line_ids: move = pick.move_lines.filtered(lambda m: m.product_id == line.product_id) if not move: @@ -613,9 +764,9 @@ class TukarGuling(models.Model): 'quantity': line.product_uom_qty, 'move_id': move.id, })) - _logger.info(f"📟 ORT (BU/PICK langsung) | {pick.name} | {line.product_id.display_name} | qty={line.product_uom_qty}") + _logger.info( + f"📟 ORT (BU/PICK langsung) | {pick.name} | {line.product_id.display_name} | qty={line.product_uom_qty}") else: - # Ambil dari mapping koli for mk in mapping_koli.filtered(lambda m: m.pick_id == pick): move = pick.move_lines.filtered(lambda m: m.product_id == mk.product_id) if not move: @@ -626,7 +777,8 @@ class TukarGuling(models.Model): 'quantity': mk.qty_return, 'move_id': move.id, })) - _logger.info(f"📟 ORT (mapping koli) | {pick.name} | {mk.product_id.display_name} | qty={mk.qty_return}") + _logger.info( + f"📟 ORT (mapping koli) | {pick.name} | {mk.product_id.display_name} | qty={mk.qty_return}") if ort_return_lines: ort_wizard = self.env['stock.return.picking'].with_context({ @@ -637,27 +789,27 @@ class TukarGuling(models.Model): }).create({ 'picking_id': pick.id, 'location_id': BU_OUTPUT_LOCATION_ID, - 'original_location_id': BU_STOCK_LOCATION_ID, 'product_return_moves': ort_return_lines }) + ort_vals = ort_wizard.create_returns() ort_picking = self.env['stock.picking'].browse(ort_vals['res_id']) + _force_locations(ort_picking, BU_OUTPUT_LOCATION_ID, BU_STOCK_LOCATION_ID) + ort_picking.write({ - 'location_id': BU_OUTPUT_LOCATION_ID, - 'location_dest_id': BU_STOCK_LOCATION_ID, 'group_id': bu_out.group_id.id, 'tukar_guling_id': record.id, 'sale_order': record.origin }) + created_returns.append(ort_picking) ort_pickings.append(ort_picking) _logger.info(f"✅ ORT created: {ort_picking.name}") record.message_post( body=f"📦 <b>{ort_picking.name}</b> created by <b>{self.env.user.name}</b> (state: <b>{ort_picking.state}</b>)") - ### ======== Tukar Guling: BU/OUT dan BU/PICK baru ======== + ### ======== BU/PICK & BU/OUT Baru dari SRT/ORT ======== if record.return_type == 'tukar_guling': - # BU/PICK Baru dari ORT for ort_p in ort_pickings: return_lines = [] @@ -683,19 +835,18 @@ class TukarGuling(models.Model): }).create({ 'picking_id': ort_p.id, 'location_id': BU_STOCK_LOCATION_ID, - 'original_location_id': BU_OUTPUT_LOCATION_ID, 'product_return_moves': return_lines }) bu_pick_vals = bu_pick_wizard.create_returns() new_pick = self.env['stock.picking'].browse(bu_pick_vals['res_id']) + _force_locations(new_pick, BU_STOCK_LOCATION_ID, BU_OUTPUT_LOCATION_ID) + new_pick.write({ - 'location_id': BU_STOCK_LOCATION_ID, - 'location_dest_id': BU_OUTPUT_LOCATION_ID, 'group_id': bu_out.group_id.id, 'tukar_guling_id': record.id, 'sale_order': record.origin }) - new_pick.action_assign() # Penting agar bisa trigger check koli + new_pick.action_assign() new_pick.action_confirm() created_returns.append(new_pick) _logger.info(f"✅ BU/PICK Baru dari ORT created: {new_pick.name}") @@ -723,14 +874,13 @@ class TukarGuling(models.Model): }).create({ 'picking_id': srt_picking.id, 'location_id': BU_OUTPUT_LOCATION_ID, - 'original_location_id': PARTNER_LOCATION_ID, 'product_return_moves': return_lines }) bu_out_vals = bu_out_wizard.create_returns() new_out = self.env['stock.picking'].browse(bu_out_vals['res_id']) + _force_locations(new_out, BU_OUTPUT_LOCATION_ID, PARTNER_LOCATION_ID) + new_out.write({ - 'location_id': BU_OUTPUT_LOCATION_ID, - 'location_dest_id': PARTNER_LOCATION_ID, 'group_id': bu_out.group_id.id, 'tukar_guling_id': record.id, 'sale_order': record.origin @@ -808,18 +958,17 @@ class StockPicking(models.Model): message = _( "📦 <b>%s</b> Validated by <b>%s</b> Status Changed <b>%s</b> at <b>%s</b>." ) % ( - picking.name, - # picking.picking_type_id.name, - picking.env.user.name, - picking.state, - fields.Datetime.now().strftime("%d/%m/%Y %H:%M") - ) + picking.name, + # picking.picking_type_id.name, + picking.env.user.name, + picking.state, + fields.Datetime.now().strftime("%d/%m/%Y %H:%M") + ) picking.tukar_guling_id.message_post(body=message) return res - class TukarGulingMappingKoli(models.Model): _name = 'tukar.guling.mapping.koli' _description = 'Mapping Koli di Tukar Guling' @@ -830,6 +979,7 @@ class TukarGulingMappingKoli(models.Model): qty_done = fields.Float(string='Qty Done BU PICK') qty_return = fields.Float(string='Qty diretur') sequence = fields.Integer(string='Sequence', default=10) + @api.constrains('qty_return') def _check_qty_return_editable(self): for rec in self: @@ -840,4 +990,4 @@ class TukarGulingMappingKoli(models.Model): for rec in self: if rec.tukar_guling_id and rec.tukar_guling_id.state not in ['draft', 'cancel']: raise UserError("Tidak bisa menghapus Mapping Koli karena status Tukar Guling bukan Draft atau Cancel.") - return super(TukarGulingMappingKoli, self).unlink()
\ No newline at end of file + return super(TukarGulingMappingKoli, self).unlink() |
