diff --git a/controllers/auth_controller.py b/controllers/auth_controller.py index 0e63627..279c959 100644 --- a/controllers/auth_controller.py +++ b/controllers/auth_controller.py @@ -6,7 +6,6 @@ from model.Log import LogHelper auth_bp = Blueprint('auth', __name__) - @auth_bp.route('/login', methods=['GET', 'POST']) def login(): diff --git a/controllers/block_controller.py b/controllers/block_controller.py index 8f2e80a..225a158 100644 --- a/controllers/block_controller.py +++ b/controllers/block_controller.py @@ -7,12 +7,12 @@ from model.Block import Block from model.Utilities import HtmlHelper block_bp = Blueprint('block', __name__) - +block = Block() # --- Add Block page ------- @block_bp.route('/add_block', methods=['GET', 'POST']) @login_required def add_block(): - block = Block() + # block = Block() if request.method == 'POST': block.AddBlock(request) @@ -62,7 +62,7 @@ def get_districts(state_id): @login_required def check_block(): - block = Block() + # block = Block() return block.CheckBlock(request) @@ -70,8 +70,8 @@ def check_block(): @login_required def edit_block(block_id): - block = Block() - + +# block = Block() if request.method == 'POST': block.EditBlock(request, block_id) block.resultMessage @@ -90,7 +90,10 @@ def edit_block(block_id): for rs in cursor.stored_results(): states = rs.fetchall() - cursor.callproc("GetAllDistrictsData") + # cursor.callproc("GetAllDistrictsData") + # for rs in cursor.stored_results(): + # districts = rs.fetchall() + cursor.callproc("GetAllDistricts") for rs in cursor.stored_results(): districts = rs.fetchall() @@ -111,7 +114,7 @@ def edit_block(block_id): @login_required def delete_block(block_id): - block = Block() + # block = Block() block.DeleteBlock(request, block_id) return redirect(url_for('block.add_block')) \ No newline at end of file diff --git a/controllers/district_controller.py b/controllers/district_controller.py index fe6efd7..7cbf337 100644 --- a/controllers/district_controller.py +++ b/controllers/district_controller.py @@ -5,12 +5,13 @@ from model.District import District from model.State import State district_bp = Blueprint('district', __name__) +district = District() # ------- District page -------- @district_bp.route('/add_district', methods=['GET', 'POST']) @login_required def add_district(): - district = District() + # district = District() if request.method == 'POST': district.AddDistrict(request=request) @@ -32,7 +33,7 @@ def add_district(): @login_required def check_district(): - district = District() + # district = District() return district.CheckDistrict(request=request) @@ -41,7 +42,7 @@ def check_district(): @login_required def delete_district(district_id): - district = District() + # district = District() district.DeleteDistrict(request=request, district_id=district_id) @@ -56,7 +57,7 @@ def delete_district(district_id): @login_required def edit_district(district_id): - district = District() + # district = District() state = State() if request.method == 'POST': diff --git a/controllers/excel_upload_controller.py b/controllers/excel_upload_controller.py index d1e4c3e..e1d7a46 100644 --- a/controllers/excel_upload_controller.py +++ b/controllers/excel_upload_controller.py @@ -59,21 +59,21 @@ def show_table(filename): try: cursor = connection.cursor(dictionary=True) - cursor.callproc('GetStateByName', [file_info['State']]) + cursor.callproc('CheckStateExists', [file_info['State']]) for result in cursor.stored_results(): state_data = result.fetchone() if not state_data: errors.append(f"State '{file_info['State']}' is not valid. Please add it.") if state_data: - cursor.callproc('GetDistrictByNameAndStates', [file_info['District'], state_data['State_ID']]) + cursor.callproc('GetDistrictByNameAndState', [file_info['District'], state_data['State_Id']]) # Change GetDistrictByNameAndStates to GetDistrictByNameAndState for result in cursor.stored_results(): district_data = result.fetchone() if not district_data: errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.") if district_data: - cursor.callproc('GetBlockByNameAndDistricts', [file_info['Block'], district_data['District_ID']]) + cursor.callproc('GetBlockByNameAndDistrict', [file_info['Block'], district_data['District_id']]) #Change District_ID to District_id and GetBlockByNameAndDistricts to GetBlockByNameAndDistrict for result in cursor.stored_results(): block_data = result.fetchone() if not block_data: @@ -84,7 +84,9 @@ def show_table(filename): subcontractor_data = result.fetchone() if not subcontractor_data: - cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']]) + # cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']]) + # connection.commit() + cursor.callproc('SaveContractor', [file_info.get('Subcontractor'),None,None,None,None,None,None,None,None]) connection.commit() cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']]) for result in cursor.stored_results(): @@ -229,7 +231,7 @@ def save_data(): else: work_type = " ".join(words[:work_pos + 1]) if Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower(): - print("village_name ::", village_name, "|| work_type ::", work_type) + # print("village_name ::", village_name, "|| work_type ::", work_type) if block_id and village_name: village_id = None cursor.callproc("GetVillageId", (block_id, village_name)) @@ -242,11 +244,11 @@ def save_data(): for result in cursor.stored_results(): result = result.fetchone() village_id = result[0] if result else None - print("village_id :", village_id) - print("block_id :", block_id) - print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, - Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount, - SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount) + # print("village_id :", village_id) + # print("block_id :", block_id) + # print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, + # Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount, + # SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount) args = ( PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, @@ -255,22 +257,39 @@ def save_data(): subcontractor_id, 0 ) - print("All invoice Details ",args) + # print("All invoice Details ",args) + # add subcontarctor id in invoice table results = cursor.callproc('SaveInvoice', args) invoice_id = results[-1] - print("invoice id from the excel ", invoice_id) + print("**************************************************************") + print(invoice_id) + print("**************************************************************") + cursor.callproc( + "SavePayment", + ( + PMC_No, + Invoice_No, # required + Payment_Amount, + TDS_Payment_Amount, + Total_Amount, + UTR, + invoice_id # last + ) + ) + + # print("invoice id from the excel ", invoice_id) if isinstance(hold_columns, str): hold_columns = ast.literal_eval(hold_columns) if isinstance(hold_columns, list) and all(isinstance(hold, dict) for hold in hold_columns): for hold in hold_columns: - print(f"Processing hold: {hold}") + # print(f"Processing hold: {hold}") hold_column_name = hold.get('column_name') # Get column name hold_type_id = hold.get('hold_type_id') # Get hold_type_id if hold_column_name: hold_amount = entry.get( hold_column_name) # Get the value for that specific hold column if hold_amount is not None: - print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}") + # print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}") hold_join_data = { "Contractor_Id": subcontractor_id, "Invoice_Id": invoice_id, @@ -289,8 +308,8 @@ def save_data(): print("Hold columns data is not a valid list of dictionaries.") #---------------------------------------------Credit Note--------------------------------------------------------------------------- elif any(keyword in Invoice_Details.lower() for keyword in ['credit note','logging report']): - print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount, - After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No) + # print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount, + # After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No) cursor.callproc( 'AddCreditNoteFromExcel', [ @@ -315,52 +334,108 @@ def save_data(): ] # Step 3: Matching condition if any(kw in normalized_details for kw in keywords): - print("✅ Match found. Inserting hold release for:", Invoice_Details) + # print("✅ Match found. Inserting hold release for:", Invoice_Details) cursor.callproc( 'AddHoldReleaseFromExcel', [PMC_No, Invoice_No, Invoice_Details, Basic_Amount, Final_Amount, UTR, subcontractor_id] ) connection.commit() - print("✅ Hold release inserted for:", PMC_No, Invoice_Details) + # print("✅ Hold release inserted for:", PMC_No, Invoice_Details) #------------------------------------------------------------------------------------------------------------------ elif Invoice_Details and any( - keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']): - print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id) + keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'gst release note']): + # print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id) cursor.callproc( 'AddGSTReleaseFromExcel', [PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id] ) - if PMC_No and Total_Amount and UTR: - print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR ) - cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )) - if not village_id: - village_id = None - cursor.callproc('InsertOrUpdateInPayment', ( - PMC_No, - village_id, - work_type, - Invoice_Details, - Invoice_Date, - Invoice_No, - Basic_Amount, - Debit_Amount, - After_Debit_Amount, - Amount, - GST_Amount, - TDS_Amount, - SD_Amount, - On_Commission, - Hydro_Testing, - 0, - GST_SD_Amount, - Final_Amount, - Payment_Amount, - TDS_Payment_Amount, - Total_Amount, - UTR, - subcontractor_id - )) +# -------------------------------------- +# If no village/work detected, only PMC/Payment + if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()): + # if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower() and 'gst' in Invoice_Details.lower() and 'gst release note' in Invoice_Details.lower() and 'release' in Invoice_Details.lower()): + + # ---------- Only PMC / Payment rows ---------- + if PMC_No and not Invoice_No and UTR : + # print("No village/work, using PMC only :", PMC_No) + + # check invoice exists + # cursor.execute( + # "SELECT invoice_id FROM invoice WHERE PMC_No=%s ORDER BY invoice_id DESC LIMIT 1", + # (PMC_No,) + # ) + # row = cursor.fetchone() + # invoice_id = row[0] if row else None + + # # insert invoice if not exists + + # if not invoice_id: + print(" extra payment :", PMC_No,Total_Amount,UTR, subcontractor_id) + + # cursor.execute( + # """ + # INSERT INTO invoice (PMC_No,Contractor_Id) VALUES (%s, %s); + # """, + # (PMC_No, subcontractor_id) + # ) + # connection.commit() + + # cursor.execute( + # "SELECT invoice_id FROM invoice WHERE PMC_No=%s AND Contractor_Id =%s ORDER BY invoice_id DESC LIMIT 1", + # (PMC_No, subcontractor_id) + # ) + # row = cursor.fetchone() + cursor.callproc("insertExtrapaymet",(PMC_No, subcontractor_id)) + for result in cursor.stored_results(): + row = result.fetchone() + invoice_id = row[0] if row else None + # insert payment + cursor.callproc( + "SavePayment", + ( + PMC_No, + Invoice_No, # required + Payment_Amount, + TDS_Payment_Amount, + Total_Amount, + UTR, + invoice_id + ) + ) + + # if PMC_No and Total_Amount and UTR: + # print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR ) + + # Add inoice id in payment table + # cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR, invoice_id)) + + # if not village_id: + # village_id = None + # cursor.callproc('InsertOrUpdateInPayment', ( + # PMC_No, + # village_id, + # work_type, + # Invoice_Details, + # Invoice_Date, + # Invoice_No, + # Basic_Amount, + # Debit_Amount, + # After_Debit_Amount, + # Amount, + # GST_Amount, + # TDS_Amount, + # SD_Amount, + # On_Commission, + # Hydro_Testing, + # 0, + # GST_SD_Amount, + # Final_Amount, + # Payment_Amount, + # TDS_Payment_Amount, + # Total_Amount, + # UTR,f + # subcontractor_id + # )) connection.commit() return jsonify({"success": "Data saved successfully!"}), 200 except Exception as e: diff --git a/controllers/hold_types_controller.py b/controllers/hold_types_controller.py index 40b2b20..6b82334 100644 --- a/controllers/hold_types_controller.py +++ b/controllers/hold_types_controller.py @@ -5,12 +5,12 @@ from model.GST import GST hold_bp = Blueprint("hold_types", __name__) - +hold = HoldTypes() # ---------------- ADD HOLD TYPE ---------------- @hold_bp.route('/add_hold_type', methods=['GET','POST']) @login_required def add_hold_type(): - hold = HoldTypes() + # hold = HoldTypes() if request.method == 'POST': hold.AddHoldType(request) @@ -30,7 +30,7 @@ def add_hold_type(): @login_required def check_hold_type(): - hold = HoldTypes() + # hold = HoldTypes() return hold.CheckHoldType(request) # if exists @@ -39,7 +39,7 @@ def check_hold_type(): @login_required def edit_hold_type(id): - hold = HoldTypes() + # hold = HoldTypes() if request.method == 'POST': hold.EditHoldType(request, id) # ✅ @@ -58,7 +58,7 @@ def edit_hold_type(id): @login_required def delete_hold_type(id): - hold = HoldTypes() + # hold = HoldTypes() hold.DeleteHoldType(request, id) # ✅ return redirect(url_for("hold_types.add_hold_type")) diff --git a/controllers/invoice_controller.py b/controllers/invoice_controller.py index 1170741..0bc947a 100644 --- a/controllers/invoice_controller.py +++ b/controllers/invoice_controller.py @@ -1,6 +1,3 @@ - - - # controllers/invoice_controller.py from flask import Blueprint, request, jsonify, render_template @@ -40,7 +37,11 @@ def add_invoice(): village_id = village_result['Village_Id'] invoice_id = insert_invoice(data, village_id) - assign_subcontractor(data, village_id) + # assign_subcontractor(data, village_id) + print("********************************************************************") + print("Manully added invoice id :",invoice_id) + print("********************************************************************") + insert_hold_types(data, invoice_id) log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'") @@ -83,7 +84,7 @@ def edit_invoice(invoice_id): if request.method == 'POST': data = request.form update_invoice(data, invoice_id) - update_inpayment(data) + # update_inpayment(data) log_action("Edit invoice", f"edited invoice '{invoice_id}'") return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200 diff --git a/controllers/payment_controller.py b/controllers/payment_controller.py index d66edab..ed10850 100644 --- a/controllers/payment_controller.py +++ b/controllers/payment_controller.py @@ -28,8 +28,8 @@ def add_payment(): utr = request.form['utr'] LogHelper.log_action("Add Payment", f"User {current_user.id} Add Payment '{pmc_no}'") - Paymentmodel.insert_payment(pmc_no, invoice_no, amount, tds_amount, total_amount, utr) - Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr) + Paymentmodel.insert_payment(subcontractor_id,pmc_no, invoice_no, amount, tds_amount, total_amount, utr) + # Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr) return redirect(url_for('payment_bp.add_payment')) @@ -72,15 +72,13 @@ def edit_payment(payment_id): Paymentmodel.call_update_payment_proc(payment_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr) # Update inpayment - connection = Paymentmodel.get_connection() - cursor = connection.cursor() - cursor.callproc( - 'UpdateInpaymentByPMCInvoiceUTR', - [amount, tds_amount, total_amount, pmc_no, invoice_no, utr] -) - connection.commit() - cursor.close() - connection.close() + # connection = Paymentmodel.get_connection() + # cursor = connection.cursor() + # cursor.callproc('UpdateInpaymentByPMCInvoiceUTR',[amount, tds_amount, total_amount, pmc_no, invoice_no, utr]) + + # connection.commit() + # cursor.close() + # connection.close() return redirect(url_for('payment_bp.add_payment')) diff --git a/controllers/pmc_report_controller.py b/controllers/pmc_report_controller.py index 76460e7..e1223ee 100644 --- a/controllers/pmc_report_controller.py +++ b/controllers/pmc_report_controller.py @@ -1,40 +1,40 @@ -from flask import Blueprint, render_template, send_from_directory -from flask_login import login_required +# from flask import Blueprint, render_template, send_from_directory +# from flask_login import login_required +# from model.PmcReport import PmcReport -from model.PmcReport import PmcReport +# pmc_report_bp = Blueprint("pmc_report", __name__) -pmc_report_bp = Blueprint("pmc_report", __name__) +# # ---------------- Contractor Report by pmc no ---------------- +# @pmc_report_bp.route("/pmc_report/") +# @login_required +# def pmc_report(pmc_no): +# data = PmcReport.get_pmc_report(pmc_no) +# if not data: +# return "No PMC found with this number", 404 -# ---------------- Contractor Report by pmc no ---------------- -@pmc_report_bp.route("/pmc_report/") -@login_required -def pmc_report(pmc_no): - data = PmcReport.get_pmc_report(pmc_no) - if not data: - return "No PMC found with this number", 404 +# return render_template( +# "pmc_report.html", +# info=data["info"], +# invoices=data["invoices"], +# hold_types=data["hold_types"], +# gst_rel=data["gst_rel"], +# payments=data["payments"], +# credit_note=data["credit_note"], +# hold_release=data["hold_release"], +# total=data["total"] +# ) - return render_template( - "pmc_report.html", - info=data["info"], - invoices=data["invoices"], - hold_types=data["hold_types"], - gst_rel=data["gst_rel"], - payments=data["payments"], - credit_note=data["credit_note"], - hold_release=data["hold_release"], - total=data["total"] - ) +# # ---------------- Contractor Download Report by pmc no ---------------- +# @pmc_report_bp.route("/download_pmc_report/") +# @login_required +# def download_pmc_report(pmc_no): -# ---------------- Contractor Download Report by pmc no ---------------- -@pmc_report_bp.route("/download_pmc_report/") -@login_required -def download_pmc_report(pmc_no): +# result = PmcReport.download_pmc_report(pmc_no) - result = PmcReport.download_pmc_report(pmc_no) +# if not result: +# return "No contractor found for this PMC No", 404 - if not result: - return "No contractor found for this PMC No", 404 +# output_folder, file_name = result - output_folder, file_name = result +# return send_from_directory(output_folder, file_name, as_attachment=True) - return send_from_directory(output_folder, file_name, as_attachment=True) \ No newline at end of file diff --git a/controllers/report_controller.py b/controllers/report_controller.py index 9fe62ce..4354ecc 100644 --- a/controllers/report_controller.py +++ b/controllers/report_controller.py @@ -1,13 +1,10 @@ -from flask import Blueprint, render_template, request, jsonify +from flask import Blueprint, render_template, request, jsonify, send_file from flask_login import login_required, current_user - +from services.ReportService import ReportService from model.Report import ReportHelper -from model.Log import LogHelper - report_bp = Blueprint("report", __name__) - # ---------------- Report Page ---------------- @report_bp.route("/report") @login_required @@ -20,28 +17,45 @@ def report_page(): @login_required def search_contractor(): - subcontractor_name = request.form.get("subcontractor_name") - - LogHelper.log_action( - "Search Contractor", - f"User {current_user.id} searched contractor '{subcontractor_name}'" - ) - data = ReportHelper.search_contractor(request) - return jsonify(data) + # Pagination (basic) + page = int(request.form.get("page", 1)) + per_page = 20 + + start = (page - 1) * per_page + end = start + per_page + + paginated_data = data[start:end] + + return jsonify({ + "data": paginated_data, + "total": len(data) + }) # ---------------- Contractor Report by contractor id ---------------- @report_bp.route('/contractor_report/') @login_required def contractor_report(contractor_id): - data = ReportHelper.get_contractor_report(contractor_id) + service = ReportService(contractor_id=contractor_id).load_data() return render_template( 'subcontractor_report.html', contractor_id=contractor_id, - **data + **service.get_web_data() + ) + +# ---------------- Contractor Report by pmc no ---------------- +@report_bp.route("/pmc_report/") +@login_required +def pmc_report(pmc_no): + + service = ReportService(pmc_no=pmc_no).load_data() + + return render_template( + "pmc_report.html", + **service.get_web_data() ) # ---------------- Contractor Download Report by contractor id ---------------- @@ -49,5 +63,24 @@ def contractor_report(contractor_id): @login_required def download_report(contractor_id): - return ReportHelper().download_report(contractor_id=contractor_id) - \ No newline at end of file + service = ReportService(contractor_id=contractor_id).load_data() + + file, error = service.download_excel() + + if error: + return error, 404 + + return send_file(file, as_attachment=True) + +# ---------------- Contractor Download Report by pmc no ---------------- +@report_bp.route("/download_pmc_report/") +@login_required +def download_pmc_report(pmc_no): + + service = ReportService(pmc_no=pmc_no).load_data() + + file, error = service.download_excel() + if error: + return error, 404 + + return send_file(file, as_attachment=True) \ No newline at end of file diff --git a/controllers/state_controller.py b/controllers/state_controller.py index a26c951..cf1bb13 100644 --- a/controllers/state_controller.py +++ b/controllers/state_controller.py @@ -3,13 +3,13 @@ from flask_login import login_required from model.State import State state_bp = Blueprint('state', __name__) - +state = State() # ----- State page ------ @state_bp.route('/add_state', methods=['GET', 'POST']) @login_required def add_state(): - state = State() + # state = State() if request.method == 'POST': state.AddState(request=request) @@ -24,7 +24,7 @@ def add_state(): @login_required def check_state(): - state = State() + # state = State() return state.CheckState(request=request) @@ -33,7 +33,7 @@ def check_state(): @login_required def deleteState(id): - state = State() + # state = State() state.DeleteState(request=request, id=id) @@ -47,7 +47,7 @@ def deleteState(id): @login_required def editState(id): - state = State() + # state = State() if request.method == 'POST': diff --git a/controllers/village_controller.py b/controllers/village_controller.py index 27a1ff2..2567c9b 100644 --- a/controllers/village_controller.py +++ b/controllers/village_controller.py @@ -11,14 +11,14 @@ from model.State import State # Create Blueprint village_bp = Blueprint('village', __name__) - +village = Village() # ------------------------- Add Village ------------------------- @village_bp.route('/add_village', methods=['GET', 'POST']) @login_required def add_village(): - village = Village() + # village = Village() if request.method == 'POST': village.AddVillage(request=request) @@ -79,14 +79,14 @@ def get_blocks(district_id): @village_bp.route('/check_village', methods=['POST']) @login_required def check_village(): - village = Village() + # village = Village() return village.CheckVillage(request=request) @village_bp.route('/delete_village/') @login_required def delete_village(village_id): - village = Village() + # village = Village() village.DeleteVillage(request=request, village_id=village_id) # ✅ Convert resultMessage to string if it's a Response or tuple @@ -112,7 +112,7 @@ def delete_village(village_id): @login_required def edit_village(village_id): - village = Village() + # village = Village() if request.method == 'POST': diff --git a/main.py b/main.py index 96a2977..f664f5a 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,7 @@ from controllers.payment_controller import payment_bp from controllers.gst_release_controller import gst_release_bp from controllers.excel_upload_controller import excel_bp from controllers.report_controller import report_bp -from controllers.pmc_report_controller import pmc_report_bp +# from controllers.pmc_report_controller import pmc_report_bp from controllers.hold_types_controller import hold_bp from dotenv import load_dotenv @@ -57,7 +57,7 @@ app.register_blueprint(payment_bp) app.register_blueprint(gst_release_bp) app.register_blueprint(excel_bp) app.register_blueprint(report_bp) -app.register_blueprint(pmc_report_bp) +# app.register_blueprint(pmc_report_bp) app.register_blueprint(hold_bp) # ---------------- Run App ---------------- diff --git a/model/Block.py b/model/Block.py index 640ab0c..aeb169c 100644 --- a/model/Block.py +++ b/model/Block.py @@ -1,16 +1,6 @@ -from flask import Blueprint, render_template, request, redirect, url_for, jsonify - from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType from model.Log import LogData, LogHelper - -import os -import config -import re - -import mysql.connector -from mysql.connector import Error - -from model.ItemCRUD import ItemCRUD, itemCRUDMapping +from model.ItemCRUD import ItemCRUD class Block: @@ -22,9 +12,7 @@ class Block: self.isSuccess = False self.resultMessage = "" - # ---------------------------------------------------------- # Add Block - # ---------------------------------------------------------- def AddBlock(self, request): block = ItemCRUD(itemType=ItemCRUDType.Block) @@ -37,17 +25,7 @@ class Block: self.resultMessage = block.resultMessage return - # ---------------------------------------------------------- - # Get All Blocks - # ---------------------------------------------------------- - # def GetAllBlocks(self): - - # block = ItemCRUD(itemType=ItemCRUDType.Block) - # blocksdata = block.GetAllData(request=request, storedproc="GetAllBlock") - # self.isSuccess = block.isSuccess - # self.resultMessage = block.resultMessage - # return blocksdata - + # Get All Blocks def GetAllBlocks(self, request): block = ItemCRUD(itemType=ItemCRUDType.Block) @@ -57,18 +35,8 @@ class Block: self.resultMessage = block.resultMessage return blocksdata - # ---------------------------------------------------------- + # Check Block Exists - # ---------------------------------------------------------- - - # def CheckBlock(self, request): - # block = ItemCRUD(itemType=ItemCRUDType.Block) - # block_name = request.json.get('block_Name', '').strip() - # district_id = request.json.get('district_Id') - # result = block.CheckItem(request=request, parentid=district_id, childname=block_name, storedprocfetch="GetBlockByNameAndDistrict") - # self.isSuccess = block.isSuccess - # self.resultMessage = block.resultMessage - # return result def CheckBlock(self, request): block = ItemCRUD(itemType=ItemCRUDType.Block) data = request.get_json(silent=True) or request.form @@ -85,24 +53,7 @@ class Block: self.resultMessage = block.resultMessage return result - # ---------------------------------------------------------- # Get Block By ID - # ---------------------------------------------------------- - # def GetBlockByID(self, id): - - # block = ItemCRUD(itemType=ItemCRUDType.Village) - # blockdata = block.GetAllData(id=id,storedproc="GetBlockDataByID") - # self.isSuccess = block.isSuccess - # self.resultMessage = block.resultMessage - # print("akash"+blockdata) - # return blockdata - - # def GetBlockByID(self,request,id): - # block = ItemCRUD(itemType=ItemCRUDType.Block) - # blockdata = block.GetDataByID(request=request,id=id,storedproc="GetBlockDataByID") - # self.isSuccess = block.isSuccess - # self.resultMessage = block.resultMessage - # return blockdata def GetBlockByID(self, id): block = ItemCRUD(itemType=ItemCRUDType.Block) @@ -116,20 +67,8 @@ class Block: self.resultMessage = block.resultMessage return blockdata - # ---------------------------------------------------------- + # Update Block - # ---------------------------------------------------------- - # def EditBlock(self, request, block_id): - - # block = ItemCRUD(itemType=ItemCRUDType.Block) - - # district_id = request.form.get('district_Id') - # block_name = request.form.get('block_Name', '').strip() - - # block.EditItem(request=request, childid=block_id, parentid=district_id, childname=block_name, storedprocadd="UpdateBlockById" ) - # self.isSuccess = block.isSuccess - # self.resultMessage = block.resultMessage - # return def EditBlock(self, request, block_id): block = ItemCRUD(itemType=ItemCRUDType.Block) @@ -149,9 +88,8 @@ class Block: self.resultMessage = block.resultMessage return - # ---------------------------------------------------------- - # Delete Block - # --------------------------------------------------------- + + # Delete Block def DeleteBlock(self,request, id): block = ItemCRUD(itemType=ItemCRUDType.Block) diff --git a/model/ContractorInfo.py b/model/ContractorInfo.py index edfa3cd..6433f93 100644 --- a/model/ContractorInfo.py +++ b/model/ContractorInfo.py @@ -1,10 +1,5 @@ - - - from mysql.connector import Error import config -from datetime import datetime - class ContractorInfo: def __init__(self, contractor_id): diff --git a/model/HoldTypes.py b/model/HoldTypes.py index b8a9a46..c8689d4 100644 --- a/model/HoldTypes.py +++ b/model/HoldTypes.py @@ -3,7 +3,6 @@ from model.ItemCRUD import ItemCRUD from model.Utilities import ItemCRUDType class HoldTypes: - """CRUD operations for Hold Types using ItemCRUD""" def __init__(self): self.isSuccess = False @@ -33,7 +32,7 @@ class HoldTypes: self.isSuccess = hold.isSuccess self.resultMessage = hold.resultMessage - # ✅ Convert tuple → dictionary + # Convert tuple → dictionary data = [] for row in rows: data.append({ @@ -51,7 +50,7 @@ class HoldTypes: self.isSuccess = hold.isSuccess self.resultMessage = hold.resultMessage - # ✅ Convert tuple → dictionary + # Convert tuple → dictionary if row: return { "hold_type_id": row[0], diff --git a/model/Invoice.py b/model/Invoice.py index d82bd0d..3501717 100644 --- a/model/Invoice.py +++ b/model/Invoice.py @@ -71,22 +71,22 @@ def get_all_villages(): def insert_invoice(data, village_id): def operation(cursor): # Insert invoice - cursor.callproc('InsertInvoice', [ - data.get('pmc_no'), - village_id, - data.get('work_type'), - data.get('invoice_details'), - data.get('invoice_date'), - data.get('invoice_no'), - *get_numeric_values(data) - ]) - invoice_row = fetch_one(cursor) - if not invoice_row: - raise Exception("Invoice ID not returned") - invoice_id = invoice_row.get('invoice_id') + # cursor.callproc('InsertInvoice', [ + # data.get('pmc_no'), + # village_id, + # data.get('work_type'), + # data.get('invoice_details'), + # data.get('invoice_date'), + # data.get('invoice_no'), + # *get_numeric_values(data), + # data.get('subcontractor_id') - # Insert inpayment - cursor.callproc('InsertInpayment', [ + # ]) + # invoice_row = fetch_one(cursor) + # if not invoice_row: + # raise Exception("Invoice ID not returned") + # invoice_id = invoice_row.get('invoice_id') + cursor.callproc('SaveInvoice', [ data.get('pmc_no'), village_id, data.get('work_type'), @@ -94,9 +94,27 @@ def insert_invoice(data, village_id): data.get('invoice_date'), data.get('invoice_no'), *get_numeric_values(data), - data.get('subcontractor_id') + data.get('subcontractor_id'), + 0 ]) - clear_results(cursor) + invoice_id = None + for result in cursor.stored_results(): + row = result.fetchone() + if row: + invoice_id = row['invoice_id'] + + # # Insert inpayment + # cursor.callproc('InsertInpayment', [ + # data.get('pmc_no'), + # village_id, + # data.get('work_type'), + # data.get('invoice_details'), + # data.get('invoice_date'), + # data.get('invoice_no'), + # *get_numeric_values(data), + # data.get('subcontractor_id') + # ]) + # clear_results(cursor) return invoice_id return execute_db_operation(operation) @@ -141,18 +159,18 @@ def update_invoice(data, invoice_id): clear_results(cursor) execute_db_operation(operation) -def update_inpayment(data): - def operation(cursor): - cursor.callproc('UpdateInpayment', [ - data.get('work_type'), - data.get('invoice_details'), - data.get('invoice_date'), - *get_numeric_values(data), - data.get('pmc_no'), - data.get('invoice_no') - ]) - clear_results(cursor) - execute_db_operation(operation) +# def update_inpayment(data): +# def operation(cursor): +# cursor.callproc('UpdateInpayment', [ +# data.get('work_type'), +# data.get('invoice_details'), +# data.get('invoice_date'), +# *get_numeric_values(data), +# data.get('pmc_no'), +# data.get('invoice_no') +# ]) +# clear_results(cursor) +# execute_db_operation(operation) def delete_invoice_data(invoice_id, user_id): def operation(cursor): @@ -173,22 +191,22 @@ def delete_invoice_data(invoice_id, user_id): clear_results(cursor) # Delete inpayment - cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no)) - clear_results(cursor) + # cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no)) + # clear_results(cursor) execute_db_operation(operation) # ------------------- Subcontractor Functions ------------------- -def assign_subcontractor(data, village_id): - def operation(cursor): - cursor.callproc('AssignSubcontractor', [ - data.get('pmc_no'), - data.get('subcontractor_id'), - village_id - ]) - clear_results(cursor) - execute_db_operation(operation) +# def assign_subcontractor(data, village_id): +# def operation(cursor): +# cursor.callproc('AssignSubcontractor', [ +# data.get('pmc_no'), +# data.get('subcontractor_id'), +# village_id +# ]) +# clear_results(cursor) +# execute_db_operation(operation) # ------------------- Hold Types Functions ------------------- diff --git a/model/ItemCRUD.py b/model/ItemCRUD.py index 3f2c656..5ba53e3 100644 --- a/model/ItemCRUD.py +++ b/model/ItemCRUD.py @@ -232,14 +232,13 @@ class ItemCRUD: if self.itemCRUDType.name == "GSTRelease" and data: cursor.callproc(storedprocupdate, ( - childid, - data['PMC_No'], - data['Invoice_No'], - data['Basic_Amount'], - data['Final_Amount'], - data['Total_Amount'], - data['UTR'], - data['Contractor_ID'] + data['p_pmc_no'], # PMC_No + data['p_invoice_no'], # Invoice_No + data['p_basic_amount'], # Basic_Amount + data['p_final_amount'], # Final_Amount + data['p_total_amount'], # Total_Amount + data['p_utr'], # UTR + data['p_gst_release_id']# GST_Release_Id )) connection.commit() diff --git a/model/Log.py b/model/Log.py index d3ed22f..e70aa2f 100644 --- a/model/Log.py +++ b/model/Log.py @@ -1,5 +1,4 @@ import os -from flask import current_app from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from datetime import datetime diff --git a/model/PmcReport.py b/model/PmcReport.py index c8ec69e..b3067f7 100644 --- a/model/PmcReport.py +++ b/model/PmcReport.py @@ -1,456 +1,137 @@ -import openpyxl -from openpyxl.styles import Font, PatternFill import config from flask_login import current_user from model.Log import LogHelper -from model.Report import ReportHelper +from services.Generalservice import GeneralUse from model.FolderAndFile import FolderAndFile +from model.Report import ReportHelper class PmcReport: + data=[] - @staticmethod - def get_pmc_report(pmc_no): + # @staticmethod + # def get_pmc_report(pmc_no): - connection = config.get_db_connection() - cursor = connection.cursor(dictionary=True, buffered=True) + # connection = config.get_db_connection() + # cursor = connection.cursor(dictionary=True, buffered=True) - try: + # try: + # pmc_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True) + # cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"])) + # hold_types = next(cursor.stored_results()).fetchall() - # cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,)) - # pmc_info = next(cursor.stored_results()).fetchone() - pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True) + # # Extract hold_type_ids + # hold_type_ids = [ht['hold_type_id'] for ht in hold_types] - if not pmc_info: - return None + # invoices = [] + # hold_type_ids_str = ",".join(map(str, hold_type_ids)) + # cursor.callproc('GetInvoices_WithHold',[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str]) + # for result in cursor.stored_results(): + # invoices = result.fetchall() - cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"])) - hold_types = next(cursor.stored_results()).fetchall() - - # Extract hold_type_ids - hold_type_ids = [ht['hold_type_id'] for ht in hold_types] - - invoices = [] - hold_amount_total = 0 - if hold_type_ids: - hold_type_ids_str = ",".join(map(str, hold_type_ids)) - cursor.callproc( - 'GetInvoices_WithHold', - [pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str] - ) - else: - cursor.callproc( - 'GetInvoices_NoHold', - [pmc_no, pmc_info["Contractor_Id"]] - ) - for result in cursor.stored_results(): - invoices = result.fetchall() - - if hold_type_ids: - hold_amount_total = sum(row.get('hold_amount', 0) or 0 for row in invoices) - - total_invo_final = sum(row.get('Final_Amount', 0) or 0 for row in invoices) - - - # GST RELEASE - # cursor.callproc('GetGSTReleaseByPMC', [pmc_no]) - # gst_rel = [] - # for result in cursor.stored_results(): - # gst_rel = result.fetchall() + # gst_rel = GeneralUse.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no]) + + # hold_release = GeneralUse.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no]) - gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no]) + # credit_note = GeneralUse.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no]) - total_gst_basic = sum(row.get('basic_amount', 0) or 0 for row in gst_rel) - total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel) + # payments = GeneralUse.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no]) + + # totals = { + # "sum_invo_basic_amt": sum(row.get('Basic_Amount', 0) or 0 for row in invoices), + # "sum_invo_debit_amt": sum(row.get('Debit_Amount', 0) or 0 for row in invoices), + # "sum_invo_after_debit_amt": sum(row.get('After_Debit_Amount', 0) or 0 for row in invoices), + # "sum_invo_amt": sum(row.get('Amount', 0) or 0 for row in invoices), + # "sum_invo_gst_amt": sum(row.get('GST_Amount', 0) or 0 for row in invoices), + # "sum_invo_tds_amt": sum(row.get('TDS_Amount', 0) or 0 for row in invoices), + # "sum_invo_ds_amt": sum(row.get('SD_Amount', 0) or 0 for row in invoices), + # "sum_invo_on_commission": sum(row.get('On_Commission', 0) or 0 for row in invoices), + # "sum_invo_hydro_test": sum(row.get('Hydro_Testing', 0) or 0 for row in invoices), + # "sum_invo_gst_sd_amt": sum(row.get('GST_SD_Amount', 0) or 0 for row in invoices), + # "sum_invo_final_amt": sum(row.get('Final_Amount', 0) or 0 for row in invoices), + # "sum_invo_hold_amt": sum(row.get('hold_amount', 0) or 0 for row in invoices), + # "sum_gst_basic_amt": sum(row.get('basic_amount', 0) or 0 for row in gst_rel), + # "sum_gst_final_amt": sum(row.get('final_amount', 0) or 0 for row in gst_rel), + # "sum_pay_payment_amt": sum(row.get('Payment_Amount', 0) or 0 for row in payments), + # "sum_pay_tds_payment_amt": sum(row.get('TDS_Payment_Amount', 0) or 0 for row in payments), + # "sum_pay_total_amt": sum(row.get('Total_amount', 0) or 0 for row in payments) + # } - # ---------------- HOLD RELEASE ---------------- - # cursor.callproc('GetHoldReleaseByPMC', [pmc_no]) - # hold_release = [] - # for result in cursor.stored_results(): - # hold_release = result.fetchall() + # return { + # "info": pmc_info, + # "invoices": invoices, + # "hold_types": hold_types, + # "gst_rel": gst_rel, + # "payments": payments, + # "credit_note": credit_note, + # "hold_release": hold_release, + # "total": totals + # } - hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no]) + # finally: + # cursor.close() + # connection.close() - # ---------------- CREDIT NOTE ---------------- - # cursor.callproc('GetCreditNoteByPMC', [pmc_no]) - # credit_note = [] - # for result in cursor.stored_results(): - # credit_note = result.fetchall() - - credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no]) - - payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no]) - - - # ---------------- PAYMENTS ---------------- - # cursor.callproc('GetPaymentsByPMC', [pmc_no]) - # payments = [] - # for result in cursor.stored_results(): - # payments = result.fetchall() - - - - total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments) - total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments) - - totals = { - "sum_invo_basic_amt": sum(row.get('Basic_Amount', 0) or 0 for row in invoices), - "sum_invo_debit_amt": sum(row.get('Debit_Amount', 0) or 0 for row in invoices), - "sum_invo_after_debit_amt": sum(row.get('After_Debit_Amount', 0) or 0 for row in invoices), - "sum_invo_amt": sum(row.get('Amount', 0) or 0 for row in invoices), - "sum_invo_gst_amt": sum(row.get('GST_Amount', 0) or 0 for row in invoices), - "sum_invo_tds_amt": sum(row.get('TDS_Amount', 0) or 0 for row in invoices), - "sum_invo_ds_amt": sum(row.get('SD_Amount', 0) or 0 for row in invoices), - "sum_invo_on_commission": sum(row.get('On_Commission', 0) or 0 for row in invoices), - "sum_invo_hydro_test": sum(row.get('Hydro_Testing', 0) or 0 for row in invoices), - "sum_invo_gst_sd_amt": sum(row.get('GST_SD_Amount', 0) or 0 for row in invoices), - "sum_invo_final_amt": total_invo_final, - "sum_invo_hold_amt": hold_amount_total, - "sum_gst_basic_amt": total_gst_basic, - "sum_gst_final_amt": total_gst_final, - "sum_pay_payment_amt": total_pay_amount, - "sum_pay_tds_payment_amt": sum(row.get('TDS_Payment_Amount', 0) or 0 for row in payments), - "sum_pay_total_amt": total_pay_total - } - - return { - "info": pmc_info, - "invoices": invoices, - "hold_types": hold_types, - "gst_rel": gst_rel, - "payments": payments, - "credit_note": credit_note, - "hold_release": hold_release, - "total": totals - } - - finally: - cursor.close() - connection.close() - - - @staticmethod - def download_pmc_report(pmc_no): - - connection = config.get_db_connection() - if not connection: - return None - - cursor = connection.cursor(dictionary=True) - - try: - # filename - filename = f"PMC_Report_{pmc_no}.xlsx" - - output_folder = FolderAndFile.get_download_folder() - output_file = FolderAndFile.get_download_path(filename) - - # ================= DATA FETCH ================= - - contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no], "one") - - if not contractor_info: - return None - - hold_types = ReportHelper.execute_sp(cursor, 'GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) - - hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} - - invoices = ReportHelper.execute_sp(cursor, 'GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) - - credit_notes = ReportHelper.execute_sp(cursor, 'GetCreditNoteByContractor', [contractor_info["Contractor_Id"]]) - - hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) - - all_payments = ReportHelper.execute_sp(cursor, 'GetAllPaymentsByPMC', [pmc_no]) - - gst_releases = ReportHelper.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no]) - - # ================= DATA MAPPING ================= - - hold_data = {} - for h in hold_amounts: - hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] - - payments_map = {} - for pay in all_payments: - if pay['invoice_no']: - payments_map.setdefault(pay['invoice_no'], []).append(pay) - - # ================= LOG ================= - LogHelper.log_action( - "Download PMC Report", - f"User {current_user.id} Download PMC Report '{pmc_no}'" - ) - - # ================= EXCEL ================= - workbook = openpyxl.Workbook() - sheet = workbook.active - sheet.title = "PMC Report" - - # HEADER INFO - sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."]) - sheet.append(["Contractor Name", contractor_info["Contractor_Name"]]) - sheet.append(["State", contractor_info["State_Name"]]) - sheet.append(["District", contractor_info["District_Name"]]) - sheet.append(["Block", contractor_info["Block_Name"]]) - sheet.append([]) - - base_headers = [ - "PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No", - "Basic Amount","Debit","After Debit Amount","GST","Amount","TDS", - "SD","On Commission","Hydro Testing","GST SD Amount" - ] - - hold_headers = [ht['hold_type'] for ht in hold_types] - - payment_headers = [ - "Final Amount","Payment Amount","TDS Payment","Total Paid","UTR" - ] - - headers = base_headers + hold_headers + payment_headers - sheet.append(headers) - - # STYLE - for cell in sheet[sheet.max_row]: - cell.font = Font(bold=True) - - # DATA - seen_invoices = set() - - for inv in invoices: - - invoice_no = inv["Invoice_No"] - payments = payments_map.get(invoice_no, []) - - if invoice_no in seen_invoices: - continue - - seen_invoices.add(invoice_no) - - first_payment = payments[0] if payments else None - - row = [ - pmc_no, - inv["Village_Name"], - inv["Work_Type"], - inv["Invoice_Details"], - inv["Invoice_Date"], - invoice_no, - inv["Basic_Amount"], - inv["Debit_Amount"], - inv["After_Debit_Amount"], - inv["GST_Amount"], - inv["Amount"], - inv["TDS_Amount"], - inv["SD_Amount"], - inv["On_Commission"], - inv["Hydro_Testing"], - inv["GST_SD_Amount"] - ] - - # HOLD DATA - invoice_holds = hold_data.get(inv["Invoice_Id"], {}) - for ht_id in hold_type_map.keys(): - row.append(invoice_holds.get(ht_id, "")) - - # PAYMENT DATA - row += [ - inv["Final_Amount"], - first_payment["Payment_Amount"] if first_payment else "", - first_payment["TDS_Payment_Amount"] if first_payment else "", - first_payment["Total_amount"] if first_payment else "", - first_payment["UTR"] if first_payment else "" - ] - - sheet.append(row) - - # AUTO WIDTH - for col in sheet.columns: - max_len = max((len(str(cell.value)) for cell in col if cell.value), default=0) - sheet.column_dimensions[col[0].column_letter].width = max_len + 2 - - # SAVE - workbook.save(output_file) - workbook.close() - - return output_folder, filename - - except Exception as e: - print(f"Error generating PMC report: {e}") - return None - - finally: - cursor.close() - connection.close() # @staticmethod # def download_pmc_report(pmc_no): # connection = config.get_db_connection() + # if not connection: + # return None + # cursor = connection.cursor(dictionary=True) - # # output_folder = "static/download" - # # output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx") - # output_folder = FolderAndFile.get_download_folder - # filename = f"PMC_Report_{pmc_no}.xlsx" - # output_file = FolderAndFile.get_download_path(filename) - # try: + # filename = f"PMC_Report_{pmc_no}.xlsx" - # cursor.callproc('GetContractorDetailsByPMC', [pmc_no]) - # contractor_info = next(cursor.stored_results()).fetchone() + # output_folder = FolderAndFile.get_download_folder() + # output_file = FolderAndFile.get_download_path(filename) + + # contractor_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no]) + + # contractor_info = contractor_info[0] if contractor_info else None + # print("contractor_info:::",contractor_info) # if not contractor_info: # return None - # cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) - # hold_types = next(cursor.stored_results()).fetchall() + # hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor',[contractor_info["Contractor_Id"]]) # hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} - # cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) - # invoices = next(cursor.stored_results()).fetchall() - - # cursor.callproc('GetCreditNoteByContractor',[contractor_info["Contractor_Id"]]) - - # credit_notes = [] - # for result in cursor.stored_results(): - # credit_notes = result.fetchall() + # invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None,pmc_no]) + # credit_notes = GeneralUse.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no]) # credit_note_map = {} # for cn in credit_notes: - # key = (cn["PMC_No"], cn["Invoice_No"]) + + # key = (str(cn['PMC_No']).strip()) # credit_note_map.setdefault(key, []).append(cn) - # cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) - # hold_amounts = next(cursor.stored_results()).fetchall() + # hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) + # gst_releases = GeneralUse.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no]) + # gst_release_map = {} + # for gr in gst_releases: + # key = (str(gr['PMC_No']).strip()) + # gst_release_map.setdefault(key, []).append(gr) + + # # ================= DATA MAPPING ================= # hold_data = {} # for h in hold_amounts: # hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] - # cursor.callproc('GetAllPaymentsByPMC', [pmc_no]) - # all_payments = next(cursor.stored_results()).fetchall() - - # payments_map = {} - # extra_payments = [] - - # for pay in all_payments: - # if pay['invoice_no']: - # payments_map.setdefault(pay['invoice_no'], []).append(pay) - # else: - # extra_payments.append(pay) - - # # ---------------- GST RELEASE DETAILS ---------------- - # cursor.callproc('GetGSTReleaseDetailsByPMC', [pmc_no]) - - # gst_releases = [] - # for result in cursor.stored_results(): - # gst_releases = result.fetchall() - - # gst_release_map = {} - - # for gr in gst_releases: - - # invoice_nos = [] - - # if gr['Invoice_No']: - - # cleaned = gr['Invoice_No'].replace(' ', '') - - # if '&' in cleaned: - # invoice_nos = cleaned.split('&') - - # elif ',' in cleaned: - # invoice_nos = cleaned.split(',') - - # else: - # invoice_nos = [cleaned] - - # for inv_no in invoice_nos: - # gst_release_map.setdefault(inv_no, []).append(gr) - - # LogHelper.log_action( - # "Download PMC Report", - # f"User {current_user.id} Download PMC Report '{pmc_no}'" - # ) - - # workbook = openpyxl.Workbook() - # sheet = workbook.active - # sheet.title = "PMC Report" - - # sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."]) - # sheet.append(["Contractor Name", contractor_info["Contractor_Name"], "", "GST No", contractor_info["GST_No"], "", "GST Type", contractor_info["GST_Registration_Type"]]) - # sheet.append(["State", contractor_info["State_Name"], "", "PAN No", contractor_info["PAN_No"], "", "Address", contractor_info["Address"]]) - # sheet.append(["District", contractor_info["District_Name"], "", "Mobile No", contractor_info["Mobile_No"]]) - # sheet.append(["Block", contractor_info["Block_Name"], "", "Email", contractor_info["Email"]]) - # sheet.append([]) - - # base_headers = [ - # "PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No", - # "Basic Amount","Debit","After Debit Amount","GST (18%)","Amount","TDS (1%)", - # "SD (5%)","On Commission","Hydro Testing","GST SD Amount" - # ] - - # hold_headers = [ht['hold_type'] for ht in hold_types] - - # payment_headers = [ - # "Final Amount","Payment Amount","TDS Payment","Total Paid","UTR" - # ] - - # sheet.append(base_headers + hold_headers + payment_headers) - - # header_fill = PatternFill(start_color="ADD8E6",end_color="ADD8E6",fill_type="solid") - # header_font = Font(bold=True) - - # for cell in sheet[sheet.max_row]: - # cell.font = header_font - # cell.fill = header_fill - - # seen_invoices = set() - # processed_payments = set() - - # for inv in invoices: - - # invoice_no = inv["Invoice_No"] - # payments = payments_map.get(invoice_no, []) - - # if invoice_no not in seen_invoices: - - # seen_invoices.add(invoice_no) - # first_payment = payments[0] if payments else None - - # row = [ - # pmc_no, inv["Village_Name"], inv["Work_Type"], - # inv["Invoice_Details"], inv["Invoice_Date"], invoice_no, - # inv["Basic_Amount"], inv["Debit_Amount"], - # inv["After_Debit_Amount"], inv["GST_Amount"], - # inv["Amount"], inv["TDS_Amount"], inv["SD_Amount"], - # inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"] - # ] - - # invoice_holds = hold_data.get(inv["Invoice_Id"], {}) - - # for ht_id in hold_type_map.keys(): - # row.append(invoice_holds.get(ht_id, "")) - - # row += [ - # inv["Final_Amount"], - # first_payment["Payment_Amount"] if first_payment else "", - # first_payment["TDS_Payment_Amount"] if first_payment else "", - # first_payment["Total_amount"] if first_payment else "", - # first_payment["UTR"] if first_payment else "" - # ] - - # sheet.append(row) - - # workbook.save(output_file) - # workbook.close() + # # ================= LOG ================= + # LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'") + # ReportHelper.generate_excel( + # 0, contractor_info, invoices, hold_types, hold_data, + # credit_note_map,gst_release_map, output_file) + # return output_folder, filename # finally: - # cursor.close() - # connection.close() \ No newline at end of file + # connection.close() + diff --git a/model/Report.py b/model/Report.py index 41d5ad2..da92bb1 100644 --- a/model/Report.py +++ b/model/Report.py @@ -2,9 +2,10 @@ import config from datetime import datetime from flask import send_file import openpyxl -from openpyxl.styles import Font +from openpyxl.styles import Font, PatternFill from model.FolderAndFile import FolderAndFile +from services.Generalservice import GeneralUse class ReportHelper: isSuccess = False @@ -16,30 +17,6 @@ class ReportHelper: self.resultMessage = "" self.data = [] - @staticmethod - def execute_sp(cursor, proc_name, params=[], fetch_one=False): - cursor.callproc(proc_name, params) - return ( - ReportHelper.fetch_one_result(cursor) - if fetch_one else - ReportHelper.fetch_all_results(cursor) - ) - - @staticmethod - def fetch_all_results(cursor): - data = [] - for result in cursor.stored_results(): - data = result.fetchall() - return data - - - @staticmethod - def fetch_one_result(cursor): - data = None - for result in cursor.stored_results(): - data = result.fetchone() - return data - @staticmethod def search_contractor(request): @@ -59,10 +36,7 @@ class ReportHelper: cursor = connection.cursor(dictionary=True) try: - data = ReportHelper.execute_sp( - cursor, - "search_contractor_info", - [ + data = GeneralUse.execute_sp(cursor,"search_contractor_info",[ subcontractor_name or None, pmc_no or None, state or None, @@ -71,8 +45,7 @@ class ReportHelper: village or None, year_from or None, year_to or None - ] - ) + ]) except Exception as e: print(f"Error in search_contractor: {e}") @@ -84,192 +57,156 @@ class ReportHelper: return data - - @staticmethod - def get_contractor_report(contractor_id): - connection = config.get_db_connection() - cursor = connection.cursor(dictionary=True, buffered=True) - - try: - # Contractor Info (only one fetch) - contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True) - # Hold Types - hold_types = ReportHelper.execute_sp(cursor, 'GetContractorHoldTypes', [contractor_id]) - # Invoices - invoices = ReportHelper.execute_sp(cursor, 'GetContractorInvoices', [contractor_id]) - # GST Release - gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTRelease', [contractor_id]) - # Hold Release - hold_release = ReportHelper.execute_sp(cursor, 'GetHoldRelease', [contractor_id]) - # Credit Note - credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNote', [contractor_id]) - # Payments - payments = ReportHelper.execute_sp(cursor, 'GetPayments', [contractor_id]) - - # Totals - total = { - "sum_invo_basic_amt": float(sum(row['Basic_Amount'] or 0 for row in invoices)), - "sum_invo_debit_amt": float(sum(row['Debit_Amount'] or 0 for row in invoices)), - "sum_invo_after_debit_amt": float(sum(row['After_Debit_Amount'] or 0 for row in invoices)), - "sum_invo_amt": float(sum(row['Amount'] or 0 for row in invoices)), - "sum_invo_gst_amt": float(sum(row['GST_Amount'] or 0 for row in invoices)), - "sum_invo_tds_amt": float(sum(row['TDS_Amount'] or 0 for row in invoices)), - "sum_invo_ds_amt": float(sum(row['SD_Amount'] or 0 for row in invoices)), - "sum_invo_on_commission": float(sum(row['On_Commission'] or 0 for row in invoices)), - "sum_invo_hydro_test": float(sum(row['Hydro_Testing'] or 0 for row in invoices)), - "sum_invo_gst_sd_amt": float(sum(row['GST_SD_Amount'] or 0 for row in invoices)), - "sum_invo_final_amt": float(sum(row['Final_Amount'] or 0 for row in invoices)), - "sum_invo_hold_amt": float(sum(row['hold_amount'] or 0 for row in invoices)), - - "sum_gst_basic_amt": float(sum(row['basic_amount'] or 0 for row in gst_rel)), - "sum_gst_final_amt": float(sum(row['final_amount'] or 0 for row in gst_rel)), - - "sum_pay_payment_amt": float(sum(row['Payment_Amount'] or 0 for row in payments)), - "sum_pay_tds_payment_amt": float(sum(row['TDS_Payment_Amount'] or 0 for row in payments)), - "sum_pay_total_amt": float(sum(row['Total_amount'] or 0 for row in payments)) - } - - current_date = datetime.now().strftime('%Y-%m-%d') - - finally: - cursor.close() - connection.close() - - return { - "contInfo": contInfo, - "invoices": invoices, - "hold_types": hold_types, - "gst_rel": gst_rel, - "payments": payments, - "credit_note": credit_note, - "hold_release": hold_release, - "total": total, - "current_date": current_date - } @staticmethod - def download_report(contractor_id): - try: - connection = config.get_db_connection() - cursor = connection.cursor(dictionary=True) + def get_contractor_info(contractor_id): + from model.ContractorInfo import ContractorInfo + contractor = ContractorInfo(contractor_id) + return contractor.contInfo if contractor.contInfo else None - # -------- Contractor Info -------- - contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True) - if not contInfo: - return "No contractor found", 404 + # call this method for excel formate written + @staticmethod + def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data, + credit_note_map, gst_release_map, output_file): + + workbook = openpyxl.Workbook() + sheet = workbook.active + sheet.title = "Contractor Report" - # -------- Invoice Data -------- - cursor.callproc('FetchInvoicesByContractor', [contractor_id]) + # Contractor Info + for field, value in contInfo.items(): + sheet.append([field.replace("_", " "), value]) + sheet.append([]) - invoices = [] - for result in cursor.stored_results(): - invoices.extend(result.fetchall()) + # Headers + base_headers = ["PMC No", "Village", "Work Type", "Invoice Details", "Invoice Date", "Invoice No", + "Basic Amount", "Debit", "After Debit Amount", "GST (18%)", "Amount", "TDS (1%)", + "SD (5%)", "On Commission", "Hydro Testing", "GST SD Amount"] - if not invoices: - return "No invoice data found" + hold_headers = [ht['hold_type'] for ht in hold_types] - # -------- Create Workbook -------- - workbook = openpyxl.Workbook() - sheet = workbook.active - sheet.title = "Contractor Report" + payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"] - # ================= CONTRACTOR DETAILS ================= - sheet.append(["SUB CONTRACTOR DETAILS"]) - sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True) - sheet.append([]) + all_headers = base_headers + hold_headers + payment_headers + sheet.append(all_headers) - sheet.append(["Name", contInfo.get("Contractor_Name") or ""]) - sheet.append(["Mobile No", contInfo.get("Mobile_No") or ""]) - sheet.append(["Email", contInfo.get("Email") or ""]) - sheet.append(["Village", contInfo.get("Village_Name") or ""]) - sheet.append(["Block", contInfo.get("Block_Name") or ""]) - sheet.append(["District", contInfo.get("District_Name") or ""]) - sheet.append(["State", contInfo.get("State_Name") or ""]) - sheet.append(["Address", contInfo.get("Address") or ""]) - sheet.append(["GST No", contInfo.get("GST_No") or ""]) - sheet.append(["PAN No", contInfo.get("PAN_No") or ""]) - sheet.append([]) - sheet.append([]) + for cell in sheet[sheet.max_row]: + cell.font = Font(bold=True) + cell.fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid") - # ================= TABLE HEADERS ================= - headers = [ - "PMC No", "Village", "Invoice No", "Invoice Date", "Work Type","Invoice_Details", - "Basic Amount", "Debit Amount", "After Debit Amount", - "Amount", "GST Amount", "TDS Amount", "SD Amount", - "On Commission", "Hydro Testing", "Hold Amount", - "GST SD Amount", "Final Amount", - "Payment Amount", "TDS Payment", - "Total Amount", "UTR" + processed_gst_releases = set() + appended_credit_keys = set() + previous_pmc_no = None + + for inv in invoices: + pmc_no = str(inv["PMC_No"]).strip() + + invoice_no = ( + inv["invoice_no"].replace(" ", "") if inv["invoice_no"] else "" + if inv["invoice_no"] not in (None, "", 0) + else "" + ) + key = (pmc_no) + + # Yellow separator + if previous_pmc_no and pmc_no != previous_pmc_no: + sheet.append([""] * len(all_headers)) + yellow_fill = PatternFill(start_color="FFFF99", end_color="FFFF99", fill_type="solid") + for cell in sheet[sheet.max_row]: + cell.fill = yellow_fill + + previous_pmc_no = pmc_no + + # Invoice Row + row = [ + pmc_no, + inv.get("Village_Name", ""), + inv.get("Work_Type", ""), + inv.get("Invoice_Details", ""), + inv.get("Invoice_Date", ""), + # inv.get("invoice_no",""), + invoice_no, + inv.get("Basic_Amount", ""), + inv.get("Debit_Amount", ""), + inv.get("After_Debit_Amount", ""), + inv.get("GST_Amount", ""), + inv.get("Amount", ""), + inv.get("TDS_Amount", ""), + inv.get("SD_Amount", ""), + inv.get("On_Commission", ""), + inv.get("Hydro_Testing", ""), + inv.get("GST_SD_Amount", "") ] - sheet.append(headers) - for col in range(1, len(headers) + 1): - sheet.cell(row=sheet.max_row, column=col).font = Font(bold=True) - # ================= DATA ================= - total_final = 0 - total_payment = 0 - total_amount = 0 + # Hold values + invoice_holds = hold_data.get(inv["Invoice_Id"], {}) + for ht_id in [ht['hold_type_id'] for ht in hold_types]: + row.append(invoice_holds.get(ht_id, "")) - for inv in invoices: - row = [ - inv.get("PMC_No"), - inv.get("Village_Name"), - inv.get("invoice_no"), - inv.get("Invoice_Date"), - inv.get("Work_Type"), - inv.get("Invoice_Details"), - inv.get("Basic_Amount"), - inv.get("Debit_Amount"), - inv.get("After_Debit_Amount"), - inv.get("Amount"), - inv.get("GST_Amount"), - inv.get("TDS_Amount"), - inv.get("SD_Amount"), - inv.get("On_Commission"), - inv.get("Hydro_Testing"), - inv.get("Hold_Amount"), - inv.get("GST_SD_Amount"), - inv.get("Final_Amount"), - inv.get("Payment_Amount"), - inv.get("TDS_Payment_Amount"), - inv.get("Total_Amount"), - inv.get("UTR") - ] + # Payment values + row += [ + inv.get("Final_Amount", ""), + inv.get("Payment_Amount", ""), + inv.get("TDS_Payment_Amount", ""), + inv.get("Total_Amount", ""), + inv.get("UTR", "") + ] - total_final += float(inv.get("Final_Amount") or 0) - total_payment += float(inv.get("Payment_Amount") or 0) - total_amount += float(inv.get("Total_Amount") or 0) + sheet.append(row) - sheet.append(row) + # GST Releases + if key in gst_release_map and key not in processed_gst_releases: + for gr in gst_release_map[key]: + gst_row = [ + pmc_no, "", "", "GST Release Note", "", gr.get("Invoice_No", ""), + gr.get("Basic_Amount", ""), "", "", "", "", "", "", "", "", "" + ] - # ================= TOTAL ROW ================= - sheet.append([]) - sheet.append([ - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "TOTAL", - total_final, - total_payment, - "", - total_amount, - "" - ]) + gst_row += [""] * len(hold_headers) - # ================= AUTO WIDTH ================= - for column in sheet.columns: - max_length = 0 - column_letter = column[0].column_letter - for cell in column: - if cell.value: - max_length = max(max_length, len(str(cell.value))) - sheet.column_dimensions[column_letter].width = max_length + 2 + gst_row += [ + gr.get("Final_Amount", ""), + "", + "", + gr.get("Total_Amount", ""), + gr.get("UTR", "") + ] + + sheet.append(gst_row) + + processed_gst_releases.add(key) + + # Credit Notes + if key in credit_note_map and key not in appended_credit_keys: + for cn in credit_note_map[key]: + cn_row = [ + pmc_no, "", "", cn.get("Invoice_Details", "Credit Note"), "", + cn.get("Invoice_No", ""), + cn.get("Basic_Amount", ""), + cn.get("Debit_Amount", ""), + cn.get("After_Debit_Amount", ""), + cn.get("GST_Amount", ""), + cn.get("Amount", ""), + "", "", "", "", "" + ] + + cn_row += [""] * len(hold_headers) + + cn_row += [ + cn.get("Final_Amount", ""), + "", + "", + cn.get("Total_Amount", ""), + cn.get("UTR", "") + ] + + sheet.append(cn_row) + + appended_credit_keys.add(key) + + # SAVE ONCE AT END + workbook.save(output_file) - # ================= SAVE FILE ================= - filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx" - output_file = FolderAndFile.get_download_path(filename) - workbook.save(output_file) - return send_file(output_file, as_attachment=True) - except Exception as e: - return str(e) \ No newline at end of file diff --git a/model/Subcontractor.py b/model/Subcontractor.py index 0ec659d..75d83d6 100644 --- a/model/Subcontractor.py +++ b/model/Subcontractor.py @@ -1,7 +1,6 @@ from model.Utilities import ItemCRUDType from model.ItemCRUD import ItemCRUD - class Subcontractor: def __init__(self): self.isSuccess = False diff --git a/model/Utilities.py b/model/Utilities.py index 4bc4262..d6e352a 100644 --- a/model/Utilities.py +++ b/model/Utilities.py @@ -9,10 +9,11 @@ class ItemCRUDType(Enum): HoldType = 5 Subcontractor = 6 GSTRelease = 7 + Invoice = 8 class RegEx: - patternAlphabetOnly = "^[A-Za-z ]+$" - allPattern = "^(?!\s*$).+" + patternAlphabetOnly = r"^[A-Za-z ]+$" + allPattern = r"^(?!\s*$).+" class ResponseHandler: diff --git a/model/Village.py b/model/Village.py index d6f0bb2..05919b8 100644 --- a/model/Village.py +++ b/model/Village.py @@ -13,14 +13,14 @@ class Village: def __init__(self): self.isSuccess = False self.resultMessage = "" - self.response = {} # ✅ ADDED + self.response = {} self.village = ItemCRUD(itemType=ItemCRUDType.Village) # 🔹 Helper: sync status def _set_status(self, village): self.isSuccess = village.isSuccess - # ✅ UPDATED (safe handling) + # UPDATED (safe handling) if hasattr(village, "response"): self.response = village.response self.resultMessage = village.response.get("message", "") @@ -37,7 +37,7 @@ class Village: block_id, village_name = self._get_form_data(request) if not village_name: - self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED + self.response = ResponseHandler.invalid_name("village") self.resultMessage = self.response["message"] self.isSuccess = False return @@ -75,7 +75,7 @@ class Village: block_id, village_name = self._get_form_data(request) if not village_name: - self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED + self.response = ResponseHandler.invalid_name("village") self.resultMessage = self.response["message"] self.isSuccess = False return None @@ -113,7 +113,7 @@ class Village: block_id, village_name = self._get_form_data(request) if not village_name: - self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED + self.response = ResponseHandler.invalid_name("village") self.resultMessage = self.response["message"] self.isSuccess = False return @@ -176,7 +176,7 @@ class Village: print(f"Error fetching blocks: {e}") self.isSuccess = False - # ✅ FIXED (removed jsonify response) + # FIXED (removed jsonify response) self.response = ResponseHandler.fetch_failure("block") self.resultMessage = self.response["message"] diff --git a/model/__pycache__/Village.cpython-314.pyc b/model/__pycache__/Village.cpython-314.pyc index 60c9c33..dee0010 100644 Binary files a/model/__pycache__/Village.cpython-314.pyc and b/model/__pycache__/Village.cpython-314.pyc differ diff --git a/model/gst_release.py b/model/gst_release.py index c30b08c..65be51e 100644 --- a/model/gst_release.py +++ b/model/gst_release.py @@ -8,12 +8,18 @@ class GSTRelease: def __init__(self): self.isSuccess = False self.resultMessage = "" - + # ------------------- Add GST Release ------------------- def AddGSTRelease(self, request): try: gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) + # Print the full form data + print("===== DEBUG: FORM DATA =====") + for key, value in request.form.items(): + print(f"{key} : {value}") + print("=============================") + data = { "PMC_No": request.form.get("PMC_No", "").strip(), "Invoice_No": request.form.get("Invoice_No", "").strip(), @@ -24,6 +30,10 @@ class GSTRelease: "Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0) } + print("===== DEBUG: PARSED DATA =====") + print(data) + print("==============================") + # Add GST Release gst.AddItem( request=request, @@ -31,12 +41,8 @@ class GSTRelease: storedprocfetch="CheckGSTReleaseExists", storedprocadd="AddGSTReleaseFromExcel" ) - - # Check if addition was successful - if gst.isSuccess: - print(f"GST Release Added: {data}") - else: - print(f"Failed to add GST Release: {gst.resultMessage}") + + print(f"AddItem result: isSuccess={gst.isSuccess}, message={gst.resultMessage}") self.isSuccess = gst.isSuccess self.resultMessage = str(gst.resultMessage) @@ -48,20 +54,26 @@ class GSTRelease: return jsonify({"success": self.isSuccess, "message": self.resultMessage}) - # ------------------- Edit GST Release ------------------- def EditGSTRelease(self, request, gst_release_id): try: gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) + # Map form inputs to stored procedure parameters data = { - "PMC_No": request.form.get("PMC_No", "").strip(), - "Invoice_No": request.form.get("Invoice_No", "").strip(), - "Basic_Amount": float(request.form.get("Basic_Amount", 0) or 0), - "Final_Amount": float(request.form.get("Final_Amount", 0) or 0), - "Total_Amount": float(request.form.get("Total_Amount", 0) or 0), - "UTR": request.form.get("UTR", "").strip() + "p_pmc_no": request.form.get("PMC_No", "").strip(), + "p_invoice_no": request.form.get("invoice_no", "").strip(), + "p_basic_amount": float(request.form.get("Basic_Amount", 0) or 0), + "p_final_amount": float(request.form.get("Final_Amount", 0) or 0), + "p_total_amount": float(request.form.get("Total_Amount", 0) or 0), + "p_utr": request.form.get("UTR", "").strip(), + "p_gst_release_id": gst_release_id } + print("===== DEBUG: UPDATE DATA =====") + print(data) + print("==============================") + + # Call your stored procedure gst.EditItem( request=request, childid=gst_release_id, @@ -77,8 +89,6 @@ class GSTRelease: self.isSuccess = False self.resultMessage = str(e) - return jsonify({"success": self.isSuccess, "message": self.resultMessage}) - # ------------------- Delete GST Release ------------------- def DeleteGSTRelease(self, gst_release_id): try: diff --git a/model/payment.py b/model/payment.py index 67dd294..2331f35 100644 --- a/model/payment.py +++ b/model/payment.py @@ -2,7 +2,6 @@ import config import mysql.connector import config import mysql.connector -from enum import Enum from model.Utilities import ItemCRUDType class Paymentmodel: @@ -34,40 +33,44 @@ class Paymentmodel: return payments @staticmethod - def insert_payment(pmc_no, invoice_no, amount, tds_amount, total_amount, utr): + def insert_payment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr): connection = Paymentmodel.get_connection() if not connection: return False - try: - cursor = connection.cursor() - cursor.callproc('InsertPayments', [pmc_no, invoice_no, amount, tds_amount, total_amount, utr]) - connection.commit() - return True - except mysql.connector.Error as e: - print(f"Error inserting payment: {e}") - return False - finally: - cursor.close() - connection.close() - @staticmethod - def update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr): - connection = Paymentmodel.get_connection() - if not connection: - return False + cursor = None try: cursor = connection.cursor() - cursor.callproc('UpdateInpaymentRecord', [ - subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr - ]) + + cursor.callproc('GetInvoiceId', [subcontractor_id, pmc_no, invoice_no]) + + invoice_id = None + for result in cursor.stored_results(): + row = result.fetchone() + if row: + invoice_id = row[0] + + if not invoice_id: + return False + + cursor.callproc( + 'InsertPayments', + [pmc_no, invoice_no, amount, tds_amount, total_amount, utr, invoice_id] + ) + connection.commit() return True - except mysql.connector.Error as e: - print(f"Error updating inpayment: {e}") + + except Exception as e: + print(e) return False + finally: - cursor.close() - connection.close() + if cursor: + cursor.close() + if connection: + connection.close() + @staticmethod def fetch_payment_by_id(payment_id): @@ -133,9 +136,7 @@ class Paymentmodel: # Delete payment cursor.callproc("DeletePayment", (payment_id,)) connection.commit() - # Reset inpayment fields - cursor.callproc("ResetInpayment", [pmc_no, invoice_no]) - connection.commit() + return True, pmc_no, invoice_no except mysql.connector.Error as e: print(f"Error deleting payment: {e}") diff --git a/services/Generalservice.py b/services/Generalservice.py new file mode 100644 index 0000000..8e698cc --- /dev/null +++ b/services/Generalservice.py @@ -0,0 +1,30 @@ + + + +class GeneralUse: + data=[] + + @staticmethod + def execute_sp(cursor, proc_name, params=[], fetch_one=False): + cursor.callproc(proc_name, params) + return ( + GeneralUse.fetch_one_result(cursor) + if fetch_one else + GeneralUse.fetch_all_results(cursor) + ) + + @staticmethod + def fetch_all_results(cursor): + data = [] + for result in cursor.stored_results(): + data = result.fetchall() + return data + + + @staticmethod + def fetch_one_result(cursor): + data = None + for result in cursor.stored_results(): + data = result.fetchone() + return data + diff --git a/services/ReportService.py b/services/ReportService.py new file mode 100644 index 0000000..5c0ce37 --- /dev/null +++ b/services/ReportService.py @@ -0,0 +1,177 @@ +import config + +from model.FolderAndFile import FolderAndFile +from services.Generalservice import GeneralUse +from model.Report import ReportHelper + +from decimal import Decimal +def safe_decimal(value): + if value is None: + return Decimal(0) + return Decimal(value) + + +class ReportService: + + + def __init__(self, contractor_id=None, pmc_no=None): + self.contractor_id = contractor_id + self.pmc_no = pmc_no + + self.contInfo = None + self.hold_types = [] + self.invoices = [] + + self.hold_amounts = [] + self.hold_data = {} + + self.credit_note_raw = [] + self.credit_note_map = {} + + self.gst_release_raw = [] + self.gst_release_map = {} + + self.output_file = None + + # ---------------- LOAD DATA ---------------- + def load_data(self): + connection = config.get_db_connection() + cursor = connection.cursor(dictionary=True, buffered=True) + + try: + # ---------- CONTRACTOR ---------- + if self.contractor_id: + self.contInfo = GeneralUse.execute_sp(cursor, 'GetContractorInfo', [self.contractor_id], True) + self.hold_types = GeneralUse.execute_sp(cursor, 'HoldTypesByContractorId', [self.contractor_id]) + self.invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [self.contractor_id, None]) + + # ---------- PMC ---------- + elif self.pmc_no: + self.contInfo = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [self.pmc_no], True) + self.contractor_id = self.contInfo["Contractor_Id"] + + self.hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor', [self.contractor_id]) + self.invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None, self.pmc_no]) + + # ---------- COMMON ---------- + self.hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [self.contractor_id]) + self.credit_note_raw = GeneralUse.execute_sp(cursor, 'GetCreditNotesByContractor', [self.contractor_id]) + self.gst_release_raw = GeneralUse.execute_sp(cursor, 'GetGSTRelease', [self.contractor_id]) + + + self.prepare_maps() + self.total = self.calculate_totals() + + finally: + cursor.close() + connection.close() + + return self + + # ---------------- MAPS ---------------- + def prepare_maps(self): + # HOLD MAP + for h in self.hold_amounts: + self.hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] + + # CREDIT MAP + for cn in self.credit_note_raw: + key = str(cn.get('PMC_No') or cn.get('pmc_no')).strip() + self.credit_note_map.setdefault(key, []).append(cn) + + # GST MAP (FIXED) + for gr in self.gst_release_raw: + pmc_value = gr.get('PMC_No') or gr.get('pmc_no') or gr.get('PMC_NO') + + if not pmc_value: + continue # skip if missing + + key = str(pmc_value).strip() + self.gst_release_map.setdefault(key, []).append(gr) + + # ---------------- calculate total ---------------- + def calculate_totals(self): + total = { + "sum_invo_basic_amt": Decimal(0), + "sum_invo_debit_amt": Decimal(0), + "sum_invo_after_debit_amt": Decimal(0), + "sum_invo_gst_amt": Decimal(0), + "sum_invo_amt": Decimal(0), + "sum_invo_tds_amt": Decimal(0), + "sum_invo_ds_amt": Decimal(0), + "sum_invo_on_commission": Decimal(0), + "sum_invo_hydro_test": Decimal(0), + "sum_invo_hold_amt": Decimal(0), + "sum_invo_gst_sd_amt": Decimal(0), + "sum_invo_final_amt": Decimal(0), + + "sum_gst_basic_amt": Decimal(0), + "sum_gst_final_amt": Decimal(0), + + "sum_pay_payment_amt": Decimal(0), + "sum_pay_tds_payment_amt": Decimal(0), + "sum_pay_total_amt": Decimal(0) + } + + # ---------- INVOICE ---------- + for inv in self.invoices: + total["sum_invo_basic_amt"] += safe_decimal(inv.get("Basic_Amount")) + total["sum_invo_debit_amt"] += safe_decimal(inv.get("Debit_Amount")) + total["sum_invo_after_debit_amt"] += safe_decimal(inv.get("After_Debit_Amount")) + total["sum_invo_gst_amt"] += safe_decimal(inv.get("GST_Amount")) + total["sum_invo_amt"] += safe_decimal(inv.get("Amount")) + total["sum_invo_tds_amt"] += safe_decimal(inv.get("TDS_Amount")) + total["sum_invo_ds_amt"] += safe_decimal(inv.get("SD_Amount")) + total["sum_invo_on_commission"] += safe_decimal(inv.get("On_Commission")) + total["sum_invo_hydro_test"] += safe_decimal(inv.get("Hydro_Testing")) + total["sum_invo_gst_sd_amt"] += safe_decimal(inv.get("GST_SD_Amount")) + total["sum_invo_final_amt"] += safe_decimal(inv.get("Final_Amount")) + total["sum_invo_hold_amt"] += safe_decimal(inv.get("hold_amount")) + + # ---------- GST ---------- + for gst in self.gst_release_raw: + total["sum_gst_basic_amt"] += safe_decimal(gst.get("basic_amount")) + total["sum_gst_final_amt"] += safe_decimal(gst.get("final_amount")) + + # ---------- PAYMENTS ---------- + if hasattr(self, "payments"): + for pay in self.payments: + total["sum_pay_payment_amt"] += safe_decimal(pay.get("Payment_Amount")) + total["sum_pay_tds_payment_amt"] += safe_decimal(pay.get("TDS_Payment_Amount")) + total["sum_pay_total_amt"] += safe_decimal(pay.get("Total_amount")) + + return total + + + # ---------------- WEB DATA ---------------- + def get_web_data(self): + return { + "contInfo": self.contInfo, + "invoices": self.invoices, + "hold_types": self.hold_types, + "credit_note": self.credit_note_raw, + "gst_rel": self.gst_release_raw, + "total": self.total + } + + # ---------------- DOWNLOAD ---------------- + def download_excel(self): + + if not self.contInfo: + return None, "No data found" + + filename = f"Report_{self.contractor_id or self.pmc_no}.xlsx" + self.output_file = FolderAndFile.get_download_path(filename=filename) + + ReportHelper.generate_excel( + self.contractor_id or 0, + self.contInfo, + self.invoices, + self.hold_types, + self.hold_data, + self.credit_note_map, + self.gst_release_map, + self.output_file + ) + + return self.output_file, None \ No newline at end of file diff --git a/static/images/icons/male_profile.jpg b/static/images/icons/male_profile.jpg new file mode 100644 index 0000000..5030590 Binary files /dev/null and b/static/images/icons/male_profile.jpg differ diff --git a/static/js/searchContractor.js b/static/js/searchContractor.js index bb0251c..38e03fe 100644 --- a/static/js/searchContractor.js +++ b/static/js/searchContractor.js @@ -1,43 +1,57 @@ -$(document).ready(function () { - function fetchResults() { - let formData = $('#search-form').serialize(); +document.addEventListener("DOMContentLoaded", function () { - $.ajax({ - type: 'POST', - url: '/search_contractor', - data: formData, - success: function (data) { - let tableBody = $('#result-table tbody'); - tableBody.empty(); + const form = document.getElementById("search-form"); + const tableBody = document.querySelector("#result-table tbody"); - if (data.length === 0) { - tableBody.append('No data found'); - } else { - data.forEach(function (row) { - tableBody.append(` - - ${row.Contractor_Name} - ${row.PMC_No} - ${row.State_Name} - ${row.District_Name} - ${row.Block_Name} - ${row.Village_Name} - - `); - }); - } - }, - error: function (xhr) { - alert(xhr.responseJSON.error); - } + function fetchData(page = 1) { + const formData = new FormData(form); + formData.append("page", page); + + fetch("/search_contractor", { + method: "POST", + body: formData + }) + .then(res => res.json()) + .then(res => { + tableBody.innerHTML = ""; + + res.data.forEach(row => { + + const tr = document.createElement("tr"); + + tr.innerHTML = ` + + ${row.Contractor_Name} + + + ${row.PMC_No} + + ${row.State_Name} + ${row.District_Name} + ${row.Block_Name} + ${row.Village_Name} + `; + + tableBody.appendChild(tr); + }); }); + } + + // Auto search + form.addEventListener("input", () => fetchData()); + + // Click Contractor + document.addEventListener("click", function (e) { + if (e.target.classList.contains("contractor-link")) { + const id = e.target.dataset.id; + window.location.href = `/contractor_report/${id}`; } - $('#search-form input').on('keyup change', function () { - fetchResults(); - }); + if (e.target.classList.contains("pmc-link")) { + const pmc = e.target.dataset.pmc; + window.location.href = `/pmc_report/${pmc}`; + } }); -window.onload = function () { - document.getElementById('subcontractor_name').focus(); - }; \ No newline at end of file + fetchData(); +}); \ No newline at end of file diff --git a/templates/add_gst_release.html b/templates/add_gst_release.html index 8d78e53..a037dca 100644 --- a/templates/add_gst_release.html +++ b/templates/add_gst_release.html @@ -15,17 +15,21 @@ - +