# -*- coding: utf-8 -*- from odoo import models, fields, api from odoo.exceptions import ValidationError class SOS_Material(models.Model): _name = 'sos_material' _description = 'Materials/Components Master' _rec_name= 'part_no' name = fields.Char(string="Display Name") material_type_id = fields.Many2one('sos_material_types', string="Material Type", required=True,ondelete='cascade') material_sub_type = fields.Many2one('sos_material_sub_types', string="Category", domain="[('material_type_id', '=', material_type_id)]") material_code = fields.Char(string="Material Code") category = fields.Selection([ ('A', 'A'),('B', 'B'),('C', 'C')], default='C' , string="Usual Lead Time") inspection_method = fields.Integer(string='Inspection Method',default=10) part_no = fields.Char(string="Part No", required= True) qp_no = fields.Char(string="QP No") hsn_code = fields.Char(string="HSN Code") uom = fields.Selection([('meters', 'Meters'), ('Packs', 'Packs'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram')], string="Uom",required=True) currency_id = fields.Many2one('res.currency', string='Currency') minimum_stock_qty = fields.Integer(string="Minimum Stock Qty") minimum_order_qty = fields.Integer(string="Minimum Order Qty") blocked_qty = fields.Integer(string="Blocked Qty") std_packing_qty = fields.Integer(string="Standard Packing Qty") inhand_stock_qty = fields.Float(string="In-Hand Stock Qty") opening_bal_qty = fields.Float(string="Opening Balance Qty") inhand_stock_val = fields.Monetary(string="In-Hand Stock Value", currency_field='currency_id', compute='_compute_stock_val', store=True,group_operator="sum") in_transit_stock_qty = fields.Integer(string="In-Transit Qty") in_transit_stock_val = fields.Monetary(string="In-Transit Stock Value", currency_field='currency_id') received_qty = fields.Integer(string="Last Received Qty") received_stock_val = fields.Monetary(string="Last Received Stock Value", currency_field='currency_id') cancelled_qty = fields.Integer(string="Canceled Qty") issued_qty = fields.Integer(string="Issue to Dispatch Qty") issued_val = fields.Monetary(string="Issue to Dispatch Value", currency_field='currency_id') defect_qty = fields.Integer(string="Defect Qty") defect_val = fields.Monetary(string="Defect Value", currency_field='currency_id') order_qty = fields.Integer(string="Required/Order Qty") unit_price = fields.Monetary(string="Unit Price", currency_field='currency_id') msp = fields.Monetary(string="Max Selling Price", currency_field='currency_id') location = fields.Char(string="Location in Stores") image = fields.Image(string="Upload Image",max_height=100,max_width=100) suppliers=fields.Many2many("sos_suppliers",string="Suppliers") description = fields.Text(string="Description") line_ids_in = fields.One2many( 'sos_material_transaction_history', 'ref_id', string="Materials History - In", domain=[('action', '=', 'in')] ) line_ids_out = fields.One2many( 'sos_material_transaction_history', 'ref_id', string="Materials History - Out", domain=[('action', '=', 'out')] ) _sql_constraints = [ ('part_no_unique', 'UNIQUE(part_no)', 'Part No is Already In Our Records') ] @api.constrains('inhand_stock_qty') def _check_inhand_stock_qty(self): for record in self: if record.inhand_stock_qty < 0: raise ValidationError( "The In-hand stock quantity for %s cannot be negative." % ( record.name or record.part_no ) ) def write(self, vals): unit_price_changed = 'unit_price' in vals res = super().write(vals) if unit_price_changed: bom_lines = self.env['sos_sfg_bom_line'].search([ ('primary_component_id', 'in', self.ids) ]) bom_ids = bom_lines.mapped('bom_id') for bom in bom_ids: bom._sync_unit_price_with_sfg() return res @api.depends('unit_price','inhand_stock_qty') def _compute_stock_val(self): for val in self: val.inhand_stock_val = val.unit_price * val.inhand_stock_qty @api.onchange('material_sub_type') def _onchange_material_sub_type(self): if self.material_sub_type: prefix = self.material_sub_type.prefix last_material = self.env['sos_material'].search([ ('material_code', 'like', prefix + '%') ], order='material_code desc', limit=1) if last_material: last_code = last_material.material_code next_number = int(last_code[len(prefix):]) + 1 else: next_number = 1 self.material_code = f"{prefix}{next_number:03d}" class SOS_Material_Line(models.Model): _name = 'sos_material_transaction_history' _description = 'Material Lines' _order = 'date desc' ref_id = fields.Many2one('sos_material', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Part No") action = fields.Selection([('in', 'IN'),('out', 'OUT')], string="Action", default='in') quantity = fields.Integer(string="Quantity") currency_id = fields.Many2one('res.currency', string='Currency') unit_price = fields.Monetary(string="Unit Price", currency_field='currency_id') date = fields.Datetime(string="Date", default=fields.Datetime.now) ir_no = fields.Many2one('sos_ir', string="Material Inward Ref No") min_no = fields.Many2one('sos_min', string="Material Issue Ref No") mrn_no = fields.Many2one('sos_mrn', string="Material Return Ref No")