9 Commits

14 changed files with 1244 additions and 823 deletions

View File

@@ -10,21 +10,21 @@ hold_bp = Blueprint("hold_types", __name__)
@hold_bp.route('/add_hold_type', methods=['GET','POST']) @hold_bp.route('/add_hold_type', methods=['GET','POST'])
@login_required @login_required
def add_hold_type(): def add_hold_type():
hold = HoldTypes() hold = HoldTypes()
if request.method == 'POST': if request.method == 'POST':
hold.AddHoldType(request) # ✅ hold.AddHoldType(request)
return hold.resultMessage # ✅ Always redirect to same page (NO JSON)
return redirect(url_for("hold_types.add_hold_type"))
hold_types = hold.GetAllHoldTypes() # ✅ # GET request → show data
hold_types = hold.GetAllHoldTypes()
return render_template( return render_template(
"add_hold_type.html", "add_hold_type.html",
Hold_Types_data=hold_types Hold_Types_data=hold_types
) )
# ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ---------------- # ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ----------------
@hold_bp.route('/check_hold_type', methods=['POST']) @hold_bp.route('/check_hold_type', methods=['POST'])
@login_required @login_required

View File

@@ -83,17 +83,29 @@ def check_village():
return village.CheckVillage(request=request) return village.CheckVillage(request=request)
# ------------------------- Delete Village -------------------------
@village_bp.route('/delete_village/<int:village_id>') @village_bp.route('/delete_village/<int:village_id>')
@login_required @login_required
def delete_village(village_id): def delete_village(village_id):
village = Village() village = Village()
village.DeleteVillage(request=request, village_id=village_id) village.DeleteVillage(request=request, village_id=village_id)
flash(village.resultMessage, "success" if village.isSuccess else "error") # ✅ Convert resultMessage to string if it's a Response or tuple
return redirect(url_for('village.add_village')) raw_msg = village.resultMessage
if isinstance(raw_msg, tuple):
# e.g., (<Response ...>, 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
else:
# fallback
msg = str(raw_msg) if raw_msg else "Village deleted successfully!"
return jsonify({
"status": "success" if village.isSuccess else "error",
"message": msg
})
# ------------------------- Edit Village ------------------------- # ------------------------- Edit Village -------------------------
@village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST']) @village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST'])

View File

@@ -167,7 +167,7 @@ class ItemCRUD:
# ====================================================== # ======================================================
# NORMAL SINGLE-FIELD (Village / Block / State) # NORMAL SINGLE-FIELD (Village / Block / State)
# ====================================================== # ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.allPattern, childname):
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400 ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
@@ -276,7 +276,7 @@ class ItemCRUD:
# ====================================================== # ======================================================
# NORMAL SINGLE-FIELD # NORMAL SINGLE-FIELD
# ====================================================== # ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.allPattern, childname):
self.isSuccess = False self.isSuccess = False
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message'] self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
return return
@@ -364,7 +364,7 @@ class ItemCRUD:
f"User {current_user.id} checked '{childname}'" f"User {current_user.id} checked '{childname}'"
) )
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.allPattern, childname):
return HtmlHelper.json_response( return HtmlHelper.json_response(
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400 ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
) )

View File

@@ -12,6 +12,7 @@ class ItemCRUDType(Enum):
class RegEx: class RegEx:
patternAlphabetOnly = "^[A-Za-z ]+$" patternAlphabetOnly = "^[A-Za-z ]+$"
allPattern = "^(?!\s*$).+"
class ResponseHandler: class ResponseHandler:

View File

@@ -3,7 +3,7 @@ $(document).ready(function () {
let holdType = $(this).val().replace(/^\s+/, ""); let holdType = $(this).val().replace(/^\s+/, "");
$(this).val(holdType); $(this).val(holdType);
let reg = /^[A-Za-z]/; let reg = /^.+$/; // all pattern allow
if (!reg.test(holdType)) { if (!reg.test(holdType)) {
$("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red"); $("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red");

View File

@@ -1,5 +1,160 @@
// Subcontractor autocomplete functionality // $(document).ready(function () {
// // ===============================
// // FORM / TABLE TOGGLE
// // ===============================
// if ($('#addForm').length && $('#addTable').length) {
// $('#addForm').show();
// $('#addTable').hide();
// $('#addButton').click(function () {
// $('#addForm').show();
// $('#addTable').hide();
// });
// $('#displayButton').click(function () {
// $('#addForm').hide();
// $('#addTable').show();
// });
// }
// // ===============================
// // Subcontractor autocomplete
// // ===============================
// $("#subcontractor").keyup(function () {
// let query = $(this).val();
// if (query !== "") {
// $.ajax({
// url: "/search_subcontractor",
// method: "POST",
// data: { query: query },
// success: function (data) {
// $("#subcontractor_list").fadeIn().html(data);
// }
// });
// } else {
// $("#subcontractor_list").fadeOut();
// }
// });
// $(document).on("click", "li", function () {
// $("#subcontractor").val($(this).text());
// $("#subcontractor_id").val($(this).attr("data-id"));
// $("#subcontractor_list").fadeOut();
// });
// // Focus
// if (document.getElementById('subcontractor')) {
// document.getElementById('subcontractor').focus();
// }
// // ===============================
// // ADD INVOICE
// // ===============================
// if ($('#invoiceForm').length && window.location.href.includes('add_invoice')) {
// $("#invoiceForm").on("submit", function (e) {
// e.preventDefault();
// let formData = $(this).serialize();
// $.ajax({
// url: '/add_invoice',
// method: 'POST',
// data: formData,
// dataType: 'json',
// success: function (response) {
// if (response.status === "success") {
// alert(response.message || "Invoice added successfully!");
// $('#invoiceForm')[0].reset(); // clear form
// $('#addForm').hide();
// $('#addTable').show(); // switch to table
// location.reload(); // optional refresh
// } else {
// alert(response.message || "Error adding invoice.");
// }
// },
// error: function (xhr) {
// alert(xhr.responseJSON?.message || "Submission failed. Please try again.");
// }
// });
// });
// }
// // Example AJAX update function
// function updateInvoice(invoiceId, formElement) {
// const formData = $(formElement).serialize();
// $.ajax({
// url: '/update_invoice/' + invoiceId,
// method: 'POST',
// data: formData,
// dataType: 'json',
// success: function(response) {
// if(response.status === "success") {
// alert(response.message || "Invoice updated successfully!");
// // ✅ Hide Add Form, Show Table
// $('#addForm').hide();
// $('#addTable').show();
// // Optional: reload table or refresh page
// location.reload();
// } else {
// alert(response.message || "Update failed. Please try again.");
// }
// },
// error: function(xhr) {
// alert(xhr.responseJSON?.message || "Error updating invoice.");
// }
// });
// }
// // ===============================
// // DELETE INVOICE
// // ===============================
// function deleteInvoice(invoiceId, element) {
// if (!confirm("Are you sure you want to delete this invoice?")) return;
// $.ajax({
// url: '/delete_invoice/' + invoiceId,
// method: 'GET',
// dataType: 'json',
// success: function (response) {
// alert(response.message || "Invoice deleted successfully!");
// if (element) $(element).closest("tr").remove();
// },
// error: function (xhr) {
// alert(xhr.responseJSON?.message || "Error deleting invoice. Please try again.");
// }
// });
// }
$(document).ready(function () { $(document).ready(function () {
// ===============================
// FORM / TABLE TOGGLE
// ===============================
if ($('#addForm').length && $('#addTable').length) {
// Default: show form, hide table
$('#addForm').show();
$('#addTable').hide();
// ✅ Check URL hash to show table instead
if (window.location.hash === "#addTable") {
$('#addForm').hide();
$('#addTable').show();
}
$('#addButton').click(function () {
$('#addForm').show();
$('#addTable').hide();
});
$('#displayButton').click(function () {
$('#addForm').hide();
$('#addTable').show();
});
}
// ===============================
// Subcontractor autocomplete
// ===============================
$("#subcontractor").keyup(function () { $("#subcontractor").keyup(function () {
let query = $(this).val(); let query = $(this).val();
if (query !== "") { if (query !== "") {
@@ -21,42 +176,96 @@
$("#subcontractor_id").val($(this).attr("data-id")); $("#subcontractor_id").val($(this).attr("data-id"));
$("#subcontractor_list").fadeOut(); $("#subcontractor_list").fadeOut();
}); });
});
// Success Alert: show alert and reload after 3 seconds // Focus
function showSuccessAlert() { if (document.getElementById('subcontractor')) {
const alertBox = document.getElementById("invoiceSuccessAlert"); document.getElementById('subcontractor').focus();
alertBox.classList.add("show");
setTimeout(() => {
alertBox.classList.remove("show");
// Reload page or redirect after alert hides
window.location.href = '/add_invoice';
}, 3000);
} }
// Submit form via AJAX // ===============================
// ADD INVOICE
// ===============================
if ($('#invoiceForm').length && window.location.href.includes('add_invoice')) {
$("#invoiceForm").on("submit", function (e) { $("#invoiceForm").on("submit", function (e) {
e.preventDefault(); e.preventDefault();
let formData = $(this).serialize(); let formData = $(this).serialize();
$.ajax({ $.ajax({
url: '/add_invoice', url: '/add_invoice',
method: 'POST', method: 'POST',
data: formData, data: formData,
dataType: 'json',
success: function (response) { success: function (response) {
if (response.status === "success") { if (response.status === "success") {
showSuccessAlert(); alert(response.message || "Invoice added successfully!");
$('#invoiceForm')[0].reset(); // clear form
$('#addForm').hide();
$('#addTable').show(); // switch to table
location.reload(); // optional refresh
} else { } else {
alert(response.message); alert(response.message || "Error adding invoice.");
} }
}, },
error: function (xhr, status, error) { error: function (xhr) {
alert("Submission failed: " + error); let msg = xhr.responseJSON?.message || "Submission failed. Please try again.";
alert(msg);
} }
}); });
}); });
}
// ===============================
// UPDATE INVOICE
// ===============================
function updateInvoice(invoiceId, formElement) {
const formData = $(formElement).serialize();
$.ajax({
url: '/update_invoice/' + invoiceId,
method: 'POST',
data: formData,
dataType: 'json',
success: function(response) {
if(response.status === "success") {
alert(response.message || "Invoice updated successfully!");
window.onload = function () { // Redirect to Add Invoice page's table part
document.getElementById('subcontractor').focus(); window.location.href = "/add_invoice#addTable";
}; } else {
alert(response.message || "Update failed. Please try again.");
}
},
error: function(xhr) {
let msg = xhr.responseJSON?.message || "Error updating invoice.";
alert(msg);
}
});
}
window.updateInvoice = updateInvoice; // make globally accessible
// ===============================
// DELETE INVOICE
// ===============================
function deleteInvoice(invoiceId, element) {
if (!confirm("Are you sure you want to delete this invoice?")) return;
$.ajax({
url: '/delete_invoice/' + invoiceId,
method: 'GET',
dataType: 'json',
success: function (response) {
if (response.status === "success") {
alert(response.message || "Invoice deleted successfully!");
if (element) $(element).closest("tr").remove();
} else {
alert(response.message || "Error deleting invoice.");
}
},
error: function (xhr) {
let msg = xhr.responseJSON?.message || "Error deleting invoice. Please try again.";
alert(msg);
}
});
}
window.deleteInvoice = deleteInvoice; // make globally accessible
});

View File

@@ -1,41 +1,37 @@
window.onload = function () { window.onload = function () {
if (document.getElementById('Village_Name')) {
document.getElementById('Village_Name').focus(); document.getElementById('Village_Name').focus();
}
}; };
$(document).ready(function () { $(document).ready(function () {
// 🔥 RESTORE VIEW MODE AFTER RELOAD // RUN ONLY IF THIS PAGE HAS FORM/TABLE
var viewMode = localStorage.getItem("viewMode"); if ($('#addForm').length && $('#addTable').length) {
if (viewMode === "table") { // ✅ DEFAULT VIEW → SHOW FORM
$('#addForm').hide();
$('#addTable').show();
} else {
$('#addForm').show(); $('#addForm').show();
$('#addTable').hide(); $('#addTable').hide();
}
// 🔥 BUTTON TOGGLE LOGIC // 🔥 BUTTON TOGGLE
$('#addButton').click(function () { $('#addButton').click(function () {
$('#addForm').show(); $('#addForm').show();
$('#addTable').hide(); $('#addTable').hide();
localStorage.setItem("viewMode", "form");
}); });
$('#displayButton').click(function () { $('#displayButton').click(function () {
$('#addForm').hide(); $('#addForm').hide();
$('#addTable').show(); $('#addTable').show();
localStorage.setItem("viewMode", "table");
}); });
}
// ===============================
// STATE → DISTRICT // STATE → DISTRICT
// ===============================
if ($('#state_Id').length) {
$('#state_Id').change(function () { $('#state_Id').change(function () {
var stateId = $(this).val(); var stateId = $(this).val();
@@ -54,25 +50,24 @@ $(document).ready(function () {
districtDropdown.append('<option value="" disabled selected>Select District</option>'); districtDropdown.append('<option value="" disabled selected>Select District</option>');
data.forEach(function (district) { data.forEach(function (district) {
districtDropdown.append( districtDropdown.append(
'<option value="' + district.id + '">' + district.name + '</option>' '<option value="' + district.id + '">' + district.name + '</option>'
); );
}); });
districtDropdown.prop('disabled', false); districtDropdown.prop('disabled', false);
}
});
}
});
} }
});
}
});
// ===============================
// DISTRICT → BLOCK // DISTRICT → BLOCK
// ===============================
if ($('#district_Id').length) {
$('#district_Id').change(function () { $('#district_Id').change(function () {
var districtId = $(this).val(); var districtId = $(this).val();
@@ -91,25 +86,24 @@ $(document).ready(function () {
blockDropdown.append('<option value="" disabled selected>Select Block</option>'); blockDropdown.append('<option value="" disabled selected>Select Block</option>');
data.forEach(function (block) { data.forEach(function (block) {
blockDropdown.append( blockDropdown.append(
'<option value="' + block.id + '">' + block.name + '</option>' '<option value="' + block.id + '">' + block.name + '</option>'
); );
}); });
blockDropdown.prop('disabled', false); blockDropdown.prop('disabled', false);
}
});
}
});
} }
});
}
});
// ===============================
// VILLAGE NAME VALIDATION // VILLAGE NAME VALIDATION
// ===============================
if ($('#Village_Name').length) {
$('#Village_Name').on('input', function () { $('#Village_Name').on('input', function () {
var villageName = $(this).val(); var villageName = $(this).val();
@@ -127,13 +121,16 @@ $(document).ready(function () {
$('#villageMessage').text(''); $('#villageMessage').text('');
$('#submitVillage').prop('disabled', false); $('#submitVillage').prop('disabled', false);
}
});
} }
});
// ===============================
// CHECK DUPLICATE VILLAGE // CHECK DUPLICATE VILLAGE
// ===============================
if ($('#Village_Name').length && $('#block_Id').length) {
$('#Village_Name, #block_Id').on('change keyup', function () { $('#Village_Name, #block_Id').on('change keyup', function () {
var blockId = $('#block_Id').val(); var blockId = $('#block_Id').val();
@@ -142,7 +139,6 @@ $(document).ready(function () {
if (blockId && villageName) { if (blockId && villageName) {
$.ajax({ $.ajax({
url: '/check_village', url: '/check_village',
type: 'POST', type: 'POST',
@@ -168,9 +164,7 @@ $(document).ready(function () {
.css('color', 'green'); .css('color', 'green');
$('#submitVillage').prop('disabled', false); $('#submitVillage').prop('disabled', false);
} }
}, },
error: function () { error: function () {
@@ -180,85 +174,77 @@ $(document).ready(function () {
.css('color', 'red'); .css('color', 'red');
$('#submitVillage').prop('disabled', true); $('#submitVillage').prop('disabled', true);
}
});
}
});
} }
});
} // ===============================
// ADD VILLAGE (SAFE SCOPE FIX)
// ===============================
if ($('#villageForm').length) {
});
// ADD VILLAGE
$('#villageForm').submit(function (event) { $('#villageForm').submit(function (event) {
event.preventDefault(); event.preventDefault();
$.ajax({ $.ajax({
url: '/add_village', url: '/add_village',
type: 'POST', type: 'POST',
data: $(this).serialize(), data: $(this).serialize(),
success: function (response) { success: function (response) {
if (response.status === 'success') { if (response && response.status === 'success') {
alert('Village added successfully!'); alert(response.message || 'Village added successfully!');
// ✅ clear form
$('#villageForm')[0].reset();
// ✅ switch to table
$('#addForm').hide();
$('#addTable').show();
// optional refresh
location.reload(); location.reload();
} else { } else {
alert(response.message || 'Error adding village. Please try again.'); alert(response.message || 'Error adding village. Please try again.');
} }
}, },
error: function () { error: function () {
alert('An error occurred. Please try again.'); alert('An error occurred. Please try again.');
}
});
});
} }
}); });
});
});
// 🔥 DELETE FUNCTION (UPDATED)
function deleteVillage(villageId) {
if (!confirm("Are you sure you want to delete this village?")) { // ===============================
return; // DELETE FUNCTION (SAFE)
} // ===============================
function deleteVillage(villageId, element) {
// ✅ save that user is on table if (!confirm("Are you sure you want to delete this village?")) return;
localStorage.setItem("viewMode", "table");
$.ajax({ $.ajax({
url: '/delete_village/' + villageId, url: '/delete_village/' + villageId,
type: 'GET', type: 'GET',
dataType: 'json',
success: function () { success: function (response) {
alert(response.message); // ✅ now shows "Village deleted successfully!"
setTimeout(function () { if (element) $(element).closest("tr").remove();
alert("Village deleted successfully!");
// reload but stay on table
location.reload();
}, 1000);
}, },
error: function () { error: function () {
alert("Error deleting village. Please try again."); alert("Error deleting village. Please try again.");
} }
}); });
} }

View File

@@ -1,5 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<title>Manage Hold Types</title> <title>Manage Hold Types</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
@@ -7,6 +8,7 @@
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
<div class="button-container"> <div class="button-container">
@@ -46,8 +48,21 @@
<tr> <tr>
<td>{{ htd['hold_type_id'] }}</td> <td>{{ htd['hold_type_id'] }}</td>
<td>{{ htd['hold_type'] }}</td> <td>{{ htd['hold_type'] }}</td>
<td><a href="{{ url_for('hold_types.edit_hold_type', id=htd['hold_type_id']) }}">Edit</a></td> <td style="text-align:center;">
<td><button class="delete-button" data-id="{{ htd['hold_type_id'] }}">Delete</button></td> <a href="{{ url_for('hold_types.edit_hold_type', id=htd['hold_type_id']) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td style="text-align:center;">
<a href="{{ url_for('hold_types.delete_hold_type', id=htd['hold_type_id']) }}"
onclick="return confirm('Are you sure you want to delete this hold type?');">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
@@ -56,4 +71,3 @@
</div> </div>
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -1,47 +1,66 @@
{% extends 'base.html' %} {% extends 'base.html' %} {% block content %}
{% block content %}
<head xmlns="http://www.w3.org/1999/html"> <head xmlns="http://www.w3.org/1999/html">
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Add Invoice</title> <title>Add Invoice</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}"> <link
rel="stylesheet"
type="text/css"
href="{{ url_for('static', filename='css/invoice.css') }}"
/>
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script> <script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script> <script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
{% if success == 'true' %} {% if success == 'true' %}
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert"> <div
class="alert alert-success alert-dismissible fade show mt-3"
role="alert"
>
✅ Invoice added successfully! ✅ Invoice added successfully!
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> <button
type="button"
class="btn-close"
data-bs-dismiss="alert"
aria-label="Close"
></button>
</div> </div>
{% endif %} {% endif %}
<!-- Flash Messages --> <!-- Flash Messages -->
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %} {% if
{% if messages %} messages %}
<div class="flash-messages"> <div class="flash-messages">
{% for category, message in messages %} {% for category, message in messages %}
<div class="alert {{ category }}">{{ message }}</div> <div class="alert {{ category }}">{{ message }}</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %} {% endwith %}
{% endwith %}
<div class="button-container"> <div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm" style="display: none;"> <div id="addForm" style="display: none">
<h2>Add Invoice</h2> <h2>Add Invoice</h2>
<form id="invoiceForm" action="{{ url_for('invoice.add_invoice') }}" method="POST"> <form
id="invoiceForm"
action="{{ url_for('invoice.add_invoice') }}"
method="POST"
>
<div class="row1"> <div class="row1">
<div> <div>
<label for="subcontractor">Subcontractor Name:</label> <label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/> <input
type="text"
id="subcontractor"
name="subcontractor"
required
autocomplete="off"
/>
<input type="hidden" id="subcontractor_id" name="subcontractor_id" /> <input type="hidden" id="subcontractor_id" name="subcontractor_id" />
<div id="subcontractor_list"></div> <div id="subcontractor_list"></div>
</div> </div>
@@ -53,7 +72,9 @@
<select id="village" name="village" required> <select id="village" name="village" required>
<option value="">-- Select Village --</option> <option value="">-- Select Village --</option>
{% for village in villages %} {% for village in villages %}
<option value="{{ village.Village_Name }}">{{ village.Village_Name }}</option> <option value="{{ village.Village_Name }}">
{{ village.Village_Name }}
</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@@ -71,7 +92,11 @@
</div> </div>
<div> <div>
<label for="invoice_details">Invoice Details:</label> <label for="invoice_details">Invoice Details:</label>
<textarea id="invoice_details" name="invoice_details" required></textarea> <textarea
id="invoice_details"
name="invoice_details"
required
></textarea>
</div> </div>
</div> </div>
@@ -89,59 +114,161 @@
<div class="row3"> <div class="row3">
<div> <div>
<label for="basic_amount">Basic Amount:</label> <label for="basic_amount">Basic Amount:</label>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required/> <input
type="number"
step="0.01"
id="basic_amount"
name="basic_amount"
placeholder="₹ - 00.00"
required
/>
</div> </div>
<div> <div>
<label for="debit_amount">Debit Amount:</label> <label for="debit_amount">Debit Amount:</label>
<input type="number" step="0.01" id="debit_amount" name="debit_amount" placeholder="₹ - 00.00" required/> <input
type="number"
step="0.01"
id="debit_amount"
name="debit_amount"
placeholder="₹ - 00.00"
required
/>
</div> </div>
<div> <div>
<label for="after_debit_amount">After Debit Amount:</label> <label for="after_debit_amount">After Debit Amount:</label>
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" placeholder="₹ - 00.00" readonly required/> <input
type="number"
step="0.01"
id="after_debit_amount"
name="after_debit_amount"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
</div> </div>
<div class="row3"> <div class="row3">
<div class="percentage-field"> <div class="percentage-field">
<label for="gst_percentage">GST %:</label> <label for="gst_percentage">GST %:</label>
<input type="number" step="0.01" id="gst_percentage" name="gst_percentage" placeholder="%"/> <input
type="number"
step="0.01"
id="gst_percentage"
name="gst_percentage"
placeholder="%"
/>
<label for="gst_amount">GST Amount:</label> <label for="gst_amount">GST Amount:</label>
<input type="number" step="0.01" id="gst_amount" name="gst_amount" placeholder="₹ - 00.00" readonly required/> <input
type="number"
step="0.01"
id="gst_amount"
name="gst_amount"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
<div> <div>
<label for="amount">Amount:</label> <label for="amount">Amount:</label>
<input type="number" step="0.01" id="amount" name="amount" placeholder="₹ - 00.00" readonly required/> <input
type="number"
step="0.01"
id="amount"
name="amount"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
<div class="percentage-field"> <div class="percentage-field">
<label for="tds_percentage">TDS %:</label> <label for="tds_percentage">TDS %:</label>
<input type="number" step="0.01" id="tds_percentage" name="tds_percentage" placeholder="%"/> <input
type="number"
step="0.01"
id="tds_percentage"
name="tds_percentage"
placeholder="%"
/>
<label for="tds_amount">TDS Amount:</label> <label for="tds_amount">TDS Amount:</label>
<input type="number" step="0.01" id="tds_amount" name="tds_amount" placeholder="₹ - 00.00" readonly required/> <input
type="number"
step="0.01"
id="tds_amount"
name="tds_amount"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
</div> </div>
<div class="row3"> <div class="row3">
<div class="percentage-field"> <div class="percentage-field">
<label for="sd_percentage">SD %:</label> <label for="sd_percentage">SD %:</label>
<input type="number" step="0.01" id="sd_percentage" name="sd_percentage" placeholder="%"/> <input
type="number"
step="0.01"
id="sd_percentage"
name="sd_percentage"
placeholder="%"
/>
<label for="sd_amount">SD Amount:</label> <label for="sd_amount">SD Amount:</label>
<input type="number" step="0.01" id="sd_amount" name="sd_amount" placeholder="₹ - 00.00" readonly required> <input
type="number"
step="0.01"
id="sd_amount"
name="sd_amount"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
<div class="percentage-field"> <div class="percentage-field">
<label for="commission_percentage">On Commission %:</label> <label for="commission_percentage">On Commission %:</label>
<input type="number" step="0.01" id="commission_percentage" name="commission_percentage" placeholder="%"/> <input
type="number"
step="0.01"
id="commission_percentage"
name="commission_percentage"
placeholder="%"
/>
<label for="on_commission">On Commission:</label> <label for="on_commission">On Commission:</label>
<input type="number" step="0.01" id="on_commission" name="on_commission" placeholder="₹ - 00.00" readonly required> <input
type="number"
step="0.01"
id="on_commission"
name="on_commission"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
<div class="percentage-field"> <div class="percentage-field">
<label for="hydro_percentage">Hydro Testing %:</label> <label for="hydro_percentage">Hydro Testing %:</label>
<input type="number" step="0.01" id="hydro_percentage" name="hydro_percentage" placeholder="%"/> <input
type="number"
step="0.01"
id="hydro_percentage"
name="hydro_percentage"
placeholder="%"
/>
<label for="hydro_testing">Hydro Testing:</label> <label for="hydro_testing">Hydro Testing:</label>
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" placeholder="₹ - 00.00" readonly required> <input
type="number"
step="0.01"
id="hydro_testing"
name="hydro_testing"
placeholder="₹ - 00.00"
readonly
required
/>
</div> </div>
</div> </div>
<div class="hold-row"> <div class="hold-row">
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button> <button type="button" id="add_hold_amount" class="button">
+ Add Hold Amount
</button>
</div> </div>
<!-- Dynamically added hold amount fields --> <!-- Dynamically added hold amount fields -->
@@ -150,11 +277,25 @@
<div class="row2"> <div class="row2">
<div> <div>
<label for="gst_sd_amount">GST SD Amount:</label> <label for="gst_sd_amount">GST SD Amount:</label>
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" placeholder="₹ - 00.00" required/> <input
type="number"
step="0.01"
id="gst_sd_amount"
name="gst_sd_amount"
placeholder="₹ - 00.00"
required
/>
</div> </div>
<div> <div>
<label for="final_amount">Final Amount:</label> <label for="final_amount">Final Amount:</label>
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required/> <input
type="number"
step="0.01"
id="final_amount"
name="final_amount"
placeholder="₹ - 00.00"
required
/>
</div> </div>
</div> </div>
@@ -162,11 +303,16 @@
</form> </form>
</div> </div>
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none">
<!-- Invoice Table Section --> <!-- Invoice Table Section -->
<div class="search-container"> <div class="search-container">
<h2>Invoice List</h2> <h2>Invoice List</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()"> <input
type="text"
id="searchBar"
placeholder="Searching..."
onkeyup="searchTable()"
/>
{% if invoices %} {% if invoices %}
<table class="invoice-table"> <table class="invoice-table">
<thead> <thead>
@@ -218,14 +364,27 @@
<td>{{ invoice.Final_Amount }}</td> <td>{{ invoice.Final_Amount }}</td>
<td> <td>
<!-- Edit --> <!-- Edit -->
<a href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"> <a
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon"> href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
>
<img
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
alt="Edit"
class="icon edit-btn"
data-id="{{ invoice.Invoice_Id }}"
/>
</a> </a>
</td> </td>
<td> <td>
<!-- Delete --> <a
<a href="{{ url_for('invoice.delete_invoice_route', invoice_id=invoice.Invoice_Id) }}" onclick="return confirm('Are you sure?')"> href="javascript:void(0);"
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon"> onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
>
<img
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
alt="Delete"
class="icon"
/>
</a> </a>
</td> </td>
</tr> </tr>
@@ -238,26 +397,28 @@
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
// Get all the input fields // Get all the input fields
const basicAmount = document.getElementById('basic_amount'); const basicAmount = document.getElementById("basic_amount");
const debitAmount = document.getElementById('debit_amount'); const debitAmount = document.getElementById("debit_amount");
const afterDebitAmount = document.getElementById('after_debit_amount'); const afterDebitAmount = document.getElementById("after_debit_amount");
const amount = document.getElementById('amount'); const amount = document.getElementById("amount");
// Percentage fields // Percentage fields
const gstPercentage = document.getElementById('gst_percentage'); const gstPercentage = document.getElementById("gst_percentage");
const gstAmount = document.getElementById('gst_amount'); const gstAmount = document.getElementById("gst_amount");
const tdsPercentage = document.getElementById('tds_percentage'); const tdsPercentage = document.getElementById("tds_percentage");
const tdsAmount = document.getElementById('tds_amount'); const tdsAmount = document.getElementById("tds_amount");
const sdPercentage = document.getElementById('sd_percentage'); const sdPercentage = document.getElementById("sd_percentage");
const sdAmountInput = document.getElementById('sd_amount'); const sdAmountInput = document.getElementById("sd_amount");
const commissionPercentage = document.getElementById('commission_percentage'); const commissionPercentage = document.getElementById(
const onCommission = document.getElementById('on_commission'); "commission_percentage",
const hydroPercentage = document.getElementById('hydro_percentage'); );
const hydroTesting = document.getElementById('hydro_testing'); const onCommission = document.getElementById("on_commission");
const gstSdAmount = document.getElementById('gst_sd_amount'); const hydroPercentage = document.getElementById("hydro_percentage");
const finalAmount = document.getElementById('final_amount'); const hydroTesting = document.getElementById("hydro_testing");
const gstSdAmount = document.getElementById("gst_sd_amount");
const finalAmount = document.getElementById("final_amount");
// Calculate after debit amount when basic or debit amount changes // Calculate after debit amount when basic or debit amount changes
function calculateAfterDebitAmount() { function calculateAfterDebitAmount() {
@@ -333,7 +494,9 @@ document.addEventListener('DOMContentLoaded', function() {
// Get hold amounts // Get hold amounts
let totalHold = 0; let totalHold = 0;
document.querySelectorAll('input[name="hold_amount[]"]').forEach(input => { document
.querySelectorAll('input[name="hold_amount[]"]')
.forEach((input) => {
totalHold += parseFloat(input.value) || 0; totalHold += parseFloat(input.value) || 0;
}); });
@@ -343,27 +506,30 @@ document.addEventListener('DOMContentLoaded', function() {
} }
// Add event listeners // Add event listeners
basicAmount.addEventListener('input', calculateAfterDebitAmount); basicAmount.addEventListener("input", calculateAfterDebitAmount);
debitAmount.addEventListener('input', calculateAfterDebitAmount); debitAmount.addEventListener("input", calculateAfterDebitAmount);
// Percentage fields // Percentage fields
gstPercentage.addEventListener('input', calculateGST); gstPercentage.addEventListener("input", calculateGST);
tdsPercentage.addEventListener('input', calculateOtherDeductions); tdsPercentage.addEventListener("input", calculateOtherDeductions);
sdPercentage.addEventListener('input', calculateOtherDeductions); sdPercentage.addEventListener("input", calculateOtherDeductions);
commissionPercentage.addEventListener('input', calculateOtherDeductions); commissionPercentage.addEventListener(
hydroPercentage.addEventListener('input', calculateOtherDeductions); "input",
calculateOtherDeductions,
);
hydroPercentage.addEventListener("input", calculateOtherDeductions);
// Listen for changes in hold amounts // Listen for changes in hold amounts
document.addEventListener('holdAmountChanged', calculateFinalAmount); document.addEventListener("holdAmountChanged", calculateFinalAmount);
}); });
// Optional JS for auto-hiding flash // Optional JS for auto-hiding flash
setTimeout(() => { setTimeout(() => {
document.querySelectorAll('.alert').forEach(el => el.style.display = 'none'); document
.querySelectorAll(".alert")
.forEach((el) => (el.style.display = "none"));
}, 5000); }, 5000);
</script> </script>
</div> </div>
</body> </body>

View File

@@ -1,22 +1,24 @@
{% extends 'base.html' %} {% extends 'base.html' %} {% block content %}
{% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Village Management</title> <title>Village Management</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <link
rel="stylesheet"
type="text/css"
href="{{ url_for('static', filename='css/style.css') }}"
/>
<script src="{{ url_for('static', filename='js/village.js') }}"></script> <script src="{{ url_for('static', filename='js/village.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
<!-- Button Container to Center Buttons --> <!-- Button Container to Center Buttons -->
<div class="button-container"> <div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm" style="display: none;"> <div id="addForm" style="display: none">
<div class="container"> <div class="container">
<div class="form-block"> <div class="form-block">
<h2>Add a New Village</h2> <h2>Add a New Village</h2>
@@ -40,7 +42,13 @@
</select> </select>
<label for="Village_Name">Village Name:</label> <label for="Village_Name">Village Name:</label>
<input type="text" id="Village_Name" name="Village_Name" placeholder="Enter Village Name" required> <input
type="text"
id="Village_Name"
name="Village_Name"
placeholder="Enter Village Name"
required
/>
<span id="villageMessage"></span> <span id="villageMessage"></span>
<button type="submit" id="submitVillage" disabled>Add Village</button> <button type="submit" id="submitVillage" disabled>Add Village</button>
@@ -49,10 +57,15 @@
</div> </div>
</div> </div>
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none">
<div class="search-container"> <div class="search-container">
<h2>Display Villages</h2> <h2>Display Villages</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()"> <input
type="text"
id="searchBar"
placeholder="Searching..."
onkeyup="searchTable()"
/>
</div> </div>
<table id="sortableTable" border="1"> <table id="sortableTable" border="1">
@@ -63,12 +76,15 @@
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span></th> </span>
<th class="sortable-header">Block Name </th>
<th class="sortable-header">
Block Name
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span></th> </span>
</th>
<th>Update</th> <th>Update</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
@@ -78,22 +94,36 @@
<td>{{ village[1] }}</td> <td>{{ village[1] }}</td>
<td>{{ village[2] }}</td> <td>{{ village[2] }}</td>
<td> <td>
<a href="{{ url_for('village.edit_village', village_id=village[0]) }}"> <a
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" href="{{ url_for('village.edit_village', village_id=village[0]) }}"
class="icon"> >
<img
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
alt="Edit"
class="icon"
/>
</a> </a>
</td> </td>
<td> <td>
<a href="#" <a href="javascript:void(0);"
onclick="deleteVillage({{ village[0] }}); return false;"> onclick="deleteVillage({{ village[0] }}, this)">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
alt="Delete" class="icon"> class="icon">
</a> </a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
<!-- Flash Alerts -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<script>
{% for category, message in messages %}
alert("{{ message }}");
{% endfor %}
</script>
{% endif %}
{% endwith %}
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<title>Edit Hold Type</title> <title>Edit Hold Type</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
@@ -10,10 +10,10 @@
<body> <body>
<h2>Edit Hold Type</h2> <h2>Edit Hold Type</h2>
<form id="updateHoldTypeForm"> <form id="updateHoldTypeForm" method="POST">
<input type="hidden" id="hold_type_id" value="{{ hold_type[0] }}"> <input type="hidden" id="hold_type_id" value="{{ hold_type.hold_type_id }}">
<label for="edit_hold_type">Hold Type:</label> <label for="edit_hold_type">Hold Type:</label>
<input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type[1] }}" required> <input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type.hold_type }}" required>
<button type="submit">Update</button> <button type="submit">Update</button>
<a href="{{ url_for('hold_types.add_hold_type') }}"></a> <a href="{{ url_for('hold_types.add_hold_type') }}"></a>
</form> </form>
@@ -37,7 +37,7 @@
formData.append('hold_type', newHoldType); formData.append('hold_type', newHoldType);
$.ajax({ $.ajax({
url: '/update_hold_type/' + holdTypeId, url: '/edit_hold_type/' + holdTypeId,
method: 'POST', method: 'POST',
data: formData, data: formData,
processData: false, processData: false,
@@ -55,8 +55,3 @@
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -20,7 +20,8 @@
Invoice successfully updated! Invoice successfully updated!
</div> </div>
<form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}" method="POST"> <form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
method="POST">
<!-- Subcontractor Field --> <!-- Subcontractor Field -->
<div class="row1"> <div class="row1">
@@ -28,7 +29,8 @@
<label for="subcontractor">Subcontractor Name:</label> <label for="subcontractor">Subcontractor Name:</label>
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor" <input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor"
value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required> value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required>
<input type="hidden" id="subcontractor_id" name="subcontractor_id" value="{{ invoice.Subcontractor_Id }}"> <input type="hidden" id="subcontractor_id" name="subcontractor_id"
value="{{ invoice.Subcontractor_Id }}">
<datalist id="subcontractor_list"></datalist> <datalist id="subcontractor_list"></datalist>
</div> </div>
</div> </div>
@@ -54,7 +56,8 @@
</div> </div>
<div> <div>
<label for="invoice_details">Invoice Details:</label> <label for="invoice_details">Invoice Details:</label>
<textarea id="invoice_details" name="invoice_details" required>{{ invoice.Invoice_Details }}</textarea> <textarea id="invoice_details" name="invoice_details"
required>{{ invoice.Invoice_Details }}</textarea>
</div> </div>
</div> </div>
@@ -62,11 +65,12 @@
<div class="row2"> <div class="row2">
<div> <div>
<label for="invoice_no">Invoice No:</label> <label for="invoice_no">Invoice No:</label>
<input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.Invoice_No }}" required/> <input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.invoice_no }}" required />
</div> </div>
<div> <div>
<label for="invoice_date">Invoice Date:</label> <label for="invoice_date">Invoice Date:</label>
<input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}" required/> <input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}"
required />
</div> </div>
</div> </div>
@@ -74,15 +78,18 @@
<div class="row3"> <div class="row3">
<div> <div>
<label for="basic_amount">Basic Amount:</label> <label for="basic_amount">Basic Amount:</label>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ invoice.Basic_Amount }}" required/> <input type="number" step="0.01" id="basic_amount" name="basic_amount"
value="{{ invoice.Basic_Amount }}" required />
</div> </div>
<div> <div>
<label for="debit_amount">Debit Amount:</label> <label for="debit_amount">Debit Amount:</label>
<input type="number" step="0.01" id="debit_amount" name="debit_amount" value="{{ invoice.Debit_Amount }}" required/> <input type="number" step="0.01" id="debit_amount" name="debit_amount"
value="{{ invoice.Debit_Amount }}" required />
</div> </div>
<div> <div>
<label for="after_debit_amount">After Debit Amount:</label> <label for="after_debit_amount">After Debit Amount:</label>
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" value="{{ invoice.After_Debit_Amount }}" required/> <input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount"
value="{{ invoice.After_Debit_Amount }}" required />
</div> </div>
</div> </div>
@@ -94,11 +101,13 @@
</div> </div>
<div> <div>
<label for="gst_amount">GST Amount:</label> <label for="gst_amount">GST Amount:</label>
<input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}" required/> <input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}"
required />
</div> </div>
<div> <div>
<label for="tds_amount">TDS Amount:</label> <label for="tds_amount">TDS Amount:</label>
<input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}" required/> <input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}"
required />
</div> </div>
</div> </div>
@@ -106,15 +115,18 @@
<div class="row3"> <div class="row3">
<div> <div>
<label for="sd_amount">SD Amount:</label> <label for="sd_amount">SD Amount:</label>
<input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}" required/> <input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}"
required />
</div> </div>
<div> <div>
<label for="on_commission">On Commission:</label> <label for="on_commission">On Commission:</label>
<input type="number" step="0.01" id="on_commission" name="on_commission" value="{{ invoice.On_Commission }}" required/> <input type="number" step="0.01" id="on_commission" name="on_commission"
value="{{ invoice.On_Commission }}" required />
</div> </div>
<div> <div>
<label for="hydro_testing">Hydro Testing:</label> <label for="hydro_testing">Hydro Testing:</label>
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" value="{{ invoice.Hydro_Testing }}" required/> <input type="number" step="0.01" id="hydro_testing" name="hydro_testing"
value="{{ invoice.Hydro_Testing }}" required />
</div> </div>
</div> </div>
@@ -126,9 +138,11 @@
{% set _ = seen_types.append(hold.hold_type) %} {% set _ = seen_types.append(hold.hold_type) %}
<div class="hold-amount-row"> <div class="hold-amount-row">
<label for="hold_type_{{ loop.index }}">Hold Type:</label> <label for="hold_type_{{ loop.index }}">Hold Type:</label>
<input type="text" id="hold_type_{{ loop.index }}" name="hold_type[]" value="{{ hold.hold_type }}" required/> <input type="text" id="hold_type_{{ loop.index }}" name="hold_type[]" value="{{ hold.hold_type }}"
required />
<label for="hold_amount_{{ loop.index }}">Hold Amount:</label> <label for="hold_amount_{{ loop.index }}">Hold Amount:</label>
<input type="number" step="0.01" id="hold_amount_{{ loop.index }}" name="hold_amount[]" value="{{ hold.hold_amount }}" required/> <input type="number" step="0.01" id="hold_amount_{{ loop.index }}" name="hold_amount[]"
value="{{ hold.hold_amount }}" required />
<button type="button" class="remove-hold-amount">Remove</button> <button type="button" class="remove-hold-amount">Remove</button>
</div> </div>
{% endif %} {% endif %}
@@ -144,11 +158,13 @@
<div class="row2"> <div class="row2">
<div> <div>
<label for="gst_sd_amount">GST SD Amount:</label> <label for="gst_sd_amount">GST SD Amount:</label>
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" value="{{ invoice.GST_SD_Amount }}" required/> <input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount"
value="{{ invoice.GST_SD_Amount }}" required />
</div> </div>
<div> <div>
<label for="final_amount">Final Amount:</label> <label for="final_amount">Final Amount:</label>
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ invoice.Final_Amount }}" required/> <input type="number" step="0.01" id="final_amount" name="final_amount"
value="{{ invoice.Final_Amount }}" required />
</div> </div>
</div> </div>

View File

@@ -28,25 +28,17 @@
<button type="submit">Update Village</button> <button type="submit">Update Village</button>
</form> </form>
</div> <!-- Flash Messages (hidden, used for JS popup) -->
<div id="flash-messages-container" style="display:none;">
<!-- Flash Message (Hidden, used for JS popup) -->
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
{% for category, message in messages %} {% for category, message in messages %}
<div id="flash-message" data-category="{{ category }}" style="display:none;">{{ message }}</div> <div class="flash-message" data-category="{{ category }}">{{ message }}</div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</div> </div>
<script>
window.onload = function () {
const flash = document.getElementById('flash-message');
if (flash && flash.innerText.trim() !== "") {
alert(flash.innerText);
}
};
</script>
</body> </body>
{% endblock %} {% endblock %}