From 0b72adef7d279b9c3e039d65ec7edbd121e418c1 Mon Sep 17 00:00:00 2001 From: pjpatil12 Date: Mon, 30 Mar 2026 11:36:16 +0530 Subject: [PATCH] updated code by aakash --- controllers/auth_controller.py | 1 - controllers/excel_upload_controller.py | 115 ++++--- controllers/gst_release_controller.py | 2 +- controllers/hold_types_controller.py | 8 +- controllers/invoice_controller.py | 6 - controllers/payment_controller.py | 4 +- controllers/pmc_report_controller.py | 3 +- controllers/report_controller.py | 11 +- controllers/subcontractor_controller.py | 12 - controllers/village_controller.py | 10 +- model/Block.py | 74 +---- model/ContractorInfo.py | 5 - model/FolderAndFile.py | 7 +- model/GST.py | 8 +- model/HoldTypes.py | 5 +- model/Invoice.py | 37 +-- model/ItemCRUD.py | 15 +- model/Log.py | 1 - model/PmcReport.py | 355 ++++++---------------- model/Report.py | 285 ++++++++++------- model/Subcontractor.py | 1 - model/Village.py | 12 +- model/__pycache__/Village.cpython-314.pyc | Bin 7662 -> 7680 bytes model/gst_release.py | 42 ++- model/payment.py | 57 ++-- templates/add_gst_release.html | 87 ++++-- templates/edit_gst_release.html | 40 +-- templates/pmc_report.html | 2 +- 28 files changed, 505 insertions(+), 700 deletions(-) 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/excel_upload_controller.py b/controllers/excel_upload_controller.py index d1e4c3e..df020d0 100644 --- a/controllers/excel_upload_controller.py +++ b/controllers/excel_upload_controller.py @@ -152,19 +152,17 @@ def show_table(filename): ) - # save Excel data +# save Excel data @excel_bp.route('/save_data', methods=['POST']) def save_data(): # Extract form data subcontractor_id = request.form.get("subcontractor_data") - state_id = request.form.get("state_data") - district_id = request.form.get("district_data") block_id = request.form.get("block_data") - variables = request.form.getlist('variables[]') hold_columns = request.form.get("hold_columns") - hold_counter = request.form.get("hold_counter") + if not data: return jsonify({"error": "No data provided to save"}), 400 + if data: connection = config.get_db_connection() cursor = connection.cursor() @@ -174,7 +172,7 @@ def save_data(): "PMC_No": entry.get("PMC_No"), "Invoice_Details": entry.get("Invoice_Details", ''), "Work_Type": 'none', - "Invoice_Date": entry.get("Invoice_Date").strftime('%Y-%m-%d') if entry.get( + "In oice_Date": entry.get("Invoice_Date").strftime('%Y-%m-%d') if entry.get( "Invoice_Date") else None, "Invoice_No": entry.get("Invoice_No", ''), "Basic_Amount": entry.get("Basic_Amount", 0.00), @@ -229,7 +227,6 @@ 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) if block_id and village_name: village_id = None cursor.callproc("GetVillageId", (block_id, village_name)) @@ -242,12 +239,7 @@ 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) - + args = ( PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount, @@ -255,22 +247,24 @@ def save_data(): subcontractor_id, 0 ) - print("All invoice Details ",args) results = cursor.callproc('SaveInvoice', args) invoice_id = results[-1] - print("invoice id from the excel ", invoice_id) + + + cursor.callproc("SavePayment",( PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount,Total_Amount, UTR,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}") - hold_column_name = hold.get('column_name') # Get column name - hold_type_id = hold.get('hold_type_id') # Get hold_type_id + + hold_column_name = hold.get('column_name') + hold_type_id = hold.get('hold_type_id') if hold_column_name: hold_amount = entry.get( - hold_column_name) # Get the value for that specific hold column + hold_column_name) if hold_amount is not None: - print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}") + hold_join_data = { "Contractor_Id": subcontractor_id, "Invoice_Id": invoice_id, @@ -287,10 +281,9 @@ def save_data(): print(f"Invalid hold entry: {hold}") else: print("Hold columns data is not a valid list of dictionaries.") -#---------------------------------------------Credit Note--------------------------------------------------------------------------- + #-------------------------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) + cursor.callproc( 'AddCreditNoteFromExcel', [ @@ -299,7 +292,7 @@ def save_data(): subcontractor_id, Invoice_No ] ) -#-----------------------------------------------Hold Amount---------------------------------------------------------------------- + #--------------------------Hold Amount------------------------------------------------- # Step 1: Normalize Invoice_Details: lowercase, trim, remove extra spaces normalized_details = re.sub(r'\s+', ' ', Invoice_Details.strip()).lower() # Step 2: Define lowercase keywords @@ -315,52 +308,57 @@ 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()): + # ---------- Only PMC / Payment rows ---------- + if PMC_No and not Invoice_No and UTR : + + 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() + invoice_id = row[0] if row else None + + # insert payment + cursor.callproc( + "SavePayment", + ( + PMC_No, + Invoice_No, + Payment_Amount, + TDS_Payment_Amount, + Total_Amount, + UTR, + invoice_id + ) + ) + connection.commit() return jsonify({"success": "Data saved successfully!"}), 200 except Exception as e: @@ -370,4 +368,3 @@ def save_data(): cursor.close() connection.close() return render_template('index.html') -# ---------------------- Report -------------------------------- \ No newline at end of file diff --git a/controllers/gst_release_controller.py b/controllers/gst_release_controller.py index 5827f8a..87f6ff1 100644 --- a/controllers/gst_release_controller.py +++ b/controllers/gst_release_controller.py @@ -1,10 +1,10 @@ -# routes/gst_release_routes.py from flask import Blueprint, render_template, request, redirect, url_for, flash from flask_login import login_required from model.gst_release import GSTRelease from model.Log import LogHelper gst_release_bp = Blueprint('gst_release_bp', __name__) + gst_service = GSTRelease() # ---------------- ADD GST RELEASE ---------------- diff --git a/controllers/hold_types_controller.py b/controllers/hold_types_controller.py index 40b2b20..3cc5c94 100644 --- a/controllers/hold_types_controller.py +++ b/controllers/hold_types_controller.py @@ -14,7 +14,7 @@ def add_hold_type(): if request.method == 'POST': hold.AddHoldType(request) - # ✅ Always redirect to same page (NO JSON) + # Always redirect to same page (NO JSON) return redirect(url_for("hold_types.add_hold_type")) # GET request → show data @@ -42,10 +42,10 @@ def edit_hold_type(id): hold = HoldTypes() if request.method == 'POST': - hold.EditHoldType(request, id) # ✅ + hold.EditHoldType(request, id) return hold.resultMessage - hold_data = hold.GetHoldTypeByID(id) # ✅ + hold_data = hold.GetHoldTypeByID(id) return render_template( "edit_hold_type.html", @@ -59,7 +59,7 @@ def edit_hold_type(id): def delete_hold_type(id): hold = HoldTypes() - hold.DeleteHoldType(request, id) # ✅ + 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..0ee43d3 100644 --- a/controllers/invoice_controller.py +++ b/controllers/invoice_controller.py @@ -1,8 +1,3 @@ - - - -# controllers/invoice_controller.py - from flask import Blueprint, request, jsonify, render_template from flask_login import login_required, current_user from model.Invoice import * @@ -83,7 +78,6 @@ def edit_invoice(invoice_id): if request.method == 'POST': data = request.form update_invoice(data, invoice_id) - 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..6e42a0e 100644 --- a/controllers/payment_controller.py +++ b/controllers/payment_controller.py @@ -28,8 +28,7 @@ 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) return redirect(url_for('payment_bp.add_payment')) @@ -71,7 +70,6 @@ def edit_payment(payment_id): LogHelper.log_action("Edit Payment", f"User {current_user.id} Edit Payment '{pmc_no}'") 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( diff --git a/controllers/pmc_report_controller.py b/controllers/pmc_report_controller.py index 76460e7..06814aa 100644 --- a/controllers/pmc_report_controller.py +++ b/controllers/pmc_report_controller.py @@ -37,4 +37,5 @@ def download_pmc_report(pmc_no): output_folder, file_name = result - return send_from_directory(output_folder, file_name, as_attachment=True) \ No newline at end of file + return send_from_directory(output_folder, file_name, as_attachment=True) + diff --git a/controllers/report_controller.py b/controllers/report_controller.py index 9fe62ce..46cf6f3 100644 --- a/controllers/report_controller.py +++ b/controllers/report_controller.py @@ -1,10 +1,9 @@ -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 model.Report import ReportHelper from model.Log import LogHelper - report_bp = Blueprint("report", __name__) @@ -46,8 +45,10 @@ def contractor_report(contractor_id): # ---------------- Contractor Download Report by contractor id ---------------- @report_bp.route('/download_report/') -@login_required def download_report(contractor_id): + output_file, error = ReportHelper.create_contractor_report(contractor_id) + + if error: + return error, 404 - return ReportHelper().download_report(contractor_id=contractor_id) - \ No newline at end of file + return send_file(output_file, as_attachment=True) \ No newline at end of file diff --git a/controllers/subcontractor_controller.py b/controllers/subcontractor_controller.py index d9f7fbd..f9733f8 100644 --- a/controllers/subcontractor_controller.py +++ b/controllers/subcontractor_controller.py @@ -3,17 +3,12 @@ from flask_login import login_required from model.Subcontractor import Subcontractor from model.Utilities import HtmlHelper, ResponseHandler - subcontractor_bp = Blueprint('subcontractor', __name__) - -# ---------------------------------------------------------- # LIST + ADD -# ---------------------------------------------------------- @subcontractor_bp.route('/subcontractor', methods=['GET', 'POST']) @login_required def subcontract(): - sub = Subcontractor() # ---------------- GET ---------------- @@ -31,27 +26,22 @@ def subcontract(): if request.method == 'POST': sub.AddSubcontractor(request) - if not sub.isSuccess: return HtmlHelper.json_response( ResponseHandler.add_failure("Subcontractor"), 500 ) - # Reload list after insert subcontractor = sub.GetAllSubcontractors(request) return render_template('add_subcontractor.html', subcontractor=subcontractor) -# ---------------------------------------------------------- # EDIT -# ---------------------------------------------------------- @subcontractor_bp.route('/edit_subcontractor/', methods=['GET', 'POST']) @login_required def edit_subcontractor(id): sub = Subcontractor() - # Fetch data subcontractor = sub.GetSubcontractorByID(id) @@ -75,9 +65,7 @@ def edit_subcontractor(id): return render_template('edit_subcontractor.html', subcontractor=subcontractor) -# ---------------------------------------------------------- # DELETE -# ---------------------------------------------------------- @subcontractor_bp.route('/deleteSubContractor/', methods=['GET', 'POST']) @login_required def deleteSubContractor(id): diff --git a/controllers/village_controller.py b/controllers/village_controller.py index 27a1ff2..e173ae1 100644 --- a/controllers/village_controller.py +++ b/controllers/village_controller.py @@ -1,7 +1,3 @@ - - - - from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify from flask_login import login_required @@ -89,15 +85,14 @@ def delete_village(village_id): village = Village() village.DeleteVillage(request=request, village_id=village_id) - # ✅ Convert resultMessage to string if it's a Response or tuple + # Convert resultMessage to string if it's a Response or tuple raw_msg = village.resultMessage if isinstance(raw_msg, tuple): - # e.g., (, 200) msg = "Village deleted successfully!" elif hasattr(raw_msg, 'get_data'): # Flask Response object - msg = raw_msg.get_data(as_text=True) # get raw text + msg = raw_msg.get_data(as_text=True) else: # fallback msg = str(raw_msg) if raw_msg else "Village deleted successfully!" @@ -135,7 +130,6 @@ def edit_village(village_id): ) else: - # ✅ FIXED HERE (removed request) village_data = village.GetVillageByID(id=village_id) if not village.isSuccess: 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/FolderAndFile.py b/model/FolderAndFile.py index 30f5336..bf63550 100644 --- a/model/FolderAndFile.py +++ b/model/FolderAndFile.py @@ -1,12 +1,11 @@ import os from flask import current_app - +# ----------------------------- +# BASE FOLDER Class +# ----------------------------- class FolderAndFile: - # ----------------------------- - # BASE FOLDER METHODS - # ----------------------------- @staticmethod def get_download_folder(): folder = os.path.join(current_app.root_path, "static", "downloads") diff --git a/model/GST.py b/model/GST.py index 71da41e..21c220e 100644 --- a/model/GST.py +++ b/model/GST.py @@ -10,7 +10,7 @@ class GST: invoices_rows = invoice_crud.GetAllData(storedproc="GetAllInvoicesBasic") if not invoice_crud.isSuccess: - return [] # Could also log invoice_crud.resultMessage + return [] invoices = [ dict( @@ -25,16 +25,16 @@ class GST: gst_rows = gst_crud.GetAllData(storedproc="GetAllGSTReleasesBasic") if not gst_crud.isSuccess: - return [] # Could also log gst_crud.resultMessage + return [] gst_invoice_nos = { - g[2] # Invoice_No is at index 2 + g[2] for g in gst_rows if g[2] } gst_basic_amounts = { - float(g[3]) # Basic_Amount at index 3 + float(g[3]) for g in gst_rows if g[3] is not None } 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..4e0843a 100644 --- a/model/Invoice.py +++ b/model/Invoice.py @@ -1,6 +1,4 @@ - import config -import mysql.connector # ------------------- Helper Functions ------------------- def clear_results(cursor): @@ -78,25 +76,15 @@ def insert_invoice(data, village_id): data.get('invoice_details'), data.get('invoice_date'), data.get('invoice_no'), - *get_numeric_values(data) + *get_numeric_values(data), + data.get('subcontractor_id') + ]) invoice_row = fetch_one(cursor) if not invoice_row: raise Exception("Invoice ID not returned") invoice_id = invoice_row.get('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 +129,6 @@ 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 delete_invoice_data(invoice_id, user_id): def operation(cursor): @@ -164,18 +140,11 @@ def delete_invoice_data(invoice_id, user_id): if not record: raise Exception("Invoice not found") - # Use exact DB keys - pmc_no = record['PMC_No'] - invoice_no = record['Invoice_No'] # Delete invoice cursor.callproc("DeleteInvoice", (invoice_id,)) clear_results(cursor) - # Delete inpayment - cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no)) - clear_results(cursor) - execute_db_operation(operation) 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..5dd6fb9 100644 --- a/model/PmcReport.py +++ b/model/PmcReport.py @@ -1,5 +1,5 @@ import openpyxl -from openpyxl.styles import Font, PatternFill +from openpyxl.styles import Font import config from flask_login import current_user from model.Log import LogHelper @@ -11,14 +11,10 @@ class PmcReport: @staticmethod def get_pmc_report(pmc_no): - connection = config.get_db_connection() cursor = connection.cursor(dictionary=True, buffered=True) try: - - # cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,)) - # pmc_info = next(cursor.stored_results()).fetchone() pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True) if not pmc_info: @@ -51,44 +47,20 @@ class PmcReport: 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 = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [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) # ---------------- HOLD RELEASE ---------------- - # cursor.callproc('GetHoldReleaseByPMC', [pmc_no]) - # hold_release = [] - # for result in cursor.stored_results(): - # hold_release = result.fetchall() - hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no]) # ---------------- 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() - - + payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no]) 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) @@ -137,51 +109,51 @@ class PmcReport: 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 ================= + # ================= DATA FETCH ============= + contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no]) - contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no], "one") + contractor_info = contractor_info[0] if contractor_info else None if not contractor_info: return None - hold_types = ReportHelper.execute_sp(cursor, 'GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) + 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"]]) + credit_notes = ReportHelper.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no]) - hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) - - all_payments = ReportHelper.execute_sp(cursor, 'GetAllPaymentsByPMC', [pmc_no]) + hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor',[contractor_info["Contractor_Id"]]) 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) + credit_note_map = {} + for cn in credit_notes: + pmc = cn.get("PMC_No") + if pmc: + credit_note_map.setdefault(pmc, []).append(cn) + + gst_map = {} + for gst in gst_releases: + pmc = gst.get("PMC_No") + if pmc: + gst_map.setdefault(pmc, []).append(gst) # ================= LOG ================= - LogHelper.log_action( - "Download PMC Report", - f"User {current_user.id} Download PMC Report '{pmc_no}'" - ) + LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'") # ================= EXCEL ================= workbook = openpyxl.Workbook() @@ -197,83 +169,101 @@ class PmcReport: 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" + "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"] - payment_headers = [ - "Final Amount","Payment Amount","TDS Payment","Total Paid","UTR" - ] - - headers = base_headers + hold_headers + payment_headers + 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() - + # ================= INVOICE ROWS ================= 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"] + inv.get("Village_Name", ""), + inv.get("Work_Type", ""), + inv.get("Invoice_Details", ""), + inv.get("Invoice_Date", ""), + inv.get("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", "") ] # HOLD DATA - invoice_holds = hold_data.get(inv["Invoice_Id"], {}) + invoice_holds = hold_data.get(inv.get("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 "" + inv.get("Final_Amount", ""), + inv.get("Payment_Amount", ""), + inv.get("TDS_Payment_Amount", ""), + inv.get("Total_Amount", ""), + inv.get("UTR", "") ] - sheet.append(row) + row += ["", ""] - # AUTO WIDTH + sheet.append(row) + # ================= CREDIT NOTE ROWS ================= + for pmc, cn_list in credit_note_map.items(): + for cn in cn_list: + cn_row = [ + pmc_no, + "", "", "Credit Note", + "", cn.get("Invoice_No", ""), + cn.get("Basic_Amount", ""), + "", "", "", "", "", "", "", "", "", "", "" + ] + cn_row += [""] * len(hold_headers) + cn_row += [ + cn.get("Final_Amount", ""), + cn.get("Total_Amount", ""), + cn.get("UTR", "") + ] + sheet.append(cn_row) + + # ================= GST RELEASE ROWS ================= + for gst in gst_releases: + gst_row = [ + gst.get("PMC_No", ""), + "", "", "GST Release Note", + "", gst.get("Invoice_No", ""), + gst.get("Basic_Amount", ""), + "", "", "", "", "", "", "", "", "" + ] + gst_row += [""] * len(hold_headers) + gst_row += [ + gst.get("Final_Amount", ""), + "", + "", + gst.get("Total_Amount", ""), + gst.get("UTR", "") + ] + sheet.append(gst_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: @@ -283,174 +273,3 @@ class PmcReport: finally: cursor.close() connection.close() - - # @staticmethod - # def download_pmc_report(pmc_no): - - # connection = config.get_db_connection() - # 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: - - # cursor.callproc('GetContractorDetailsByPMC', [pmc_no]) - # contractor_info = next(cursor.stored_results()).fetchone() - - # if not contractor_info: - # return None - - # cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) - # hold_types = next(cursor.stored_results()).fetchall() - - # 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() - - # credit_note_map = {} - # for cn in credit_notes: - # key = (cn["PMC_No"], cn["Invoice_No"]) - # credit_note_map.setdefault(key, []).append(cn) - - # cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) - # hold_amounts = next(cursor.stored_results()).fetchall() - - # 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() - - # return output_folder, filename - - # finally: - - # cursor.close() - # connection.close() \ No newline at end of file diff --git a/model/Report.py b/model/Report.py index 41d5ad2..0b86544 100644 --- a/model/Report.py +++ b/model/Report.py @@ -1,8 +1,9 @@ import config from datetime import datetime from flask import send_file +import os import openpyxl -from openpyxl.styles import Font +from openpyxl.styles import Font, PatternFill from model.FolderAndFile import FolderAndFile @@ -147,129 +148,199 @@ class ReportHelper: "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 + @staticmethod + def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data, + credit_note_map, gst_release_map, output_file): - # -------- Invoice Data -------- - cursor.callproc('FetchInvoicesByContractor', [contractor_id]) + workbook = openpyxl.Workbook() + sheet = workbook.active + sheet.title = "Contractor Report" - invoices = [] - for result in cursor.stored_results(): - invoices.extend(result.fetchall()) + # Contractor Info + for field, value in contInfo.items(): + sheet.append([field.replace("_", " "), value]) + sheet.append([]) - if not invoices: - return "No invoice data found" + # 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"] - # -------- Create Workbook -------- - workbook = openpyxl.Workbook() - sheet = workbook.active - sheet.title = "Contractor Report" + hold_headers = [ht['hold_type'] for ht in hold_types] - # ================= CONTRACTOR DETAILS ================= - sheet.append(["SUB CONTRACTOR DETAILS"]) - sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True) - sheet.append([]) + payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"] - 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([]) + all_headers = base_headers + hold_headers + payment_headers + sheet.append(all_headers) - # ================= 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" + for cell in sheet[sheet.max_row]: + cell.font = Font(bold=True) + cell.fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid") + + 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) + + 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) + + + @staticmethod + def create_contractor_report(contractor_id): + fileName = f"Contractor_Report_{contractor_id}.xlsx" + output_file = FolderAndFile.get_download_path(filename=fileName) + + # Fetch Data + contInfo = ReportHelper.get_contractor_info(contractor_id) + if not contInfo: + return None, "No contractor found" + + connection = config.get_db_connection() + cursor = connection.cursor(dictionary=True, buffered=True) + + hold_types = ReportHelper.execute_sp(cursor, 'HoldTypesByContractorId', [contractor_id]) + invoices = ReportHelper.execute_sp(cursor, 'FetchInvoicesByContractor', [contractor_id]) + hold_amounts = ReportHelper.execute_sp(cursor, 'HoldAmountsByContractorId', [contractor_id]) + hold_data = {} + for h in hold_amounts: + hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] + + + # -------- Credit Note MAP -------- + credit_note_raw = ReportHelper.execute_sp(cursor, 'GetCreditNotesByContractor', [contractor_id]) + credit_note_map = {} + for cn in credit_note_raw: + key = ( + str(cn['PMC_No']).strip() + ) + credit_note_map.setdefault(key, []).append(cn) + + # -------- GST MAP -------- + gst_release_raw = ReportHelper.execute_sp(cursor, 'GstReleasesByContractorId', [contractor_id]) + gst_release_map = {} + for gr in gst_release_raw: + key = ( + str(gr['PMC_No']).strip() + ) + gst_release_map.setdefault(key, []).append(gr) + + # Generate Excel + ReportHelper.generate_excel( + contractor_id, contInfo, invoices, hold_types, hold_data, + credit_note_map, gst_release_map, output_file + ) + + return output_file, None - # ================= 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 - # ================= 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/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 60c9c331f60e712c2ed3780461eeb04937865b9a..dee0010ff744b174dd9856df872fd5e75d8d751b 100644 GIT binary patch delta 66 zcmaE7-C)D5&Bx2d00dW`9@)sPz@*{tY!wq)oLW>IV`*q%X%ypyUl5a)nU|Oo UkXV_UnpfhSpOU)Sk!h_o0I%v68vpAdd - +