summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-07-16 08:47:04 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-07-16 08:47:04 +0700
commit77d3bd2541a52270f03b84e38dd691630bcd82af (patch)
tree7ef3c633591cb1d7fdf0d06e5037c647ba0541b0
parent85caa56671d90cde807c44179680ef790d1a58c5 (diff)
<miqdad> mapping koli tukar guling
-rw-r--r--indoteknik_custom/models/stock_picking.py2
-rw-r--r--indoteknik_custom/models/stock_picking_return.py20
-rw-r--r--indoteknik_custom/models/tukar_guling.py77
-rw-r--r--indoteknik_custom/models/tukar_guling_po.py37
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv3
-rw-r--r--indoteknik_custom/views/tukar_guling.xml155
6 files changed, 179 insertions, 115 deletions
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 7d3d963a..dc5b8ebd 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -2518,6 +2518,8 @@ class KonfirmKoli(models.Model):
copy=False,
)
pick_id = fields.Many2one('stock.picking', string='Pick')
+ product_id = fields.Many2one('product.product', string='Product')
+ qty_done = fields.Float(string='Qty Done')
@api.constrains('pick_id')
def _check_duplicate_pick_id(self):
diff --git a/indoteknik_custom/models/stock_picking_return.py b/indoteknik_custom/models/stock_picking_return.py
index a9781d3c..fa557ce8 100644
--- a/indoteknik_custom/models/stock_picking_return.py
+++ b/indoteknik_custom/models/stock_picking_return.py
@@ -89,6 +89,26 @@ class StockReturnPicking(models.TransientModel):
if line_vals:
context['default_line_ids'] = line_vals
+ if picking.picking_type_id.id == 29:
+ mapping_koli_vals = []
+ sequence = 10
+ returned_product_ids = set()
+
+ # Ambil move lines dari BU/PICK
+ for move_line in picking.move_line_ids_without_package:
+ # Cek apakah produk ini ada di daftar retur dan qty_done > 0
+ if move_line.product_id.id in returned_product_ids and move_line.qty_done > 0:
+ mapping_koli_vals.append((0, 0, {
+ 'sequence': sequence,
+ 'pick_id': picking.id, # ID BU/PICK itu sendiri
+ 'product_id': move_line.product_id.id,
+ 'qty_done': move_line.qty_done,
+ }))
+ sequence += 10
+
+ if mapping_koli_vals:
+ context['default_mapping_koli_ids'] = mapping_koli_vals
+
if picking.purchase_id or 'PO' in picking.origin:
_logger.info("Redirect ke Tukar Guling PO via purchase_id / origin")
return {
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py
index 7e857d02..f0fe13f6 100644
--- a/indoteknik_custom/models/tukar_guling.py
+++ b/indoteknik_custom/models/tukar_guling.py
@@ -55,6 +55,7 @@ class TukarGuling(models.Model):
], default='draft', tracking=True, required=True)
line_ids = fields.One2many('tukar.guling.line', 'tukar_guling_id', string='Product Lines')
+ mapping_koli_ids = fields.One2many('tukar.guling.mapping.koli', 'tukar_guling_id', string='Mapping Koli')
@api.onchange('operations')
def _onchange_operations(self):
@@ -71,10 +72,10 @@ class TukarGuling(models.Model):
# 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)]
+ self.mapping_koli_ids = [(5, 0, 0)] # Clear existing mapping koli juga
# Set origin dari operations
if self.operations.origin:
@@ -94,26 +95,59 @@ class TukarGuling(models.Model):
elif hasattr(self.operations, 'move_lines') and self.operations.move_lines:
moves_to_check = self.operations.move_lines
+ # Collect product data for both lines and mapping koli
+ product_data = {}
for move in moves_to_check:
- _logger.info(
- f"Move: {move.name}, Product: {move.product_id.name if move.product_id else 'No Product'}, Qty: {move.product_uom_qty}, State: {move.state}")
-
- # Ambil semua move yang ada quantity
if move.product_id and move.product_uom_qty > 0:
- lines_data.append((0, 0, {
- 'sequence': sequence,
- 'product_id': move.product_id.id,
- 'product_uom_qty': move.product_uom_qty,
- 'product_uom': move.product_uom.id,
- 'name': move.name or move.product_id.display_name,
- }))
- sequence += 10
+ product_id = move.product_id.id
+ if product_id not in product_data:
+ product_data[product_id] = {
+ 'product': move.product_id,
+ 'qty': move.product_uom_qty,
+ 'uom': move.product_uom.id,
+ 'name': move.name or move.product_id.display_name
+ }
+
+ # Create lines_data for product lines
+ for product_id, data in product_data.items():
+ lines_data.append((0, 0, {
+ 'sequence': sequence,
+ 'product_id': product_id,
+ 'product_uom_qty': data['qty'],
+ 'product_uom': data['uom'],
+ 'name': data['name'],
+ }))
+ sequence += 10
if lines_data:
self.line_ids = lines_data
- _logger.info(f"Created {len(lines_data)} lines")
+ _logger.info(f"Created {len(lines_data)} product lines")
+
+ # Prepare mapping koli based on picking type
+ mapping_koli_data = []
+ sequence = 10
+
+ # Case 1: BU/OUT (picking_type_id.id == 29)
+ if self.operations.picking_type_id.id == 29:
+ # Ambil dari konfirm_koli_lines BU/OUT
+ for koli_line in self.operations.konfirm_koli_lines:
+ if koli_line.pick_id.move_line_ids_without_package.product_id.id in product_data:
+ mapping_koli_data.append((0, 0, {
+ 'sequence': sequence,
+ 'pick_id': koli_line.pick_id.move_line_ids_without_package.picking_id.id,
+ 'product_id': koli_line.pick_id.move_line_ids_without_package.product_id.id,
+ 'qty_done': koli_line.pick_id.move_line_ids_without_package.qty_done
+ }))
+ sequence += 10
+
+
+ if mapping_koli_data:
+ self.mapping_koli_ids = mapping_koli_data
+ _logger.info(f"Created {len(mapping_koli_data)} mapping koli lines")
+ else:
+ _logger.info("No mapping koli lines created")
else:
- _logger.info("No lines created - no valid moves found")
+ _logger.info("No product lines created - no valid moves found")
else:
# Clear lines jika operations dikosongkan, kecuali dari return picking
from_return_picking = self.env.context.get('from_return_picking', False) or \
@@ -121,6 +155,7 @@ class TukarGuling(models.Model):
if not from_return_picking:
self.line_ids = [(5, 0, 0)]
+ self.mapping_koli_ids = [(5, 0, 0)]
self.origin = False
@@ -470,7 +505,6 @@ class TukarGuling(models.Model):
})
return_lines = []
- # 🔥 Hanya pakai qty dari tukar guling line
for line in record.line_ids:
move = picking.move_lines.filtered(lambda m: m.product_id == line.product_id)
if move:
@@ -568,3 +602,14 @@ class StockPicking(models.Model):
_inherit = 'stock.picking'
tukar_guling_id = fields.Many2one('tukar.guling', string='Tukar Guling Ref')
+
+
+class TukarGulingMappingKoli(models.Model):
+ _name = 'tukar.guling.mapping.koli'
+ _description = 'Mapping Koli di Tukar Guling'
+
+ tukar_guling_id = fields.Many2one('tukar.guling', string='Tukar Guling')
+ pick_id = fields.Many2one('stock.picking', string='BU PICK')
+ product_id = fields.Many2one('product.product', string='Product')
+ qty_done = fields.Float(string='Qty Done di BU PICK')
+ sequence = fields.Integer(string='Sequence', default=10)
diff --git a/indoteknik_custom/models/tukar_guling_po.py b/indoteknik_custom/models/tukar_guling_po.py
index 3292eb7d..88c4722a 100644
--- a/indoteknik_custom/models/tukar_guling_po.py
+++ b/indoteknik_custom/models/tukar_guling_po.py
@@ -389,7 +389,7 @@ class TukarGulingPO(models.Model):
if not record.operations:
raise UserError("BU Operations belum dipilih.")
- created_returns = []
+ created_returns = self.env['stock.picking']
group = record.operations.group_id
bu_inputs = bu_puts = self.env['stock.picking']
@@ -404,17 +404,17 @@ class TukarGulingPO(models.Model):
else:
raise UserError("Group ID tidak ditemukan pada BU Operations.")
- PARTNER_LOCATION_ID = 4
- BU_INPUT_LOCATION_ID = 58
- BU_STOCK_LOCATION_ID = 57
-
def _create_return_from_picking(picking):
if not picking:
- return None
+ return self.env['stock.picking']
grup = record.operations.group_id
- # Mapping lokasi sesuai picking type
+ # Tentukan location
+ PARTNER_LOCATION_ID = 4
+ BU_INPUT_LOCATION_ID = 58
+ BU_STOCK_LOCATION_ID = 57
+
if picking.picking_type_id.id == 28:
default_location_id = BU_INPUT_LOCATION_ID
default_location_dest_id = PARTNER_LOCATION_ID
@@ -428,7 +428,7 @@ class TukarGulingPO(models.Model):
default_location_id = PARTNER_LOCATION_ID
default_location_dest_id = BU_INPUT_LOCATION_ID
else:
- return None
+ return self.env['stock.picking']
return_context = dict(self.env.context)
return_context.update({
@@ -444,7 +444,6 @@ class TukarGulingPO(models.Model):
'original_location_id': default_location_id
})
- # Sesuai line tukar guling
return_lines = []
for line in record.line_ids:
move = picking.move_lines.filtered(lambda m: m.product_id == line.product_id)
@@ -456,20 +455,17 @@ class TukarGulingPO(models.Model):
}))
else:
raise UserError(
- _("Tidak ditemukan move line di picking %s untuk produk %s")
- % (picking.name, line.product_id.display_name)
+ _("Tidak ditemukan move line di picking %s untuk produk %s") %
+ (picking.name, line.product_id.display_name)
)
if not return_lines:
- return None
+ raise UserError(_("Tidak ada product line valid untuk retur picking %s") % picking.name)
return_wizard.product_return_moves = return_lines
return_vals = return_wizard.create_returns()
return_picking = self.env['stock.picking'].browse(return_vals.get('res_id'))
- if not return_picking:
- raise UserError("Retur gagal dibuat. Hasil create_returns: %s" % str(return_vals))
-
return_picking.write({
'location_id': default_location_id,
'location_dest_id': default_location_dest_id,
@@ -477,7 +473,6 @@ class TukarGulingPO(models.Model):
'tukar_guling_po_id': record.id,
})
- # Paksa lokasi di move lines juga
for move in return_picking.move_lines:
move.write({
'location_id': default_location_id,
@@ -491,31 +486,31 @@ class TukarGulingPO(models.Model):
# Kalau dari BU INPUT → hanya PRT
prt = _create_return_from_picking(record.operations)
if prt:
- created_returns.append(prt)
+ created_returns |= prt
else:
# 1. Dari BU PUT buat VRT
for bu_put in bu_puts:
vrt = _create_return_from_picking(bu_put)
if vrt:
- created_returns.append(vrt)
+ created_returns |= vrt
# 2. Dari BU INPUT buat PRT
for bu_input in bu_inputs:
prt = _create_return_from_picking(bu_input)
if prt:
- created_returns.append(prt)
+ created_returns |= prt
# 3. Kalau tukar guling buat lanjut INPUT & PUT
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)
if bu_input:
- created_returns.append(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)
if bu_put:
- created_returns.append(bu_put)
+ created_returns |= bu_put
if not created_returns:
raise UserError("Tidak ada dokumen retur yang berhasil dibuat.")
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 85781524..eb646dfb 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -187,4 +187,5 @@ access_approval_payment_term,access.approval.payment.term,model_approval_payment
access_tukar_guling_all_users,tukar.guling.all.users,model_tukar_guling,base.group_user,1,1,1,1
access_tukar_guling_line_all_users,tukar.guling.line.all.users,model_tukar_guling_line,base.group_user,1,1,1,1
access_tukar_guling_po_all_users,tukar.guling.po.all.users,model_tukar_guling_po,base.group_user,1,1,1,1
-access_tukar_guling_line_po_all_users,tukar.guling.line.po.all.users,model_tukar_guling_line_po,base.group_user,1,1,1,1 \ No newline at end of file
+access_tukar_guling_line_po_all_users,tukar.guling.line.po.all.users,model_tukar_guling_line_po,base.group_user,1,1,1,1
+access_tukar_guling_mapping_koli_all_users,tukar.guling.mapping.koli.all.users,model_tukar_guling_mapping_koli,base.group_user,1,1,1,1 \ No newline at end of file
diff --git a/indoteknik_custom/views/tukar_guling.xml b/indoteknik_custom/views/tukar_guling.xml
index 41e9a18d..903a47fd 100644
--- a/indoteknik_custom/views/tukar_guling.xml
+++ b/indoteknik_custom/views/tukar_guling.xml
@@ -36,81 +36,82 @@
</field>
</record>
<!-- Form View -->
- <record id="pengajuan_tukar_guling_form" model="ir.ui.view">
- <field name="name">pengajuan.tukar.guling.form</field>
- <field name="model">tukar.guling</field>
- <field name="arch" type="xml">
- <form>
- <header>
- <button name="action_submit" string="Submit" type="object"
- class="btn-primary"
- attrs="{'invisible': [('state', '!=', 'draft')]}"/>
- <button name="action_approve" string="Approve" type="object"
- class="btn-primary"
- attrs="{'invisible': [('state', 'not in', ['approval_sales', 'approval_logistic', 'approval_finance'])]}"/>
- <button name="action_cancel" string="Cancel" type="object"
- class="btn-secondary"
- attrs="{'invisible': [('state', '=', 'cancel')]}"
- confirm="Are you sure you want to cancel this record?"/>
- <button name="action_draft" string="Set to Draft" type="object"
- class="btn-secondary"
- attrs="{'invisible': [('state', '!=', 'cancel')]}"
- confirm="Are you sure you want to reset this record to draft?"/>
- <field name="state" widget="statusbar" readonly="1"
- statusbar_visible="draft,approval_sales,approval_logistic,approval_finance,done"/>
- </header>
- <sheet>
- <div class="oe_button_box">
- <button name="action_view_picking"
- type="object"
- class="oe_stat_button"
- icon="fa-truck"
- attrs="{'invisible': [('picking_ids', '=', False), ('state', 'in', ['draft', 'approval_sales', 'approval_logistic', 'approval_finance'])]}">
- <field name="picking_ids" widget="statinfo" string="Delivery"/>
- </button>
- </div>
- <div class="oe_title">
- <h1>
- <field name="name" readonly="1" class="oe_inline"/>
- </h1>
- </div>
- <group>
- <group>
- <field name="date" string="Date" readonly="1"/>
- <field name="return_type"/>
- <!-- <field name="ort_num" readonly="1"/>-->
- <!-- <field name="srt_num" readonly="1"/>-->
- <field name="operations" string="Operations"
- attrs="{
- 'required': [('return_type', 'in', ['revisi_so', 'tukar_guling'])]
- }"/>
- <field name="origin" readonly="1"/>
- <!-- <field name="origin_so" readonly="1"/>-->
- </group>
- <group>
- <field name="ba_num" string="Nomor BA"/>
- <field name="notes"/>
- </group>
- </group>
- <!-- Product Lines -->
- <notebook>
- <page string="Product Lines" name="product_lines" create="0" edit="0">
- <field name="line_ids" delete="1" readonly="1">
- <tree string="Product Lines">
- <field name="sequence" widget="handle"/>
- <field name="product_id" required="1"
- options="{'no_create': True, 'no_create_edit': True}"/>
- <field name="name" force_save="1"/>
- <field name="product_uom_qty" string="Quantity"/>
- <field name="product_uom" string="UoM"
- options="{'no_create': True, 'no_create_edit': True}"/>
- </tree>
- </field>
- </page>
- </notebook>
- </sheet>
- </form>
- </field>
- </record>
- </data>
+ <record id="pengajuan_tukar_guling_form" model="ir.ui.view">
+ <field name="name">pengajuan.tukar.guling.form</field>
+ <field name="model">tukar.guling</field>
+ <field name="arch" type="xml">
+ <form>
+ <header>
+ <button name="action_submit" string="Submit" type="object"
+ class="btn-primary"
+ attrs="{'invisible': [('state', '!=', 'draft')]}"/>
+ <button name="action_approve" string="Approve" type="object"
+ class="btn-primary"
+ attrs="{'invisible': [('state', 'not in', ['approval_sales', 'approval_logistic', 'approval_finance'])]}"/>
+ <button name="action_cancel" string="Cancel" type="object"
+ class="btn-secondary"
+ attrs="{'invisible': [('state', '=', 'cancel')]}"/>
+ <button name="action_draft" string="Set to Draft" type="object"
+ class="btn-secondary"
+ attrs="{'invisible': [('state', '!=', 'cancel')]}"/>
+ <field name="state" widget="statusbar" readonly="1"
+ statusbar_visible="draft,approval_sales,approval_logistic,approval_finance,done"/>
+ </header>
+ <sheet>
+ <div class="oe_button_box">
+ <button name="action_view_picking"
+ type="object"
+ class="oe_stat_button"
+ icon="fa-truck"
+ attrs="{'invisible': [('picking_ids', '=', False), ('state', 'in', ['draft', 'approval_sales', 'approval_logistic', 'approval_finance'])]}">
+ <field name="picking_ids" widget="statinfo" string="Delivery"/>
+ </button>
+ </div>
+ <div class="oe_title">
+ <h1>
+ <field name="name" readonly="1" class="oe_inline"/>
+ </h1>
+ </div>
+ <group>
+ <group>
+ <field name="date" string="Date" readonly="1"/>
+ <field name="return_type"/>
+ <field name="operations"
+ attrs="{'required': [('return_type', 'in', ['revisi_so', 'tukar_guling'])]}"/>
+ <field name="origin" readonly="1"/>
+ </group>
+ <group>
+ <field name="ba_num" string="Nomor BA"/>
+ <field name="notes"/>
+ </group>
+ </group>
+ <notebook>
+ <page string="Product Lines" name="product_lines" create="0" edit="0">
+ <field name="line_ids" delete="1" readonly="1">
+ <tree string="Product Lines">
+ <field name="sequence" widget="handle"/>
+ <field name="product_id" required="1"
+ options="{'no_create': True, 'no_create_edit': True}"/>
+ <field name="name" force_save="1"/>
+ <field name="product_uom_qty" string="Quantity"/>
+ <field name="product_uom" string="UoM"
+ options="{'no_create': True, 'no_create_edit': True}"/>
+ </tree>
+ </field>
+ </page>
+ <page string="Mapping Koli" name="mapping_koli" create="0" edit="0">
+ <field name="mapping_koli_ids" readonly="1">
+ <tree>
+ <field name="pick_id"/>
+ <field name="product_id"/>
+ <field name="qty_done"/>
+ </tree>
+ </field>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+ </data>
</odoo> \ No newline at end of file