539 lines
17 KiB
HTML
539 lines
17 KiB
HTML
{% extends 'base.html' %} {% block content %}
|
|
<head xmlns="http://www.w3.org/1999/html">
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Add Invoice</title>
|
|
<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/holdAmount.js') }}"></script>
|
|
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
|
</head>
|
|
<body>
|
|
{% if success == 'true' %}
|
|
<div
|
|
class="alert alert-success alert-dismissible fade show mt-3"
|
|
role="alert"
|
|
>
|
|
✅ Invoice added successfully!
|
|
<button
|
|
type="button"
|
|
class="btn-close"
|
|
data-bs-dismiss="alert"
|
|
aria-label="Close"
|
|
></button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Flash Messages -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %} {% if
|
|
messages %}
|
|
<div class="flash-messages">
|
|
{% for category, message in messages %}
|
|
<div class="alert {{ category }}">{{ message }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %} {% endwith %}
|
|
|
|
<div class="button-container">
|
|
<button id="addButton" class="action-button">Add</button>
|
|
<button id="displayButton" class="action-button">Display</button>
|
|
</div>
|
|
|
|
<div id="addForm" style="display: none">
|
|
<h2>Add Invoice</h2>
|
|
|
|
<form
|
|
id="invoiceForm"
|
|
action="{{ url_for('invoice.add_invoice') }}"
|
|
method="POST"
|
|
>
|
|
<div class="row1">
|
|
<div>
|
|
<label for="subcontractor">Subcontractor Name:</label>
|
|
<input
|
|
type="text"
|
|
id="subcontractor"
|
|
name="subcontractor"
|
|
required
|
|
autocomplete="off"
|
|
/>
|
|
<input type="hidden" id="subcontractor_id" name="subcontractor_id" />
|
|
<div id="subcontractor_list"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row2">
|
|
<div>
|
|
<label for="village">Village Name:</label>
|
|
<select id="village" name="village" required>
|
|
<option value="">-- Select Village --</option>
|
|
{% for village in villages %}
|
|
<option value="{{ village.Village_Name }}">
|
|
{{ village.Village_Name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="pmc_no">PMC No:</label>
|
|
<input type="text" id="pmc_no" name="pmc_no" required />
|
|
<div id="pmc_no_list" class="autocomplete-list"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row2">
|
|
<div>
|
|
<label for="work_type">Work Type:</label>
|
|
<input type="text" id="work_type" name="work_type" required />
|
|
</div>
|
|
<div>
|
|
<label for="invoice_details">Invoice Details:</label>
|
|
<textarea
|
|
id="invoice_details"
|
|
name="invoice_details"
|
|
required
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row2">
|
|
<div>
|
|
<label for="invoice_no">Invoice No:</label>
|
|
<input type="text" id="invoice_no" name="invoice_no" required />
|
|
</div>
|
|
<div>
|
|
<label for="invoice_date">Invoice Date:</label>
|
|
<input type="date" id="invoice_date" name="invoice_date" required />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row3">
|
|
<div>
|
|
<label for="basic_amount">Basic Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="basic_amount"
|
|
name="basic_amount"
|
|
placeholder="₹ - 00.00"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="debit_amount">Debit Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="debit_amount"
|
|
name="debit_amount"
|
|
placeholder="₹ - 00.00"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<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
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row3">
|
|
<div class="percentage-field">
|
|
<label for="gst_percentage">GST %:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="gst_percentage"
|
|
name="gst_percentage"
|
|
placeholder="%"
|
|
/>
|
|
<label for="gst_amount">GST Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="gst_amount"
|
|
name="gst_amount"
|
|
placeholder="₹ - 00.00"
|
|
readonly
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="amount">Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="amount"
|
|
name="amount"
|
|
placeholder="₹ - 00.00"
|
|
readonly
|
|
required
|
|
/>
|
|
</div>
|
|
<div class="percentage-field">
|
|
<label for="tds_percentage">TDS %:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="tds_percentage"
|
|
name="tds_percentage"
|
|
placeholder="%"
|
|
/>
|
|
<label for="tds_amount">TDS Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="tds_amount"
|
|
name="tds_amount"
|
|
placeholder="₹ - 00.00"
|
|
readonly
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row3">
|
|
<div class="percentage-field">
|
|
<label for="sd_percentage">SD %:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="sd_percentage"
|
|
name="sd_percentage"
|
|
placeholder="%"
|
|
/>
|
|
<label for="sd_amount">SD Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="sd_amount"
|
|
name="sd_amount"
|
|
placeholder="₹ - 00.00"
|
|
readonly
|
|
required
|
|
/>
|
|
</div>
|
|
<div class="percentage-field">
|
|
<label for="commission_percentage">On Commission %:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="commission_percentage"
|
|
name="commission_percentage"
|
|
placeholder="%"
|
|
/>
|
|
<label for="on_commission">On Commission:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="on_commission"
|
|
name="on_commission"
|
|
placeholder="₹ - 00.00"
|
|
readonly
|
|
required
|
|
/>
|
|
</div>
|
|
<div class="percentage-field">
|
|
<label for="hydro_percentage">Hydro Testing %:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="hydro_percentage"
|
|
name="hydro_percentage"
|
|
placeholder="%"
|
|
/>
|
|
<label for="hydro_testing">Hydro Testing:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="hydro_testing"
|
|
name="hydro_testing"
|
|
placeholder="₹ - 00.00"
|
|
readonly
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="hold-row">
|
|
<button type="button" id="add_hold_amount" class="button">
|
|
+ Add Hold Amount
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Dynamically added hold amount fields -->
|
|
<div id="hold_amount_container"></div>
|
|
|
|
<div class="row2">
|
|
<div>
|
|
<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
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="final_amount">Final Amount:</label>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
id="final_amount"
|
|
name="final_amount"
|
|
placeholder="₹ - 00.00"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="button">Submit</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div id="addTable" style="display: none">
|
|
<!-- Invoice Table Section -->
|
|
<div class="search-container">
|
|
<h2>Invoice List</h2>
|
|
<input
|
|
type="text"
|
|
id="searchBar"
|
|
placeholder="Searching..."
|
|
onkeyup="searchTable()"
|
|
/>
|
|
{% if invoices %}
|
|
<table class="invoice-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Invoice Id</th>
|
|
<th>SubContractor Name</th>
|
|
<th>PMC No</th>
|
|
<th>Village</th>
|
|
<th>Work Type</th>
|
|
<th>Invoice Details</th>
|
|
<th>Invoice Date</th>
|
|
<th>Invoice No</th>
|
|
<th>Basic Amount</th>
|
|
<th>Debit Amount</th>
|
|
<th>After Debit Amount</th>
|
|
<th>Amount</th>
|
|
<th>GST Amount</th>
|
|
<th>TDS Amount</th>
|
|
<th>SD Amount</th>
|
|
<th>On Commission</th>
|
|
<th>Hydro Testing</th>
|
|
<th>GST SD Amount</th>
|
|
<th>Final Amount</th>
|
|
<th>Update</th>
|
|
<th>Delete</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for invoice in invoices %}
|
|
<tr>
|
|
<td>{{ invoice.Invoice_Id }}</td>
|
|
<td>{{ invoice.Contractor_Name }}</td>
|
|
<td>{{ invoice.PMC_No }}</td>
|
|
<td>{{ invoice.Village_Name or 'N/A' }}</td>
|
|
<td>{{ invoice.Work_Type }}</td>
|
|
<td>{{ invoice.Invoice_Details }}</td>
|
|
<td>{{ invoice.Invoice_Date }}</td>
|
|
<td>{{ invoice.Invoice_No }}</td>
|
|
<td>{{ invoice.Basic_Amount }}</td>
|
|
<td>{{ invoice.Debit_Amount }}</td>
|
|
<td>{{ invoice.After_Debit_Amount }}</td>
|
|
<td>{{ invoice.Amount }}</td>
|
|
<td>{{ invoice.GST_Amount }}</td>
|
|
<td>{{ invoice.TDS_Amount }}</td>
|
|
<td>{{ invoice.SD_Amount }}</td>
|
|
<td>{{ invoice.On_Commission }}</td>
|
|
<td>{{ invoice.Hydro_Testing }}</td>
|
|
<td>{{ invoice.GST_SD_Amount }}</td>
|
|
<td>{{ invoice.Final_Amount }}</td>
|
|
<td>
|
|
<!-- Edit -->
|
|
<a
|
|
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>
|
|
</td>
|
|
<td>
|
|
<!-- <a
|
|
href="javascript:void(0);"
|
|
onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
|
|
> -->
|
|
<a href="javascript:void(0);"
|
|
onclick="deleteInvoice('{{ invoice.Invoice_Id }}', this)">
|
|
<img
|
|
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
|
alt="Delete"
|
|
class="icon"
|
|
/>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<p>No invoices found.</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Get all the input fields
|
|
const basicAmount = document.getElementById("basic_amount");
|
|
const debitAmount = document.getElementById("debit_amount");
|
|
const afterDebitAmount = document.getElementById("after_debit_amount");
|
|
const amount = document.getElementById("amount");
|
|
|
|
// Percentage fields
|
|
const gstPercentage = document.getElementById("gst_percentage");
|
|
const gstAmount = document.getElementById("gst_amount");
|
|
const tdsPercentage = document.getElementById("tds_percentage");
|
|
const tdsAmount = document.getElementById("tds_amount");
|
|
const sdPercentage = document.getElementById("sd_percentage");
|
|
const sdAmountInput = document.getElementById("sd_amount");
|
|
const commissionPercentage = document.getElementById(
|
|
"commission_percentage",
|
|
);
|
|
const onCommission = document.getElementById("on_commission");
|
|
const hydroPercentage = document.getElementById("hydro_percentage");
|
|
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
|
|
function calculateAfterDebitAmount() {
|
|
const basic = parseFloat(basicAmount.value) || 0;
|
|
const debit = parseFloat(debitAmount.value) || 0;
|
|
const afterDebit = basic - debit;
|
|
afterDebitAmount.value = afterDebit.toFixed(2);
|
|
calculateGST();
|
|
}
|
|
|
|
// Calculate GST and Amount
|
|
function calculateGST() {
|
|
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
|
|
|
|
if (gstPercentage.value) {
|
|
const gstPerc = parseFloat(gstPercentage.value) || 0;
|
|
const gstAmt = (baseAmount * gstPerc) / 100;
|
|
gstAmount.value = gstAmt.toFixed(2);
|
|
gstSdAmount.value = gstAmt.toFixed(2);
|
|
|
|
// Calculate Amount (After Debit + GST)
|
|
amount.value = (baseAmount + gstAmt).toFixed(2);
|
|
} else {
|
|
amount.value = baseAmount.toFixed(2);
|
|
}
|
|
|
|
calculateOtherDeductions();
|
|
}
|
|
|
|
// Calculate other deductions (TDS, SD, Commission, Hydro)
|
|
function calculateOtherDeductions() {
|
|
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
|
|
|
|
// Calculate TDS
|
|
if (tdsPercentage.value) {
|
|
const tdsPerc = parseFloat(tdsPercentage.value) || 0;
|
|
const tdsAmt = (baseAmount * tdsPerc) / 100;
|
|
tdsAmount.value = tdsAmt.toFixed(2);
|
|
}
|
|
|
|
// Calculate SD
|
|
if (sdPercentage.value) {
|
|
const sdPerc = parseFloat(sdPercentage.value) || 0;
|
|
const sdAmt = (baseAmount * sdPerc) / 100;
|
|
sdAmountInput.value = sdAmt.toFixed(2);
|
|
}
|
|
|
|
// Calculate Commission
|
|
if (commissionPercentage.value) {
|
|
const commPerc = parseFloat(commissionPercentage.value) || 0;
|
|
const commAmt = (baseAmount * commPerc) / 100;
|
|
onCommission.value = commAmt.toFixed(2);
|
|
}
|
|
|
|
// Calculate Hydro Testing
|
|
if (hydroPercentage.value) {
|
|
const hydroPerc = parseFloat(hydroPercentage.value) || 0;
|
|
const hydroAmt = (baseAmount * hydroPerc) / 100;
|
|
hydroTesting.value = hydroAmt.toFixed(2);
|
|
}
|
|
|
|
calculateFinalAmount();
|
|
}
|
|
|
|
// Calculate final amount
|
|
function calculateFinalAmount() {
|
|
const amt = parseFloat(amount.value) || 0;
|
|
const tds = parseFloat(tdsAmount.value) || 0;
|
|
const sd = parseFloat(sdAmountInput.value) || 0;
|
|
const commission = parseFloat(onCommission.value) || 0;
|
|
const hydro = parseFloat(hydroTesting.value) || 0;
|
|
const gstSd = parseFloat(gstSdAmount.value) || 0;
|
|
|
|
// Get hold amounts
|
|
let totalHold = 0;
|
|
document
|
|
.querySelectorAll('input[name="hold_amount[]"]')
|
|
.forEach((input) => {
|
|
totalHold += parseFloat(input.value) || 0;
|
|
});
|
|
|
|
// Final Amount = Amount - TDS - SD - Commission - Hydro - GST SD - Hold Amounts
|
|
const final = amt - tds - sd - commission - hydro - gstSd - totalHold;
|
|
finalAmount.value = final.toFixed(2);
|
|
}
|
|
|
|
// Add event listeners
|
|
basicAmount.addEventListener("input", calculateAfterDebitAmount);
|
|
debitAmount.addEventListener("input", calculateAfterDebitAmount);
|
|
|
|
// Percentage fields
|
|
gstPercentage.addEventListener("input", calculateGST);
|
|
tdsPercentage.addEventListener("input", calculateOtherDeductions);
|
|
sdPercentage.addEventListener("input", calculateOtherDeductions);
|
|
commissionPercentage.addEventListener(
|
|
"input",
|
|
calculateOtherDeductions,
|
|
);
|
|
hydroPercentage.addEventListener("input", calculateOtherDeductions);
|
|
|
|
// Listen for changes in hold amounts
|
|
document.addEventListener("holdAmountChanged", calculateFinalAmount);
|
|
});
|
|
|
|
// Optional JS for auto-hiding flash
|
|
setTimeout(() => {
|
|
document
|
|
.querySelectorAll(".alert")
|
|
.forEach((el) => (el.style.display = "none"));
|
|
}, 5000);
|
|
</script>
|
|
</div>
|
|
</body>
|
|
|
|
{% endblock %}
|