178 lines
7.7 KiB
Python
Executable File
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)
|
|
|
|
|