299 lines
14 KiB
Python
Executable File
299 lines
14 KiB
Python
Executable File
from odoo import models, fields, api
|
|
from odoo.exceptions import UserError
|
|
from odoo.exceptions import ValidationError
|
|
from datetime import datetime,date,timedelta
|
|
|
|
class FIR_Only(models.Model):
|
|
_name = 'sos_fir'
|
|
_description = 'Final Inspection Report'
|
|
_rec_name='fir_no'
|
|
_order = 'id desc'
|
|
|
|
fir_no = fields.Char(string="FIR No",default=lambda self: self._generate_id(),readonly= True, required= True)
|
|
fir_date = fields.Date(string="FIR Date")
|
|
fg_name = fields.Many2many('sos_fg', string='FG Name')
|
|
product_type = fields.Selection(
|
|
[
|
|
('BHMS 1.2V', 'BHMS 1.2V'),
|
|
('BHMS 2V', 'BHMS 2V'),
|
|
('BHMS 12V', 'BHMS 12V'),
|
|
('BHMS 48V', 'BHMS 48V'),
|
|
('BMS-HV', 'BMS-HV'),
|
|
('BMS-LV 100A', 'BMS-LV 100A'),
|
|
('BMS-LV 40A', 'BMS-LV 40A'),
|
|
('SBMS 55A', 'SBMS 55A'),
|
|
('MC 250W', 'MC 250W'),
|
|
('HeartTarang', 'HeartTarang')
|
|
],
|
|
string="Product Name")
|
|
plan_ref_no = fields.Many2one('sos_fg_plan', string='Indent Ref No')
|
|
batch_size = fields.Integer(string="Batch Size / Received Quantity")
|
|
batch_No = fields.Char(string="Batch No")
|
|
serial_no = fields.Char(string="Serial No")
|
|
mfg_date = fields.Char(string="Manufacturing Date")
|
|
sampling_size = fields.Integer(string="Sampling Size")
|
|
calibration_line_ids = fields.One2many('sos_calibration_devices_fir_only', 'ref_id',copy=True)
|
|
testing_parameter_line_ids = fields.One2many('sos_fir_line', 'ref_line_id',copy=True)
|
|
approved_qty = fields.Integer(string="Approved Quantity")
|
|
rejected_qty = fields.Integer(string="Rejected Quantity")
|
|
rejection_percentage = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True)
|
|
rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display')
|
|
qc_by_name = fields.Many2one('res.users', string='QC Tested&Provided by Sign')
|
|
qc_by_image = fields.Image(related="qc_by_name.signature_image",string='Prepared by Sign',readonly=True)
|
|
qc_tested_on = fields.Date(string="Approved On")
|
|
reworked_count = fields.Integer(string="Reworked Count",default=0)
|
|
qa_by_name = fields.Many2one('res.users', string='QA by Sign')
|
|
qa_by_image = fields.Image(related="qa_by_name.signature_image",string='Prepared by Sign',readonly=True)
|
|
qa_tested_on = fields.Date(string="Approved On")
|
|
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
|
|
stores_received_by = fields.Many2one('res.users', string='Store Received by Sign')
|
|
stores_received_image = fields.Image(related="stores_received_by.signature_image",string='Stores Received by Sign',readonly=True)
|
|
stores_received_on = fields.Date(string="Stores Received On")
|
|
ncmr_ref = fields.Many2one('sos_ncmr',string="NCMR Reference (If any Rejected)")
|
|
customer_name = fields.Many2one('sos_inventory_customers', string="Customer Name", required=True)
|
|
remarks = fields.Text(string="Remarks")
|
|
test_log = fields.Binary("Test Log", required=False, attachment=True)
|
|
test_log_filename = fields.Char("Test Log Filename")
|
|
rejected_line_ids = fields.One2many('sos_fir_rejected_lines', 'ref_id', string="Finished Goods",copy=True, ondelete='cascade')
|
|
serial_no_line_ids = fields.One2many('sos_fir_serial_no_lines', 'ref_id',copy=True)
|
|
sd_card_data = fields.Binary("SD Card Data", required=False, attachment=True)
|
|
sd_card_data_filename = fields.Char("SD Card Data Filename")
|
|
cloud_data = fields.Binary("Cloud Data", required=False, attachment=True)
|
|
cloud_data_filename = fields.Char("Cloud Data Filename")
|
|
firmware_data = fields.Binary("Firmware Data", required=False, attachment=True)
|
|
firmware_data_filename = fields.Char("Firmware Data Filename")
|
|
serial_no_parse = fields.Text(string="Serial no's to parse")
|
|
def parse_serial_nos(self):
|
|
self.ensure_one()
|
|
if not self.serial_no_parse:
|
|
return
|
|
|
|
# Split into clean serial numbers
|
|
serial_numbers = [
|
|
line.strip() for line in self.serial_no_parse.splitlines() if line.strip()
|
|
]
|
|
|
|
SerialLine = self.env['sos_fir_serial_no_lines']
|
|
|
|
for serial in serial_numbers:
|
|
# Check if already exists for this ref_id
|
|
exists = SerialLine.search([
|
|
('ref_id', '=', self.id),
|
|
('serial_no', '=', serial)
|
|
], limit=1)
|
|
|
|
if not exists:
|
|
SerialLine.create({
|
|
'ref_id': self.id,
|
|
'serial_no': serial,
|
|
'inspection_decision': 'PASS', # default
|
|
})
|
|
|
|
|
|
@api.onchange('batch_size')
|
|
def _onchange_batch_size(self):
|
|
if self._origin and self.batch_size is not False:
|
|
lines = self.env['sos_fir_line'].search([('ref_line_id', '=', self._origin.id)])
|
|
line_values = [
|
|
(1, line.id, {
|
|
'sampled_qty': self.batch_size,
|
|
'accepted_qty': self.batch_size
|
|
}) for line in lines
|
|
]
|
|
self.testing_parameter_line_ids = line_values
|
|
|
|
@api.constrains('test_log_filename', 'sd_card_data_filename', 'cloud_data_filename', 'firmware_data_filename')
|
|
def _check_file_extension(self):
|
|
allowed_extensions = ['xlsx', 'xls', 'csv', 'zip', 'pdf']
|
|
for record in self:
|
|
for field_name in ['test_log_filename', 'sd_card_data_filename', 'cloud_data_filename','firmware_data_filename']:
|
|
file_name = getattr(record, field_name)
|
|
if file_name:
|
|
ext = file_name.split('.')[-1].lower()
|
|
if ext not in allowed_extensions:
|
|
raise ValidationError("Only .pdf, .xlsx, .xls, .csv, and .zip files are allowed!")
|
|
def action_report_fir_btn(self):
|
|
try:
|
|
action = self.env.ref("sos_inventory.action_report_fir").report_action(self)
|
|
return action
|
|
except ValueError as e:
|
|
print(f"Failed to find report action: {e}")
|
|
@api.depends('batch_size', 'rejected_qty')
|
|
def _compute_ppm(self):
|
|
for record in self:
|
|
if record.rejected_qty != 0:
|
|
record.ppm = (record.rejected_qty / record.batch_size) * 10**6
|
|
else:
|
|
record.ppm = 0
|
|
@api.depends('rejection_percentage')
|
|
def _compute_rejected_percentage_display(self):
|
|
for record in self:
|
|
record.rejection_percentage_display = "{:.2f}%".format(record.rejection_percentage)
|
|
@api.depends('batch_size', 'rejected_qty')
|
|
def _compute_rejected_percentage(self):
|
|
for record in self:
|
|
if record.batch_size > 0:
|
|
record.rejection_percentage = (record.rejected_qty / record.batch_size) * 100
|
|
else:
|
|
record.rejection_percentage = 0
|
|
def action_qc_esign_btn(self):
|
|
ncmr_record = False
|
|
sequence_util = self.env['sos_common_scripts']
|
|
ncmr_id = sequence_util.generate_sequence('sos_ncmr', 'NCMR', 'ncmr_no')
|
|
if self.rejected_qty > 0:
|
|
for line in self.rejected_line_ids :
|
|
ncmr_record = self.env['sos_ncmr'].create({
|
|
'ncmr_no': ncmr_id,
|
|
'fg_option':True,
|
|
'material_option':False,
|
|
'sfg_option':False,
|
|
'batch_no':self.batch_No,
|
|
'rejected_qty':line.quantity,
|
|
'fg_name': line.fg_name.id,
|
|
'fir_incoming_doc_ref':self.id,
|
|
'department':'Quality Control'
|
|
})
|
|
self.ncmr_ref = ncmr_record.id
|
|
ncmr_body_html = f"""
|
|
<p>Below <b>NCMR</b> is waiting for your Inspection</p>
|
|
"""
|
|
sequence_util.send_group_email(self.env,'sos_ncmr',ncmr_id,"deenalaura.m@sosaley.in","NCMR Inspection Pending",ncmr_body_html,'sos_inventory.sos_qc_user')
|
|
|
|
# Email part
|
|
body_html = f"""
|
|
<p>Below <b>Final Inspection Report</b> is waiting for your Approval</p>
|
|
"""
|
|
|
|
sequence_util.send_group_email(self.env,"sos_fir",self.id,"deenalaura.m@sosaley.in","FIR Approval Request",body_html,'sos_inventory.sos_qa_user')
|
|
|
|
# Email part ends
|
|
return sequence_util.action_assign_signature(
|
|
self,
|
|
'qc_by_name',
|
|
'qc_tested_on'
|
|
)
|
|
def action_qa_esign_btn(self):
|
|
# Email part
|
|
body_html = f"""
|
|
<p>Below <b>FIR</b> is waiting for your Approval</p>
|
|
"""
|
|
|
|
send_email = self.env['sos_common_scripts']
|
|
send_email.send_group_email(self.env,"sos_fir",self.id,"deenalaura.m@sosaley.in","FIR Approval Request",body_html,'sos_inventory.sos_scg_group_user')
|
|
# Email part ends
|
|
sequence_util = self.env['sos_common_scripts']
|
|
return sequence_util.action_assign_signature(
|
|
self,
|
|
'qa_by_name',
|
|
'qa_tested_on'
|
|
)
|
|
def action_stores_esign_btn(self):
|
|
for serial in self.serial_no_line_ids:
|
|
self.env['sos_serial_nos'].create({
|
|
'customer_name': self.customer_name.id,
|
|
# 'fg_name': self.fg_name.id,
|
|
'serial_no': serial.serial_no,
|
|
'batch_no': self.batch_No,
|
|
'delivery_date': fields.Date.today()
|
|
})
|
|
sequence_util = self.env['sos_common_scripts']
|
|
sequence_util.action_assign_signature(
|
|
self,
|
|
'stores_received_by',
|
|
'stores_received_on',
|
|
'sos_inventory.sos_scg_group_user'
|
|
)
|
|
|
|
|
|
def _generate_id(self):
|
|
sequence_util = self.env['sos_common_scripts']
|
|
return sequence_util.generate_sequence('sos_fir','FIR', 'fir_no')
|
|
|
|
@api.onchange('product_type')
|
|
def _onchange_product_type(self):
|
|
if self.product_type:
|
|
self._load_testing_parameters()
|
|
|
|
# @api.model
|
|
# def create(self, vals):
|
|
# record = super(FIR_Only, self).create(vals)
|
|
# if record.product_type:
|
|
# record._load_testing_parameters()
|
|
# return record
|
|
|
|
# def write(self, vals):
|
|
# result = super(FIR_Only, self).write(vals)
|
|
# if 'product_type' in vals:
|
|
# self._load_testing_parameters()
|
|
# return result
|
|
|
|
def _load_testing_parameters(self):
|
|
if self.product_type:
|
|
testing_parameters = self.env['sos_fir_testing_parameters'].search([('product_type', '=', self.product_type)])
|
|
if not testing_parameters:
|
|
raise UserError('No testing parameters found for this Product.')
|
|
|
|
# Clear any existing lines
|
|
lines = [(5, 0, 0)]
|
|
|
|
sorted_parameters = testing_parameters.fir_parameter_ids.sorted(key=lambda param: param.sequence)
|
|
# Append the sorted parameters
|
|
for param in sorted_parameters:
|
|
lines.append((0, 0, {
|
|
'testing_parameter': param.id,
|
|
'sequence': param.sequence,
|
|
'specification': param.specification,
|
|
'results': param.results,
|
|
'inspection_decision':param.inspection_decision
|
|
}))
|
|
|
|
# Set the sorted lines to testing_parameter_line_ids
|
|
self.testing_parameter_line_ids = lines
|
|
|
|
|
|
class FIR_Only_Line(models.Model):
|
|
_name = 'sos_fir_line'
|
|
_description = 'Final Inspection Report Line Items'
|
|
|
|
ref_line_id = fields.Many2one('sos_fir', ondelete="cascade")
|
|
sequence = fields.Integer(string="sequence")
|
|
testing_parameter = fields.Many2one('sos_fir_testing_parameters_lines', string='Testing Parameter')
|
|
sampled_qty = fields.Integer(string="Sampled Quantity")
|
|
accepted_qty = fields.Integer(string="Accepted Quantity")
|
|
rejected_qty = fields.Integer(string="Rejected Quantity")
|
|
inspection_decision = fields.Selection([('PASS','PASS'),('FAIL','FAIL')],string="Inspection Decision")
|
|
specification = fields.Char(string="Specification")
|
|
results = fields.Text(string="Results")
|
|
|
|
class Calibration_devices(models.Model):
|
|
_name = 'sos_calibration_devices_fir_only'
|
|
_description = 'Calibartion Devices List'
|
|
|
|
ref_id = fields.Many2one('sos_fir', ondelete="cascade")
|
|
calibration_device = fields.Many2one('sos_calibration_devices',string="Equipment Name", required=True)
|
|
identification_No = fields.Char(string="Identification No",related="calibration_device.identification_no")
|
|
certification_No = fields.Char(string="Certification No",related="calibration_device.certification_no")
|
|
calibrated_date = fields.Date(string="Calibrated Date",related="calibration_device.calibrated_on")
|
|
due_date = fields.Date(string="Due Date",related="calibration_device.calibrated_due")
|
|
|
|
class firModel_Rejected_Lines(models.Model):
|
|
_name = 'sos_fir_rejected_lines'
|
|
_description = 'Rejected FG Lines'
|
|
|
|
ref_id = fields.Many2one('sos_fir')
|
|
fg_name = fields.Many2one('sos_fg',string="FG Name")
|
|
quantity = fields.Integer(string="Rejected Quantity")
|
|
available_fg_names = fields.Many2many('sos_fg', compute="_compute_available_fg_names", store=False)
|
|
|
|
@api.depends('ref_id')
|
|
def _compute_available_fg_names(self):
|
|
for record in self:
|
|
record.available_fg_names = record.ref_id.fg_name.ids if record.ref_id else []
|
|
|
|
class BRR_serial_no_Lines(models.Model):
|
|
_name = 'sos_fir_serial_no_lines'
|
|
_description = 'Serial No FIR Line Items'
|
|
|
|
ref_id = fields.Many2one('sos_fir', ondelete="cascade")
|
|
serial_no = fields.Char(string="Serial No")
|
|
inspection_decision = fields.Selection([('PASS','PASS'),('FAIL','FAIL')],string="Inspection Decision",default="PASS") |