Slink/sos_inventory/models/sos_fir.py

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")