352 lines
15 KiB
Python
Executable File
352 lines
15 KiB
Python
Executable File
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import models, fields, api
|
|
|
|
|
|
class SOS_FG(models.Model):
|
|
_name = 'sos_fg'
|
|
_description = 'Finished Goods Master'
|
|
_order = 'fg_code asc'
|
|
|
|
fg_code = fields.Char(string="Part No", required= True)
|
|
code_no = fields.Char(string="Code")
|
|
name = fields.Char(string="Product Name", required= True)
|
|
display_name = fields.Char(string="Display Name", required= True)
|
|
qp_no = fields.Char(string="QP No")
|
|
hsn_code = fields.Char(string="HSN Code")
|
|
opening_bal_qty = fields.Float(string="Opening Balance Qty")
|
|
uom = fields.Selection([ ("Nos", "Nos"),('set', 'set'), ('Packs', 'Packs')], default="Nos" , string="UOM")
|
|
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")
|
|
inhand_stock_qty = fields.Integer(string="In-Hand Stock Qty")
|
|
inhand_stock_val = fields.Monetary(string="In-Hand Stock Value", currency_field='currency_id',compute='_compute_stock_val', store=True)
|
|
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')
|
|
blocked_qty = fields.Integer(string="Blocked Qty")
|
|
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)
|
|
description = fields.Text(string="Remarks")
|
|
line_ids_in = fields.One2many(
|
|
'sos_fg_transaction_history', 'ref_id',
|
|
string="FG History - In",
|
|
domain=[('action', '=', 'in')]
|
|
)
|
|
|
|
line_ids_out = fields.One2many(
|
|
'sos_fg_transaction_history', 'ref_id',
|
|
string="FG History - Out",
|
|
domain=[('action', '=', 'out')]
|
|
)
|
|
fg_type = fields.Selection(
|
|
[
|
|
('BHMS', 'BHMS'),
|
|
('LV-BMS', 'BMS-LV'),
|
|
('HV-BMS', 'BMS-HV'),
|
|
('SBMS', 'SBMS'),
|
|
('Motor Controller', 'Motor Controller'),
|
|
('Health Care', 'Health Care')
|
|
],
|
|
default='BHMS',
|
|
string="Type",
|
|
required=True
|
|
)
|
|
sub_type = fields.Many2one(
|
|
'sos.fg.subtype',
|
|
string="Sub Type",
|
|
domain="[('fg_type', '=', fg_type)]"
|
|
)
|
|
sub_type = fields.Selection(
|
|
[
|
|
('1.2V', 'BHMS 1.2V'),
|
|
('2V', 'BHMS 2V'),
|
|
('12V', 'BHMS 12V'),
|
|
('48V', 'BHMS 48V'),
|
|
('100A', 'BMS-LV 100A'),
|
|
('40A', 'BMS-LV 40A'),
|
|
('100A-HV', 'BMS-HV 100A'),
|
|
('250A-HV', 'BMS-HV 250A'),
|
|
('15S Slave-HV', 'BMS-HV 15S Slave'),
|
|
('SBMS55A', 'SBMS 55A'),
|
|
('250W', 'MC 250W'),
|
|
('HeartTarang', 'HeartTarang')
|
|
],
|
|
string="Sub Type",
|
|
required=True
|
|
)
|
|
_sql_constraints = [
|
|
('fg_code_unique', 'UNIQUE(fg_code)', 'The Product Code No must be unique!')
|
|
]
|
|
@api.onchange('fg_type')
|
|
def _onchange_fg_type(self):
|
|
self.sub_type = False
|
|
if self.fg_type == 'BHMS':
|
|
return {'domain': {'sub_type': [('1.2V', 'BHMS 1.2V'),('2V', 'BHMS 2V'),('12V', 'BHMS 12V'),('48V', 'BHMS 48V')]}}
|
|
elif self.fg_type == 'LV-BMS':
|
|
return {'domain': {'sub_type': [('100A', 'BMS-LV 100A'),('40A', 'BMS-LV 40A')]}}
|
|
elif self.fg_type == 'HV-BMS':
|
|
return {'domain': {'sub_type': [('100A-HV', 'BMS-HV 100A'),('250A-HV', 'BMS-HV 250A')]}}
|
|
elif self.fg_type == 'Motor Controller':
|
|
return {'domain': {'sub_type': [('250W', 'MC 250W')]}}
|
|
elif self.fg_type == 'SBMS':
|
|
return {'domain': {'sub_type': [('SBMS55A', 'SBMS 55A')]}}
|
|
elif self.fg_type == 'Health Care':
|
|
return {'domain': {'sub_type': [('HeartTarang', 'HeartTarang') ]}}
|
|
else:
|
|
return {'domain': {'sub_type': []}}
|
|
@api.onchange('sub_type')
|
|
def onchange_sub_type(self):
|
|
if self.sub_type:
|
|
prefix_map = {
|
|
"12V": "H1",
|
|
"1.2V": "H2",
|
|
"2V": "H3",
|
|
"48V": "H4",
|
|
"100A": "M1",
|
|
"40A": "M2",
|
|
"250W": "C1",
|
|
"HeartTarang": "T1"
|
|
}
|
|
prefix = prefix_map.get(self.sub_type, "")
|
|
|
|
self.code_no = prefix if prefix else False
|
|
def action_naming_culture(self):
|
|
print("Test")
|
|
@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
|
|
def action_calculate_msp(self):
|
|
part_no_quantities = {}
|
|
sfg_stores_model = self.env['sos_sfg']
|
|
sfg_line_model = self.env['sos_sfg_plan_msp']
|
|
material_line_model = self.env['sos_material_plan_msp']
|
|
product_bom = self.env['sos_fg_bom'].search([
|
|
('fg_name', '=', self.id),
|
|
('is_primary', '=', True)
|
|
], limit=1)
|
|
if product_bom:
|
|
existing_sfg_lines = sfg_line_model.search([('fg_name', '=', self.id)])
|
|
if existing_sfg_lines:
|
|
existing_sfg_lines.unlink()
|
|
existing_material_lines = material_line_model.search([('fg_name', '=', self.id)])
|
|
if existing_material_lines:
|
|
existing_material_lines.unlink()
|
|
lines = self.env['sos_fg_bom_line'].search([('bom_id', '=', product_bom.id)])
|
|
|
|
for sfg_line in lines:
|
|
sfg_name = sfg_line.sfg_bom_id.name.id # Use the ID for Many2one relationship
|
|
req_sfg_qty = sfg_line.quantity
|
|
sfg_line_model.create({
|
|
'fg_name':self.id,
|
|
'sfg_name': sfg_name,
|
|
'required_qty': req_sfg_qty,
|
|
'unit_price':sfg_line.sfg_bom_id.name.unit_price
|
|
})
|
|
|
|
# sfg_bom = self.env['sos_sfg_bom'].search([
|
|
# ('name', '=', sfg_line.sfg_bom_id.name.id)
|
|
# ])
|
|
# sfg_lines = self.env['sos_sfg_bom_line'].search([('bom_id', '=', sfg_bom.id)])
|
|
# for sfg_line in sfg_lines:
|
|
# for component_id in sfg_line.primary_component_id:
|
|
# req_qty = sfg_line.quantity
|
|
# # If part_no is already in the dictionary, increase the req_qty
|
|
# if component_id.part_no in part_no_quantities:
|
|
# part_no_quantities[component_id.part_no]['req_qty'] += req_qty
|
|
# else:
|
|
# part_no_quantities[component_id.part_no] = {
|
|
# 'req_qty': req_qty,
|
|
# 'part_no_id':component_id.id,
|
|
# 'approx_price':component_id.unit_price
|
|
|
|
# }
|
|
|
|
# for part_no, data in part_no_quantities.items():
|
|
# req_qty = data['req_qty']
|
|
# pick_line = self.env['sos_material_plan_msp'].search([
|
|
# ('fg_name', '=', self.id),
|
|
# ('material_name', '=', data['part_no_id'])
|
|
# ],limit=1)
|
|
# if pick_line:
|
|
# pick_line.write({
|
|
# 'required_qty': pick_line.required_qty + req_qty,
|
|
# })
|
|
# else:
|
|
|
|
|
|
# material_line_model.create({
|
|
# 'material_name': data['part_no_id'],
|
|
# 'fg_name': self.id,
|
|
# 'required_qty': req_qty,
|
|
# 'approx_price':data['approx_price']
|
|
# })
|
|
material_lines = self.env['sos_sfg_bom_line'].search([('fg_bom_id', '=', product_bom.id)])
|
|
|
|
|
|
for material_line in material_lines:
|
|
req_qty = material_line.quantity
|
|
material_line_model.create({
|
|
'fg_name':self.id,
|
|
'material_name': material_line.primary_component_id.id,
|
|
'required_qty': req_qty,
|
|
'approx_price':material_line.primary_component_id.unit_price
|
|
|
|
})
|
|
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'name': 'Calculate MSP',
|
|
'res_model': 'sos_msp_wizard',
|
|
'view_mode': 'form',
|
|
'target': 'new',
|
|
'context': {
|
|
'fg_name': self.id,
|
|
'old_msp':self.msp
|
|
},
|
|
}
|
|
|
|
class SOS_FG_Line(models.Model):
|
|
_name = 'sos_fg_transaction_history'
|
|
_description = 'FG Lines'
|
|
_order = 'date desc'
|
|
|
|
ref_id = fields.Many2one('sos_fg', string="FG", ondelete="cascade")
|
|
component_id = fields.Many2one('sos_fg', 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)
|
|
min_no = fields.Many2one('sos_min', string="Issue Ref No")
|
|
fir_no = fields.Many2one('sos_fir_brr', string="BRR No")
|
|
return_fir_no = fields.Many2one('sos_return_fir', string="Return - BRR No")
|
|
mrn_no = fields.Many2one('sos_mrn', string="Material Return Ref No")
|
|
|
|
|
|
class SOS_Material_Plan_MSP(models.Model):
|
|
_name = 'sos_material_plan_msp'
|
|
_description = 'Material Plan Lines For MSP'
|
|
|
|
material_name = fields.Many2one('sos_material',string="Material Name")
|
|
fg_name = fields.Many2one('sos_fg',string="FG Name")
|
|
company_id = fields.Many2one('res.company', store=True, copy=False,
|
|
string="Company",
|
|
default=lambda self: self.env.user.company_id.id)
|
|
currency_id = fields.Many2one('res.currency', string="Currency",
|
|
related='company_id.currency_id',
|
|
default=lambda
|
|
self: self.env.user.company_id.currency_id.id)
|
|
required_qty = fields.Integer(string='Required Qty')
|
|
approx_price = fields.Monetary(currency_field='currency_id', string='Unit Price')
|
|
total_cost = fields.Monetary(
|
|
currency_field='currency_id',
|
|
string="Total Cost",
|
|
compute="_compute_total_cost",
|
|
store=True
|
|
)
|
|
margin = fields.Float(string='Margin (%)', default="10", store=True)
|
|
final_cost = fields.Monetary(
|
|
currency_field='currency_id',
|
|
string="Final Cost",
|
|
compute="_compute_final_cost",
|
|
inverse="_set_final_cost",
|
|
store=True
|
|
)
|
|
@api.depends('required_qty', 'approx_price')
|
|
def _compute_total_cost(self):
|
|
for record in self:
|
|
record.total_cost = record.required_qty * record.approx_price
|
|
|
|
@api.depends('total_cost', 'margin')
|
|
def _compute_final_cost(self):
|
|
for record in self:
|
|
record.final_cost = record.total_cost + (record.total_cost * (record.margin / 100))
|
|
|
|
def _set_final_cost(self):
|
|
for record in self:
|
|
if record.total_cost > 0:
|
|
record.margin = (record.final_cost / record.total_cost) * 100
|
|
@api.onchange('material_name')
|
|
def _onchange_material_name(self):
|
|
if self.material_name:
|
|
self.approx_price = self.material_name.unit_price
|
|
else:
|
|
self.approx_price = 0.0
|
|
class SOS_SFG_Plan_MSP(models.Model):
|
|
_name = 'sos_sfg_plan_msp'
|
|
_description = 'SFG Plan Lines For MSP'
|
|
|
|
sfg_name = fields.Many2one('sos_sfg',string="SFG Name")
|
|
category = fields.Selection([ ('pcba', 'PCB Board'),('cables', 'Cables & Connectors'),('others', 'Others')], default='pcba' , string="Category", related="sfg_name.category" )
|
|
fg_name = fields.Many2one('sos_fg',string="FG Name")
|
|
company_id = fields.Many2one('res.company', store=True, copy=False,
|
|
string="Company",
|
|
default=lambda self: self.env.user.company_id.id)
|
|
currency_id = fields.Many2one('res.currency', string="Currency",
|
|
related='company_id.currency_id',
|
|
default=lambda
|
|
self: self.env.user.company_id.currency_id.id)
|
|
required_qty = fields.Integer(string='Required Qty')
|
|
unit_price = fields.Monetary(currency_field='currency_id',string="Unit Price")
|
|
total_cost = fields.Monetary(
|
|
currency_field='currency_id',
|
|
string="Total Cost",
|
|
compute="_compute_total_cost",
|
|
store=True
|
|
)
|
|
margin = fields.Float(string='Margin (%)', compute="_compute_margin", store=True)
|
|
final_cost = fields.Monetary(
|
|
currency_field='currency_id',
|
|
string="Final Cost",
|
|
compute="_compute_final_cost",
|
|
inverse="_set_final_cost",
|
|
store=True
|
|
)
|
|
|
|
@api.depends('required_qty', 'unit_price')
|
|
def _compute_total_cost(self):
|
|
for record in self:
|
|
record.total_cost = record.required_qty * record.unit_price
|
|
|
|
@api.depends('total_cost', 'margin')
|
|
def _compute_final_cost(self):
|
|
for record in self:
|
|
record.final_cost = record.total_cost + (record.total_cost * (record.margin / 100))
|
|
|
|
def _set_final_cost(self):
|
|
for record in self:
|
|
if record.total_cost > 0:
|
|
record.margin = (record.final_cost / record.total_cost) * 100
|
|
|
|
@api.depends('category')
|
|
def _compute_margin(self):
|
|
for record in self:
|
|
if record.category == 'pcba':
|
|
record.margin = 42.85 # Default value for PCBA
|
|
else:
|
|
record.margin = 15 # Default value for Other categories
|
|
class SosFgSubType(models.Model):
|
|
_name = 'sos_fg_subtype'
|
|
_description = 'FG Sub Type Master'
|
|
|
|
name = fields.Char(required=True, string="Sub Type Name") # E.g., BHMS 1.2V
|
|
code = fields.Char(string="Code") # Optional
|
|
fg_type = fields.Selection([
|
|
('BHMS', 'BHMS'),
|
|
('LV-BMS', 'BMS-LV'),
|
|
('HV-BMS', 'BMS-HV'),
|
|
('SBMS', 'SBMS'),
|
|
('Motor Controller', 'Motor Controller'),
|
|
('Health Care', 'Health Care')
|
|
], required=True, string="Main FG Type") |