summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-10-20 16:13:29 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-10-20 16:13:29 +0700
commit826f19a3f5de7747192fd8ed4ba0c247084ed03c (patch)
tree86011a57ff749325b02bbb833ffcc5b967fa4dd7
parentda01b745094082f7efd837bef2a796d8dcede50b (diff)
push locator
-rwxr-xr-xindoteknik_custom/models/__init__.py2
-rw-r--r--indoteknik_custom/models/stock_location.py40
-rw-r--r--indoteknik_custom/models/stock_move.py72
-rw-r--r--indoteknik_custom/models/stock_picking.py33
-rw-r--r--indoteknik_custom/models/stock_quant.py6
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv3
-rw-r--r--indoteknik_custom/views/stock_location.xml25
-rw-r--r--indoteknik_custom/views/stock_quant.xml14
8 files changed, 184 insertions, 11 deletions
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 5ac4d6ca..c6a85b75 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -162,3 +162,5 @@ from . import letter_receivable
from . import sj_tele
from . import partial_delivery
from . import domain_apo
+from . import stock_location
+from . import stock_quant
diff --git a/indoteknik_custom/models/stock_location.py b/indoteknik_custom/models/stock_location.py
new file mode 100644
index 00000000..d075ff2a
--- /dev/null
+++ b/indoteknik_custom/models/stock_location.py
@@ -0,0 +1,40 @@
+from odoo import models, fields, api, _
+from odoo.exceptions import ValidationError
+
+class StockLocation(models.Model):
+ _inherit = 'stock.location'
+
+ rack_level = fields.Integer(
+ string='Sequence',
+ default=1,
+ help='Indicates the vertical rack level (1 = lowest, 4 = highest).'
+ )
+
+ # level = fields.Integer(
+ # string='Rack Level',
+ # default=1,
+ # help='Indicates the vertical rack level (1 = lowest, 4 = highest).'
+ # )
+
+ is_locked = fields.Boolean(
+ string="Locked",
+ default=False,
+ help="Jika dicentang, lokasi ini tidak dapat digunakan untuk reservasi atau penerimaan barang."
+ )
+
+ @api.constrains('rack_level')
+ def _check_rack_level(self):
+ for rec in self:
+ if rec.rack_level < 1 or rec.rack_level > 4:
+ raise ValidationError(_("Rack level harus antara 1 sampai 4."))
+
+ @api.constrains('is_locked')
+ def _sync_locked_quant(self):
+ Quant = self.env['stock.quant']
+ for rec in self:
+ quants = Quant.search([('location_id', '=', rec.id)])
+ if quants:
+ if rec.is_locked:
+ quants.write({'note': 'Locked'})
+ else:
+ quants.write({'note': False})
diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py
index 1da2befe..a0c3ed95 100644
--- a/indoteknik_custom/models/stock_move.py
+++ b/indoteknik_custom/models/stock_move.py
@@ -2,6 +2,8 @@ from odoo import fields, models, api
from odoo.tools.misc import format_date, OrderedSet
from odoo.exceptions import UserError
import logging
+from odoo.tools.float_utils import float_compare, float_is_zero, float_round
+
_logger = logging.getLogger(__name__)
@@ -20,7 +22,7 @@ class StockMove(models.Model):
hold_outgoingg = fields.Boolean('Hold Outgoing', default=False)
product_image = fields.Binary(related="product_id.image_128", string="Product Image", readonly=True)
partial = fields.Boolean('Partial?', default=False)
-
+
# Ambil product uom dari SO line
@api.model
def create(self, vals):
@@ -28,7 +30,66 @@ class StockMove(models.Model):
sale_line = self.env['sale.order.line'].browse(vals['sale_line_id'])
vals['product_uom'] = sale_line.product_uom.id
return super().create(vals)
+
+ def _update_reserved_quantity(
+ self, need, available_quantity, location_id,
+ lot_id=None, package_id=None, owner_id=None, strict=True
+ ):
+ self.ensure_one()
+
+ picking = self.picking_id
+ if picking and 'BU/PICK' in (picking.name or ''):
+ _logger.info(f"[LocatorLogic] Running custom locator logic for {picking.name}")
+
+ # Ambil semua lokasi anak dari source location (ex: BU/Stock)
+ locations = self.env['stock.location'].search([
+ ('id', 'child_of', self.location_id.id),
+ ('usage', '=', 'internal'),
+ ('is_locked', '=', False),
+ # ('id', '!=', 57),
+ ], order='rack_level asc')
+
+ total_reserved = 0.0
+ remaining_need = need
+
+ for loc in locations:
+ if remaining_need <= 0:
+ break
+
+ quants = self.env['stock.quant']._gather(self.product_id, loc)
+ for quant in quants:
+ if quant.available_quantity <= 0:
+ continue
+ qty_to_take = min(quant.available_quantity, remaining_need)
+ _logger.info(
+ f"[LocatorLogic] Reserving {qty_to_take}/{remaining_need} "
+ f"from {loc.display_name} (avail={quant.available_quantity})"
+ )
+
+ reserved_now = super(StockMove, self)._update_reserved_quantity(
+ qty_to_take, quant.available_quantity, quant.location_id,
+ lot_id, package_id, owner_id, strict
+ )
+
+ total_reserved += reserved_now
+ remaining_need -= reserved_now
+
+ if remaining_need <= 0:
+ break
+
+ if total_reserved > 0:
+ _logger.info(f"[LocatorLogic] Total reserved: {total_reserved} / {need}")
+ return total_reserved
+ else:
+ _logger.info("[LocatorLogic] No available stock found in unlocked locations by level order.")
+ return 0
+
+ return super(StockMove, self)._update_reserved_quantity(
+ need, available_quantity, location_id, lot_id, package_id, owner_id, strict
+ )
+
+
# @api.model_create_multi
# def create(self, vals_list):
# moves = super(StockMove, self).create(vals_list)
@@ -194,4 +255,11 @@ class StockMoveLine(models.Model):
move = self.env['stock.move'].browse(vals['move_id'])
if move.product_uom:
vals['product_uom_id'] = move.product_uom.id
- return super().create(vals) \ No newline at end of file
+ return super().create(vals)
+ def _action_done(self):
+ for line in self:
+ if line.location_dest_id and line.location_dest_id.is_locked:
+ raise UserError(f"Lokasi '{line.location_dest_id.display_name}' sedang dikunci dan tidak bisa menerima barang.")
+ if line.location_id and line.location_id.is_locked:
+ raise UserError(f"Lokasi '{line.location_id.display_name}' sedang dikunci dan tidak bisa reserve barang.")
+ return super(StockMoveLine, self)._action_done()
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 4772c433..3491ec26 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -2249,19 +2249,34 @@ class CheckProduct(models.Model):
def _sync_check_product_to_moves(self, picking):
"""
- Sinkronisasi quantity_done di move_ids_without_package
- dengan total quantity dari check.product berdasarkan product_id.
+ Sinkronisasi quantity_done di move_line_ids_without_package
+ berdasarkan total quantity dari check_product_lines per product_id,
+ dan distribusikan ke masing-masing move_line.
"""
for product_id in picking.check_product_lines.mapped('product_id'):
- # Totalkan quantity dari semua baris check.product untuk product_id ini
total_quantity = sum(
- line.quantity for line in
- picking.check_product_lines.filtered(lambda line: line.product_id == product_id)
+ line.quantity
+ for line in picking.check_product_lines.filtered(lambda l: l.product_id == product_id)
)
- # Update quantity_done di move yang relevan
- moves = picking.move_ids_without_package.filtered(lambda move: move.product_id == product_id)
- for move in moves:
- move.quantity_done = total_quantity
+
+ move_lines = picking.move_line_ids_without_package.filtered(lambda m: m.product_id == product_id)
+
+ remaining_qty = total_quantity
+ for move_line in move_lines:
+ # ambil qty yang idealnya diisi (biasanya product_uom_qty - quantity_done)
+ needed = move_line.product_uom_qty - move_line.qty_done
+ if needed <= 0:
+ continue
+
+ # kalau sisa qty cukup, isi penuh; kalau enggak, isi sebagian
+ assigned_qty = min(needed, remaining_qty)
+ move_line.qty_done = assigned_qty
+ remaining_qty -= assigned_qty
+
+ # kalau sisa udah 0, berhenti aja
+ if remaining_qty <= 0:
+ break
+
def _consolidate_duplicate_lines(self):
"""
diff --git a/indoteknik_custom/models/stock_quant.py b/indoteknik_custom/models/stock_quant.py
new file mode 100644
index 00000000..05335115
--- /dev/null
+++ b/indoteknik_custom/models/stock_quant.py
@@ -0,0 +1,6 @@
+from odoo import _, api, fields, models
+
+class StockQuant(models.Model):
+ _inherit = 'stock.quant'
+
+ note = fields.Char(string="Note") \ No newline at end of file
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index a6175b21..53560f44 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -205,3 +205,6 @@ access_unpaid_invoice_view,access.unpaid.invoice.view,model_unpaid_invoice_view,
access_surat_piutang_user,surat.piutang user,model_surat_piutang,,1,1,1,1
access_surat_piutang_line_user,surat.piutang.line user,model_surat_piutang_line,,1,1,1,1
access_sj_tele,access.sj.tele,model_sj_tele,base.group_system,1,1,1,1
+
+access_stock_location,access.stock.location,model_stock_location,,1,1,1,1
+access_stock_quant,access.stock.quant,model_stock_quant,,1,1,1,1 \ No newline at end of file
diff --git a/indoteknik_custom/views/stock_location.xml b/indoteknik_custom/views/stock_location.xml
index 82ab2bc5..af6706e9 100644
--- a/indoteknik_custom/views/stock_location.xml
+++ b/indoteknik_custom/views/stock_location.xml
@@ -5,4 +5,29 @@
<field name="location_id">3</field>
<field name="usage">inventory</field>
</record>
+
+ <record id="view_location_tree_inherit_rack_level" model="ir.ui.view">
+ <field name="name">stock.location.tree.rack_level</field>
+ <field name="model">stock.location</field>
+ <field name="inherit_id" ref="stock.view_location_tree2"/>
+ <field name="arch" type="xml">
+ <field name="complete_name" position="after">
+ <field name="rack_level"/>
+ <field name="is_locked"/>
+ </field>
+ </field>
+ </record>
+
+ <!-- Tambahin field rack_level di Form View -->
+ <record id="view_location_form_inherit_rack_level" model="ir.ui.view">
+ <field name="name">stock.location.form.rack_level</field>
+ <field name="model">stock.location</field>
+ <field name="inherit_id" ref="stock.view_location_form"/>
+ <field name="arch" type="xml">
+ <field name="usage" position="after">
+ <field name="rack_level"/>
+ <field name="is_locked" widget="boolean_toggle"/>
+ </field>
+ </field>
+ </record>
</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/stock_quant.xml b/indoteknik_custom/views/stock_quant.xml
index 107f75f3..a665529e 100644
--- a/indoteknik_custom/views/stock_quant.xml
+++ b/indoteknik_custom/views/stock_quant.xml
@@ -9,6 +9,20 @@
<field name="inventory_quantity" position="after">
<field name="reserved_quantity" readonly="1" />
</field>
+ <field name="value" position="after">
+ <field name="note" readonly="1" />
+ </field>
+ </field>
+ </record>
+
+ <record id="stock_view_stock_quant_tree_inherited" model="ir.ui.view">
+ <field name="name">stock.view_stock_quant_tree_inherited</field>
+ <field name="model">stock.quant</field>
+ <field name="inherit_id" ref="stock.view_stock_quant_tree"/>
+ <field name="arch" type="xml">
+ <field name="value" position="after">
+ <field name="note" readonly="1" />
+ </field>
</field>
</record>
</data>