updated code
This commit is contained in:
Binary file not shown.
BIN
app/Controllers/__pycache__/reports.cpython-314.pyc
Normal file
BIN
app/Controllers/__pycache__/reports.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -104,6 +104,57 @@ def filter_tasks_controller():
|
||||
|
||||
|
||||
|
||||
# def download_filtered_tasks_controller():
|
||||
# district = request.args.get('district')
|
||||
# block = request.args.get('block')
|
||||
# village = request.args.get('village')
|
||||
|
||||
# query = (
|
||||
# db.session.query(Task)
|
||||
# .join(WorkDetail,
|
||||
# Task.village_name == WorkDetail.name_of_village)
|
||||
# .filter(
|
||||
# WorkDetail.district == district,
|
||||
# WorkDetail.block == block,
|
||||
# WorkDetail.name_of_village == village
|
||||
# )
|
||||
# )
|
||||
|
||||
# tasks = query.all()
|
||||
|
||||
# data = []
|
||||
# for task in tasks:
|
||||
# data.append({
|
||||
# "Task Name": task.task_name,
|
||||
# "Unit": task.unit,
|
||||
# "Qty": task.qty,
|
||||
# "Rate": task.rate,
|
||||
# "BOQ Amount": task.boq_amount,
|
||||
# "Prev Billed Qty": task.previous_billed_qty,
|
||||
# "Prev Billing Amount": task.previous_billing_amount,
|
||||
# "RA Bill Qty": task.in_this_ra_bill_qty,
|
||||
# "RA Bill Amount": task.in_this_ra_billing_amount,
|
||||
# "Cum Billed Qty": task.cumulative_billed_qty,
|
||||
# "Cum Billed Amount": task.cumulative_billed_amount,
|
||||
# "Variation Qty": task.variation_qty,
|
||||
# "Variation Amount": task.variation_amount,
|
||||
# })
|
||||
|
||||
# df = pd.DataFrame(data)
|
||||
|
||||
# output = BytesIO()
|
||||
# df.to_excel(output, index=False, engine='openpyxl')
|
||||
# output.seek(0)
|
||||
|
||||
# filename = f"{district}_{block}_{village}_tasks.xlsx"
|
||||
|
||||
# return send_file(
|
||||
# output,
|
||||
# download_name=filename,
|
||||
# as_attachment=True,
|
||||
# mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
# )
|
||||
|
||||
def download_filtered_tasks_controller():
|
||||
district = request.args.get('district')
|
||||
block = request.args.get('block')
|
||||
@@ -112,7 +163,7 @@ def download_filtered_tasks_controller():
|
||||
query = (
|
||||
db.session.query(Task)
|
||||
.join(WorkDetail,
|
||||
Task.village_name == WorkDetail.name_of_village)
|
||||
Task.village_name == WorkDetail.name_of_village)
|
||||
.filter(
|
||||
WorkDetail.district == district,
|
||||
WorkDetail.block == block,
|
||||
@@ -140,10 +191,86 @@ def download_filtered_tasks_controller():
|
||||
"Variation Amount": task.variation_amount,
|
||||
})
|
||||
|
||||
df = pd.DataFrame(data)
|
||||
df = pd.DataFrame(data).fillna("")
|
||||
|
||||
output = BytesIO()
|
||||
df.to_excel(output, index=False, engine='openpyxl')
|
||||
|
||||
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
|
||||
df.to_excel(writer, index=False, sheet_name='Tasks')
|
||||
|
||||
workbook = writer.book
|
||||
worksheet = writer.sheets['Tasks']
|
||||
|
||||
# ================= HEADER =================
|
||||
header_format = workbook.add_format({
|
||||
'bold': True,
|
||||
'text_wrap': True,
|
||||
'valign': 'center',
|
||||
'align': 'center',
|
||||
'bg_color': '#D9E1F2',
|
||||
'border': 1
|
||||
})
|
||||
|
||||
for col_num, value in enumerate(df.columns.values):
|
||||
worksheet.write(0, col_num, value, header_format)
|
||||
|
||||
# ================= FORMATS =================
|
||||
normal_format = workbook.add_format({
|
||||
'text_wrap': True,
|
||||
'valign': 'top',
|
||||
'border': 1
|
||||
})
|
||||
|
||||
bold_format = workbook.add_format({
|
||||
'text_wrap': True,
|
||||
'valign': 'top',
|
||||
'bold': True,
|
||||
'border': 1
|
||||
})
|
||||
|
||||
# ================= COLUMN WIDTH =================
|
||||
for i, col in enumerate(df.columns):
|
||||
|
||||
max_len = (
|
||||
df[col]
|
||||
.astype(str)
|
||||
.map(lambda x: len(str(x)))
|
||||
.max()
|
||||
)
|
||||
|
||||
max_len = max(max_len, len(col)) + 2
|
||||
|
||||
if col == "Task Name":
|
||||
worksheet.set_column(i, i, 50)
|
||||
worksheet.set_row(1, 40)
|
||||
else:
|
||||
worksheet.set_column(i, i, max_len)
|
||||
|
||||
# ================= ROW LOGIC =================
|
||||
unit_col = 1 # Unit is 2nd column
|
||||
|
||||
for row_idx in range(len(df)):
|
||||
|
||||
unit_value = str(df.iloc[row_idx, unit_col]).strip()
|
||||
|
||||
# 🔥 RULE:
|
||||
# numeric → normal
|
||||
# letters OR empty → bold
|
||||
|
||||
is_numeric = unit_value.replace(".", "", 1).isdigit()
|
||||
|
||||
if is_numeric:
|
||||
row_format = normal_format
|
||||
else:
|
||||
row_format = bold_format
|
||||
|
||||
for col_idx in range(len(df.columns)):
|
||||
worksheet.write(row_idx + 1, col_idx, df.iloc[row_idx, col_idx], row_format)
|
||||
|
||||
# ================= FEATURES =================
|
||||
worksheet.freeze_panes(1, 0)
|
||||
worksheet.autofilter(0, 0, len(df), len(df.columns) - 1)
|
||||
|
||||
output.seek(0)
|
||||
|
||||
filename = f"{district}_{block}_{village}_tasks.xlsx"
|
||||
|
||||
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
|
||||
)
|
||||
@@ -29,6 +29,54 @@ def recalc_task(task):
|
||||
|
||||
|
||||
|
||||
# def update_tasks_controller():
|
||||
# try:
|
||||
# updates = request.get_json()
|
||||
# update_count = 0
|
||||
|
||||
# formula_fields = [
|
||||
# "previous_billing_amount",
|
||||
# "in_this_ra_billing_amount",
|
||||
# "cumulative_billed_qty",
|
||||
# "cumulative_billed_amount",
|
||||
# "variation_qty",
|
||||
# "variation_amount"
|
||||
# ]
|
||||
# for key, new_value in updates.items():
|
||||
# if '_' not in key:
|
||||
# continue
|
||||
# field_name, task_id_str = key.rsplit('_', 1)
|
||||
# if not task_id_str.isdigit():
|
||||
# continue
|
||||
# task = Task.query.get(int(task_id_str))
|
||||
# if task:
|
||||
# if field_name in formula_fields:
|
||||
# continue
|
||||
# current_value = getattr(task, field_name, None)
|
||||
# if str(current_value) != str(new_value):
|
||||
# setattr(task, field_name, new_value)
|
||||
# recalc_task(task)
|
||||
# update_count += 1
|
||||
# log_activity(
|
||||
# current_user.username,
|
||||
# "Task Update",
|
||||
# f"Task ID {task.id} - {field_name} changed to {new_value}"
|
||||
# )
|
||||
# if update_count > 0:
|
||||
# db.session.commit()
|
||||
# log_activity(
|
||||
# current_user.username,
|
||||
# "Database Commit",
|
||||
# f"{update_count} task field(s) updated"
|
||||
# )
|
||||
# return jsonify({'message': f'count: {update_count} field(s) updated.'})
|
||||
# return jsonify({'message': 'No fields were updated.'})
|
||||
# except Exception as e:
|
||||
# log_activity(current_user.username, "Error", str(e))
|
||||
# return jsonify({'error': 'Update failed'}), 500
|
||||
|
||||
|
||||
|
||||
def update_tasks_controller():
|
||||
try:
|
||||
updates = request.get_json()
|
||||
@@ -42,39 +90,72 @@ def update_tasks_controller():
|
||||
"variation_qty",
|
||||
"variation_amount"
|
||||
]
|
||||
|
||||
numeric_fields = [
|
||||
"qty","rate","boq_amount",
|
||||
"previous_billed_qty",
|
||||
"in_this_ra_bill_qty"
|
||||
]
|
||||
|
||||
for key, new_value in updates.items():
|
||||
if '_' not in key:
|
||||
continue
|
||||
|
||||
field_name, task_id_str = key.rsplit('_', 1)
|
||||
|
||||
if not task_id_str.isdigit():
|
||||
continue
|
||||
|
||||
task = Task.query.get(int(task_id_str))
|
||||
|
||||
if task:
|
||||
|
||||
# Skip formula fields
|
||||
if field_name in formula_fields:
|
||||
continue
|
||||
|
||||
current_value = getattr(task, field_name, None)
|
||||
|
||||
# Convert numeric fields
|
||||
if field_name in numeric_fields:
|
||||
try:
|
||||
new_value = float(new_value) if new_value != "" else 0
|
||||
except:
|
||||
new_value = 0
|
||||
|
||||
# Update only if changed
|
||||
if str(current_value) != str(new_value):
|
||||
setattr(task, field_name, new_value)
|
||||
|
||||
# Recalculate formulas
|
||||
recalc_task(task)
|
||||
|
||||
update_count += 1
|
||||
|
||||
log_activity(
|
||||
current_user.username,
|
||||
"Task Update",
|
||||
f"Task ID {task.id} - {field_name} changed to {new_value}"
|
||||
)
|
||||
|
||||
if update_count > 0:
|
||||
db.session.commit()
|
||||
|
||||
log_activity(
|
||||
current_user.username,
|
||||
"Database Commit",
|
||||
f"{update_count} task field(s) updated"
|
||||
)
|
||||
|
||||
return jsonify({'message': f'count: {update_count} field(s) updated.'})
|
||||
|
||||
return jsonify({'message': 'No fields were updated.'})
|
||||
|
||||
except Exception as e:
|
||||
log_activity(current_user.username, "Error", str(e))
|
||||
return jsonify({'error': 'Update failed'}), 500
|
||||
|
||||
|
||||
def display_tasks_controller():
|
||||
work_details = WorkDetail.query.order_by(
|
||||
WorkDetail.uploaded_at.desc()
|
||||
|
||||
@@ -6,15 +6,16 @@ from app import db
|
||||
from app.models import Task, WorkDetail
|
||||
from app.service.logger import log_activity
|
||||
|
||||
# keep helper inside controller
|
||||
|
||||
def to_2_decimal(value):
|
||||
try:
|
||||
if value is None or value == "":
|
||||
return None
|
||||
return round(float(value), 2)
|
||||
return round(float(str(value).replace(",", "")), 2)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def upload_controller():
|
||||
if 'file' not in request.files:
|
||||
return "No file part"
|
||||
@@ -29,7 +30,11 @@ def upload_controller():
|
||||
|
||||
log_activity(current_user.username, "File Upload", f"Uploaded file: {file.filename}")
|
||||
|
||||
# =========================
|
||||
# READ WORK DETAILS (TOP PART)
|
||||
# =========================
|
||||
work_details_data = pd.read_excel(filepath, nrows=11, header=None, dtype=str)
|
||||
|
||||
work_details_dict = {
|
||||
"name_of_work": work_details_data.iloc[0, 1],
|
||||
"cover_agreement_no": work_details_data.iloc[1, 1],
|
||||
@@ -43,11 +48,43 @@ def upload_controller():
|
||||
"measurement_book": work_details_data.iloc[9, 1],
|
||||
"district": work_details_data.iloc[10, 1]
|
||||
}
|
||||
|
||||
work_details_dict = {k: (None if pd.isna(v) else v) for k, v in work_details_dict.items()}
|
||||
work_detail = WorkDetail(**work_details_dict)
|
||||
db.session.add(work_detail)
|
||||
|
||||
# =========================
|
||||
# CHECK EXISTING WORKDETAIL (FOR OVERWRITE)
|
||||
# =========================
|
||||
existing_work = WorkDetail.query.filter_by(
|
||||
scheme_id=work_details_dict["scheme_id"],
|
||||
date_of_billing=work_details_dict["date_of_billing"],
|
||||
name_of_village=work_details_dict["name_of_village"]
|
||||
).first()
|
||||
|
||||
if existing_work:
|
||||
# 🔥 DELETE OLD TASKS
|
||||
Task.query.filter_by(work_detail_id=existing_work.id).delete()
|
||||
|
||||
# UPDATE WORK DETAIL
|
||||
for key, value in work_details_dict.items():
|
||||
setattr(existing_work, key, value)
|
||||
|
||||
work_detail = existing_work
|
||||
|
||||
log_activity(current_user.username, "Overwrite", "Old data deleted and replaced")
|
||||
|
||||
else:
|
||||
# CREATE NEW WORK DETAIL
|
||||
work_detail = WorkDetail(**work_details_dict)
|
||||
db.session.add(work_detail)
|
||||
|
||||
db.session.flush() # 🔥 get work_detail.id
|
||||
|
||||
# =========================
|
||||
# READ MAIN DATA
|
||||
# =========================
|
||||
data = pd.read_excel(filepath, skiprows=10)
|
||||
data = data.astype(object).where(pd.notna(data), None)
|
||||
|
||||
expected_columns = [
|
||||
"serial_number", "task_name", "unit", "qty", "rate", "boq_amount",
|
||||
"previous_billed_qty", "previous_billing_amount",
|
||||
@@ -55,22 +92,48 @@ def upload_controller():
|
||||
"cumulative_billed_qty", "cumulative_billed_amount",
|
||||
"variation_qty", "variation_amount", "remark"
|
||||
]
|
||||
if data.shape[1] == len(expected_columns):
|
||||
data.columns = expected_columns
|
||||
|
||||
# Validate excel columns
|
||||
if data.shape[1] < len(expected_columns):
|
||||
|
||||
missing_cols = expected_columns[data.shape[1]:]
|
||||
|
||||
return (
|
||||
"Excel is missing required columns: "
|
||||
+ ", ".join(missing_cols),
|
||||
400
|
||||
)
|
||||
|
||||
elif data.shape[1] > len(expected_columns):
|
||||
|
||||
return (
|
||||
"Invalid Excel format. Extra unexpected columns found.",
|
||||
400
|
||||
)
|
||||
|
||||
else:
|
||||
data.columns = expected_columns[:data.shape[1]]
|
||||
data.columns = expected_columns
|
||||
# =========================
|
||||
# INSERT DATA (FRESH)
|
||||
# =========================
|
||||
tasks_to_add = []
|
||||
|
||||
current_main_task_serial = None
|
||||
current_main_task_name = None
|
||||
for _, row in data.iterrows():
|
||||
|
||||
for index, row in data.iterrows():
|
||||
task_name = str(row["task_name"]) if row["task_name"] else ""
|
||||
serial_number = str(row["serial_number"]) if row["serial_number"] else None
|
||||
|
||||
if serial_number:
|
||||
current_main_task_serial = serial_number
|
||||
current_main_task_name = task_name
|
||||
parent_id = None
|
||||
parent_id = None
|
||||
else:
|
||||
parent_id = current_main_task_serial
|
||||
|
||||
task = Task(
|
||||
work_detail_id=work_detail.id,
|
||||
district=work_details_dict.get("district"),
|
||||
block_name=work_details_dict["block"],
|
||||
village_name=work_details_dict["name_of_village"],
|
||||
@@ -90,17 +153,20 @@ def upload_controller():
|
||||
variation_amount=to_2_decimal(row["variation_amount"]),
|
||||
parent_id=parent_id,
|
||||
parent_task_name=current_main_task_name if not serial_number else None,
|
||||
remark=row["remark"]
|
||||
# remark=row["remark"],
|
||||
remark=None if pd.isna(row["remark"]) else str(row["remark"]).strip(),
|
||||
row_index=index # 🔥 optional but useful
|
||||
)
|
||||
db.session.add(task)
|
||||
|
||||
tasks_to_add.append(task)
|
||||
|
||||
db.session.bulk_save_objects(tasks_to_add) # 🔥 FAST INSERT
|
||||
db.session.commit()
|
||||
|
||||
|
||||
log_activity(
|
||||
current_user.username,
|
||||
"Database Insert",
|
||||
f"Inserted work details and tasks from {file.filename}"
|
||||
f"Inserted {len(tasks_to_add)} rows from {file.filename}"
|
||||
)
|
||||
|
||||
return redirect(url_for('main.display_tasks'))
|
||||
|
||||
|
||||
return redirect(url_for('main.display_tasks'))
|
||||
Reference in New Issue
Block a user