summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-01-16 10:30:17 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-01-16 10:30:17 +0700
commit3d672f12eecd77af9a805cebd8ce3a7083957a1f (patch)
treeff079f6e18d9d38653aec79a55ef4f89778728a0
parent27f333cc14b8673b3c46e1969736d2fb60d9924f (diff)
wms push
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rw-r--r--indoteknik_custom/models/stock_move.py4
-rw-r--r--indoteknik_custom/models/stock_picking.py234
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv2
-rw-r--r--indoteknik_custom/views/stock_backorder_confirmation_views.xml14
-rw-r--r--indoteknik_custom/views/stock_picking.xml23
6 files changed, 226 insertions, 52 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index d44f85db..1ffe9419 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -150,6 +150,7 @@
'views/form_vendor_approval_multi_approve.xml',
'views/form_vendor_approval_multi_reject.xml',
'views/user_pengajuan_tempo.xml',
+ 'views/stock_backorder_confirmation_views.xml',
'report/report.xml',
'report/report_banner_banner.xml',
'report/report_banner_banner2.xml',
diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py
index e1d4e74c..6b631713 100644
--- a/indoteknik_custom/models/stock_move.py
+++ b/indoteknik_custom/models/stock_move.py
@@ -12,9 +12,13 @@ class StockMove(models.Model):
default=lambda self: self.product_id.print_barcode,
)
qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant')
+ barcode = fields.Char(string='Barcode', related='product_id.barcode')
def _compute_qr_code_variant(self):
for rec in self:
+ if rec.picking_id.picking_type_code == 'outgoing' and rec.picking_id and rec.picking_id.origin and rec.picking_id.origin.startswith('SO/'):
+ rec.qr_code_variant = rec.product_id.qr_code_variant
+ rec.print_barcode = True
if rec.print_barcode and rec.print_barcode == True and rec.product_id and rec.product_id.qr_code_variant:
rec.qr_code_variant = rec.product_id.qr_code_variant
else:
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index cd330aeb..05a7ee4a 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -16,7 +16,8 @@ _logger = logging.getLogger(__name__)
class StockPicking(models.Model):
_inherit = 'stock.picking'
- # check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True)
+ check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True)
+ barcode_product_lines = fields.One2many('barcode.product', 'picking_id', string='Barcode Product', auto_join=True)
is_internal_use = fields.Boolean('Internal Use', help='flag which is internal use or not')
account_id = fields.Many2one('account.account', string='Account')
efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak')
@@ -176,7 +177,8 @@ class StockPicking(models.Model):
pickings = self.env['stock.picking'].search([
('picking_type_code', '=', 'outgoing'),
('state', '=', 'done'),
- ('carrier_id', '=', 9)
+ ('carrier_id', '=', 9),
+ ('lalamove_order_id', '!=', False)
])
for picking in pickings:
try:
@@ -810,7 +812,24 @@ class StockPicking(models.Model):
self.date_done = datetime.datetime.utcnow()
self.state_reserve = 'done'
return res
-
+
+
+ def check_qty_done_stock(self):
+ for line in self.move_line_ids_without_package:
+ def check_qty_per_inventory(self, product, location):
+ quant = self.env['stock.quant'].search([
+ ('product_id', '=', product.id),
+ ('location_id', '=', location.id),
+ ])
+
+ if quant:
+ return quant.quantity
+
+ return 0
+
+ qty_onhand = check_qty_per_inventory(self, line.product_id, line.location_id)
+ if line.qty_done > qty_onhand:
+ raise UserError('Quantity Done melebihi Quantity Onhand')
def send_mail_bills(self):
if self.picking_type_code == 'incoming' and self.purchase_id:
@@ -1008,48 +1027,167 @@ class StockPicking(models.Model):
return f'{formatted_fastest_eta} - {formatted_longest_eta}'
-# class CheckProduct(models.Model):
-# _name = 'check.product'
-# _description = 'Check Product'
-# _order = 'picking_id, id'
-
-# picking_id = fields.Many2one('stock.picking', string='Picking Reference', required=True, ondelete='cascade', index=True, copy=False)
-# product_id = fields.Many2one('product.product', string='Product')
-
-
-# @api.constrains('product_id')
-# def check_product_validity(self):
-# """
-# Validate if the product exists in the related stock.picking's move_ids_without_package
-# and ensure that the product's quantity does not exceed the available product_uom_qty.
-# """
-# for record in self:
-# if not record.picking_id or not record.product_id:
-# continue
-
-# # Filter move lines in the related picking for the selected product
-# moves = record.picking_id.move_ids_without_package.filtered(
-# lambda move: move.product_id.id == record.product_id.id
-# )
-
-# if not moves:
-# raise UserError((
-# "The product '%s' is not available in the related stock picking's moves. "
-# "Please check and try again."
-# ) % record.product_id.display_name)
-
-# # Calculate the total entries for the product in check.product for the same picking
-# product_entries_count = self.search_count([
-# ('picking_id', '=', record.picking_id.id),
-# ('product_id', '=', record.product_id.id)
-# ])
-
-# # Sum the product_uom_qty for all relevant moves
-# total_qty_in_moves = sum(moves.mapped('product_uom_qty'))
-
-# # Compare the count of entries against the available quantity
-# if product_entries_count > total_qty_in_moves:
-# raise UserError((
-# "The product '%s' exceeds the allowable quantity (%s) in the related stock picking's moves. "
-# "You can only add it %s times."
-# ) % (record.product_id.display_name, total_qty_in_moves, total_qty_in_moves))
+class CheckProduct(models.Model):
+ _name = 'check.product'
+ _description = 'Check Product'
+ _order = 'picking_id, id'
+
+ picking_id = fields.Many2one(
+ 'stock.picking',
+ string='Picking Reference',
+ required=True,
+ ondelete='cascade',
+ index=True,
+ copy=False,
+ )
+ product_id = fields.Many2one('product.product', string='Product', required=True)
+ quantity = fields.Float(string='Quantity', default=1.0, required=True)
+ status = fields.Char(string='Status', compute='_compute_status')
+
+ @api.depends('quantity')
+ def _compute_status(self):
+ for record in self:
+ moves = record.picking_id.move_ids_without_package.filtered(
+ lambda move: move.product_id.id == record.product_id.id
+ )
+ total_qty_in_moves = sum(moves.mapped('product_uom_qty'))
+
+ if record.quantity < total_qty_in_moves:
+ record.status = 'Pending'
+ else:
+ record.status = 'Done'
+
+
+ def create(self, vals):
+ # Create the record
+ record = super(CheckProduct, self).create(vals)
+ # Ensure uniqueness after creation
+ if not self.env.context.get('skip_consolidate'):
+ record.with_context(skip_consolidate=True)._consolidate_duplicate_lines()
+ return record
+
+ def write(self, vals):
+ # Write changes to the record
+ result = super(CheckProduct, self).write(vals)
+ # Ensure uniqueness after writing
+ if not self.env.context.get('skip_consolidate'):
+ self.with_context(skip_consolidate=True)._consolidate_duplicate_lines()
+ return result
+
+ 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.
+ """
+ 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)
+ )
+ # 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
+
+ def _consolidate_duplicate_lines(self):
+ """
+ Consolidate duplicate lines with the same product_id under the same picking_id
+ and sync the total quantity to related moves.
+ """
+ for picking in self.mapped('picking_id'):
+ lines_to_remove = self.env['check.product'] # Recordset untuk menyimpan baris yang akan dihapus
+ product_lines = picking.check_product_lines.filtered(lambda line: line.product_id)
+
+ # Group lines by product_id
+ product_groups = {}
+ for line in product_lines:
+ product_groups.setdefault(line.product_id.id, []).append(line)
+
+ for product_id, lines in product_groups.items():
+ if len(lines) > 1:
+ # Consolidate duplicate lines
+ first_line = lines[0]
+ total_quantity = sum(line.quantity for line in lines)
+
+ # Update the first line's quantity
+ first_line.with_context(skip_consolidate=True).write({'quantity': total_quantity})
+
+ # Add the remaining lines to the lines_to_remove recordset
+ lines_to_remove |= self.env['check.product'].browse([line.id for line in lines[1:]])
+
+ # Perform unlink after consolidation
+ if lines_to_remove:
+ lines_to_remove.unlink()
+
+ # Sync total quantities to moves
+ self._sync_check_product_to_moves(picking)
+
+ @api.onchange('product_id', 'quantity')
+ def check_product_validity(self):
+ for record in self:
+ if not record.picking_id or not record.product_id:
+ continue
+
+ # Filter moves related to the selected product
+ moves = record.picking_id.move_ids_without_package.filtered(
+ lambda move: move.product_id.id == record.product_id.id
+ )
+
+ if not moves:
+ raise UserError((
+ "The product '%s' is not available in the related stock picking's moves. "
+ "Please check and try again."
+ ) % record.product_id.display_name)
+
+ total_qty_in_moves = sum(moves.mapped('product_uom_qty'))
+
+ # Find existing lines for the same product, excluding the current line
+ existing_lines = record.picking_id.check_product_lines.filtered(
+ lambda line: line.product_id == record.product_id and line.id != record.id
+ )
+
+ if existing_lines:
+ # Get the first existing line
+ first_line = existing_lines[0]
+
+ # Calculate the total quantity after addition
+ total_quantity = sum(existing_lines.mapped('quantity')) - record.quantity
+
+ if total_quantity > total_qty_in_moves:
+ raise UserError((
+ "Quantity Product '%s' sudah melebihi quantity demand: (%s)."
+ ) % (record.product_id.display_name))
+
+ else:
+ # Check if the quantity exceeds the allowed total
+ if record.quantity > total_qty_in_moves:
+ raise UserError((
+ "Quantity Product '%s' sudah melebihi quantity demand: (%s)."
+ ) % (record.product_id.display_name))
+
+ # Set the quantity to the entered value
+ record.quantity = record.quantity
+
+class BarcodeProduct(models.Model):
+ _name = 'barcode.product'
+ _description = 'Barcode Product'
+ _order = 'picking_id, id'
+
+ picking_id = fields.Many2one(
+ 'stock.picking',
+ string='Picking Reference',
+ required=True,
+ ondelete='cascade',
+ index=True,
+ copy=False,
+ )
+ product_id = fields.Many2one('product.product', string='Product', required=True)
+ barcode = fields.Char(string='Barcode')
+
+ @api.constrains('barcode')
+ def send_barcode_to_product(self):
+ for record in self:
+ if record.barcode and not record.product_id.barcode:
+ record.product_id.barcode = record.barcode
+ else:
+ raise UserError('Barcode sudah terisi') \ 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 4e1ecd7d..a26bce31 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -149,6 +149,7 @@ access_sales_order_fulfillment_v2,access.sales.order.fulfillment.v2,model_sales_
access_v_move_outstanding,access.v.move.outstanding,model_v_move_outstanding,,1,1,1,1
access_va_multi_approve,access.va.multi.approve,model_va_multi_approve,,1,1,1,1
access_va_multi_reject,access.va.multi.reject,model_va_multi_reject,,1,1,1,1
+access_check_product,access.check.product,model_check_product,,1,1,1,1
access_stock_immediate_transfer,access.stock.immediate.transfer,model_stock_immediate_transfer,,1,1,1,1
access_coretax_faktur,access.coretax.faktur,model_coretax_faktur,,1,1,1,1
access_purchase_order_unlock_wizard,access.purchase.order.unlock.wizard,model_purchase_order_unlock_wizard,,1,1,1,1
@@ -157,3 +158,4 @@ access_User_pengajuan_tempo_line,access.user.pengajuan.tempo.line,model_user_pen
access_user_pengajuan_tempo,access.user.pengajuan.tempo,model_user_pengajuan_tempo,,1,1,1,1
access_reject_reason_wizard,reject.reason.wizard,model_reject_reason_wizard,,1,1,1,0
access_confirm_approval_wizard,confirm.approval.wizard,model_confirm_approval_wizard,,1,1,1,0
+access_barcode_product,access.barcode.product,model_barcode_product,,1,1,1,1 \ No newline at end of file
diff --git a/indoteknik_custom/views/stock_backorder_confirmation_views.xml b/indoteknik_custom/views/stock_backorder_confirmation_views.xml
new file mode 100644
index 00000000..a622899e
--- /dev/null
+++ b/indoteknik_custom/views/stock_backorder_confirmation_views.xml
@@ -0,0 +1,14 @@
+<odoo>
+ <record id="view_backorder_confirmation_inherit" model="ir.ui.view">
+ <field name="name">stock_backorder_confirmation_inherit</field>
+ <field name="model">stock.backorder.confirmation</field>
+ <field name="inherit_id" ref="stock.view_backorder_confirmation"/>
+ <field name="arch" type="xml">
+ <xpath expr="//group/p[1]" position="replace">
+ <p>
+ Ada product yang quantity done nya kurang dari quantity demand.
+ </p>
+ </xpath>
+ </field>
+ </record>
+</odoo>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 8acba608..1c6ae8f7 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -132,6 +132,7 @@
<field name="sale_id" attrs="{'readonly': 1}" optional="hide"/>
<field name="print_barcode" optional="hide"/>
<field name="qr_code_variant" widget="image" optional="hide"/>
+ <field name="barcode" optional="hide"/>
</field>
<page name="note" position="after">
<page string="E-Faktur" name="efaktur" attrs="{'invisible': [['is_internal_use', '=', False]]}">
@@ -191,15 +192,18 @@
</group>
</group>
</page>
- <!-- <page string="Check Product" name="check_product">
+ <page string="Check Product" name="check_product">
<field name="check_product_lines"/>
- </page> -->
+ </page>
+ <page string="Barcode Product" name="barcode_product" attrs="{'invisible': [('picking_type_code', '!=', 'incoming')]}">
+ <field name="barcode_product_lines"/>
+ </page>
</page>
</field>
</record>
- <!-- <record id="check_product_tree" model="ir.ui.view">
+ <record id="check_product_tree" model="ir.ui.view">
<field name="name">check.product.tree</field>
<field name="model">check.product</field>
<field name="arch" type="xml">
@@ -209,7 +213,18 @@
<field name="status"/>
</tree>
</field>
- </record> -->
+ </record>
+
+ <record id="barcode_product_tree" model="ir.ui.view">
+ <field name="name">barcode.product.tree</field>
+ <field name="model">barcode.product</field>
+ <field name="arch" type="xml">
+ <tree editable="bottom">
+ <field name="product_id"/>
+ <field name="barcode"/>
+ </tree>
+ </field>
+ </record>
<record id="view_stock_move_line_detailed_operation_tree_inherit" model="ir.ui.view">
<field name="name">stock.move.line.operations.tree.inherit</field>