393 lines
16 KiB
PHP
393 lines
16 KiB
PHP
<div class="">
|
|
<div class="text-right mb-3" style="margin-bottom: 15px;">
|
|
<button id="downloadPdf" class="btn btn-primary">Download Demand Sheet</button>
|
|
</div>
|
|
|
|
<table class="table table-striped table-bordered table-hover table-responsive">
|
|
<tr>
|
|
<th>SL</th>
|
|
<th>Type</th>
|
|
<th>AC No</th>
|
|
<th>Name</th>
|
|
<th>Mobile</th>
|
|
<th>Account Create Date</th>
|
|
<th>Maturity Value</th>
|
|
<th>Balance</th>
|
|
<th>Total EMI</th>
|
|
<th>Total Paid EMI</th>
|
|
<th>Deu EMI Till Date</th>
|
|
<th>EMI Amount</th>
|
|
<th>Total Due Amount</th>
|
|
|
|
</tr>
|
|
|
|
<?php
|
|
// function countCycles($cycle, $createDate, $totalInstallment) {
|
|
// $today = new DateTime();
|
|
// $startDate = new DateTime($createDate);
|
|
|
|
// $cycle = strtoupper(trim($cycle)); // normalize input (W/M/D)
|
|
|
|
// if ($cycle === "D") {
|
|
// // For daily cycles, count starts from the next day
|
|
// $startDate->modify('+1 day');
|
|
// if ($startDate > $today) {
|
|
// $count = 0;
|
|
// } else {
|
|
// $diff = $startDate->diff($today);
|
|
// $count = $diff->days;
|
|
// }
|
|
// } elseif ($cycle === "W") {
|
|
// // For weekly cycles, first payment is next week
|
|
// $startDate->modify('next monday'); // or use '+1 week' if you want exactly 7 days later
|
|
|
|
// if ($startDate > $today) {
|
|
// $count = 0;
|
|
// } else {
|
|
// $diff = $startDate->diff($today);
|
|
// $count = floor($diff->days / 7);
|
|
// }
|
|
// } elseif ($cycle === "M") {
|
|
// // For monthly cycles, first payment is next month
|
|
// $startDate->modify('first day of next month');
|
|
|
|
// if ($startDate > $today) {
|
|
// $count = 0;
|
|
// } else {
|
|
// $diff = $startDate->diff($today);
|
|
// $count = ($diff->y * 12) + $diff->m;
|
|
|
|
// // If we're in the same month but after the start date, add one
|
|
// if ($diff->y == 0 && $diff->m == 0 && $diff->d > 0) {
|
|
// $count++;
|
|
// }
|
|
// }
|
|
// } else {
|
|
// $count = 0; // unknown cycle
|
|
// }
|
|
|
|
// // Ensure count doesn't exceed total installments
|
|
// return min($count, $totalInstallment);
|
|
// }
|
|
function countCycles($cycle, $createDate, $totalInstallment, $accountType) {
|
|
$today = new DateTime();
|
|
$startDate = new DateTime($createDate);
|
|
|
|
$cycle = strtoupper(trim($cycle));
|
|
$accountType = strtoupper(trim($accountType));
|
|
|
|
if ($accountType === "Recurring") {
|
|
// Recurring account: creation date ই first EMI date
|
|
$firstPaymentDate = clone $startDate;
|
|
|
|
if ($firstPaymentDate > $today) {
|
|
$count = 0;
|
|
} else {
|
|
if ($cycle === "D") {
|
|
$diff = $firstPaymentDate->diff($today);
|
|
$count = $diff->days + 1;
|
|
} elseif ($cycle === "W") {
|
|
$diff = $firstPaymentDate->diff($today);
|
|
$count = floor($diff->days / 7) + 1;
|
|
} elseif ($cycle === "M") {
|
|
$count = 1; // প্রথম EMI already due
|
|
$nextPaymentDate = clone $firstPaymentDate;
|
|
|
|
while ($nextPaymentDate <= $today) {
|
|
$nextPaymentDate->modify('+1 month');
|
|
|
|
if ($nextPaymentDate->format('d') != $firstPaymentDate->format('d')) {
|
|
$nextPaymentDate->modify('last day of this month');
|
|
}
|
|
|
|
if ($nextPaymentDate <= $today) {
|
|
$count++;
|
|
}
|
|
}
|
|
} else {
|
|
$count = 0;
|
|
}
|
|
}
|
|
} elseif ($accountType === "Loan") {
|
|
// Loan account: cycle অনুযায়ী first EMI later
|
|
if ($cycle === "D") {
|
|
$firstPaymentDate = (clone $startDate)->modify('+1 day');
|
|
|
|
if ($firstPaymentDate > $today) {
|
|
$count = 0;
|
|
} else {
|
|
$diff = $firstPaymentDate->diff($today);
|
|
$count = $diff->days + 1;
|
|
}
|
|
} elseif ($cycle === "W") {
|
|
$firstPaymentDate = (clone $startDate)->modify('+7 days');
|
|
|
|
if ($firstPaymentDate > $today) {
|
|
$count = 0;
|
|
} else {
|
|
$diff = $firstPaymentDate->diff($today);
|
|
$count = floor($diff->days / 7) + 1;
|
|
}
|
|
} elseif ($cycle === "M") {
|
|
$firstPaymentDate = (clone $startDate)->modify('+1 month');
|
|
|
|
if ($firstPaymentDate->format('d') != $startDate->format('d')) {
|
|
$firstPaymentDate->modify('last day of this month');
|
|
}
|
|
|
|
if ($firstPaymentDate > $today) {
|
|
$count = 0;
|
|
} else {
|
|
$count = 1;
|
|
$nextPaymentDate = clone $firstPaymentDate;
|
|
|
|
while ($nextPaymentDate <= $today) {
|
|
$nextPaymentDate->modify('+1 month');
|
|
|
|
if ($nextPaymentDate->format('d') != $firstPaymentDate->format('d')) {
|
|
$nextPaymentDate->modify('last day of this month');
|
|
}
|
|
|
|
if ($nextPaymentDate <= $today) {
|
|
$count++;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$count = 0;
|
|
}
|
|
} else {
|
|
$count = 0; // Unknown account type
|
|
}
|
|
|
|
return min($count, $totalInstallment);
|
|
}
|
|
|
|
$conn = new mysqli($GLOBALS['host'], $GLOBALS['user'], $GLOBALS['pass'], $GLOBALS['db']);
|
|
if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); }
|
|
|
|
$agent_id = $_SESSION['user_id'];
|
|
$types = ['Loan', 'Recurring'];
|
|
$pdfData = [];
|
|
$sl = 1;
|
|
|
|
// Grand total for PDF
|
|
$grandTotal = [
|
|
'accounts' => 0,
|
|
'paidInstallments' => 0,
|
|
'dueInstallments' => 0,
|
|
'dueAmount' => 0
|
|
];
|
|
|
|
foreach($types as $type){
|
|
$typeLike = "%$type%";
|
|
if($_SESSION['type']==='admin'){
|
|
$sql = "SELECT * FROM `" . $GLOBALS['arif_ac'] . "` WHERE `AA_TYPE` LIKE ? AND (`STATUS` IS NULL OR (`STATUS`!='closed' AND `STATUS`!='matured')) ORDER BY `AA_ID` DESC";
|
|
$stmt = $conn->prepare($sql);
|
|
$stmt->bind_param("s", $typeLike);
|
|
} elseif($_SESSION['type']==='agent'){
|
|
$sql = "SELECT * FROM `" . $GLOBALS['arif_ac'] . "` WHERE `AA_TYPE` LIKE ? AND (`STATUS` IS NULL OR (`STATUS`!='closed' AND `STATUS`!='matured')) AND `AA_AGENT`=? ORDER BY `AA_ID` DESC";
|
|
$stmt = $conn->prepare($sql);
|
|
$stmt->bind_param("ss", $typeLike, $agent_id);
|
|
}
|
|
|
|
$stmt->execute();
|
|
$result = $stmt->get_result();
|
|
|
|
if($result->num_rows>0){
|
|
echo "<tr><td colspan='13' style='text-align:center; font-weight:bold; background:#f0f0f0;'>$type Demand</td></tr>";
|
|
|
|
while($row = $result->fetch_assoc()){
|
|
$totalDueAmt = $row['AA_BAL'];
|
|
|
|
|
|
if ($row['AA_INSTALLMENT'] > 0) {
|
|
$paidInst = ($row['AA_MATURE_VALUE'] + $row['AA_BAL']) / $row['AA_INSTALLMENT'];
|
|
$paidInst = number_format($paidInst, 2);
|
|
|
|
$remainInst = abs($row['AA_BAL']) / $row['AA_INSTALLMENT'];
|
|
$remainInst = number_format($remainInst, 2);
|
|
} else {
|
|
$paidInst = 0; // বা অন্য লজিক
|
|
$remainInst = 0;
|
|
}
|
|
if($row['AA_TYPE'] === 'Loan'){
|
|
$paidInstallment = ($row['AA_MATURE_VALUE'] + $row['AA_BAL']) / $row['AA_INSTALLMENT'];
|
|
$paidInstallment = number_format($paidInstallment, 2, '.', '');
|
|
|
|
$deuEMITillDate = countCycles($row['AA_ACTYPE'], $row['AA_DATE'], $row['AA_NO_OF_PAYMENT'], $row['AA_TYPE']) - $paidInstallment;
|
|
// $deuEMITillDate = abs($deuEMITillDate);
|
|
$deuEMITillDate = number_format($deuEMITillDate, 2, '.', '');
|
|
|
|
}elseif($row['AA_TYPE'] === 'Recurring'){
|
|
$paidInstallment = $row['AA_BAL'] / $row['AA_INSTALLMENT'];
|
|
$paidInstallment = number_format($paidInstallment, 2, '.', '');
|
|
|
|
$deuEMITillDate = countCycles($row['AA_ACTYPE'], $row['AA_DATE'], $row['AA_NO_OF_PAYMENT'], $row['AA_TYPE']) - $paidInstallment;
|
|
// $deuEMITillDate = abs($deuEMITillDate);
|
|
$deuEMITillDate = number_format($deuEMITillDate, 2, '.', '');
|
|
|
|
}
|
|
// HTML table row
|
|
echo "<tr>
|
|
<td>".$sl."</td>
|
|
<td>".$row['AA_ACTYPE'].", ".$row['AA_TYPE']."</td>
|
|
<td>".$row['AA_ACNO']."</td>
|
|
<td>".$row['AA_NAME']."</td>
|
|
<td>".$row['AA_PHONE']."</td>
|
|
<td>".$row['AA_DATE']."</td>
|
|
<td>".$row['AA_MATURE_VALUE']."</td>
|
|
<td>".$row['AA_BAL']."</td>
|
|
<td>".$row['AA_NO_OF_PAYMENT']."</td>
|
|
<td>".$paidInstallment."</td>
|
|
<td>".$deuEMITillDate."</td>
|
|
<td>".$row['AA_INSTALLMENT']."</td>
|
|
<td>".$totalDueAmt."</td>
|
|
|
|
</tr>";
|
|
// <td>".$remainInst."</td> <td>".$row['AA_NO_OF_PAYMENT']."</td>
|
|
// PDF simplified row
|
|
// "SL","NAME ","MOBILE NO", "CYCLE", "ACCOUNT NO","EMI PAID","EMI DUE", "EMI AMOUNT", "CUSTOMER. SIGN"
|
|
if($deuEMITillDate > 0){
|
|
$pdfData[] = [
|
|
$type,
|
|
$sl,
|
|
$row['AA_NAME'], // NAME OF ACCOUNT HOLDER
|
|
$row['AA_PHONE'], // MOBILE NO (blank)
|
|
$row['AA_ACTYPE'], // EMI Cycle
|
|
$row['AA_ACNO'], // ACCOUNT NO
|
|
$paidInstallment, // NO OF INSTALLMENT PAID
|
|
$deuEMITillDate, // NO OF INSTALLMENT DUE
|
|
$row['AA_INSTALLMENT'], // EMI AMOUNT
|
|
// $totalDueAmt, // TOTAL DUE AMOUNT
|
|
"" // CUSTOMER SIGNATURE
|
|
];
|
|
}
|
|
|
|
|
|
// Update grand total
|
|
$grandTotal['accounts']++;
|
|
$grandTotal['paidInstallments'] += $paidInstallment;
|
|
$grandTotal['dueInstallments'] += $deuEMITillDate;
|
|
$grandTotal['dueAmount'] += $totalDueAmt;
|
|
|
|
$sl++;
|
|
|
|
// echo $dueInst . '<br>';
|
|
}
|
|
}
|
|
}
|
|
$conn->close();
|
|
|
|
?>
|
|
</table>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.28/jspdf.plugin.autotable.min.js"></script>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.getElementById('downloadPdf').addEventListener('click', function() {
|
|
const { jsPDF } = window.jspdf;
|
|
const doc = new jsPDF('p', 'pt', 'a4');
|
|
|
|
const userType = "<?php echo $_SESSION['type']; ?>";
|
|
const userName = "<?php echo $_SESSION['name']; ?>";
|
|
const now = new Date();
|
|
const dateTime = now.toLocaleDateString() + " " + now.toLocaleTimeString();
|
|
const titleText = "Grafin Ventures Demand Sheet";
|
|
|
|
const pdfData = <?php echo json_encode($pdfData); ?>;
|
|
const grandTotal = <?php echo json_encode($grandTotal); ?>;
|
|
|
|
const logo = new Image();
|
|
logo.src = '/asset/images/logo.webp';
|
|
logo.onload = () => addHeader();
|
|
logo.onerror = () => addHeader();
|
|
|
|
function addHeader(){
|
|
try { doc.addImage(logo, 'PNG', 40, 30, 40, 40); } catch(e) {}
|
|
doc.setFontSize(16);
|
|
doc.text(titleText, 100, 50);
|
|
doc.setFontSize(10);
|
|
doc.text(`Generated on: ${dateTime}`, 40, 80);
|
|
doc.text(`User Type: ${userType}`, 40, 95);
|
|
doc.text(`Agen Name: ${userName}`, 40, 110);
|
|
|
|
let y = 130;
|
|
|
|
const headers = ["SL","NAME ","MOBILE NO", "CYCLE", "ACCOUNT NO","EMI PAID","EMI DUE", "EMI AMOUNT", "CUSTOMER. SIGN"];
|
|
let currentType = '';
|
|
let rows = [];
|
|
|
|
pdfData.forEach(row=>{
|
|
if(row[0] !== currentType){
|
|
if(rows.length>0){
|
|
doc.autoTable({
|
|
head:[headers],
|
|
body:rows,
|
|
startY:y,
|
|
styles:{
|
|
fontSize:7,
|
|
cellPadding:3,
|
|
lineWidth: 0.1, // border width
|
|
lineColor: [0, 0, 0] // black border color
|
|
},
|
|
headStyles:{ fillColor: false, textColor: 0 },
|
|
bodyStyles:{ valign:'middle', fillColor: false },
|
|
alternateRowStyles: { fillColor: false },
|
|
columnStyles: { 1: { cellWidth: 110 } }
|
|
});
|
|
y = doc.lastAutoTable.finalY + 10;
|
|
rows=[];
|
|
}
|
|
currentType = row[0];
|
|
doc.setFont(undefined,'bold');
|
|
doc.text(`${currentType} Demand`,40,y);
|
|
y+=15;
|
|
doc.setFont(undefined,'normal');
|
|
}
|
|
rows.push(row.slice(1));
|
|
});
|
|
|
|
if(rows.length>0){
|
|
doc.autoTable({
|
|
head:[headers],
|
|
body:rows,
|
|
startY:y,
|
|
styles:{
|
|
fontSize:7,
|
|
cellPadding:3,
|
|
lineWidth: 0.1, // border width
|
|
lineColor: [0, 0, 0] // black border color
|
|
},
|
|
headStyles:{ fillColor: false, textColor: 0 },
|
|
bodyStyles:{ valign:'middle', fillColor: false },
|
|
alternateRowStyles: { fillColor: false },
|
|
columnStyles: { 1: { cellWidth: 110 } }
|
|
});
|
|
y = doc.lastAutoTable.finalY + 20;
|
|
}
|
|
|
|
// Grand Total
|
|
doc.setFont(undefined,'bold');
|
|
doc.text(`Grand Total Accounts: ${grandTotal.accounts}`,40,y);
|
|
doc.text(`Grand Total Paid Installments: ${grandTotal.paidInstallments}`,40,y+15);
|
|
doc.text(`Grand Total Due Installments: ${grandTotal.dueInstallments}`,40,y+30);
|
|
doc.text(`Grand Total Due Amount: ${grandTotal.dueAmount.toLocaleString('en-IN',{minimumFractionDigits:2, maximumFractionDigits:2})}`,40,y+45);
|
|
|
|
// Footer with page numbers
|
|
const pageCount = doc.internal.getNumberOfPages();
|
|
for(let i=1;i<=pageCount;i++){
|
|
doc.setPage(i);
|
|
doc.setFontSize(9);
|
|
doc.setFont(undefined,'normal');
|
|
doc.text(`Generated by Loan Portal - Confidential`,40,doc.internal.pageSize.height-20);
|
|
doc.text(`Page ${i} of ${pageCount}`,doc.internal.pageSize.width-60,doc.internal.pageSize.height-20);
|
|
}
|
|
|
|
doc.save(`Demand_Sheet_${userType}_${userName}_${now.toISOString().slice(0,10)}.pdf`);
|
|
}
|
|
});
|
|
});
|
|
</script>
|