summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-08-08 09:16:15 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-08-08 09:16:15 +0700
commit176dd85c3d809c035128847378bf78d96aa0896a (patch)
treedb560e64f6d2ca124849666662e90460f30c8488
parent26b1df8d150a46297d84f24283687c56b81e4e65 (diff)
<miqdad> handle duplicate prod in stock move line
-rw-r--r--indoteknik_custom/models/tukar_guling.py87
1 files changed, 67 insertions, 20 deletions
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py
index 4c7722d5..eadb164c 100644
--- a/indoteknik_custom/models/tukar_guling.py
+++ b/indoteknik_custom/models/tukar_guling.py
@@ -2,6 +2,7 @@ from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
import logging
from datetime import datetime
+from collections import defaultdict
_logger = logging.getLogger(__name__)
@@ -540,7 +541,7 @@ class TukarGuling(models.Model):
])
if self.state == 'approved' and done_ort:
self.state = 'done'
- else:
+ elif self.operations.picking_type_id.id == 30 and self.return_type == 'revisi_so' and not has_bu_pick:
raise UserError("Tidak bisa menentukan jenis retur.")
def action_approve(self):
@@ -676,30 +677,47 @@ class TukarGuling(models.Model):
### ======== SRT dari BU/OUT =========
srt_return_lines = []
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}")
+ move_per_product = defaultdict(list)
+ for move in bu_out.move_lines:
+ move_per_product[move.product_id.id].append(move)
+
+ mapped_product_ids = set(mapping_koli.mapped('product_id').ids)
+
+ for product_id in mapped_product_ids:
+ qty_ret = sum(
+ line.qty_return for line in mapping_koli.filtered(lambda l: l.product_id.id == product_id))
+ if qty_ret <= 0:
+ continue
+
+ product_moves = move_per_product[product_id]
+ if not product_moves:
+ raise UserError(f"❌ Move BU/OUT tidak ditemukan untuk product ID {product_id}")
+
+ if len(product_moves) > 1:
+ _logger.warning(f"🟠 Detected duplicate moves for product {product_id}, picking {bu_out.name}")
+ chosen_move = product_moves[0]
+ else:
+ chosen_move = product_moves[0]
+
srt_return_lines.append((0, 0, {
- 'product_id': prod.id,
- 'quantity': qty_total,
- 'move_id': move.id,
+ 'product_id': product_id,
+ 'quantity': qty_ret,
+ 'move_id': chosen_move.id,
}))
- _logger.info(f"📟 SRT line: {prod.display_name} | qty={qty_total}")
+ _logger.info(f"📟 SRT line: {chosen_move.product_id.display_name} | qty={qty_ret}")
- elif not mapping_koli:
+ else:
+ # --- Fallback ke line_ids jika tidak ada 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}")
+ 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}")
+ _logger.info(f"📟 SRT line (fallback): {line.product_id.display_name} | qty={line.product_uom_qty}")
srt_picking = None
if srt_return_lines:
@@ -738,33 +756,62 @@ class TukarGuling(models.Model):
for pick in picks_to_return:
ort_return_lines = []
+
if is_retur_from_bu_pick:
+ # Build map produk -> move list
+ move_map = defaultdict(list)
+ for move in pick.move_lines:
+ move_map[move.product_id.id].append(move)
+
for line in record.line_ids:
- move = pick.move_lines.filtered(lambda m: m.product_id == line.product_id)
- if not move:
+ moves = move_map.get(line.product_id.id)
+ if not moves:
raise UserError(
f"Move tidak ditemukan di BU/PICK {pick.name} untuk {line.product_id.display_name}")
+
+ chosen_move = moves[0]
+ if len(moves) > 1:
+ _logger.warning(
+ f"🟠 Duplicate move detected for {line.product_id.display_name} in {pick.name}. Using the first move only.")
+ pick.message_post(
+ body=f"🟠 Duplicate move ditemukan untuk produk <b>{line.product_id.display_name}</b>. Hanya 1 move yang dipakai.")
+
ort_return_lines.append((0, 0, {
'product_id': line.product_id.id,
'quantity': line.product_uom_qty,
- 'move_id': move.id,
+ 'move_id': chosen_move.id,
}))
_logger.info(
f"📟 ORT (BU/PICK langsung) | {pick.name} | {line.product_id.display_name} | qty={line.product_uom_qty}")
+
else:
+ # Mapping koli case
+ move_map = defaultdict(list)
+ for move in pick.move_lines:
+ move_map[move.product_id.id].append(move)
+
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:
+ moves = move_map.get(mk.product_id.id)
+ if not moves:
raise UserError(
f"Move tidak ditemukan di BU/PICK {pick.name} untuk {mk.product_id.display_name}")
+
+ chosen_move = moves[0]
+ if len(moves) > 1:
+ _logger.warning(
+ f"🟠 Duplicate move detected for {mk.product_id.display_name} in {pick.name}. Using the first move only.")
+ pick.message_post(
+ body=f"🟠 Duplicate move ditemukan untuk produk <b>{mk.product_id.display_name}</b>. Hanya 1 move yang dipakai.")
+
ort_return_lines.append((0, 0, {
'product_id': mk.product_id.id,
'quantity': mk.qty_return,
- 'move_id': move.id,
+ 'move_id': chosen_move.id,
}))
_logger.info(
f"📟 ORT (mapping koli) | {pick.name} | {mk.product_id.display_name} | qty={mk.qty_return}")
+ # Buat retur jika ada return line
if ort_return_lines:
ort_wizard = self.env['stock.return.picking'].with_context({
'active_id': pick.id,