307 lines
12 KiB
Python
Executable File
307 lines
12 KiB
Python
Executable File
import os
|
|
import base64
|
|
from datetime import datetime
|
|
from odoo import models, fields, api
|
|
from weasyprint import HTML
|
|
import calendar
|
|
|
|
class ReportGenerator(models.Model):
|
|
_name = "sos_report_generator"
|
|
_description = "Monthly Report Generation"
|
|
|
|
report_file = fields.Binary("Report File")
|
|
report_filename = fields.Char("Report Filename")
|
|
|
|
@api.model
|
|
def generate_and_save_pdf(self):
|
|
sales_group = self.env.ref("sos_inventory.sos_sales_user", raise_if_not_found=False)
|
|
management_group = self.env.ref("sos_inventory.sos_management_user", raise_if_not_found=False)
|
|
|
|
# Get users from both groups
|
|
sales_users = self.env['res.users'].search([('groups_id', 'in', [sales_group.id])]) if sales_group else []
|
|
management_users = self.env['res.users'].search([('groups_id', 'in', [management_group.id])]) if management_group else []
|
|
|
|
# Get current month and year
|
|
current_year = datetime.now().year
|
|
current_month = datetime.now().month
|
|
current_month_alpha = datetime.now().strftime("%B")
|
|
from_date = f"01/{current_month:02d}/{current_year}"
|
|
to_date = f"{calendar.monthrange(current_year, current_month)[1]}/{current_month:02d}/{current_year}"
|
|
|
|
# Generate reports for sales users individually
|
|
for sales_user in sales_users:
|
|
title = f"SPENCO REPORT {current_month_alpha} {current_year}"
|
|
filename = f"spenco_report_{current_month}_{current_year}_{sales_user.name}.pdf"
|
|
domain = [('status', '=', 'open'), ('sales_person', '=', sales_user.id)]
|
|
domain += [
|
|
('line_ids.status_changed_on', '>=', from_date),
|
|
('line_ids.status_changed_on', '<=', to_date),
|
|
('spenco_status', '!=', 'Suspects'),
|
|
]
|
|
email_cc=''
|
|
self._generate_pdf_for_users(domain, filename,title,sales_user.login,email_cc)
|
|
|
|
# Generate a single report for all management users
|
|
if management_users:
|
|
title = f"SPENCO REPORT {current_month_alpha} {current_year}"
|
|
filename = f"spenco_report_{current_month}_{current_year}_top_management.pdf"
|
|
domain = [('status', '=', 'open')]
|
|
domain += [
|
|
('line_ids.status_changed_on', '>=', from_date),
|
|
('line_ids.status_changed_on', '<=', to_date),
|
|
('spenco_status', '!=', 'Suspects'),
|
|
]
|
|
|
|
email_to = 'ramachandran.r@sosaley.com'
|
|
email_cc = 'sethuraman.n@sosaley.com,anitha.a@sosaley.com'
|
|
self._generate_pdf_for_users(domain, filename,title,email_to,email_cc)
|
|
|
|
return True
|
|
|
|
def _generate_pdf_for_users(self, domain, filename,title,email_to,email_cc):
|
|
"""Common function to generate reports for given domain and filename."""
|
|
records = self.env['sos_case_diary'].search(domain)
|
|
if not records:
|
|
return
|
|
|
|
case_diary_data = []
|
|
totals = {
|
|
'Prospects': 0,
|
|
'Engaged': 0,
|
|
'Negotiation': 0,
|
|
'Commercial Order': 0,
|
|
'Expected Order Value': 0,
|
|
}
|
|
|
|
for record in records:
|
|
product_or_project = record.project_name if record.interested_in == "projects" else record.products
|
|
latest_record = self.env['sos_case_diary_line'].search(
|
|
[('ref_id', '=', record.id)], order="id desc", limit=1
|
|
)
|
|
|
|
current_state_value = round(latest_record.current_state_value, 2)
|
|
spenco_status = latest_record.spenco_status
|
|
|
|
# Update totals based on spenco_status
|
|
if spenco_status == 'Prospects':
|
|
totals['Prospects'] += current_state_value
|
|
totals['Expected Order Value'] += round(current_state_value * 0.1, 2)
|
|
elif spenco_status == 'Engaged':
|
|
totals['Engaged'] += current_state_value
|
|
totals['Expected Order Value'] += round(current_state_value * 0.3, 2)
|
|
elif spenco_status == 'Negotiation':
|
|
totals['Negotiation'] += current_state_value
|
|
totals['Expected Order Value'] += round(current_state_value * 0.5, 2)
|
|
elif spenco_status == 'Commercial Order':
|
|
totals['Commercial Order'] += current_state_value
|
|
totals['Expected Order Value'] += round(current_state_value, 2)
|
|
|
|
case_diary_data.append({
|
|
'customer_name': record.customer_name.customer_name,
|
|
'customer_city': record.customer_city,
|
|
'lead_generated_by': record.lead_generated_by,
|
|
'products': product_or_project,
|
|
'quantity': record.quantity,
|
|
'sales_person': record.sales_person.name,
|
|
'account_start_date': record.account_start_date,
|
|
'status_changed_on': latest_record.status_changed_on,
|
|
'spenco_status': latest_record.spenco_status,
|
|
'current_state_value': latest_record.current_state_value,
|
|
'status_values': {
|
|
'Prospects': current_state_value if spenco_status == 'Prospects' else '',
|
|
'Engaged': current_state_value if spenco_status == 'Engaged' else '',
|
|
'Negotiation': current_state_value if spenco_status == 'Negotiation' else '',
|
|
'Commercial Order': current_state_value if spenco_status == 'Commercial Order' else '',
|
|
},
|
|
'expected_order_value': round(
|
|
current_state_value * (
|
|
0.1 if spenco_status == 'Prospects' else
|
|
0.3 if spenco_status == 'Engaged' else
|
|
0.5 if spenco_status == 'Negotiation' else
|
|
1.0 if spenco_status == 'Commercial Order' else 0
|
|
), 2
|
|
),
|
|
'totals': totals,
|
|
})
|
|
|
|
self.generate_html_report(case_diary_data, filename,title,email_to,email_cc)
|
|
|
|
|
|
def generate_html_report(self, data,filename,title,email_to, email_cc):
|
|
"""Converts the given data list into an HTML table format and generates a PDF."""
|
|
|
|
# Define the table header
|
|
html = f"""
|
|
<html>
|
|
<head>
|
|
<style>
|
|
@page {{
|
|
size: A4 landscape;
|
|
margin: 20mm;
|
|
}}
|
|
body {{
|
|
font-family: Arial, sans-serif;
|
|
margin: 10px;
|
|
font-size: 11px;
|
|
}}
|
|
table {{
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
table-layout: fixed;
|
|
word-wrap: break-word;
|
|
}}
|
|
th, td {{
|
|
border: 1px solid #ddd;
|
|
padding: 5px;
|
|
text-align: left;
|
|
white-space: normal;
|
|
}}
|
|
th {{
|
|
background-color: #f2f2f2;
|
|
}}
|
|
tr:nth-child(even) {{
|
|
background-color: #f9f9f9;
|
|
}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h2 style="text-align: center;">{title}</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th rowspan="2">S.No</th>
|
|
<th rowspan="2">Customer</th>
|
|
|
|
|
|
<th rowspan="2">Sales Person</th>
|
|
<th rowspan="2">Status Changed On</th>
|
|
<th rowspan="2">Project/Product</th>
|
|
<th rowspan="2">Quantity</th>
|
|
<th colspan="4">Order Booking (In Lakhs)</th>
|
|
<th rowspan="2">Expected Order Value (In Lakhs)</th>
|
|
</tr>
|
|
<tr>
|
|
<th>Prospects</th>
|
|
<th>Engaged</th>
|
|
<th>Negotiation</th>
|
|
<th>Commercial Order</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
"""
|
|
# Populate table rows
|
|
for index, record in enumerate(data, start=1):
|
|
current_state_value = record.get("current_state_value", 0)
|
|
spenco_status = record.get("spenco_status", "")
|
|
html += """
|
|
<tr>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
<td>{}</td>
|
|
</tr>
|
|
""".format(
|
|
index,
|
|
record.get('customer_name', '-'),
|
|
record.get('sales_person', '-'),
|
|
record.get('status_changed_on', '-'),
|
|
record.get('products', '-'),
|
|
record.get('quantity', '-'),
|
|
f"₹ {current_state_value:.2f}" if spenco_status == "Prospects" else "-",
|
|
f"₹ {current_state_value:.2f}" if spenco_status == "Engaged" else "-",
|
|
f"₹ {current_state_value:.2f}" if spenco_status == "Negotiation" else "-",
|
|
f"₹ {current_state_value:.2f}" if spenco_status == "Commercial Order" else "-",
|
|
|
|
f"₹ {record.get('expected_order_value', 0):.2f}"
|
|
)
|
|
|
|
# Add totals row
|
|
totals = data[0].get('totals', {})
|
|
total_prospects = f"₹ {totals.get('Prospects', 0):.2f}"
|
|
total_engaged = f"₹ {totals.get('Engaged', 0):.2f}"
|
|
total_negotiation = f"₹ {totals.get('Negotiation', 0):.2f}"
|
|
total_commercial_order = f"₹ {totals.get('Commercial Order', 0):.2f}"
|
|
total_expected_value = f"₹ {totals.get('Expected Order Value', 0):.2f}"
|
|
|
|
html += """
|
|
<tr>
|
|
<td colspan="6"><b>Total</b></td>
|
|
<td><b>{}</b></td>
|
|
<td><b>{}</b></td>
|
|
<td><b>{}</b></td>
|
|
<td><b>{}</b></td>
|
|
<td><b>{}</b></td>
|
|
</tr>
|
|
""".format(
|
|
total_prospects, total_engaged, total_negotiation, total_commercial_order, total_expected_value
|
|
)
|
|
|
|
# Close the table and body
|
|
html += """
|
|
</tbody>
|
|
</table>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
# Define the output directory and file path
|
|
current_year = datetime.now().year
|
|
current_month = datetime.now().month
|
|
current_month_alpha = datetime.now().strftime("%B")
|
|
output_dir = f"/var/www/html/slink_reports/spenco_reports/{current_year}/{current_month_alpha}"
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
new_output_dir = f"spenco_reports/{current_year}/{current_month_alpha}"
|
|
|
|
output_path = os.path.join(output_dir, filename)
|
|
new_path = os.path.join(new_output_dir, filename)
|
|
# Generate PDF
|
|
HTML(string=html).write_pdf(output_path)
|
|
|
|
# Email part
|
|
url = f"https://slinkreport.sosaley.in/{new_path}"
|
|
message = f"""
|
|
<p>This Month consolidated <b>SPENCO REPORT</b> is ready</p>
|
|
"""
|
|
body_html = f"""
|
|
<p>Hello User,</p>
|
|
{message}
|
|
<p>Click the button below to Download:</p>
|
|
<table width="100%" cellspacing="0" cellpadding="0">
|
|
<tr>
|
|
<td>
|
|
<table cellspacing="0" cellpadding="0">
|
|
<tr>
|
|
<td style="border-radius: 5px;" bgcolor="#71639e">
|
|
<a href="{url}" target="_blank" style="padding: 4px 8px; border: 1px solid #71639e;border-radius: 5px;font-family: Helvetica, Arial, sans-serif;font-size: 14px; color: #ffffff;text-decoration: none;font-weight:bold;display: inline-block;">
|
|
Click Here
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
"""
|
|
subject = f"Monthly SPENCO Report"
|
|
mail_values = {
|
|
'subject': subject,
|
|
'body_html': body_html,
|
|
'email_to': email_to,
|
|
'email_cc': email_cc if email_cc else False,
|
|
'email_from': "slink <alert@sosaley.in>",
|
|
}
|
|
mail = self.env['mail.mail'].sudo().create(mail_values)
|
|
mail.sudo().send()
|
|
# Email part ends
|
|
|
|
return output_path
|
|
|
|
|