Slink/sos_inventory/models/sos_quote_generation.py

309 lines
13 KiB
Python
Executable File

from odoo import api, fields, models, _
import logging
from datetime import date,datetime
from math import isnan
import io
import xlsxwriter
from odoo.tools.misc import xlsxwriter
import base64
_logger = logging.getLogger(__name__)
class SOS_Quote_Generation(models.Model):
_name = 'sos_quote_generation'
_description = 'Quote Generation'
_rec_name = 'plan_ref_no'
plan_ref_no = fields.Char(
readonly=True, required=True, string='Plan ID'
)
line_ids = fields.One2many('sos_quote_generation_line', 'plan_id', string='Lines', ondelete='cascade')
def action_export(self):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
headers = {
'material_name' : 'Material Name',
'required_qty': 'Required Quantity',
'status': 'Status',
}
self._write_sheet(workbook, 'Materials', self.line_ids, headers)
workbook.close()
output.seek(0)
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)
for col, header in enumerate(headers.values()):
worksheet.write(0, col, header)
for row, record in enumerate(line_records, start=1):
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)
def action_generate_po(self):
po_model = self.env['sos_po']
po_line_model = self.env['sos_po_line']
supplier_dict = {}
for record in self.line_ids:
if record.final_supplier1_name:
supplier = record.final_supplier1_name
if supplier not in supplier_dict:
supplier_dict[supplier] = []
supplier_dict[supplier].append({
'name': record.material_name,
'product_qty': record.final_supplier1_qty,
'price_unit': record.final_supplier1_quoted_price
})
# if record.supplier2_name:
# supplier = record.supplier2_name
# if supplier not in supplier_dict:
# supplier_dict[supplier] = []
# supplier_dict[supplier].append({
# 'name': record.material_name,
# 'product_qty': record.supplier2_qty,
# 'price_unit': record.supplier2_quoted_price
# })
# if record.supplier3_name:
# supplier = record.supplier3_name
# if supplier not in supplier_dict:
# supplier_dict[supplier] = []
# supplier_dict[supplier].append({
# 'name': record.material_name,
# 'product_qty': record.supplier3_qty,
# 'price_unit': record.supplier3_quoted_price
# })
for x, y in supplier_dict.items():
sequence_util = self.env['sos_common_scripts']
po_no = sequence_util.generate_sequence('sos_po','PO', 'po_no')
po_record = po_model.create({
'po_no': po_no, 'po_date': date.today(),'supplier_name': x.id,
'supplier_gst_no': x.gst_no, 'sarf_no':x.supplier_code,
'supplier_address': x.address
})
for components in y:
po_line_model.create({
'po_id': po_record.id, 'component_id': components['name'].id,'qp':components['name'].qp_no,'hsn_code':components['name'].hsn_code,
'quantity': components['product_qty'],'unit_price': components['price_unit'], 'total_price': components['product_qty'] * components['price_unit']
})
message = 'Purchase Order(s) successfully generated.'
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': message,
'type': 'success',
'sticky': False
}
}
def action_generate_quotation(self):
supplier_materials = {}
for item in self.line_ids:
if item.purchase_type == "supplier":
for supplier in item.supplier_name:
if supplier not in supplier_materials:
supplier_materials[supplier] = []
supplier_materials[supplier].append({
'material_name': item.material_name.id,
'required_qty': item.required_qty
})
wizards = []
for supplier, materials in supplier_materials.items():
wizard_lines = [(0, 0, {
'material_name': material['material_name'],
'required_qty': material['required_qty']
}) for material in materials]
wizard = self.env['supplier_quotation_wizard'].create({
'supplier_id': supplier.id,
'plan_id': self.id,
'line_ids': wizard_lines
})
wizards.append(wizard.id)
return {
'type': 'ir.actions.act_window',
'name': 'Generate Quotation',
'view_mode': 'tree,form',
'res_model': 'supplier_quotation_wizard',
'domain': [('id', 'in', wizards)],
'target': 'new',
}
class SOS_Quote_Generation_Line(models.Model):
_name = 'sos_quote_generation_line'
_description = 'Quote Generation Lines'
plan_id = fields.Many2one('sos_quote_generation', string='Quote Generation', ondelete='cascade')
required_qty = fields.Integer(string='Required Qty')
purchase_type = fields.Selection([
('local', 'Local Purchase'),
('supplier', 'Supplier Purchase'),
('online', 'Online Purchase')
], string='Purchase Type', required=True, default='supplier')
supplier_name = fields.Many2many('sos_suppliers', string='Supplier', domain="[('id', 'in', suppliers_ids)]")
suppliers_ids = fields.Many2many('sos_suppliers', compute='_compute_suppliers_ids', store=False)
is_supplier_name_readonly = fields.Boolean(compute='_compute_is_supplier_name_readonly')
# Quote Comparison
material_name = fields.Many2one('sos_material',string="Material Name")
in_transit_stock_qty = fields.Integer(string="In-Transit Qty",related="material_name.in_transit_stock_qty")
supplier1_name = fields.Many2one('sos_suppliers',string="Supplier 1")
supplier1_quoted_price = fields.Float(string='Price')
supplier1_qty = fields.Integer(string='Qty')
supplier2_name = fields.Many2one('sos_suppliers',string="Supplier 2")
supplier2_quoted_price = fields.Float(string='Price')
supplier2_qty = fields.Integer(string='Qty')
supplier3_name = fields.Many2one('sos_suppliers',string="Supplier 3")
supplier3_quoted_price = fields.Float(string='Price')
supplier3_qty = fields.Integer(string='Qty')
final_supplier1_name = fields.Many2one('sos_suppliers',string="Supplier 1")
final_supplier1_quoted_price = fields.Float(string='Price')
final_supplier1_qty = fields.Integer(string='Qty')
best_supplier = fields.Many2one('sos_suppliers', string="Best Deal", compute='_compute_best_supplier', store=True)
available_suppliers = fields.Many2many('sos_service_providers', compute='_compute_available_suppliers')
status = fields.Selection(
[
('open', 'Open'),
('close', 'Closed')
],
default='open',
string="Status",
compute="_compute_from_ir",
inverse="_set_status",
store=True
)
@api.depends('required_qty', 'in_transit_stock_qty')
def _compute_from_ir(self):
for record in self:
if record.in_transit_stock_qty <= 0:
record.status = "close"
else:
record.status = "open"
def _set_status(self):
for record in self:
# Custom logic based on user changes
if record.status == 'close':
# Perform actions for 'close'
pass
elif record.status == 'open':
# Perform actions for 'open'
pass
@api.depends('supplier1_name', 'supplier2_name', 'supplier3_name')
def _compute_available_suppliers(self):
for record in self:
suppliers = []
if record.supplier1_name:
suppliers.append(record.supplier1_name.id)
if record.supplier2_name:
suppliers.append(record.supplier2_name.id)
if record.supplier3_name:
suppliers.append(record.supplier3_name.id)
record.available_suppliers = [(6, 0, suppliers)]
@api.onchange('final_supplier1_name')
def _onchange_final_supplier1_name(self):
if self.final_supplier1_name:
# Check which supplier is selected and update price and quantity accordingly
if self.final_supplier1_name == self.supplier1_name:
self.final_supplier1_quoted_price = self.supplier1_quoted_price
self.final_supplier1_qty = self.supplier1_qty
# elif self.final_supplier1_name == self.supplier2_name:
# self.final_supplier1_quoted_price = self.supplier2_quoted_price
# self.final_supplier1_qty = self.supplier2_qty
# elif self.final_supplier1_name == self.supplier3_name:
# self.final_supplier1_quoted_price = self.supplier3_quoted_price
# self.final_supplier1_qty = self.supplier3_qty
@api.depends('supplier1_quoted_price', 'supplier1_qty',
'supplier2_quoted_price', 'supplier2_qty',
'supplier3_quoted_price', 'supplier3_qty')
def _compute_best_supplier(self):
for record in self:
best_supplier = None
best_score = float('inf')
suppliers = [
(record.supplier1_name, record.supplier1_quoted_price, record.supplier1_qty),
(record.supplier2_name, record.supplier2_quoted_price, record.supplier2_qty),
(record.supplier3_name, record.supplier3_quoted_price, record.supplier3_qty)
]
final_supplier_qty = 0
final_supplier_price = 0
for supplier, price, qty in suppliers:
if supplier:
score = price / qty if qty else float('inf')
if score < best_score:
best_score = score
best_supplier = supplier
final_supplier_qty = qty
final_supplier_price = price
record.best_supplier = best_supplier
record.final_supplier1_name = best_supplier
if best_supplier:
record.final_supplier1_qty = final_supplier_qty
record.final_supplier1_quoted_price = final_supplier_price
@api.depends('purchase_type')
def _compute_is_supplier_name_readonly(self):
for line in self:
line.is_supplier_name_readonly = (line.purchase_type == 'local')
@api.onchange('material_name')
def _onchange_material_name(self):
if self.material_name:
supplier_ids = self.material_name.suppliers.ids
if supplier_ids:
self.suppliers_ids = supplier_ids
else:
self.suppliers_ids = self.env['sos_suppliers'].search([]).ids
else:
self.suppliers_ids = self.env['sos_suppliers'].search([]).ids
@api.depends('material_name')
def _compute_suppliers_ids(self):
for record in self:
if record.material_name:
supplier_ids = record.material_name.suppliers.ids
if supplier_ids:
record.suppliers_ids = supplier_ids
else:
record.suppliers_ids = self.env['sos_suppliers'].search([]).ids
else:
record.suppliers_ids = self.env['sos_suppliers'].search([]).ids