updated code
This commit is contained in:
268
app/Controllers/reports.py
Normal file
268
app/Controllers/reports.py
Normal file
@@ -0,0 +1,268 @@
|
||||
from flask import Blueprint, request, send_from_directory, redirect, url_for, current_app, flash
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
from app.models import Task
|
||||
|
||||
reports = Blueprint('reports', __name__)
|
||||
|
||||
|
||||
def clean_text(text):
|
||||
if not isinstance(text, str):
|
||||
return ""
|
||||
return text.strip().replace(",", "").replace("(", "").replace(")", "") \
|
||||
.replace(".", "").replace("&", "").replace("\n", "").lower()
|
||||
|
||||
|
||||
def safe_float(value):
|
||||
try:
|
||||
return round(float(value), 2)
|
||||
except (ValueError, TypeError):
|
||||
return 0.0
|
||||
|
||||
|
||||
@reports.route('/report_excel', methods=['GET'])
|
||||
def generate_report():
|
||||
|
||||
main_task_rexp = r'[\\/*?:"<>|]'
|
||||
|
||||
block = request.args.get('block', '')
|
||||
main_task = request.args.get('main_task', '')
|
||||
|
||||
block_clean = clean_text(block)
|
||||
main_task_clean = clean_text(main_task)
|
||||
|
||||
if not block_clean:
|
||||
return "Please select a Block.", 400
|
||||
|
||||
if not main_task_clean:
|
||||
return "Please select a Main Task.", 400
|
||||
|
||||
# ---------------- FETCH DATA ----------------
|
||||
all_tasks = Task.query.filter(Task.block_name == block).all()
|
||||
|
||||
# MAIN TASK
|
||||
# main_task_record = next(
|
||||
# (task for task in all_tasks
|
||||
# if clean_text(task.task_name) == main_task_clean),
|
||||
# None
|
||||
# )
|
||||
|
||||
main_task_records = [
|
||||
task for task in all_tasks
|
||||
# if clean_text(task.task_name) == main_task_clean
|
||||
if main_task_clean in clean_text(task.task_name)
|
||||
]
|
||||
# SUBTASKS (ONLY TRUE CHILDREN)
|
||||
subtasks_query = [
|
||||
task for task in all_tasks
|
||||
if task.parent_task_name
|
||||
and main_task_clean in clean_text(task.parent_task_name)
|
||||
# and clean_text(task.parent_task_name) == main_task_clean
|
||||
]
|
||||
|
||||
# ---------------- VALIDATION ----------------
|
||||
if not subtasks_query and not main_task_records:
|
||||
flash("No Task Data Found", "error")
|
||||
return redirect(url_for('main.generate_report_page'))
|
||||
|
||||
# ---------------- BUILD REPORT ----------------
|
||||
report_data = []
|
||||
|
||||
# CASE 1: SUBTASKS EXIST
|
||||
if subtasks_query:
|
||||
|
||||
for task in subtasks_query:
|
||||
|
||||
boq_amount = safe_float(task.boq_amount)
|
||||
previous_billing_amount = safe_float(task.previous_billing_amount)
|
||||
remaining_amount = boq_amount - previous_billing_amount
|
||||
tender_amount = safe_float(task.qty) * safe_float(task.rate)
|
||||
|
||||
report_data.append([
|
||||
task.id,
|
||||
(task.village_name or "").strip(),
|
||||
(task.task_name or "").strip(),
|
||||
(task.unit or "").strip(),
|
||||
safe_float(task.qty),
|
||||
safe_float(task.rate),
|
||||
tender_amount,
|
||||
safe_float(task.previous_billed_qty),
|
||||
previous_billing_amount,
|
||||
remaining_amount
|
||||
])
|
||||
|
||||
# CASE 2: ONLY MAIN TASK EXISTS
|
||||
# elif main_task_record:
|
||||
|
||||
# task = main_task_record
|
||||
|
||||
# boq_amount = safe_float(task.boq_amount)
|
||||
# previous_billing_amount = safe_float(task.previous_billing_amount)
|
||||
# remaining_amount = boq_amount - previous_billing_amount
|
||||
# tender_amount = safe_float(task.qty) * safe_float(task.rate)
|
||||
|
||||
# report_data.append([
|
||||
# task.id,
|
||||
# (task.village_name or "").strip(),
|
||||
# (task.task_name or "").strip(),
|
||||
# safe_float(task.qty),
|
||||
# safe_float(task.rate),
|
||||
# tender_amount,
|
||||
# safe_float(task.previous_billed_qty),
|
||||
# previous_billing_amount,
|
||||
# remaining_amount
|
||||
# ])
|
||||
elif main_task_records:
|
||||
|
||||
for task in main_task_records:
|
||||
|
||||
boq_amount = safe_float(task.boq_amount)
|
||||
previous_billing_amount = safe_float(task.previous_billing_amount)
|
||||
remaining_amount = boq_amount - previous_billing_amount
|
||||
tender_amount = safe_float(task.qty) * safe_float(task.rate)
|
||||
|
||||
report_data.append([
|
||||
task.id,
|
||||
(task.village_name or "").strip(),
|
||||
(task.task_name or "").strip(),
|
||||
(task.unit or "").strip(),
|
||||
safe_float(task.qty),
|
||||
safe_float(task.rate),
|
||||
tender_amount,
|
||||
safe_float(task.previous_billed_qty),
|
||||
previous_billing_amount,
|
||||
remaining_amount
|
||||
])
|
||||
# ---------------- FILE NAME ----------------
|
||||
sanitized_main_task = re.sub(main_task_rexp, "", main_task)
|
||||
|
||||
if len(sanitized_main_task) > 30:
|
||||
sanitized_main_task = sanitized_main_task[:30]
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
file_name = f"{sanitized_main_task}_{timestamp}.xlsx"
|
||||
file_path = os.path.join(current_app.config['UPLOAD_FOLDER'], file_name)
|
||||
|
||||
# ---------------- EXCEL ----------------
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "Report"
|
||||
|
||||
thin_border = Border(
|
||||
left=Side(style="thin"),
|
||||
right=Side(style="thin"),
|
||||
top=Side(style="thin"),
|
||||
bottom=Side(style="thin")
|
||||
)
|
||||
|
||||
header_fill = PatternFill(start_color="FFC000", end_color="FFC000", fill_type="solid")
|
||||
|
||||
# ---------------------------------------------------
|
||||
# REPORT TITLE
|
||||
# ---------------------------------------------------
|
||||
|
||||
ws.merge_cells("A1:J1")
|
||||
title_cell = ws["A1"]
|
||||
|
||||
title_cell.value = "MAIN TASK REPORT"
|
||||
title_cell.font = Font(bold=True, size=14)
|
||||
title_cell.alignment = Alignment(horizontal="center")
|
||||
title_cell.fill = header_fill
|
||||
title_cell.border = thin_border
|
||||
|
||||
|
||||
# ---------------------------------------------------
|
||||
# DETAIL ROWS
|
||||
# ---------------------------------------------------
|
||||
|
||||
ws["A2"] = "District"
|
||||
ws["B2"] = request.args.get("district", "")
|
||||
|
||||
ws["A3"] = "Block"
|
||||
ws["B3"] = block
|
||||
|
||||
ws["A4"] = "Main Task"
|
||||
ws["B4"] = main_task
|
||||
|
||||
|
||||
# Style details rows
|
||||
for r in range(2,5):
|
||||
ws[f"A{r}"].font = Font(bold=True)
|
||||
ws[f"A{r}"].fill = header_fill
|
||||
ws[f"A{r}"].border = thin_border
|
||||
ws[f"B{r}"].border = thin_border
|
||||
|
||||
|
||||
# ---------------------------------------------------
|
||||
# TABLE HEADER STARTS ROW 6
|
||||
# ---------------------------------------------------
|
||||
|
||||
start_row = 6
|
||||
|
||||
headers = [
|
||||
"Task ID",
|
||||
"Village",
|
||||
"Task Name",
|
||||
"Unit",
|
||||
"Tender Qty",
|
||||
"Tender Rate",
|
||||
"Tender Amount",
|
||||
"Previous Bill Qty",
|
||||
"Previous Bill Amount",
|
||||
"Remaining Amount"
|
||||
]
|
||||
|
||||
|
||||
for col_num, value in enumerate(headers,1):
|
||||
cell = ws.cell(row=start_row, column=col_num)
|
||||
cell.value = value
|
||||
cell.font = Font(bold=True)
|
||||
cell.alignment = Alignment(horizontal="center")
|
||||
cell.fill = header_fill
|
||||
cell.border = thin_border
|
||||
|
||||
|
||||
# ---------------------------------------------------
|
||||
# DATA ROWS START AFTER HEADER
|
||||
# ---------------------------------------------------
|
||||
|
||||
data_row = start_row + 1
|
||||
|
||||
for row_data in report_data:
|
||||
for col_num, value in enumerate(row_data,1):
|
||||
cell = ws.cell(
|
||||
row=data_row,
|
||||
column=col_num,
|
||||
value=value
|
||||
)
|
||||
cell.border = thin_border
|
||||
|
||||
data_row += 1
|
||||
|
||||
|
||||
# Freeze header while scrolling
|
||||
ws.freeze_panes = "A7"
|
||||
|
||||
|
||||
# Column Width
|
||||
for i in range(1, len(headers)+1):
|
||||
ws.column_dimensions[
|
||||
ws.cell(row=start_row,column=i).column_letter
|
||||
].width = 20
|
||||
|
||||
wb.save(file_path)
|
||||
|
||||
return redirect(url_for('reports.download_report', filename=file_name))
|
||||
|
||||
|
||||
@reports.route('/download/<filename>')
|
||||
def download_report(filename):
|
||||
return send_from_directory(
|
||||
current_app.config['UPLOAD_FOLDER'],
|
||||
filename,
|
||||
as_attachment=True
|
||||
)
|
||||
Reference in New Issue
Block a user