Slink/sos_inventory/models/sos_fg_plan.py

782 lines
38 KiB
Python
Executable File

from odoo import api, fields, models, _
import logging
_logger = logging.getLogger(__name__)
from odoo.exceptions import ValidationError
from datetime import datetime,date,timedelta
from odoo.exceptions import UserError
import io
import xlsxwriter
from odoo.tools.misc import xlsxwriter
import base64
class SOS_FG_Plan(models.Model):
_name = 'sos_fg_plan'
_description = 'FG Plan'
_rec_name = 'plan_ref_no'
plan_ref_no = fields.Char(
readonly=True, required=True, string='Plan ID',
default=lambda self: self._generate_id()
)
line_ids = fields.One2many('sos_fg_plan_line', 'plan_id', string='Lines', ondelete='cascade')
sfg_line_ids = fields.One2many('sos_sfg_plan_line', 'plan_id', string='SFG Lines', ondelete='cascade')
material_line_ids = fields.One2many('sos_material_plan_line', 'plan_id', string='Lines', ondelete='cascade')
approved_by = fields.Many2one('res.users', string='Approved By')
approval_image = fields.Image(related="approved_by.signature_image",string='Top Management Approval Sign',readonly=True)
approved_on = fields.Datetime(string="Approved On")
prepared_by = fields.Many2one('res.users', string='Planned By')
prepared_image = fields.Image(related="prepared_by.signature_image",string='Prepared By Sign',readonly=True)
prepared_on = fields.Datetime(string="Planned On")
blowup = fields.Boolean(string="Blowup Done",default=False)
target_date = fields.Date(string="Target Date",required=True)
indent_start_date = fields.Date(string="Indent Start Date", default=lambda self: fields.Date.context_today(self))
indent_status = fields.Selection([('open', 'Open'), ('cancel', 'Cancel'), ('hold', 'Hold'), ('close', 'Closed')], string='Indent Status', default="open")
hold_cancel_reason = fields.Text(string='Hold/Cancel Reason')
hold_cancel_by = fields.Many2one('res.users', string='Hold & Cancelled By')
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)
estimated_assembling_charges = fields.Monetary(compute='_compute_assembling_charges', string="SFG Assembling Charges", currency_field='currency_id', readonly=True)
estimated_material_cost = fields.Monetary(compute='_compute_material_charges', string="Material Procurement Cost", currency_field='currency_id', readonly=True)
other_charges = fields.Monetary(string="Transport & Other Charges",currency_field='currency_id')
overall_total = fields.Monetary(compute='_compute_overall_total',string ="Overall Estimated Cost",currency_field='currency_id')
tax_value = fields.Monetary(string="Tax(18%)")
@api.depends('estimated_assembling_charges', 'estimated_material_cost', 'other_charges')
def _compute_overall_total(self):
for record in self:
overall_total = (
(record.estimated_assembling_charges or 0) +
(record.estimated_material_cost or 0) +
(record.other_charges or 0)
)
with_tax = overall_total * (1.18)
record.tax_value = with_tax - overall_total
record.overall_total = with_tax
@api.depends('sfg_line_ids.total_assembling_cost')
def _compute_assembling_charges(self):
for record in self:
record.estimated_assembling_charges = round(sum(line.total_assembling_cost for line in record.sfg_line_ids), 2)
@api.depends('material_line_ids.total_approx_price')
def _compute_material_charges(self):
for record in self:
record.estimated_material_cost = round(sum(line.total_approx_price for line in record.material_line_ids), 2)
def open_reason_wizard(self):
return {
'type': 'ir.actions.act_window',
'res_model': 'hold_cancel_reason_wizard',
'name':'Indent Status Change',
'view_mode': 'form',
'target': 'new',
'context': {
'default_model_id': self.id,
}
}
@api.onchange('target_date', 'indent_start_date')
def _onchange_dates(self):
for record in self:
if record.target_date:
max_target_date = date.today() + timedelta(days=90)
if record.target_date > max_target_date:
raise UserError("Target Date cannot exceed 90 days from the Indent Start Date(Today)")
@api.model
def default_get(self, fields_list):
res = super(SOS_FG_Plan, self).default_get(fields_list)
if 'line_ids' in fields_list and 'line_ids' not in res:
default_lines = self._get_default_lines('sos_fg','fg_name')
res['line_ids'] = [(0, 0, line) for line in default_lines]
if 'sfg_line_ids' in fields_list and 'sfg_line_ids' not in res:
default_lines = self._get_default_lines('sos_sfg','sfg_name')
res['sfg_line_ids'] = [(0, 0, line) for line in default_lines]
if 'material_line_ids' in fields_list and 'material_line_ids' not in res:
default_lines = self._get_default_lines('sos_material','material_name')
res['material_line_ids'] = [(0, 0, line) for line in default_lines]
return res
def _generate_id(self):
model_name = 'sos_fg_plan'
form_name = 'INDENT'
field_name = 'plan_ref_no'
today = fields.Date.today()
year_start = today.year if today.month > 3 else today.year - 1
year_end = year_start + 1
fy = f"{year_start % 100}-{year_end % 100}"
month = today.strftime('%m')
base_sequence_prefix = f"SOS/{form_name}/{fy}/{month}/"
records = self.env[model_name].sudo().search(
[(field_name, 'like', f"{base_sequence_prefix}%")],
order=f"{field_name} desc",
limit=1
)
if records:
last_sequence = records[0][field_name]
last_suffix = last_sequence.split('/')[-1]
if last_suffix.isdigit():
new_suffix = f"{last_suffix}a"
else:
base_num = last_suffix[:-1]
last_alpha = last_suffix[-1]
next_alpha = chr(ord(last_alpha) + 1) if last_alpha < 'z' else 'a'
new_suffix = f"{base_num}{next_alpha}"
else:
new_suffix = '016'
return f"{base_sequence_prefix}{new_suffix}"
def _get_default_lines(self,model,column):
products = self.env[model].search([])
default_lines = []
for product in products:
if (product.order_qty + product.minimum_stock_qty) > product.inhand_stock_qty:
to_be_produce = (product.order_qty + product.minimum_stock_qty) - (product.inhand_stock_qty + product.in_transit_stock_qty)
if to_be_produce > product.minimum_order_qty:
final_qty = to_be_produce
else:
final_qty = product.minimum_order_qty
default_line = {
column: product.id,
'inhand_qty': product.inhand_stock_qty,
'in_transit_stock_qty': product.in_transit_stock_qty,
'minimum_stock_qty': product.minimum_stock_qty,
'required_qty': product.order_qty,
'minimum_order_qty':product.minimum_order_qty,
'approved_cnt':final_qty,
'actual_required_qty':to_be_produce
}
if column == "material_name":
default_line['approx_price'] = product.unit_price
elif column == "sfg_name":
default_line['assembling_cost'] = product.assembling_charges
default_lines.append(default_line)
return default_lines
def send_indent_plan_email(self, email_ids):
template = self.env.ref('sos_inventory.send_indent_plan_email_template')
if template:
template.email_to = ','.join(email_ids)
template.send_mail(self.id, force_send=True)
def get_unique_emails(self):
group_refs = [
'sos_inventory.sos_scg_group_user',
'sos_inventory.sos_scg_group_manager',
'sos_inventory.sos_finance_user',
'sos_inventory.sos_management_user',
'sos_inventory.sos_qc_user',
'sos_inventory.sos_qa_user',
'sos_inventory.sos_production_user'
]
group_ids = [self.env.ref(group_ref).id for group_ref in group_refs]
users = self.env['res.users'].search([('groups_id', 'in', group_ids)])
emails = list(set(users.mapped('email')))
return emails
def action_export_final(self):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
# Define custom headers for each sheet
line_headers = {
'fg_name': 'FG Name',
'approved_cnt': 'Planned Qty'
}
sfg_headers = {
'sfg_name': 'SFG Name',
'actual_required_qty': 'Actual Req Qty ',
'minimum_order_qty': 'Minimum Order Qty',
'assembling_cost':'Assembling Cost per unit',
'total_assembling_cost':'Total Assembling Cost',
'approved_cnt':'Planned Qty'
}
material_headers = {
'material_name': 'Material Name',
'approx_price': 'Unit Price',
'actual_required_qty': 'Field Z Header',
'minimum_order_qty':'Minimum Order Qty',
'total_approx_price':'Approx Price',
'approved_cnt':'Planned Qty'
}
custom_headers = {
'estimated_assembling_charges': 'SFG Assembling Charges',
'estimated_material_cost': 'Material Procurement Cost',
'other_charges': 'Transport & Other Charges',
'tax_value':'Tax (18%)',
'overall_total':'Overall Estimated Cost'
}
self._write_sheet(workbook, 'FG Plan', self.line_ids, line_headers)
self._write_sheet(workbook, 'SFG Plan', self.sfg_line_ids, sfg_headers)
self._write_sheet(workbook, 'Material Plan', self.material_line_ids, material_headers)
# Write the custom sheet with fields from the main model (self) and custom headers
self._write_custom_sheet(workbook, 'Budget', custom_headers)
workbook.close()
output.seek(0)
# Create attachment and initiate download
attachment = self.env['ir.attachment'].create({
'name': f'{self.plan_ref_no}_Export.xlsx',
'type': 'binary',
'datas': base64.b64encode(output.read()),
'res_model': self._name,
'res_id': self.id,
'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
return {
'type': 'ir.actions.act_url',
'url': f'/web/content/{attachment.id}?download=true',
'target': 'self',
}
def _write_sheet(self, workbook, sheet_name, line_records, headers):
"""Write data to each sheet based on specified fields and custom headers."""
worksheet = workbook.add_worksheet(sheet_name)
# Write custom headers
for col, header in enumerate(headers.values()):
worksheet.write(0, col, header)
# Write data rows
for row, record in enumerate(line_records, start=1):
for col, field in enumerate(headers.keys()):
value = getattr(record, field, '')
# Convert value if necessary (Many2one, Date, etc.)
if isinstance(value, models.Model):
worksheet.write(row, col, value.display_name if value else '')
elif isinstance(value, (fields.Date, fields.Datetime)):
worksheet.write(row, col, value.strftime('%Y-%m-%d') if value else '')
else:
worksheet.write(row, col, value)
def _write_custom_sheet(self, workbook, sheet_name, headers):
"""Write a custom sheet with fields from the main model, row by row with custom headers."""
worksheet = workbook.add_worksheet(sheet_name)
# Write each field as a separate row with its custom header and value
for row, (field, header) in enumerate(headers.items()):
# Write the header in the first column
worksheet.write(row, 0, header)
# Retrieve the value for the field and write it in the second column
value = getattr(self, field, '')
# Convert value if necessary (Many2one, Date, etc.)
if isinstance(value, models.Model):
worksheet.write(row, 1, value.display_name if value else '')
elif isinstance(value, (fields.Date, fields.Datetime)):
worksheet.write(row, 1, value.strftime('%Y-%m-%d') if value else '')
else:
worksheet.write(row, 1, value)
def action_top_approver_esign_btn(self):
sequence_util = self.env['sos_common_scripts']
result = sequence_util.action_assign_signature(
self,
'approved_by',
'approved_on',
'sos_inventory.sos_management_user'
)
email_addresses = self.get_unique_emails()
self.send_indent_plan_email(email_addresses)
self.env['sos_audit_log'].create_log('Approval', f'Indent <b>{self.plan_ref_no}</b> approved by {self.env.user.name}')
self.update_store_qty(self.line_ids,self.sfg_line_ids,self.material_line_ids)
self.create_production_plan(self.line_ids)
self.create_procurement_plan(self.material_line_ids)
self.create_fptc(self.line_ids)
self.create_sfg_quotation(self.sfg_line_ids)
def action_report_esign_btn(self):
if self.blowup == False:
self.blowup = True
missing_boms = []
for item in self.line_ids:
if item.approved_cnt != 0:
fg_name = item.fg_name.id
product_bom = self.env['sos_fg_bom'].search([
('fg_name', '=', fg_name),
('is_primary', '=', True)
], limit=1)
if not product_bom:
missing_boms.append(item.fg_name.name)
if missing_boms:
raise UserError(f"BOM for following product(s) are Missing, Delete those for this Indent or add BOM(s) : {', '.join(missing_boms)}")
else:
self.create_sfg_plan(self.line_ids)
self.create_material_plan(self.sfg_line_ids)
else:
raise UserError("Already Blowed up")
def action_approve_esign_btn(self):
body_html = f"""
<p>Below <b>Indent Budget</b> is waiting for your Approval</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_direct_email(self.env,"sos_fg_plan",self.id,"ramachandran.r@sosaley.in","Indent Budget Approval",body_html)
sequence_util = self.env['sos_common_scripts']
result = sequence_util.action_assign_signature(
self,
'prepared_by',
'prepared_on'
)
def update_store_qty(self,line_ids,sfg_line_ids,material_line_ids):
model_names = ['sos_fg', 'sos_sfg', 'sos_material']
for model_name in model_names:
if model_name == 'sos_fg':
column_name = 'fg_name'
line_ids_final = line_ids
elif model_name == 'sos_sfg':
column_name = 'sfg_name'
line_ids_final = sfg_line_ids
else:
column_name = 'material_name'
line_ids_final = material_line_ids
for item in line_ids_final:
f_id = getattr(item, column_name).id
sos_record = self.env[model_name].search([('id', '=', f_id)], limit=1)
if sos_record:
new_in_transit_qty = sos_record.in_transit_stock_qty + item.approved_cnt
sos_record.write({
'order_qty': 0,
'in_transit_stock_qty': new_in_transit_qty,
})
if model_name != "sos_fg":
sos_record.write({
'blocked_qty': sos_record.blocked_qty + item.approved_cnt
})
def create_sfg_quotation(self, line_ids):
quotation_model = self.env['sos_sfg_quote_generation']
quotation_line_model = self.env['sos_sfg_quote_generation_line']
quotation_record = quotation_model.search([('plan_ref_no', '=', self.plan_ref_no)], limit=1)
if not quotation_record:
quotation_record = quotation_model.create({'plan_ref_no': self.plan_ref_no})
for item in line_ids:
if item.approved_cnt != 0:
if item.blowup_action == "yes":
blowup_action_result = "with_materials"
else:
blowup_action_result = "without_materials"
quotation_line_model.create({
'material_name': item.sfg_name.id,
'required_qty': item.approved_cnt,
'inprogress_qty': item.approved_cnt,
'plan_id': quotation_record.id,
'purchase_type':blowup_action_result,
'supplier_name':item.sfg_name.service_providers
})
def create_procurement_plan(self, line_ids):
quotation_model = self.env['sos_quote_generation']
quotation_line_model = self.env['sos_quote_generation_line']
quotation_record = quotation_model.search([('plan_ref_no', '=', self.plan_ref_no)], limit=1)
if not quotation_record:
quotation_record = quotation_model.create({'plan_ref_no': self.plan_ref_no})
for item in line_ids:
if item.approved_cnt != 0:
quotation_line_model.create({
'material_name': item.material_name.id,
'required_qty': item.approved_cnt,
'plan_id': quotation_record.id,
'supplier_name':item.material_name.suppliers
})
def create_material_plan(self, line_ids):
material_stores_model = self.env['sos_material']
material_line_model = self.env['sos_material_plan_line']
# Dictionary to store component quantities
part_no_quantities = {}
# Process each line to populate the quantities
for item in line_ids:
if item.approved_cnt != 0 and item.blowup_action != 'no':
# Fetch the SFG BOM for the current item
sfg_bom = self.env['sos_sfg_bom'].search([
('name', '=', item.sfg_name.id)
], limit=1)
if sfg_bom:
# Fetch SFG BOM lines
sfg_lines = self.env['sos_sfg_bom_line'].search([('bom_id', '=', sfg_bom.id)])
for sfg_line in sfg_lines:
component = sfg_line.primary_component_id
if component:
req_qty = sfg_line.quantity * item.approved_cnt
# Aggregate quantities for the component
if component.part_no in part_no_quantities:
part_no_quantities[component.part_no]['req_qty'] += req_qty
else:
part_no_quantities[component.part_no] = {
'inhand_stock_qty': max(0, component.inhand_stock_qty - component.blocked_qty),
'in_transit_stock_qty': component.in_transit_stock_qty,
'minimum_stock_qty': component.minimum_stock_qty,
'minimum_order_qty': component.minimum_order_qty,
'req_qty': req_qty,
'part_no_id': component.id
}
# Process the aggregated quantities to update or create material plan lines
for part_no, data in part_no_quantities.items():
inhand_stock_qty = data['inhand_stock_qty']
minimum_stock_qty = data['minimum_stock_qty']
req_qty = data['req_qty']
minimum_order_qty = data['minimum_order_qty']
in_transit_stock_qty = data['in_transit_stock_qty']
# Check if the material line already exists
pick_line = material_line_model.search([
('plan_id', '=', self.id),
('material_name', '=', data['part_no_id'])
], limit=1)
if pick_line:
# Update existing material line
pick_line.write({
'actual_required_qty': pick_line.actual_required_qty + req_qty,
'required_qty': pick_line.required_qty + req_qty,
'approved_cnt': pick_line.approved_cnt + (req_qty if pick_line.approved_cnt else 0)
})
else:
# Calculate the approved count if creating a new line
if minimum_stock_qty > (inhand_stock_qty + in_transit_stock_qty) - req_qty:
approved_cnt = max(req_qty + minimum_stock_qty - (inhand_stock_qty + in_transit_stock_qty), minimum_order_qty)
else:
approved_cnt = 0
# Create a new material plan line
material_line_model.create({
'material_name': data['part_no_id'],
'inhand_qty': inhand_stock_qty,
'minimum_stock_qty': minimum_stock_qty,
'plan_id': self.id,
'required_qty': req_qty,
'actual_required_qty': req_qty, # Set correctly for new records
'approved_cnt': approved_cnt,
'minimum_order_qty': minimum_order_qty
})
def create_sfg_plan(self, line_ids):
sfg_stores_model = self.env['sos_sfg']
sfg_line_model = self.env['sos_sfg_plan_line']
# Loop through the lines to process each item
for item in line_ids:
if item.approved_cnt != 0:
fg_name = item.fg_name.id # Use the ID for Many2one relationship
fg_qty_to_produce = int(item.approved_cnt)
# Fetch the primary BOM for the FG
product_bom = self.env['sos_fg_bom'].search([
('fg_name', '=', fg_name),
('is_primary', '=', True)
], limit=1)
if product_bom:
lines = self.env['sos_fg_bom_line'].search([('bom_id', '=', product_bom.id)])
# Fetch existing SFG plan lines for the current plan
old_lines = sfg_line_model.search([('plan_id', '=', self.id)])
already_created_sfg = {line.sfg_name.id: line for line in old_lines}
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 * fg_qty_to_produce
sfg_inhand_qty = max(0, sfg_line.sfg_bom_id.name.inhand_stock_qty - sfg_line.sfg_bom_id.name.blocked_qty)
sfg_minimum_stock_qty = sfg_line.sfg_bom_id.name.minimum_stock_qty
sfg_intransit_stock_qty = sfg_line.sfg_bom_id.name.in_transit_stock_qty
# Calculate approved quantity
if sfg_minimum_stock_qty <= (sfg_inhand_qty + sfg_intransit_stock_qty) - req_sfg_qty:
approved_cnt = 0
else:
#approved_cnt = req_sfg_qty + sfg_minimum_stock_qty - (sfg_inhand_qty + sfg_intransit_stock_qty)
approved_cnt = req_sfg_qty - (sfg_inhand_qty + sfg_intransit_stock_qty)
# If the SFG already exists in the plan, update its values
if sfg_name in already_created_sfg:
existing_line = already_created_sfg[sfg_name]
# Determine the new approved count
if existing_line.actual_required_qty + req_sfg_qty > sfg_line.sfg_bom_id.name.minimum_order_qty:
order_to_be = existing_line.actual_required_qty + req_sfg_qty
else:
order_to_be = sfg_line.sfg_bom_id.name.minimum_order_qty
# Update the existing line
existing_line.write({
'required_qty': existing_line.required_qty + req_sfg_qty,
'actual_required_qty': existing_line.actual_required_qty + req_sfg_qty,
'approved_cnt': order_to_be,
'blowup_action': 'yes'
})
else:
# Create a new SFG plan line
sfg_line_model.create({
'fg_name': fg_name,
'sfg_name': sfg_name,
'inhand_qty': sfg_inhand_qty,
'minimum_stock_qty': sfg_minimum_stock_qty,
'plan_id': self.id,
'actual_required_qty': approved_cnt,
'required_qty': req_sfg_qty,
'approved_cnt': approved_cnt,
'blowup_action': 'yes',
'assembling_cost': sfg_line.sfg_bom_id.name.assembling_charges
})
material_lines = self.env['sos_sfg_bom_line'].search([('fg_bom_id', '=', product_bom.id)])
material_stores_model = self.env['sos_material']
material_line_model = self.env['sos_material_plan_line']
# Fetch existing material plan lines for the current plan
old_lines_material = material_line_model.search([('plan_id', '=', self.id)])
already_created_material = {line_material.material_name.id: line_material for line_material in old_lines_material}
for material_line in material_lines:
inhand_stock_qty = material_line.primary_component_id.inhand_stock_qty
minimum_stock_qty = material_line.primary_component_id.minimum_stock_qty
req_qty = material_line.quantity * fg_qty_to_produce
minimum_order_qty = material_line.primary_component_id.minimum_order_qty
intransit_qty_material = material_line.primary_component_id.in_transit_stock_qty
# Calculate the approved count for the material
if minimum_stock_qty > (inhand_stock_qty + intransit_qty_material) - req_qty:
#approved_cnt_material = max(req_qty + minimum_stock_qty - (inhand_stock_qty + intransit_qty_material), minimum_order_qty)
approved_cnt_material = max(req_qty - (inhand_stock_qty + intransit_qty_material), 0, minimum_order_qty)
else:
approved_cnt_material = 0
# Check if the material already exists in the current plan
if material_line.primary_component_id.id in already_created_material:
existing_line = already_created_material[material_line.primary_component_id.id]
# Accumulate approved_cnt
new_approved_cnt = existing_line.approved_cnt + approved_cnt_material
existing_line.write({
'actual_required_qty': existing_line.actual_required_qty + req_qty,
'required_qty': existing_line.required_qty + req_qty,
'approved_cnt': new_approved_cnt
})
else:
# Create a new material line
material_line_model.create({
'material_name': material_line.primary_component_id.id,
'inhand_qty': inhand_stock_qty,
'minimum_stock_qty': minimum_stock_qty,
'plan_id': self.id,
'minimum_order_qty': minimum_order_qty,
'actual_required_qty': req_qty,
'required_qty': req_qty,
'approved_cnt': approved_cnt_material
})
def create_production_plan(self,line_ids):
indent_model = self.env['sos_production_plan']
indent_record = indent_model.search([('plan_ref_no', '=', self.plan_ref_no)], limit=1)
if not indent_record:
for item in line_ids:
fg_name = item.fg_name.id
qp_no = item.fg_name.qp_no
fg_qty_to_produce = int(item.approved_cnt)
indent_model.create({
'plan_ref_no': self.plan_ref_no,
'fg_name': fg_name,
'qp_no': qp_no,
'required_qty': fg_qty_to_produce,
'target_date': self.target_date,
'indent_start_date' : self.indent_start_date
})
def create_fptc(self,line_ids):
tc_model = self.env['sos_transfer_challan']
tc_record = tc_model.search([('plan_ref_no', '=', self.plan_ref_no)], limit=1)
if not tc_record:
for item in line_ids:
fg_name = item.fg_name.id
tc_record_new = tc_model.create({
'plan_ref_no': self.plan_ref_no,
'planned_qty': item.approved_cnt,
'fg_name': fg_name,
'indent_start_date':self.indent_start_date,
'indent_target_date':self.target_date
})
if tc_record_new:
try:
specifications = self.env['sos_testing_parameters'].search([('fg_name', '=', fg_name)], limit=1)
if not specifications:
continue
lines = [(5, 0, 0)]
for param in specifications.specification_ids:
lines.append((0, 0, {
'specification': param.name,
'specification_value': ''
}))
tc_record_new.specification_line_ids = lines
except Exception as e:
_logger.error("Error processing specifications for FG %s: %s", fg_name, str(e))
continue
class SOS_FG_Plan_Line(models.Model):
_name = 'sos_fg_plan_line'
_description = 'FG Plan Lines'
_order = 'approved_cnt desc'
fg_name = fields.Many2one('sos_fg',string="FG Name")
inhand_qty = fields.Integer(string="FG Stocks")
minimum_stock_qty = fields.Integer(string="Minimum Stock Qty")
in_transit_stock_qty = fields.Integer(string="In-transit Stock Qty")
plan_id = fields.Many2one('sos_fg_plan', string='FG Plan', ondelete='cascade')
required_qty = fields.Integer(string='Required Qty')
actual_required_qty = fields.Integer(string='Actual Req Qty')
minimum_order_qty = fields.Integer(string='Minimum Order Qty')
approved_cnt = fields.Integer(string='Planned Qty', store=True)
planned_week_1 = fields.Integer(string='Week 1')
planned_week_2 = fields.Integer(string='Week 2')
planned_week_3 = fields.Integer(string='Week 3')
planned_week_4 = fields.Integer(string='Week 4')
planned_week_5 = fields.Integer(string='Week 5')
planned_week_6 = fields.Integer(string='Week 6')
planned_week_7 = fields.Integer(string='Week 7')
planned_week_8 = fields.Integer(string='Week 8')
completed_qty = fields.Integer(string='Completed Qty', compute='_compute_completed', store=True)
@api.depends('planned_week_1', 'planned_week_2', 'planned_week_3', 'planned_week_4', 'planned_week_5', 'planned_week_6', 'planned_week_7', 'planned_week_8')
def _compute_completed(self):
for record in self:
total_completed = (
record.planned_week_1 +
record.planned_week_2 +
record.planned_week_3 +
record.planned_week_4 +
record.planned_week_5 +
record.planned_week_6 +
record.planned_week_7 +
record.planned_week_8
)
record.completed_qty = total_completed
class SOS_SFG_Plan_Line(models.Model):
_name = 'sos_sfg_plan_line'
_description = 'SFG Plan Lines'
_order = 'approved_cnt desc'
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)
sfg_name = fields.Many2one('sos_sfg',string="SFG Name")
assembling_cost = fields.Monetary(currency_field='currency_id',string="Assembling Cost per unit")
blowup_action = fields.Selection(
[('yes', 'Yes'), ('no', 'No')],
string='Blowup',default="yes"
)
inhand_qty = fields.Integer(string="SFG Stocks")
minimum_stock_qty = fields.Integer(string="Minimum Stock Qty")
in_transit_stock_qty = fields.Integer(string="In-transit Stock Qty")
minimum_order_qty = fields.Integer(string="Minimum Order Qty")
plan_id = fields.Many2one('sos_fg_plan', string='SFG Plan', ondelete='cascade')
required_qty = fields.Integer(string='Required Qty')
approved_cnt = fields.Integer(string='Planned Qty',default='1')
actual_required_qty = fields.Integer(string='Actual Req Qty')
total_assembling_cost = fields.Float(compute='_compute_total_assembling_cost', string='Total Assembling Cost')
@api.onchange('sfg_name')
def _onchange_sfg_name(self):
for record in self:
if record.sfg_name:
record.assembling_cost = record.sfg_name.assembling_charges
@api.depends('assembling_cost', 'approved_cnt')
def _compute_total_assembling_cost(self):
for record in self:
if record.assembling_cost is not None and record.approved_cnt is not None:
record.total_assembling_cost = record.assembling_cost * record.approved_cnt
else:
record.total_assembling_cost = 0
class SOS_Material_Plan_Line(models.Model):
_name = 'sos_material_plan_line'
_description = 'Material Plan Lines'
_order = 'approved_cnt desc'
material_name = fields.Many2one('sos_material',string="Material 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)
inhand_qty = fields.Integer(string="Material Stocks")
in_transit_stock_qty = fields.Integer(string="In-transit Stock Qty")
minimum_stock_qty = fields.Integer(string="Minimum Stock Qty")
plan_id = fields.Many2one('sos_fg_plan', string='Material Plan', ondelete='cascade')
required_qty = fields.Integer(string='Required Qty')
actual_required_qty = fields.Integer(string='Actual Req Qty')
minimum_order_qty = fields.Integer(string='Minimum Order Qty')
approved_cnt = fields.Integer(string='Planned Qty')
approx_price = fields.Monetary(related="material_name.unit_price",currency_field='currency_id', string='Unit Price',store=True)
total_approx_price = fields.Float(compute='_compute_total_approx_price', string='Approx Price',store=True)
@api.onchange('material_name')
def _onchange_material_name(self):
for record in self:
if record.material_name:
record.approx_price = record.material_name.unit_price
@api.depends('approx_price', 'approved_cnt')
def _compute_total_approx_price(self):
for record in self:
if record.approx_price is not None and record.approved_cnt is not None:
record.total_approx_price = record.approx_price * record.approved_cnt
else:
record.total_approx_price = 0