summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-07-18 14:05:48 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-07-18 14:05:48 +0700
commitc6f3edf6eaf705511b926b961b7ae4fcf017e17f (patch)
treee30d52f5c0b0858f549756f4ae4b63d577794e95
parent82c1a95f447d191018bed2f3a3c93831f6d398cc (diff)
<miqdad> don
-rw-r--r--indoteknik_custom/models/stock_picking_return.py4
-rw-r--r--indoteknik_custom/models/tukar_guling_po.py116
2 files changed, 84 insertions, 36 deletions
diff --git a/indoteknik_custom/models/stock_picking_return.py b/indoteknik_custom/models/stock_picking_return.py
index e274a147..1fc8d088 100644
--- a/indoteknik_custom/models/stock_picking_return.py
+++ b/indoteknik_custom/models/stock_picking_return.py
@@ -5,7 +5,7 @@ import logging
_logger = logging.getLogger(__name__)
-class StockReturnPicking(models.TransientModel):
+class ReturnPicking(models.TransientModel):
_inherit = 'stock.return.picking'
# return_type = fields.Selection([
@@ -26,7 +26,7 @@ class StockReturnPicking(models.TransientModel):
if self._context.get('from_ui', True):
return self._redirect_to_tukar_guling()
- return super(StockReturnPicking, self).create_returns()
+ return super(ReturnPicking, self).create_returns()
def _redirect_to_tukar_guling(self):
"""Redirect ke Tukar Guling SO atau PO form dengan pre-filled data"""
diff --git a/indoteknik_custom/models/tukar_guling_po.py b/indoteknik_custom/models/tukar_guling_po.py
index 997e1963..72417a72 100644
--- a/indoteknik_custom/models/tukar_guling_po.py
+++ b/indoteknik_custom/models/tukar_guling_po.py
@@ -238,7 +238,8 @@ class TukarGulingPO(models.Model):
def _is_already_returned(self, picking):
return self.env['stock.picking'].search_count([
('origin', '=', 'Return of %s' % picking.name),
- ('state', '!=', 'cancel')
+ # ('returned_from_id', '=', picking.id),
+ ('state', 'not in', ['cancel', 'draft']),
]) > 0
def copy(self, default=None):
@@ -286,9 +287,9 @@ class TukarGulingPO(models.Model):
if self.operations.picking_type_id.id == 28 and tipe == 'tukar_guling':
raise UserError("❌ BU/INPUT tidak boleh di retur tukar guling")
- if self.operations.picking_type_id.id != 28:
- if self._is_already_returned(self.operations):
- raise UserError("BU ini sudah pernah diretur oleh dokumen lain.")
+ # if self.operations.picking_type_id.id != 28:
+ # if self._is_already_returned(self.operations):
+ # raise UserError("BU ini sudah pernah diretur oleh dokumen lain.")
if 'operations' in vals and not vals.get('origin'):
picking = self.env['stock.picking'].browse(vals['operations'])
if picking.origin:
@@ -413,6 +414,14 @@ class TukarGulingPO(models.Model):
group = record.operations.group_id
bu_inputs = bu_puts = self.env['stock.picking']
+ # Buat qty map awal dari line_ids
+ bu_input_qty_map = {
+ line.product_id.id: line.product_uom_qty
+ for line in record.line_ids
+ if line.product_id and line.product_uom_qty > 0
+ }
+ bu_put_qty_map = bu_input_qty_map.copy()
+
if group:
po_pickings = self.env['stock.picking'].search([
('group_id', '=', group.id),
@@ -423,27 +432,28 @@ class TukarGulingPO(models.Model):
else:
raise UserError("Group ID tidak ditemukan pada BU Operations.")
- def _create_return_from_picking(picking):
+ def _create_return_from_picking(picking, qty_map):
if not picking:
return self.env['stock.picking']
grup = record.operations.group_id
- # Tentukan location
+ # Tentukan lokasi
PARTNER_LOCATION_ID = 4
BU_INPUT_LOCATION_ID = 58
BU_STOCK_LOCATION_ID = 57
- if picking.picking_type_id.id == 28:
+ picking_type = picking.picking_type_id.id
+ if picking_type == 28:
default_location_id = BU_INPUT_LOCATION_ID
default_location_dest_id = PARTNER_LOCATION_ID
- elif picking.picking_type_id.id == 75:
+ elif picking_type == 75:
default_location_id = BU_STOCK_LOCATION_ID
default_location_dest_id = BU_INPUT_LOCATION_ID
- elif picking.picking_type_id.id == 77:
+ elif picking_type == 77:
default_location_id = BU_INPUT_LOCATION_ID
default_location_dest_id = BU_STOCK_LOCATION_ID
- elif picking.picking_type_id.id == 76:
+ elif picking_type == 76:
default_location_id = PARTNER_LOCATION_ID
default_location_dest_id = BU_INPUT_LOCATION_ID
else:
@@ -464,18 +474,46 @@ class TukarGulingPO(models.Model):
})
return_lines = []
+ moves = getattr(picking, 'move_ids_without_package', False) or picking.move_lines
+
+ for move in moves:
+ product = move.product_id
+ if not product:
+ continue
+
+ pid = product.id
+ available_qty = qty_map.get(pid, 0.0)
+ move_qty = move.product_uom_qty
+ allocate_qty = min(available_qty, move_qty)
+
+ if allocate_qty <= 0:
+ continue
- for move in picking.move_lines:
- line = record.line_ids.filtered(lambda l: l.product_id == move.product_id)
- qty = line.product_uom_qty if line else 0.0
return_lines.append((0, 0, {
- 'product_id': move.product_id.id,
- 'quantity': qty,
+ 'product_id': pid,
+ 'quantity': allocate_qty,
'move_id': move.id,
}))
+ qty_map[pid] -= allocate_qty
+
+ _logger.info(f"📦 Alokasi {allocate_qty} untuk {product.display_name} | Sisa: {qty_map[pid]}")
if not return_lines:
- raise UserError(_("Tidak ada product line valid untuk retur picking %s") % picking.name)
+ # Tukar Guling lanjut dari PRT/VRT
+ if picking.picking_type_id.id in [76, 77]:
+ for move in moves:
+ if move.product_uom_qty > 0:
+ return_lines.append((0, 0, {
+ 'product_id': move.product_id.id,
+ 'quantity': move.product_uom_qty,
+ 'move_id': move.id,
+ }))
+ _logger.info(
+ f"🔁 TG lanjutan: Alokasi {move.product_uom_qty} untuk {move.product_id.display_name}")
+ else:
+ _logger.warning(
+ f"⏭️ Skipped return picking {picking.name}, tidak ada qty yang bisa dialokasikan.")
+ return self.env['stock.picking']
return_wizard.product_return_moves = return_lines
return_vals = return_wizard.create_returns()
@@ -488,42 +526,52 @@ class TukarGulingPO(models.Model):
'tukar_guling_po_id': record.id,
})
- for move in return_picking.move_lines:
- move.write({
- 'location_id': default_location_id,
- 'location_dest_id': default_location_dest_id,
- })
-
return return_picking
- # === Eksekusi pembuatan picking ===
+ # ============================
+ # Eksekusi utama return logic
+ # ============================
+
if record.operations.picking_type_id.id == 28:
- # Kalau dari BU INPUT → hanya PRT
- prt = _create_return_from_picking(record.operations)
+ # Dari BU INPUT langsung buat PRT
+ prt = _create_return_from_picking(record.operations, bu_input_qty_map)
if prt:
created_returns |= prt
else:
- # 1. Dari BU PUT buat VRT
- for bu_put in bu_puts:
- vrt = _create_return_from_picking(bu_put)
+ # ✅ Pairing BU PUT ↔ BU INPUT
+ # Temukan index dari BU PUT yang dipilih user
+ try:
+ bu_put_index = sorted(bu_puts, key=lambda p: p.name).index(record.operations)
+ except ValueError:
+ raise UserError("Dokumen BU PUT yang dipilih tidak ditemukan dalam daftar BU PUT.")
+
+ # Ambil pasangannya di BU INPUT (asumsi urutan sejajar)
+ sorted_bu_puts = sorted(bu_puts, key=lambda p: p.name)
+ sorted_bu_inputs = sorted(bu_inputs, key=lambda p: p.name)
+
+ if bu_put_index >= len(sorted_bu_inputs):
+ raise UserError("Tidak ditemukan pasangan BU INPUT untuk BU PUT yang dipilih.")
+
+ paired = [(sorted_bu_puts[bu_put_index], sorted_bu_inputs[bu_put_index])]
+
+ for bu_put, bu_input in paired:
+ vrt = _create_return_from_picking(bu_put, bu_put_qty_map)
if vrt:
created_returns |= vrt
- # 2. Dari BU INPUT buat PRT
- for bu_input in bu_inputs:
- prt = _create_return_from_picking(bu_input)
+ prt = _create_return_from_picking(bu_input, bu_input_qty_map)
if prt:
created_returns |= prt
- # 3. Kalau tukar guling buat lanjut INPUT & PUT
+ # 🌀 Tukar Guling: buat dokumen baru dari PRT & VRT
if record.return_type == 'tukar_guling':
for prt in created_returns.filtered(lambda p: p.picking_type_id.id == 76):
- bu_input = _create_return_from_picking(prt)
+ bu_input = _create_return_from_picking(prt, bu_input_qty_map)
if bu_input:
created_returns |= bu_input
for vrt in created_returns.filtered(lambda p: p.picking_type_id.id == 77):
- bu_put = _create_return_from_picking(vrt)
+ bu_put = _create_return_from_picking(vrt, bu_put_qty_map)
if bu_put:
created_returns |= bu_put