Slink/sos_inventory/models/sos_sfg_bom.py

178 lines
7.7 KiB
Python
Executable File

# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from math import isnan
import io
import xlsxwriter
from odoo.tools.misc import xlsxwriter
import base64
class SOS_Sfg_Bom(models.Model):
_name = 'sos_sfg_bom'
_description = 'BOM of Semi-Finished Goods'
name = fields.Many2one('sos_sfg', string="BOM Name")
fg_name = fields.Many2many('sos_fg', string="Belongs To")
prepared_by_name = fields.Many2one('res.users', string='Prepared by')
reporting_to = fields.Many2one('res.users',related="prepared_by_name.reporting_to", string='Prepared by')
bom_version=fields.Char(string="BOM Version")
pcb_version=fields.Char(string="PCB Version")
assembling_charges = fields.Monetary(related="name.assembling_charges",string="Assembling Charges")
sfg_bom_line_ids = fields.One2many('sos_sfg_bom_line', 'bom_id', string='BOM Lines', copy=True, ondelete='cascade')
currency_id = fields.Many2one('res.currency', string='Currency')
overall_total = fields.Monetary(store=True,compute='_compute_overall_total', string="Overall Total", currency_field='currency_id')
material_bom_line_ids = fields.Many2many(
'sos_material_bom', # Target model
'sos_sfg_bom_sos_material_bom_rel', # Relation table
'sos_sfg_bom_id', # Column for "sos_sfg_bom"
'sos_material_bom_id', # Column for "sos_material_bom"
string='Material BOM Lines',
copy=True
)
def action_export(self):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
headers = {
'material_code' : 'Material Code',
'primary_component_id': 'Material Name',
'quantity': 'Quantity',
'inhand_stock_qty':'Inhand Qty',
'uom':'UOM',
'unit_price':'Unit Price',
'total_cost':'Total'
}
self._write_sheet(workbook, 'Materials', self.sfg_bom_line_ids, headers)
workbook.close()
output.seek(0)
attachment = self.env['ir.attachment'].create({
'name': f'{self.name.name}_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):
worksheet = workbook.add_worksheet(sheet_name)
number_format = workbook.add_format({'num_format': '#,##0.00'})
bold_format = workbook.add_format({'bold': True})
name_value = getattr(self, 'name', False)
worksheet.write(0, 0, 'Name',bold_format) # Label for the first value
worksheet.write(0, 1, name_value.display_name if name_value else '') # Handle Many2one field
assembling_charges = getattr(self, 'assembling_charges', 0.0)
worksheet.write(1, 0, 'Assembly Charges',bold_format) # Label for the second value
worksheet.write(1, 1, assembling_charges, number_format) # Assume numeric (float)
overall_total = getattr(self, 'overall_total', 0.0)
worksheet.write(2, 0, 'Overall Cost (Including assembling charges)',bold_format) # Label for the third value
worksheet.write(2, 1, overall_total, number_format) # Assume numeric (float)
for col, header in enumerate(headers.values()):
worksheet.write(4, col, header,bold_format)
for row, record in enumerate(line_records, start=5):
for col, field in enumerate(headers.keys()):
value = getattr(record, field, '')
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)
@api.depends('sfg_bom_line_ids.total_cost', 'assembling_charges')
def _compute_overall_total(self):
for record in self:
total_costs = sum(
0 if line.total_cost is None or isnan(line.total_cost) else line.total_cost
for line in record.sfg_bom_line_ids
)
assembling_charges = 0 if isnan(record.assembling_charges) else record.assembling_charges
record.overall_total = total_costs + assembling_charges
def write(self, vals):
res = super(SOS_Sfg_Bom, self).write(vals)
self._sync_unit_price_with_sfg()
return res
@api.model
def create(self, vals):
res = super(SOS_Sfg_Bom, self).create(vals)
res._sync_unit_price_with_sfg()
return res
def _sync_unit_price_with_sfg(self):
sos_sfg_obj = self.env['sos_sfg']
for record in self:
sfg_record = sos_sfg_obj.search([('name', '=', record.name.name)], limit=1)
if sfg_record:
sfg_record.write({'unit_price': record.overall_total})
def action_bulk_upload(self):
view_id = self.env.ref('sos_inventory.bulk_upload_wizard_form').id
return {
'type': 'ir.actions.act_window',
'name': 'Bulk Upload',
'res_model': 'bulk_upload_wizard',
'view_mode': 'form',
'views': [(view_id, 'form')],
'target': 'new',
'context': {
'default_sos_sfg_id': self.id
}
}
class SOS_Sfg_Bom_Line(models.Model):
_name = 'sos_sfg_bom_line'
_description = 'BOM Lines of Semi-Finished Goods'
bom_id = fields.Many2one('sos_sfg_bom', string="SFG BOM Reference")
fg_bom_id = fields.Many2one('sos_fg_bom', string="FG BOM Reference")
primary_component_id = fields.Many2one('sos_material', string='Part No', required=True)
location = fields.Char(related="primary_component_id.location")
inhand_stock_qty = fields.Float(related="primary_component_id.inhand_stock_qty")
material_code = fields.Char(related="primary_component_id.material_code")
quantity = fields.Float(string="Qty", default=1)
inspection_method = fields.Integer(related="primary_component_id.inspection_method",string='Inspection Method',readonly=False)
currency_id = fields.Many2one('res.currency', string='Currency')
unit_price = fields.Monetary(related='primary_component_id.unit_price', string="Unit Price", currency_field='currency_id', readonly=True)
uom = fields.Selection(
related='primary_component_id.uom',
string="UOM"
)
total_cost = fields.Monetary(compute='_compute_total_cost', string="Total Cost", currency_field='currency_id', readonly=True)
@api.depends('unit_price', 'quantity')
def _compute_total_cost(self):
for record in self:
record.total_cost = record.unit_price * record.quantity
@api.onchange('inspection_method')
def _onchange_inspection_method(self):
if self.inspection_method:
self.primary_component_id.inspection_method = self.inspection_method
# @api.model
# def create(self, vals):
# existing_record = self.search([
# ('primary_component_id', '=', vals.get('primary_component_id')),
# ('fg_bom_id', '=', vals.get('fg_bom_id'))
# ], limit=1)
# if existing_record:
# existing_record.quantity += vals.get('quantity', 0)
# return existing_record
# else:
# return super(SOS_Sfg_Bom_Line, self).create(vals)