summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-06-21 09:07:05 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-06-21 09:07:05 +0700
commit41b26b7fca60533fe30240d19b972cbe7022f333 (patch)
tree6d8624279cbbfa99dafb56790b77184874852889
parentbce4d940dc90bf50e045a8fde3fd1c7bb53e8562 (diff)
<miqdad> return oke
-rw-r--r--indoteknik_custom/models/stock_picking_return.py127
-rw-r--r--indoteknik_custom/models/tukar_guling.py242
-rw-r--r--indoteknik_custom/views/tukar_guling.xml1
3 files changed, 221 insertions, 149 deletions
diff --git a/indoteknik_custom/models/stock_picking_return.py b/indoteknik_custom/models/stock_picking_return.py
index d6225f1a..74bf6407 100644
--- a/indoteknik_custom/models/stock_picking_return.py
+++ b/indoteknik_custom/models/stock_picking_return.py
@@ -1,10 +1,6 @@
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_round
from odoo import models, fields, api, _
-from odoo.exceptions import UserError
-
-from odoo import models, fields, api, _
-from odoo.exceptions import UserError
class StockReturnPicking(models.TransientModel):
@@ -16,8 +12,7 @@ class StockReturnPicking(models.TransientModel):
], string='Jenis Retur', default='revisi_so')
def create_returns(self):
- """Override method to handle Tukar Guling redirection"""
- if self.return_type == 'tukar_guling':
+ if self._context.get('from_ui', True) and self.return_type == 'tukar_guling':
return self._redirect_to_tukar_guling()
return super(StockReturnPicking, self).create_returns()
@@ -26,53 +21,100 @@ class StockReturnPicking(models.TransientModel):
self.ensure_one()
picking = self.picking_id
- # Gunakan pendekatan yang lebih kompatibel untuk Odoo 14
- # Cari hanya baris yang masih ada dan memiliki quantity > 0
+ # Get valid return lines with better error handling
valid_lines = []
- for line in self.product_return_moves:
- # Periksa apakah baris masih ada di database atau baru dibuat
- if line.id:
- # Untuk baris yang sudah ada di database, pastikan masih ada
- if not self.env['stock.return.picking.line'].browse(line.id).exists():
- continue
- # Baris baru yang belum disimpan tidak memiliki id
- if line.quantity > 0:
- valid_lines.append(line)
+ try:
+ # Refresh the recordset to ensure we have the latest data
+ self.env.cr.execute("SELECT id FROM stock_return_picking_line WHERE wizard_id = %s", (self.id,))
+ line_ids = [row[0] for row in self.env.cr.fetchall()]
+
+ if line_ids:
+ # Use sudo to avoid access rights issues and browse existing lines
+ existing_lines = self.env['stock.return.picking.line'].sudo().browse(line_ids)
+ for line in existing_lines:
+ if line.exists() and line.quantity > 0:
+ valid_lines.append(line)
+
+ # If no lines found via direct query, try the original approach
+ if not valid_lines:
+ for line in self.product_return_moves:
+ if hasattr(line, 'quantity') and line.quantity > 0:
+ # Additional check to ensure the line is valid
+ if line.product_id and line.move_id:
+ valid_lines.append(line)
+
+ except Exception as e:
+ # Fallback: create lines based on picking moves
+ valid_lines = []
+ for move in picking.move_ids_without_package:
+ if move.product_uom_qty > 0 and move.state == 'done':
+ # Create a temporary line object for data extraction
+ temp_line = type('TempLine', (), {
+ 'product_id': move.product_id,
+ 'quantity': move.quantity_done or move.product_uom_qty,
+ 'move_id': move
+ })()
+ valid_lines.append(temp_line)
if not valid_lines:
- raise UserError(_("Please specify at least one product to return with positive quantity."))
+ raise UserError(_("Tidak ada produk yang bisa diretur. Pastikan ada produk dengan quantity > 0."))
# Prepare context for Tukar Guling form
context = {
'default_operations': picking.id,
- 'default_partner_id': picking.partner_id.id,
- 'default_origin': picking.origin or picking.name,
'default_return_type': 'tukar_guling',
'default_date': fields.Datetime.now(),
'default_state': 'draft',
'default_ba_num': _('Retur dari %s') % picking.name,
+ 'from_return_picking': True, # Flag to prevent onchange from overriding lines
}
+ # Set origin
+ if picking.origin:
+ context['default_origin'] = picking.origin
+
+ # Set partner
+ if picking.partner_id:
+ context['default_partner_id'] = picking.partner_id.id
+
+ # Set shipping address
+ if hasattr(picking, 'real_shipping_id') and picking.real_shipping_id:
+ context['default_real_shipping_id'] = picking.real_shipping_id.id
+ elif picking.partner_id:
+ context['default_real_shipping_id'] = picking.partner_id.id
+
# Prepare product lines
line_vals = []
+ sequence = 10
+
for line in valid_lines:
- line_vals.append((0, 0, {
- 'product_id': line.product_id.id,
- 'product_uom_qty': line.quantity,
- 'product_uom': line.product_id.uom_id.id,
- 'name': line.product_id.display_name,
- }))
+ try:
+ # Get quantity - handle both real lines and temp objects
+ quantity = getattr(line, 'quantity', 0)
+ if quantity <= 0:
+ continue
- context['default_line_ids'] = line_vals
+ # Get product
+ product = getattr(line, 'product_id', None)
+ if not product:
+ continue
- # Set SO if available
- if picking.sale_id:
- context['default_so_id'] = picking.sale_id.id
+ line_vals.append((0, 0, {
+ 'sequence': sequence,
+ 'product_id': product.id,
+ 'product_uom_qty': quantity,
+ 'product_uom': product.uom_id.id,
+ 'name': product.display_name,
+ }))
+ sequence += 10
- # Set shipping address
- if picking.partner_id:
- context['default_real_shipping_id'] = picking.partner_id.id
+ except Exception as e:
+ # Skip problematic lines
+ continue
+
+ if line_vals:
+ context['default_line_ids'] = line_vals
return {
'name': _('Tukar Guling'),
@@ -83,13 +125,24 @@ class StockReturnPicking(models.TransientModel):
'context': context,
}
+
class ReturnPickingLine(models.TransientModel):
_inherit = 'stock.return.picking.line'
@api.onchange('quantity')
def _onchange_quantity(self):
+ """Validate quantity against done quantity"""
for rec in self:
- qty_done = rec.move_id.quantity_done
-
- if rec.quantity > qty_done:
- raise UserError(f"Quantity yang Anda masukkan tidak boleh melebihi quantity done yaitu: {qty_done}") \ No newline at end of file
+ if rec.move_id and rec.quantity > 0:
+ # Get quantity done from the move
+ qty_done = rec.move_id.quantity_done
+
+ # If quantity_done is 0, use product_uom_qty as fallback
+ if qty_done == 0:
+ qty_done = rec.move_id.product_uom_qty
+
+ if rec.quantity > qty_done:
+ raise UserError(
+ _("Quantity yang Anda masukkan (%.2f) tidak boleh melebihi quantity done yaitu: %.2f untuk produk %s")
+ % (rec.quantity, qty_done, rec.product_id.name)
+ ) \ No newline at end of file
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py
index 7bcf5e80..bdd2a2f5 100644
--- a/indoteknik_custom/models/tukar_guling.py
+++ b/indoteknik_custom/models/tukar_guling.py
@@ -11,6 +11,11 @@ class TukarGuling(models.Model):
_order = 'date desc, id desc'
_rec_name = 'name'
+ picking_ids = fields.One2many(
+ 'stock.picking',
+ 'tukar_guling_id',
+ string='Transfers')
+
origin = fields.Char(string='Origin SO')
real_shipping_id = fields.Many2one('res.partner', string='Shipping Address')
@@ -44,7 +49,16 @@ class TukarGuling(models.Model):
def _onchange_operations(self):
"""Auto-populate lines ketika operations dipilih"""
if self.operations:
- # Clear existing lines
+ from_return_picking = self.env.context.get('from_return_picking', False) or \
+ self.env.context.get('default_line_ids', False)
+
+ if self.line_ids and from_return_picking:
+ # Hanya update origin, jangan ubah lines
+ if self.operations.origin:
+ self.origin = self.operations.origin
+ return
+
+ # Clear existing lines hanya jika tidak dari return picking
self.line_ids = [(5, 0, 0)]
# Set origin dari operations
@@ -91,10 +105,14 @@ class TukarGuling(models.Model):
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
+ # Clear lines jika operations dikosongkan, kecuali dari return picking
+ from_return_picking = self.env.context.get('from_return_picking', False) or \
+ self.env.context.get('default_line_ids', False)
+ if not from_return_picking:
+ self.line_ids = [(5, 0, 0)]
+
+ self.origin = False
def action_populate_lines(self):
"""Manual button untuk populate lines - sebagai alternatif"""
self.ensure_one()
@@ -272,113 +290,115 @@ class TukarGuling(models.Model):
self.state = 'cancel'
def _create_pickings(self):
- if not self.operations:
- raise UserError("BU/Out harus diisi terlebih dahulu.")
-
- origin_so = self.operations.origin
- if not origin_so:
- raise UserError("BU/OUT tidak memiliki origin (SO), tidak bisa cari BU/PICK.")
-
- # Cari DO dari SO
- get_group_id = self.env['stock.picking'].search([
- ('origin', '=', origin_so),
- ], limit=1)
-
- if not get_group_id:
- raise UserError(f"Delivery Order dari SO {origin_so} tidak ditemukan.")
-
- group_id = get_group_id.group_id.id if get_group_id.group_id else False
-
- Picking = self.env['stock.picking']
- srt_type = self.env['stock.picking.type'].search([
- ('sequence_code', '=', 'SRT')
- ], limit=1)
-
- ort_type = self.env['stock.picking.type'].search([
- ('sequence_code', '=', 'ORT')
- ], limit=1)
-
- # 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.operations.location_dest_id
-
- # 1. BU/SRT: retur dari operations
- srt_picking = Picking.create({
- 'partner_id': self.operations.partner_id.id,
- 'real_shipping_id': self.operations.real_shipping_id.id,
- 'picking_type_id': srt_type.id,
- 'location_id': location_customer.id,
- 'location_dest_id': location_dest_id,
- 'origin': f"Retur {self.operations.name}",
- 'tukar_guling_id': self.id,
- 'group_id': group_id,
- 'move_ids_without_package': [
- (0, 0, {
- 'name': line.name or line.product_id.name,
- 'product_id': line.product_id.id,
- 'product_uom_qty': line.product_uom_qty,
- 'product_uom': line.product_uom.id,
- 'location_id': location_customer.id,
- 'location_dest_id': location_dest_id,
- 'group_id': group_id,
- }) for line in self.line_ids
- ]
- })
- srt_picking.action_confirm()
-
- # 2. Cari BU/PICK dari SO yang sama
- origin_so = self.operations.origin
- if not origin_so:
- raise UserError("BU/OUT tidak memiliki origin (SO), tidak bisa cari BU/PICK.")
-
- pick = Picking.search([
- ('origin', '=', origin_so),
- ('picking_type_id.code', '=', 'internal')
- ], limit=1)
-
- if not pick:
- raise UserError(f"BU/PICK dengan origin {origin_so} tidak ditemukan.")
-
- # 3. BU/ORT: retur dari BU/PICK
- ort_picking = Picking.create({
- 'partner_id': self.operations.partner_id.id,
- 'real_shipping_id': self.operations.real_shipping_id.id,
- 'picking_type_id': ort_type.id,
- 'location_id': location_dest_id,
- 'location_dest_id': location_dest_id_ort,
- 'origin': f"Retur {pick.name}",
- 'tukar_guling_id': self.id,
- 'group_id': group_id,
- 'move_ids_without_package': [
- (0, 0, {
- 'name': line.name or line.product_id.name,
- 'product_id': line.product_id.id,
- 'product_uom_qty': line.product_uom_qty,
- 'product_uom': line.product_uom.id,
- 'location_id': location_dest_id,
- 'location_dest_id': location_dest_id_ort,
- 'group_id': group_id,
- }) for line in self.line_ids
- ]
- })
- for line in self.line_ids:
- move = ort_picking.move_ids_without_package.filtered(
- lambda m: m.product_id == line.product_id
- )[:1]
-
- if move:
- self.env['stock.move.line'].create({
- 'move_id': move.id,
- 'picking_id': ort_picking.id,
- 'product_id': line.product_id.id,
- 'product_uom_id': line.product_uom.id,
- 'qty_done': line.product_uom_qty, # Ambil dari return.picking.line.quantity
- 'location_id': location_customer.id,
- 'location_dest_id': location_dest_id,
+ for record in self:
+ if not record.operations:
+ raise UserError("BU/OUT dari field operations tidak ditemukan.")
+
+ operation_picking = record.operations
+
+ # 1. Cari semua picking DONE berdasarkan origin SO
+ related_pickings = self.env['stock.picking'].search([
+ ('origin', '=', record.origin),
+ ('state', '=', 'done'),
+ ])
+ if not related_pickings:
+ raise UserError("Tidak ditemukan BU/PICK atau BU/OUT dari SO: %s" % record.origin + "Atau masih belum Done")
+
+ # 2. Filter berdasarkan tipe picking
+ bu_pick_to_return = related_pickings.filtered(lambda p: p.picking_type_id.id == 30) # BU/PICK
+ bu_out_to_return = related_pickings.filtered(lambda p: p.picking_type_id.id == 29) # BU/OUT
+
+ if not bu_pick_to_return and not bu_out_to_return:
+ raise UserError("Tidak ada BU/PICK atau BU/OUT yang selesai untuk diretur.")
+
+ created_returns = []
+
+ # Lokasi default untuk retur
+ bu_out_type = self.env['stock.picking.type'].browse(73)
+ bu_stock_type = self.env['stock.picking.type'].browse(74)
+
+ bu_out = bu_out_type.default_location_src_id.id
+ bu_stock = bu_out_type.default_location_dest_id.id
+
+ if not bu_out or not bu_stock:
+ raise UserError("salahwoi")
+
+ partner_location = self.env['stock.location'].browse(2)
+ if not partner_location:
+ raise UserError("Lokasi partner (real_shipping_id) tidak ditemukan pada BU/OUT utama.")
+
+ # Fungsi membuat retur dari picking tertentu
+ def _create_return_from_picking(picking):
+ grup = self.env['stock.picking'].search([('origin', '=', self.operations.origin)])
+ # Tentukan lokasi berdasarkan jenis picking
+ if picking.picking_type_id.id == 29: # BU/OUT → BU/SRT
+ default_location_id = partner_location.id
+ default_location_dest_id = bu_out
+ elif picking.picking_type_id.id == 30: # BU/PICK → BU/ORT
+ default_location_id = bu_out
+ default_location_dest_id = bu_stock
+ else:
+ return None
+
+ return_context = dict(self.env.context)
+ return_context.update({
+ 'active_id': picking.id,
+ 'default_location_id': default_location_id,
+ 'default_location_dest_id': default_location_dest_id,
+ 'from_ui': False,
})
- ort_picking.action_confirm()
- ort_picking.action_assign()
+
+ return_wizard = self.env['stock.return.picking'].with_context(return_context).create({
+ 'picking_id': picking.id,
+ 'location_id': default_location_id,
+ })
+
+ # Buat return lines
+ return_lines = []
+ for move in picking.move_lines:
+ if move.quantity_done > 0:
+ return_lines.append((0, 0, {
+ 'product_id': move.product_id.id,
+ 'quantity': move.quantity_done,
+ 'move_id': move.id,
+ }))
+ if not return_lines:
+ return None
+
+ return_wizard.product_return_moves = return_lines
+
+ _logger.info("Creating return for picking %s", picking.name)
+ _logger.info("Default location src: %s", default_location_id)
+ _logger.info("Default location dest: %s", default_location_dest_id)
+ _logger.info("Move lines: %s", picking.move_lines)
+ return_vals = return_wizard.create_returns()
+ return_id = return_vals.get('res_id')
+
+ if not return_id:
+ raise UserError("Retur gagal dibuat. Hasil create_returns: %s" % str(return_vals))
+
+ picking_obj = self.env['stock.picking'].browse(return_id)
+ for p in picking_obj:
+ p.group_id = self.operations.group_id.id
+ p.origin_tukar_guling_id = record.id
+
+ return picking_obj.name
+
+ # Buat return dari BU/PICK
+ for picking in bu_pick_to_return:
+ name = _create_return_from_picking(picking)
+ if name:
+ created_returns.append(name)
+
+ # Buat return dari BU/OUT
+ for picking in bu_out_to_return:
+ name = _create_return_from_picking(picking)
+ if name:
+ created_returns.append(name)
+
+ if not created_returns:
+ raise UserError("wkwkwk")
+
class TukarGulingLine(models.Model):
_name = 'tukar.guling.line'
@@ -418,4 +438,4 @@ class TukarGulingLine(models.Model):
class StockPicking(models.Model):
_inherit = 'stock.picking'
- origin_tukar_guling_id = fields.Many2one('tukar.guling', string='Tukar Guling Ref') \ No newline at end of file
+ tukar_guling_id = fields.Many2one('tukar.guling', string='Tukar Guling Ref') \ No newline at end of file
diff --git a/indoteknik_custom/views/tukar_guling.xml b/indoteknik_custom/views/tukar_guling.xml
index 765c913d..942f085d 100644
--- a/indoteknik_custom/views/tukar_guling.xml
+++ b/indoteknik_custom/views/tukar_guling.xml
@@ -73,7 +73,6 @@
<h1>
<field name="name" readonly="1" class="oe_inline"/>
</h1>
- <hr/>
</div>
<group>
<group>