« Back to History
salary_slip_and_payment.php
|
20260721_154033.php
Initial Bulk Import
Copy Code
<?php /* ============================================================================ File: /erp/salary_slip_and_payment.php Purpose: Single-person salary calculate → slip PDF → payment (cash/bank) Modes: karigar (production-based) | employee (attendance/fixed-based) Functions: 1) Calculate salary 2) Download salary slip PDF (dompdf) 3) Pay Cash → records in karigar_deduction/employee_deduction + payments 4) Pay Bank → records deduction + generates Excel via loom_payment_export.php ============================================================================ */ header('X-Frame-Options: SAMEORIGIN'); error_reporting(E_ALL); ini_set('display_errors', 1); require_once __DIR__ . '/modules/auth/page_acl.php'; $ctx = page_require_access('salary_slip_and_payment'); $pdo = $ctx['pdo']; $company_id = (int)$ctx['company_id']; $u = $ctx['user']; $user_id = (int)$u['id']; /* ---- Dompdf bootstrap ---- */ $PDF_AVAILABLE = false; foreach ([__DIR__.'/lib/dompdf/autoload.inc.php', __DIR__.'/vendor/autoload.php'] as $_al) { if (is_file($_al)) { require_once $_al; if (class_exists(\Dompdf\Dompdf::class)) { $PDF_AVAILABLE = true; break; } } } /* ---- CSRF ---- */ if (session_status() !== PHP_SESSION_ACTIVE) session_start(); if (empty($_SESSION['csrf_token'])) $_SESSION['csrf_token'] = bin2hex(random_bytes(16)); /* ---- Helpers ---- */ if (!function_exists('h')) { function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } } function gv_ssp($k,$d=null){ return isset($_GET[$k]) ? trim((string)$_GET[$k]) : $d; } function pv_ssp($k,$d=null){ return isset($_POST[$k]) ? trim((string)$_POST[$k]) : $d; } function safe_json_ssp($s){ $a=json_decode($s,true); return is_array($a)?$a:[]; } function ssp_half_range(int $y, int $m, string $half): array { $first = sprintf('%04d-%02d-01', $y, $m); $last = date('Y-m-t', strtotime($first)); if ($half==='1') $last = sprintf('%04d-%02d-15', $y, $m); if ($half==='2') $first = sprintf('%04d-%02d-16', $y, $m); return [$first, $last]; } function ssp_period_label(int $y, int $m, string $half): string { $mn = date('M', mktime(0,0,0,$m,1,$y)); if ($half==='1') return "1-15 $mn $y"; if ($half==='2') return "16-End $mn $y"; return "Full $mn $y"; } function ssp_save_slip(PDO $pdo, int $cid, string $mode, int $pid, string $pmode, string $pay_date, string $pfrom, string $pto, float $net, string $remark, string $sjson, int $uid): int { $d=json_decode($sjson,true)?:[]; $pname=$d['name']??($mode.'#'.$pid); $plabel=$d['period']??''; $gross=(float)($d['gross']??0); $ded=(float)($d['deduction']??0); $adv=(float)($d['advance']??0); $pdo->prepare("INSERT INTO salary_slips (company_id,person_type,person_id,person_name,period_label,period_from,period_to,payment_mode,payment_date,gross,deduction,advance,net_amount,remark,slip_data,created_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())")->execute([$cid,$mode,$pid,$pname,$plabel,$pfrom,$pto,$pmode,$pay_date,round($gross,2),round($ded,2),round($adv,2),round($net,2),$remark,$sjson,$uid]); return (int)$pdo->lastInsertId(); } /* =================================================================== AJAX: Karigar list =================================================================== */ if (gv_ssp('ajax') === 'karigars') { $khata = (int)(gv_ssp('khata_id') ?? 0); $sql = "SELECT id, karigar_name AS name FROM loom_karigar_master WHERE company_id=? AND COALESCE(is_active,1)=1" . ($khata ? " AND khata_id=?" : "") . " ORDER BY karigar_name"; $st = $pdo->prepare($sql); $st->execute($khata ? [$company_id,$khata] : [$company_id]); header('Content-Type: application/json'); echo json_encode($st->fetchAll(PDO::FETCH_ASSOC)); exit; } /* =================================================================== AJAX: Employee list =================================================================== */ if (gv_ssp('ajax') === 'employees') { $dept = (int)(gv_ssp('dept_id') ?? 0); $sql = "SELECT id, name FROM company_employee_master WHERE company_id=? AND COALESCE(is_active,0)=1" . ($dept ? " AND department_id=?" : "") . " ORDER BY name"; $st = $pdo->prepare($sql); $st->execute($dept ? [$company_id,$dept] : [$company_id]); header('Content-Type: application/json'); echo json_encode($st->fetchAll(PDO::FETCH_ASSOC)); exit; } /* =================================================================== AJAX: Calculate karigar salary =================================================================== */ if (gv_ssp('ajax') === 'calc_karigar') { $year = (int)(gv_ssp('year') ?: date('Y')); $month = (int)(gv_ssp('month') ?: date('n')); $half = gv_ssp('half','F'); $kid = (int)(gv_ssp('karigar_id') ?? 0); if ($kid <= 0) { header('Content-Type:application/json'); echo json_encode(['error'=>'Karigar select karo']); exit; } [$from,$to] = ssp_half_range($year,$month,$half); $QUAL_RATE=[]; $QUAL_NAME=[]; $st=$pdo->prepare("SELECT quality_id,quality_name,rate FROM quality_rates WHERE company_id=?"); $st->execute([$company_id]); foreach($st as $r){ $QUAL_RATE[(int)$r['quality_id']]=(float)$r['rate']; $QUAL_NAME[(int)$r['quality_id']]=$r['quality_name']; } $st=$pdo->prepare("SELECT karigar_name,beneficiary_ac_number,ifsc_code FROM loom_karigar_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$kid]); $kar = $st->fetch(PDO::FETCH_ASSOC) ?: []; $quality_earn=[]; $total_meters=0.0; $st=$pdo->prepare("SELECT quality_id,lines_json FROM production_entry WHERE company_id=? AND entry_date BETWEEN ? AND ?"); $st->execute([$company_id,$from,$to]); foreach($st as $row){ $qid=(int)$row['quality_id']; foreach(safe_json_ssp($row['lines_json']??'') as $li){ if((int)($li['karigar_id']??0)!==$kid) continue; $m=(float)($li['meter']??0); if($m<=0) continue; $quality_earn[$qid]=($quality_earn[$qid]??0)+$m*($QUAL_RATE[$qid]??0); $total_meters+=$m; } } $gross=array_sum($quality_earn); $quality_lines=[]; foreach($quality_earn as $qid=>$earn) $quality_lines[]=['name'=>$QUAL_NAME[$qid]??'Q'.$qid,'earn'=>round($earn,2)]; $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM karigar_extra WHERE company_id=? AND karigar_id=? AND entry_date BETWEEN ? AND ?"); $st->execute([$company_id,$kid,$from,$to]); $extra=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM karigar_deduction WHERE company_id=? AND karigar_id=? AND entry_date BETWEEN ? AND ? AND (notes NOT LIKE '%| Payment Date:%')"); $st->execute([$company_id,$kid,$from,$to]); $deduction=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM karigar_advance WHERE company_id=? AND karigar_id=? AND date BETWEEN ? AND ?"); $st->execute([$company_id,$kid,$from,$to]); $advance=(float)$st->fetchColumn(); $net=$gross+$extra-$deduction-$advance; $has_bank=!empty(trim((string)($kar['beneficiary_ac_number']??'')))&&!empty(trim((string)($kar['ifsc_code']??''))); header('Content-Type: application/json'); echo json_encode(['name'=>$kar['karigar_name']??'','period'=>ssp_period_label($year,$month,$half),'from'=>$from,'to'=>$to,'quality_lines'=>$quality_lines,'gross'=>round($gross,2),'extra'=>round($extra,2),'deduction'=>round($deduction,2),'advance'=>round($advance,2),'net'=>round($net,2),'has_bank'=>$has_bank,'total_meters'=>round($total_meters,3)]); exit; } /* =================================================================== AJAX: Calculate employee salary =================================================================== */ if (gv_ssp('ajax') === 'calc_employee') { $year = (int)(gv_ssp('year') ?: date('Y')); $month = (int)(gv_ssp('month') ?: date('n')); $half = gv_ssp('half','F'); $emp_id = (int)(gv_ssp('employee_id') ?? 0); if ($emp_id <= 0) { header('Content-Type:application/json'); echo json_encode(['error'=>'Employee select karo']); exit; } $total_days=(int)date('t',mktime(0,0,0,$month,1,$year)); [$from,$to]=ssp_half_range($year,$month,$half); $st=$pdo->prepare("SELECT * FROM company_employee_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$emp_id]); $e=$st->fetch(PDO::FETCH_ASSOC) ?: []; if(!$e){ header('Content-Type:application/json'); echo json_encode(['error'=>'Employee nahi mila']); exit; } $stype=trim((string)($e['salary_type_name']??'')); $per_day=(float)($e['per_day']??0); $basic=(float)($e['basic_salary']??0); if($per_day<=0&&$basic>0) $per_day=$basic/max($total_days,1); $st=$pdo->prepare("SELECT COALESCE(SUM(total_attendance),0) FROM manual_attendance_data WHERE company_id=? AND employee_id=? AND period_start>=? AND period_end<=?"); $st->execute([$company_id,$emp_id,$from,$to]); $att_days=(float)$st->fetchColumn(); if (strcasecmp($stype,'Attendance')===0) $calc_basic=$per_day*$att_days; elseif (strcasecmp($stype,'Fixed')===0) $calc_basic=($half!=='F')?(float)($e[$half==='1'?'h1_fixed_amount':'h2_fixed_amount']??$basic):$basic; elseif (strcasecmp($stype,'Fixed Attendance')===0) $calc_basic=($att_days>0)?$per_day*$att_days:0; else $calc_basic=$basic>0?$basic:$per_day*$att_days; $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM employee_extra WHERE company_id=? AND employee_id=? AND entry_date BETWEEN ? AND ?"); $st->execute([$company_id,$emp_id,$from,$to]); $extra=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM employee_deduction WHERE company_id=? AND employee_id=? AND entry_date BETWEEN ? AND ? AND (notes NOT LIKE '%| Payment Date:%')"); $st->execute([$company_id,$emp_id,$from,$to]); $deduction=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(remaining_amount),0) FROM employee_advance WHERE company_id=? AND employee_id=? AND status='OPEN' AND `date` BETWEEN ? AND ?"); $st->execute([$company_id,$emp_id,$from,$to]); $advance=(float)$st->fetchColumn(); $gross=$calc_basic+$extra; $net=$gross-$deduction-$advance; $has_bank=!empty(trim((string)($e['account_number']??'')))&&!empty(trim((string)($e['ifsc']??''))); header('Content-Type: application/json'); echo json_encode(['name'=>$e['name']??'','designation'=>$e['designation_name']??'','department'=>$e['department_name']??'','period'=>ssp_period_label($year,$month,$half),'from'=>$from,'to'=>$to,'salary_type'=>$stype,'per_day'=>round($per_day,2),'basic_salary'=>round($basic,2),'attendance'=>round($att_days,2),'calc_basic'=>round($calc_basic,2),'extra'=>round($extra,2),'deduction'=>round($deduction,2),'advance'=>round($advance,2),'gross'=>round($gross,2),'net'=>round($net,2),'has_bank'=>$has_bank,'payment_type'=>$e['payment_type']??'CASH','account_number'=>$e['account_number']??'','ifsc'=>$e['ifsc']??'']); exit; } /* =================================================================== POST: Pay cash =================================================================== */ if ($_SERVER['REQUEST_METHOD']==='POST' && pv_ssp('action')==='pay_cash') { if (($_POST['csrf_token']??'')!==($_SESSION['csrf_token']??'')) { http_response_code(403); header('Content-Type:application/json'); echo json_encode(['error'=>'Bad CSRF']); exit; } $mode=pv_ssp('mode'); $person_id=(int)pv_ssp('person_id'); $amount=(float)pv_ssp('amount'); $pay_date=pv_ssp('pay_date')?: date('Y-m-d'); $period_from=pv_ssp('period_from')?: $pay_date; $period_to=pv_ssp('period_to')?: $pay_date; $raw_notes=pv_ssp('notes')?:'Salary payment'; $notes=$raw_notes.' | Payment Date: '.$pay_date; $slip_json=pv_ssp('slip_json')?:'{}'; if(!in_array($mode,['karigar','employee'],true)||$person_id<=0||$amount<=0){ header('Content-Type:application/json'); echo json_encode(['error'=>'Invalid input']); exit; } try{ $pdo->beginTransaction(); if($mode==='karigar'){ $st=$pdo->prepare("SELECT karigar_name FROM loom_karigar_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$person_id]); $nm=$st->fetchColumn()?:'Karigar#'.$person_id; $pdo->prepare("INSERT INTO karigar_deduction (company_id,karigar_id,karigar_name,entry_date,amount,notes,created_by,updated_at) VALUES (?,?,?,?,?,?,?,NOW())")->execute([$company_id,$person_id,$nm,$period_to,$amount,$notes,$user_id]); } else { $st=$pdo->prepare("SELECT name FROM company_employee_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$person_id]); $nm=$st->fetchColumn()?:'Employee#'.$person_id; $pdo->prepare("INSERT INTO employee_deduction (company_id,employee_id,employee_name,entry_date,amount,notes,created_by,updated_at) VALUES (?,?,?,?,?,?,?,NOW())")->execute([$company_id,$person_id,$nm,$period_to,$amount,$notes,$user_id]); } $pdo->prepare("INSERT INTO payments (company_id,person_type,person_id,payment_type,amount,payment_date,payment_mode,remark,created_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())")->execute([$company_id,$mode,$person_id,'salary',$amount,$pay_date,'CASH',$notes,$user_id]); $slip_id=ssp_save_slip($pdo,$company_id,$mode,$person_id,'CASH',$pay_date,$period_from,$period_to,$amount,$raw_notes,$slip_json,$user_id); $pdo->commit(); header('Content-Type:application/json'); echo json_encode(['success'=>true,'slip_id'=>$slip_id]); } catch(Throwable $ex){ $pdo->rollBack(); header('Content-Type:application/json'); echo json_encode(['error'=>$ex->getMessage()]); } exit; } /* =================================================================== POST: Pay bank → record deduction + auto-submit to export =================================================================== */ if ($_SERVER['REQUEST_METHOD']==='POST' && pv_ssp('action')==='pay_bank') { if (($_POST['csrf_token']??'')!==($_SESSION['csrf_token']??'')) { http_response_code(403); exit('Bad CSRF'); } $mode=pv_ssp('mode'); $person_id=(int)pv_ssp('person_id'); $amount=(float)pv_ssp('amount'); $pay_date=pv_ssp('pay_date')?:date('Y-m-d'); $period_from=pv_ssp('period_from')?: $pay_date; $period_to=pv_ssp('period_to')?: $pay_date; $raw_notes=pv_ssp('notes')?:'Salary payment (Bank)'; $notes=$raw_notes.' | Payment Date: '.$pay_date; $slip_json=pv_ssp('slip_json')?:'{}'; if(!in_array($mode,['karigar','employee'],true)||$person_id<=0||$amount<=0) { header('Content-Type:application/json'); echo json_encode(['error'=>'Invalid input']); exit; } try{ $pdo->beginTransaction(); if($mode==='karigar'){ $st=$pdo->prepare("SELECT karigar_name FROM loom_karigar_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$person_id]); $nm=$st->fetchColumn()?:'Karigar#'.$person_id; $pdo->prepare("INSERT INTO karigar_deduction (company_id,karigar_id,karigar_name,entry_date,amount,notes,created_by,updated_at) VALUES (?,?,?,?,?,?,?,NOW())")->execute([$company_id,$person_id,$nm,$period_to,$amount,$notes,$user_id]); } else { $st=$pdo->prepare("SELECT name FROM company_employee_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$person_id]); $nm=$st->fetchColumn()?:'Employee#'.$person_id; $pdo->prepare("INSERT INTO employee_deduction (company_id,employee_id,employee_name,entry_date,amount,notes,created_by,updated_at) VALUES (?,?,?,?,?,?,?,NOW())")->execute([$company_id,$person_id,$nm,$period_to,$amount,$notes,$user_id]); } $pdo->prepare("INSERT INTO payments (company_id,person_type,person_id,payment_type,amount,payment_date,payment_mode,remark,created_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())")->execute([$company_id,$mode,$person_id,'salary',$amount,$pay_date,'BANK',$notes,$user_id]); $slip_id=ssp_save_slip($pdo,$company_id,$mode,$person_id,'BANK',$pay_date,$period_from,$period_to,$amount,$raw_notes,$slip_json,$user_id); $pdo->commit(); $export_rows=json_encode([['employee_id'=>$person_id,'amount'=>round($amount,2)]],JSON_UNESCAPED_UNICODE); $export_action=($mode==='karigar')?'/erp/loom_payment_export.php':'/erp/expoeter_company_employee_master.php'; header('Content-Type:application/json'); echo json_encode(['success'=>true,'slip_id'=>$slip_id,'export_rows'=>$export_rows,'export_action'=>$export_action]); } catch(Throwable $ex){ $pdo->rollBack(); header('Content-Type:application/json'); echo json_encode(['error'=>$ex->getMessage()]); } exit; } /* =================================================================== GET: View saved salary slip =================================================================== */ if (gv_ssp('view_slip')) { $sid=(int)gv_ssp('view_slip'); if($sid<=0){ http_response_code(404); echo 'Invalid slip ID'; exit; } $st=$pdo->prepare("SELECT name FROM companies WHERE id=? LIMIT 1"); $st->execute([$company_id]); $cn_raw=$st->fetchColumn()?:'Company'; $st=$pdo->prepare("SELECT * FROM salary_slips WHERE id=? AND company_id=? LIMIT 1"); $st->execute([$sid,$company_id]); $slip=$st->fetch(PDO::FETCH_ASSOC); if(!$slip){ http_response_code(404); echo 'Slip not found'; exit; } $d=json_decode($slip['slip_data'],true)?:[]; $rows_arr=$d['rows']??[]; $remark_v=$d['remark']??''; $dept_n=$d['dept']??''; $desig_n=$d['desig']??''; $name_lbl=$d['name_label']??'Name'; $cn=h($cn_raw); $pn=h($slip['person_name']); $nl=h($name_lbl); $ph=h($slip['period_label']); $from=$slip['period_from']; $to=$slip['period_to']; $net_fmt=number_format(max(0,(float)$slip['net_amount']),2); $pay_mode=strtoupper($slip['payment_mode']); $pay_date_fmt=date('d M Y',strtotime($slip['payment_date'])); $dept_html=$dept_n?"<span><strong>Department:</strong> ".h($dept_n).($desig_n?" – ".h($desig_n):'')."</span>":''; $remark_html=$remark_v?"<div class='rem-row'><strong>Remark:</strong> ".h($remark_v)."</div>":''; /* build table rows html */ $rh=''; foreach($rows_arr as $row){ $lbl=$row[0]??''; $val=$row[1]??0; $typ=$row[2]??'info'; if($typ==='days'){ $rh.="<tr><td>".h($lbl)."</td><td class='ar' style='color:#555'>".number_format((float)$val,2)." days</td></tr>"; continue; } $cls=$typ==='ded'?'color:#c00':($typ==='earn'||$typ==='info_money'?'color:#1a7a3c':'color:#555'); $pre=$typ==='ded'?'- ':''; $rh.="<tr><td>".h($lbl)."</td><td class='ar' style='$cls'>$pre Rs.".number_format(abs((float)$val),2)."</td></tr>"; } /* reusable slip builder */ $make_slip=function(string $copy_label, bool $show_paid, string $sign_label, string $sign_line) use ($cn,$pn,$nl,$ph,$from,$to,$net_fmt,$dept_html,$rh,$remark_html,$pay_mode,$pay_date_fmt): string { $paid_html=''; if($show_paid){ $paid_html="<div class='paid-stamp'>PAID • $pay_mode • $pay_date_fmt</div>"; } return " <div class='slip'> <div class='slip-copy-label'>$copy_label</div> <div class='slip-head'><strong>$cn</strong><br><span>Salary Slip — $ph</span></div> <div class='slip-info'><span><strong>$nl:</strong> $pn</span>$dept_html<span><strong>Period:</strong> $from to $to</span></div> <table><tr><th>Description</th><th class='ar'>Amount</th></tr>$rh <tr class='net-row'><td>NET PAYABLE</td><td class='ar'>Rs. $net_fmt</td></tr> </table> $remark_html $paid_html <div class='sign-area'> <div class='sign-box'><div class='sign-line'>$sign_line</div><div class='sign-lbl'>$sign_label</div></div> </div> </div>"; }; $copy1=$make_slip('— Cashier Copy —', true, 'Employee Signature', $pn); $copy2_sign_label = ($pay_mode==='BANK') ? 'Owner Signature' : 'Reporting Manager Signature'; $copy2=$make_slip($pay_mode==='BANK'?'— Owner Copy —':'— Reporting Manager Copy —', false, $copy2_sign_label, ' '); $css="*{box-sizing:border-box;margin:0;padding:0}body{font-family:Arial,sans-serif;font-size:11.5px;background:#fff;padding:10px}@page{margin-top:38mm} .slip{border:2px solid #333;max-width:520px;margin:0 auto 0 auto;page-break-inside:avoid} .slip-copy-label{text-align:center;font-size:10px;font-weight:700;letter-spacing:1px;color:#555;padding:4px 0;background:#f5f5f5;border-bottom:1px dashed #bbb} .slip-head{text-align:center;padding:10px 16px 8px;border-bottom:2px solid #333} .slip-head strong{font-size:15px} .slip-head span{font-size:10px;color:#444} .slip-info{display:flex;flex-wrap:wrap;gap:4px;justify-content:space-between;padding:7px 16px;border-bottom:1px solid #ccc;font-size:10.5px} table{width:100%;border-collapse:collapse} table th{font-size:9.5px;text-transform:uppercase;padding:5px 16px;text-align:left;border-bottom:2px solid #333;background:#f0f0f0} table td{padding:5px 16px;border-bottom:1px solid #e8e8e8} td.ar{text-align:right;font-weight:bold} .net-row td{border-top:2px solid #333;border-bottom:none;font-size:13px;font-weight:bold;padding:8px 16px} .rem-row{padding:5px 16px;font-size:10px;color:#555;border-top:1px solid #eee} .paid-stamp{margin:6px 16px;padding:5px 10px;border:2px solid #1a7a3c;color:#1a7a3c;font-weight:700;font-size:11px;display:inline-block;border-radius:4px;letter-spacing:.5px} .sign-area{padding:10px 16px 12px;display:flex;justify-content:flex-end} .sign-box{text-align:center;min-width:160px} .sign-line{border-top:1px solid #333;padding-top:3px;min-height:28px;font-size:10.5px;color:#555} .sign-lbl{font-size:9.5px;color:#777;margin-top:2px;font-weight:600} .page-cut{border:none;border-top:2px dashed #aaa;margin:10px auto;max-width:520px} .no-print{text-align:center;padding:12px} .btn-print{padding:8px 28px;background:#1a1a2e;color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:13px} @media print{.no-print{display:none}.page-cut{border-top:2px dashed #bbb}}"; $pjs="<div class='no-print'><button class='btn-print' onclick='window.print()'>🖨 Print Both Copies</button></div><script>window.onload=function(){window.print();};<\/script>"; echo "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Salary Slip - $pn</title><style>$css</style></head><body>$copy1<hr class='page-cut'>$copy2$pjs</body></html>"; exit; } /* =================================================================== GET: Salary slip PDF / printable HTML =================================================================== */ if (gv_ssp('slip')) { $is_print=(gv_ssp('print')==='1'); $mode=gv_ssp('slip'); $year=(int)(gv_ssp('year')?:date('Y')); $month=(int)(gv_ssp('month')?:date('n')); $half=gv_ssp('half','F'); $pid=(int)(gv_ssp('pid')??0); [$from,$to]=ssp_half_range($year,$month,$half); $period=ssp_period_label($year,$month,$half); $st=$pdo->prepare("SELECT name FROM companies WHERE id=? LIMIT 1"); $st->execute([$company_id]); $company_name=$st->fetchColumn()?:'Company'; $person_name=''; $slip_rows=[]; $gross=$extra=$deduction=$advance=0.0; $dept_name=''; $desig_name=''; $name_label='Name'; $remark=gv_ssp('remark',''); if($mode==='karigar'){ $QUAL_RATE=[]; $QUAL_NAME=[]; $st=$pdo->prepare("SELECT quality_id,quality_name,rate FROM quality_rates WHERE company_id=?"); $st->execute([$company_id]); foreach($st as $r){ $QUAL_RATE[(int)$r['quality_id']]=(float)$r['rate']; $QUAL_NAME[(int)$r['quality_id']]=$r['quality_name']; } $st=$pdo->prepare("SELECT karigar_name FROM loom_karigar_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$pid]); $person_name=$st->fetchColumn()?:'Karigar'; $quality_earn=[]; $st=$pdo->prepare("SELECT quality_id,lines_json FROM production_entry WHERE company_id=? AND entry_date BETWEEN ? AND ?"); $st->execute([$company_id,$from,$to]); foreach($st as $row){ $qid=(int)$row['quality_id']; foreach(safe_json_ssp($row['lines_json']??'') as $li){ if((int)($li['karigar_id']??0)!==$pid) continue; $m=(float)($li['meter']??0); if($m<=0) continue; $quality_earn[$qid]=($quality_earn[$qid]??0)+$m*($QUAL_RATE[$qid]??0); } } foreach($quality_earn as $qid=>$earn) $slip_rows[]=[$QUAL_NAME[$qid]??'Q'.$qid,round($earn,2),'earn']; $gross=array_sum($quality_earn); $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM karigar_extra WHERE company_id=? AND karigar_id=? AND entry_date BETWEEN ? AND ?"); $st->execute([$company_id,$pid,$from,$to]); $extra=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM karigar_deduction WHERE company_id=? AND karigar_id=? AND entry_date BETWEEN ? AND ? AND (notes NOT LIKE '%| Payment Date:%')"); $st->execute([$company_id,$pid,$from,$to]); $deduction=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM karigar_advance WHERE company_id=? AND karigar_id=? AND date BETWEEN ? AND ?"); $st->execute([$company_id,$pid,$from,$to]); $advance=(float)$st->fetchColumn(); $net=$gross+$extra-$deduction-$advance; } else { $st=$pdo->prepare("SELECT * FROM company_employee_master WHERE company_id=? AND id=?"); $st->execute([$company_id,$pid]); $e=$st->fetch(PDO::FETCH_ASSOC)?:[]; $person_name=$e['name']??'Employee'; $dept_name=$e['department_name']??''; $desig_name=$e['designation_name']??''; $name_label='Employee Name'; $total_days=(int)date('t',mktime(0,0,0,$month,1,$year)); $per_day=(float)($e['per_day']??0); $basic=(float)($e['basic_salary']??0); if($per_day<=0&&$basic>0) $per_day=$basic/max($total_days,1); $stype=trim((string)($e['salary_type_name']??'')); $st=$pdo->prepare("SELECT COALESCE(SUM(total_attendance),0) FROM manual_attendance_data WHERE company_id=? AND employee_id=? AND period_start>=? AND period_end<=?"); $st->execute([$company_id,$pid,$from,$to]); $att_days=(float)$st->fetchColumn(); if(strcasecmp($stype,'Attendance')===0) $calc_basic=$per_day*$att_days; elseif(strcasecmp($stype,'Fixed')===0) $calc_basic=($half!=='F')?(float)($e[$half==='1'?'h1_fixed_amount':'h2_fixed_amount']??$basic):$basic; elseif(strcasecmp($stype,'Fixed Attendance')===0) $calc_basic=($att_days>0)?$per_day*$att_days:0; else $calc_basic=$basic>0?$basic:$per_day*$att_days; $slip_rows[]=['Basic Salary ('.$stype.')',round($calc_basic,2),'earn']; if($per_day>0) $slip_rows[]=['Per Day Rate',round($per_day,2),'info_money']; if($att_days>0) $slip_rows[]=['Attendance Days',$att_days,'days']; $gross=$calc_basic; $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM employee_extra WHERE company_id=? AND employee_id=? AND entry_date BETWEEN ? AND ?"); $st->execute([$company_id,$pid,$from,$to]); $extra=(float)$st->fetchColumn(); $gross+=$extra; $st=$pdo->prepare("SELECT COALESCE(SUM(amount),0) FROM employee_deduction WHERE company_id=? AND employee_id=? AND entry_date BETWEEN ? AND ? AND (notes NOT LIKE '%| Payment Date:%')"); $st->execute([$company_id,$pid,$from,$to]); $deduction=(float)$st->fetchColumn(); $st=$pdo->prepare("SELECT COALESCE(SUM(remaining_amount),0) FROM employee_advance WHERE company_id=? AND employee_id=? AND status='OPEN' AND `date` BETWEEN ? AND ?"); $st->execute([$company_id,$pid,$from,$to]); $advance=(float)$st->fetchColumn(); $net=$gross-$deduction-$advance; } if($extra>0) $slip_rows[]=['Extra / Bonus',round($extra,2),'earn']; if($deduction>0) $slip_rows[]=['Deduction',round($deduction,2),'ded']; if($advance>0) $slip_rows[]=['Advance',round($advance,2),'ded']; $net_fmt=number_format(max(0,$net),2); $dept_html=$dept_name ? "<span><strong>Department:</strong> ".h($dept_name).($desig_name ? " – ".h($desig_name) : '')."</span>" : ''; $remark_html=$remark ? "<div style='padding:6px 18px;font-size:11px;color:#555;border-top:1px solid #eee'><strong>Remark:</strong> ".h($remark)."</div>" : ''; $rows_html=''; foreach($slip_rows as [$label,$val,$type]){ if($type==='days'){ $rows_html.="<tr><td>".h($label)."</td><td style='text-align:right;color:#555;font-weight:bold'>".number_format((float)$val,2)." days</td></tr>"; continue; } $cls=$type==='ded'?'color:#dc3545':($type==='earn'||$type==='info_money'?'color:#198754':'color:#555'); $prefix=$type==='ded'?'- ':''; $rows_html.="<tr><td>".h($label)."</td><td style='text-align:right;$cls;font-weight:bold'>$prefix Rs.".number_format(abs((float)$val),2)."</td></tr>"; } $cn=h($company_name); $pn=h($person_name); $ph=h($period); $nl=h($name_label); if($is_print){ $slip_css="*{box-sizing:border-box;margin:0;padding:0}body{font-family:Arial,sans-serif;font-size:12px;padding:20px;background:#fff}.slip{border:2px solid #333;max-width:560px;margin:auto}.slip-head{border-bottom:2px solid #333;padding:14px 18px;text-align:center}.slip-head h2{font-size:16px;margin-bottom:2px;color:#000}.slip-head p{font-size:11px;color:#333}.slip-info{display:flex;flex-wrap:wrap;gap:6px;justify-content:space-between;padding:10px 18px;border-bottom:1px solid #ccc;font-size:11px}table{width:100%;border-collapse:collapse}table th{font-size:10px;text-transform:uppercase;padding:6px 18px;text-align:left;border-bottom:2px solid #333}table td{padding:6px 18px;border-bottom:1px solid #ddd}.net-row td{border-top:2px solid #333;border-bottom:none;font-size:14px;font-weight:bold;padding:10px 18px}.footer{text-align:center;padding:8px;font-size:9px;color:#999;border-top:1px solid #eee}@media print{.no-print{display:none}}"; $print_js="<div id='pdone' class='no-print' style='display:none;position:fixed;top:20px;left:50%;transform:translateX(-50%);background:#198754;color:#fff;padding:12px 24px;border-radius:8px;font-size:14px;z-index:9999'>✓ Slip print ho gayi! Payment aur deduction save ho chuka hai.</div><script>window.onload=function(){window.print();window.onafterprint=function(){document.getElementById('pdone').style.display='block';};};<\/script>"; $slip_html="<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Salary Slip</title><style>$slip_css</style></head><body><div class='slip'><div class='slip-head'><h2>$cn</h2><p>Salary Slip — $ph</p></div><div class='slip-info'><span><strong>$nl:</strong> $pn</span>$dept_html<span><strong>Period:</strong> $from to $to</span></div><table><tr><th>Description</th><th style='text-align:right'>Amount</th></tr>$rows_html<tr class='net-row'><td>NET PAYABLE</td><td style='text-align:right'>Rs. $net_fmt</td></tr></table>$remark_html<div class='footer'>Computer generated slip. No signature required.</div></div>$print_js</body></html>"; echo $slip_html; exit; } $slip_html="<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Salary Slip</title><style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:Arial,sans-serif;font-size:12px;padding:20px;background:#fff}.slip{border:2px solid #1a1a2e;max-width:560px;margin:auto}.slip-head{background:#1a1a2e;color:#fff;padding:14px 18px;text-align:center}.slip-head h2{font-size:16px;margin-bottom:2px}.slip-head p{font-size:11px;opacity:.85}.slip-info{display:flex;justify-content:space-between;padding:10px 18px;background:#f5f5f5;border-bottom:1px solid #ddd;font-size:11px}table{width:100%;border-collapse:collapse}table th{background:#f0f0f0;font-size:10px;text-transform:uppercase;padding:6px 18px;text-align:left;border-bottom:2px solid #1a1a2e}table td{padding:6px 18px;border-bottom:1px solid #eee}.net-row td{background:#1a1a2e;color:#fff;font-size:14px;font-weight:bold;padding:10px 18px}.footer{text-align:center;padding:8px;font-size:9px;color:#999;border-top:1px solid #eee}</style></head><body><div class='slip'><div class='slip-head'><h2>$cn</h2><p>Salary Slip — $ph</p></div><div class='slip-info'><span><strong>$nl:</strong> $pn</span>$dept_html<span><strong>Period:</strong> $from to $to</span></div><table><tr><th>Description</th><th style='text-align:right'>Amount</th></tr>$rows_html<tr class='net-row'><td>NET PAYABLE</td><td style='text-align:right'>Rs. $net_fmt</td></tr></table>$remark_html<div class='footer'>Computer generated slip. No signature required.</div></div></body></html>"; if($PDF_AVAILABLE){ $dompdf=new \Dompdf\Dompdf(['isHtml5ParserEnabled'=>true,'isPhpEnabled'=>false]); $dompdf->loadHtml($slip_html,'UTF-8'); $dompdf->setPaper('A5','portrait'); $dompdf->render(); $fname=preg_replace('/[^a-z0-9_\-]/i','_',"salary_slip_{$person_name}_{$period}").'.pdf'; $dompdf->stream($fname,['Attachment'=>true]); } else { echo $slip_html; } exit; } /* =================================================================== MAIN PAGE =================================================================== */ $khatas_st=$pdo->prepare("SELECT id,code FROM khatas WHERE company_id=? AND is_active=1 ORDER BY code"); $khatas_st->execute([$company_id]); $khatas_list=$khatas_st->fetchAll(PDO::FETCH_ASSOC); $depts_st=$pdo->prepare("SELECT id,name FROM company_departments WHERE company_id=? ORDER BY name"); $depts_st->execute([$company_id]); $depts_list=$depts_st->fetchAll(PDO::FETCH_ASSOC); require_once __DIR__ . '/partials/header.php'; $year_now=(int)date('Y'); $month_now=(int)date('n'); ?> <style> .ssp-card { border:none; border-radius:10px; box-shadow:0 2px 14px rgba(0,0,0,.09); } .ssp-tab-btn { border:none; background:none; padding:10px 22px; font-weight:600; color:#777; border-bottom:3px solid transparent; cursor:pointer; transition:.2s; font-size:14px; } .ssp-tab-btn.active { color:#1a1a2e; border-bottom-color:#1a1a2e; } .ssp-panel { display:none; } .ssp-panel.active { display:block; } .salary-box { background:#f8f9fc; border-radius:8px; border:1px solid #dee2e6; padding:18px; } .sal-row { display:flex; justify-content:space-between; padding:6px 0; border-bottom:1px solid #eee; font-size:13px; } .sal-row:last-child { border:none; } .sal-row.net { font-weight:700; font-size:16px; padding-top:10px; margin-top:4px; border-top:2px solid #1a1a2e; border-bottom:none; } .earn { color:#198754; } .ded { color:#dc3545; } .info-badge { font-size:11px; background:#e9ecef; border-radius:4px; padding:2px 7px; color:#555; } #karigar-result, #employee-result { display:none; margin-top:4px; } </style> <div class="container-fluid py-4"> <div class="ssp-card card p-0"> <div class="d-flex border-bottom px-3 pt-2 gap-1 align-items-center"> <button class="ssp-tab-btn active" id="tab-karigar" onclick="switchTab('karigar')"> 🧧 Karigar </button> <button class="ssp-tab-btn" id="tab-employee" onclick="switchTab('employee')"> 👥 Employee </button> <small class="text-muted ms-auto pe-3">Salary Calculate → Slip → Payment</small> </div> <div class="p-4"> <!-- ===== KARIGAR PANEL ===== --> <div class="ssp-panel active" id="panel-karigar"> <div class="row g-3 align-items-end mb-3"> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Year</label> <select id="k-year" class="form-select form-select-sm"> <?php for($y=$year_now;$y>=$year_now-3;$y--): ?> <option value="<?= $y ?>" <?= $y===$year_now?'selected':'' ?>><?= $y ?></option> <?php endfor; ?> </select> </div> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Month</label> <select id="k-month" class="form-select form-select-sm"> <?php for($m=1;$m<=12;$m++): ?> <option value="<?= $m ?>" <?= $m===$month_now?'selected':'' ?>><?= date('F',mktime(0,0,0,$m,1)) ?></option> <?php endfor; ?> </select> </div> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Period</label> <select id="k-half" class="form-select form-select-sm"> <option value="F">Full Month</option> <option value="1">1 – 15</option> <option value="2">16 – End</option> </select> </div> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Khata</label> <select id="k-khata" class="form-select form-select-sm" onchange="loadKarigars()"> <option value="">All Khatas</option> <?php foreach($khatas_list as $k): ?> <option value="<?= (int)$k['id'] ?>"><?= h($k['code']) ?></option> <?php endforeach; ?> </select> </div> <div class="col-md-3"> <label class="form-label small fw-bold mb-1">Karigar</label> <select id="k-karigar" class="form-select form-select-sm"> <option value="">-- Select Karigar --</option> </select> </div> <div class="col-md-1"> <button class="btn btn-dark btn-sm w-100" onclick="calcKarigar()" title="Calculate"> 🔢 Calc </button> </div> </div> <div id="karigar-result"> <div class="row g-3"> <div class="col-md-5"> <div class="salary-box"> <div class="d-flex justify-content-between align-items-start mb-3"> <div> <div class="fw-bold fs-6" id="k-name">—</div> <small class="text-muted" id="k-period-lbl">—</small> </div> <span class="info-badge" id="k-meters">—</span> </div> <div id="k-quality-rows"></div> <div class="sal-row"><span>Gross Earning</span><span class="earn fw-bold" id="k-gross">₹0</span></div> <div class="sal-row" id="k-extra-row" style="display:none"><span>Extra</span><span class="earn" id="k-extra">₹0</span></div> <div class="sal-row" id="k-ded-row" style="display:none"><span>Deduction</span><span class="ded" id="k-ded">₹0</span></div> <div class="sal-row" id="k-adv-row" style="display:none"><span>Advance</span><span class="ded" id="k-adv">₹0</span></div> <div class="sal-row net"><span>Net Payable</span><span id="k-net">₹0</span></div> </div> </div> <div class="col-md-7"> <div class="row g-2 mb-3"> <div class="col-md-5"> <label class="form-label small fw-bold mb-1">Payment Date</label> <input type="date" id="k-pay-date" class="form-control form-control-sm" value="<?= date('Y-m-d') ?>"> </div> <div class="col-md-7"> <label class="form-label small fw-bold mb-1">Remark</label> <input type="text" id="k-notes" class="form-control form-control-sm" placeholder="Salary payment"> </div> </div> <div class="d-flex gap-2 flex-wrap"> <button class="btn btn-success btn-sm" onclick="payCash('karigar')">💵 Pay Cash</button> <button class="btn btn-primary btn-sm" id="k-bank-btn" style="display:none" onclick="payBank('karigar')">🏭 Pay Bank (Excel)</button> <button class="btn btn-outline-dark btn-sm" id="k-print-btn" style="display:none" onclick="printSlip('karigar')">🖨 Print Slip</button> </div> <div id="k-msg" class="mt-3"></div> </div> </div> </div> </div> <!-- ===== EMPLOYEE PANEL ===== --> <div class="ssp-panel" id="panel-employee"> <div class="row g-3 align-items-end mb-3"> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Year</label> <select id="e-year" class="form-select form-select-sm"> <?php for($y=$year_now;$y>=$year_now-3;$y--): ?> <option value="<?= $y ?>" <?= $y===$year_now?'selected':'' ?>><?= $y ?></option> <?php endfor; ?> </select> </div> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Month</label> <select id="e-month" class="form-select form-select-sm"> <?php for($m=1;$m<=12;$m++): ?> <option value="<?= $m ?>" <?= $m===$month_now?'selected':'' ?>><?= date('F',mktime(0,0,0,$m,1)) ?></option> <?php endfor; ?> </select> </div> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Period</label> <select id="e-half" class="form-select form-select-sm"> <option value="F">Full Month</option> <option value="1">H1 (1–15)</option> <option value="2">H2 (16–End)</option> </select> </div> <div class="col-6 col-md-2"> <label class="form-label small fw-bold mb-1">Department</label> <select id="e-dept" class="form-select form-select-sm" onchange="loadEmployees()"> <option value="">All Depts</option> <?php foreach($depts_list as $d): ?> <option value="<?= (int)$d['id'] ?>"><?= h($d['name']) ?></option> <?php endforeach; ?> </select> </div> <div class="col-md-3"> <label class="form-label small fw-bold mb-1">Employee</label> <select id="e-emp" class="form-select form-select-sm"> <option value="">-- Select Employee --</option> </select> </div> <div class="col-md-1"> <button class="btn btn-dark btn-sm w-100" onclick="calcEmployee()" title="Calculate"> 🔢 Calc </button> </div> </div> <div id="employee-result"> <div class="row g-3"> <div class="col-md-5"> <div class="salary-box"> <div class="d-flex justify-content-between align-items-start mb-3"> <div> <div class="fw-bold fs-6" id="e-name">—</div> <small class="text-muted" id="e-desig">—</small> <br><small class="text-muted" id="e-period-lbl">—</small> </div> <span class="info-badge" id="e-att">—</span> </div> <div class="sal-row"> <span>Basic <span class="info-badge" id="e-stype"></span></span> <span class="earn" id="e-basic">₹0</span> </div> <div class="sal-row" id="e-extra-row" style="display:none"><span>Extra</span><span class="earn" id="e-extra">₹0</span></div> <div class="sal-row"><span class="fw-semibold">Gross</span><span class="earn fw-bold" id="e-gross">₹0</span></div> <div class="sal-row" id="e-ded-row" style="display:none"><span>Deduction</span><span class="ded" id="e-ded">₹0</span></div> <div class="sal-row" id="e-adv-row" style="display:none"><span>Advance</span><span class="ded" id="e-adv">₹0</span></div> <div class="sal-row net"><span>Net Payable</span><span id="e-net">₹0</span></div> </div> </div> <div class="col-md-7"> <div class="row g-2 mb-3"> <div class="col-md-5"> <label class="form-label small fw-bold mb-1">Payment Date</label> <input type="date" id="e-pay-date" class="form-control form-control-sm" value="<?= date('Y-m-d') ?>"> </div> <div class="col-md-7"> <label class="form-label small fw-bold mb-1">Remark</label> <input type="text" id="e-notes" class="form-control form-control-sm" placeholder="Salary payment"> </div> </div> <div class="d-flex gap-2 flex-wrap"> <button class="btn btn-success btn-sm" onclick="payCash('employee')">💵 Pay Cash</button> <button class="btn btn-primary btn-sm" id="e-bank-btn" style="display:none" onclick="payBank('employee')">🏭 Pay Bank (Excel)</button> <button class="btn btn-outline-dark btn-sm" id="e-print-btn" style="display:none" onclick="printSlip('employee')">🖨 Print Slip</button> </div> <div id="e-msg" class="mt-3"></div> </div> </div> </div> </div> </div><!-- /p-4 --> </div><!-- /ssp-card --> </div> <form id="bankExportForm" method="post" action="" target="_blank" style="display:none"> <input type="hidden" name="csrf_token" value="<?= h($_SESSION['csrf_token']) ?>"> <input type="hidden" name="salary_rows" id="bef-rows"> </form> <script> const CSRF = <?= json_encode($_SESSION['csrf_token']) ?>; let kS={}, eS={}, kPaid=false, ePaid=false; function buildSlipData(mode,s,remark){ const rows=[]; if(mode==='karigar'){ (s.quality_lines||[]).forEach(q=>rows.push([q.name,q.earn,'earn'])); if((s.extra||0)>0) rows.push(['Extra / Bonus',s.extra,'earn']); if((s.deduction||0)>0) rows.push(['Deduction',s.deduction,'ded']); if((s.advance||0)>0) rows.push(['Advance',s.advance,'ded']); return JSON.stringify({name:s.name,period:s.period,from:s.from,to:s.to,dept:'',desig:'',name_label:'Name',gross:s.gross,deduction:s.deduction||0,advance:s.advance||0,net:s.net,rows,remark}); } else { rows.push(['Basic Salary ('+(s.salary_type||'')+')',s.calc_basic,'earn']); if((s.per_day||0)>0) rows.push(['Per Day Rate',s.per_day,'info_money']); if((s.attendance||0)>0) rows.push(['Attendance Days',s.attendance,'days']); if((s.extra||0)>0) rows.push(['Extra / Bonus',s.extra,'earn']); if((s.deduction||0)>0) rows.push(['Deduction',s.deduction,'ded']); if((s.advance||0)>0) rows.push(['Advance',s.advance,'ded']); return JSON.stringify({name:s.name,period:s.period,from:s.from,to:s.to,dept:s.department||'',desig:s.designation||'',name_label:'Employee Name',gross:s.gross,deduction:s.deduction||0,advance:s.advance||0,net:s.net,rows,remark}); } } function switchTab(t){ document.querySelectorAll('.ssp-tab-btn').forEach(b=>b.classList.remove('active')); document.querySelectorAll('.ssp-panel').forEach(p=>p.classList.remove('active')); document.getElementById('tab-'+t).classList.add('active'); document.getElementById('panel-'+t).classList.add('active'); } function rs(n){ return '₹'+parseFloat(n).toLocaleString('en-IN',{minimumFractionDigits:2,maximumFractionDigits:2}); } function showRow(id, cond){ document.getElementById(id).style.display = cond ? '' : 'none'; } function loadKarigars(){ fetch('?ajax=karigars&khata_id='+document.getElementById('k-khata').value) .then(r=>r.json()).then(data=>{ const s=document.getElementById('k-karigar'); s.innerHTML='<option value="">-- Select Karigar --</option>'; data.forEach(k=>s.insertAdjacentHTML('beforeend',`<option value="${k.id}">${k.name}</option>`)); }); } function loadEmployees(){ fetch('?ajax=employees&dept_id='+document.getElementById('e-dept').value) .then(r=>r.json()).then(data=>{ const s=document.getElementById('e-emp'); s.innerHTML='<option value="">-- Select Employee --</option>'; data.forEach(e=>s.insertAdjacentHTML('beforeend',`<option value="${e.id}">${e.name}</option>`)); }); } function calcKarigar(){ const kid=document.getElementById('k-karigar').value; if(!kid){alert('Karigar select karo');return;} const y=document.getElementById('k-year').value, m=document.getElementById('k-month').value, h=document.getElementById('k-half').value; fetch(`?ajax=calc_karigar&karigar_id=${kid}&year=${y}&month=${m}&half=${h}`) .then(r=>r.json()).then(d=>{ if(d.error){alert(d.error);return;} kS=d; kS.kid=kid; kS.year=y; kS.month=m; kS.half=h; document.getElementById('karigar-result').style.display='block'; document.getElementById('k-name').textContent=d.name; document.getElementById('k-period-lbl').textContent=d.period+' ('+d.from+' to '+d.to+')'; document.getElementById('k-meters').textContent=d.total_meters+' mtr'; let qh=''; (d.quality_lines||[]).forEach(q=>{ qh+=`<div class="sal-row"><span>${q.name}</span><span class="earn">${rs(q.earn)}</span></div>`; }); document.getElementById('k-quality-rows').innerHTML=qh; document.getElementById('k-gross').textContent=rs(d.gross); showRow('k-extra-row',d.extra>0); document.getElementById('k-extra').textContent=rs(d.extra); showRow('k-ded-row',d.deduction>0); document.getElementById('k-ded').textContent=rs(d.deduction); showRow('k-adv-row',d.advance>0); document.getElementById('k-adv').textContent=rs(d.advance); document.getElementById('k-net').textContent=rs(Math.max(0,d.net)); showRow('k-bank-btn',d.has_bank); document.getElementById('k-msg').innerHTML=''; }).catch(e=>alert('Error: '+e)); } function calcEmployee(){ const eid=document.getElementById('e-emp').value; if(!eid){alert('Employee select karo');return;} const y=document.getElementById('e-year').value, m=document.getElementById('e-month').value, h=document.getElementById('e-half').value; fetch(`?ajax=calc_employee&employee_id=${eid}&year=${y}&month=${m}&half=${h}`) .then(r=>r.json()).then(d=>{ if(d.error){alert(d.error);return;} eS=d; eS.eid=eid; eS.year=y; eS.month=m; eS.half=h; document.getElementById('employee-result').style.display='block'; document.getElementById('e-name').textContent=d.name; document.getElementById('e-desig').textContent=[d.designation,d.department].filter(Boolean).join(' · '); document.getElementById('e-period-lbl').textContent=d.period+' ('+d.from+' to '+d.to+')'; document.getElementById('e-att').textContent=d.attendance+' days'; document.getElementById('e-stype').textContent=d.salary_type; document.getElementById('e-basic').textContent=rs(d.calc_basic); showRow('e-extra-row',d.extra>0); document.getElementById('e-extra').textContent=rs(d.extra); document.getElementById('e-gross').textContent=rs(d.gross); showRow('e-ded-row',d.deduction>0); document.getElementById('e-ded').textContent=rs(d.deduction); showRow('e-adv-row',d.advance>0); document.getElementById('e-adv').textContent=rs(d.advance); document.getElementById('e-net').textContent=rs(Math.max(0,d.net)); showRow('e-bank-btn',d.has_bank); document.getElementById('e-msg').innerHTML=''; }).catch(e=>alert('Error: '+e)); } function printSlip(mode){ const paid=mode==='karigar'?kPaid:ePaid; if(!paid){alert('Pehle payment karo (Pay Cash ya Pay Bank).\n\nPayment complete hone ke baad hi Print Slip button kaam karega.');return;} const s=mode==='karigar'?kS:eS; if(s.slipId){ window.open('?view_slip='+s.slipId,'_blank'); return; } // fallback: re-generate on-the-fly (should not normally reach here) const pid=mode==='karigar'?s.kid:s.eid; const remark=document.getElementById(mode==='karigar'?'k-notes':'e-notes').value||''; window.open(`?slip=${mode}&pid=${pid}&year=${s.year}&month=${s.month}&half=${s.half}&remark=${encodeURIComponent(remark)}&print=1`,'_blank'); } function payCash(mode){ const s=mode==='karigar'?kS:eS; if(!s.hasOwnProperty('net')){alert('Pehle calculate karo');return;} const net=Math.max(0,s.net); if(net<=0){alert('Net payable 0 hai, payment nahi hogi');return;} if(!confirm(`${s.name} ko ${rs(net)} CASH payment karein?\n\nDeduction table me bhi add hoga.`)) return; const pid=mode==='karigar'?s.kid:s.eid; const pd=document.getElementById(mode==='karigar'?'k-pay-date':'e-pay-date').value; const notes=document.getElementById(mode==='karigar'?'k-notes':'e-notes').value||'Salary payment'; const msgEl=document.getElementById(mode==='karigar'?'k-msg':'e-msg'); msgEl.innerHTML='<div class="text-muted small">Processing...</div>'; const fd=new FormData(); fd.append('csrf_token',CSRF); fd.append('action','pay_cash'); fd.append('mode',mode); fd.append('person_id',pid); fd.append('amount',net); fd.append('pay_date',pd); fd.append('notes',notes); fd.append('period_to',s.to||pd); fd.append('period_from',s.from||pd); fd.append('slip_json',buildSlipData(mode,s,notes)); fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{ if(d.success){ if(mode==='karigar'){kPaid=true;kS.slipId=d.slip_id;}else{ePaid=true;eS.slipId=d.slip_id;} document.getElementById(mode==='karigar'?'k-print-btn':'e-print-btn').style.display=''; msgEl.innerHTML='<div class="alert alert-success py-2"><strong>✓ Done!</strong> Cash payment recorded. Deduction me add ho gaya. <strong>Ab Print Slip kar sakte hain.</strong></div>'; } else msgEl.innerHTML='<div class="alert alert-danger py-2">Error: '+d.error+'</div>'; }); } function payBank(mode){ const s=mode==='karigar'?kS:eS; if(!s.hasOwnProperty('net')){alert('Pehle calculate karo');return;} const net=Math.max(0,s.net); if(net<=0){alert('Net payable 0 hai');return;} if(!confirm(`${s.name} ko ${rs(net)} BANK payment karein?\n\nDeduction record hoga aur Excel file download hogi.`)) return; const pid=mode==='karigar'?s.kid:s.eid; const pd=document.getElementById(mode==='karigar'?'k-pay-date':'e-pay-date').value; const notes=document.getElementById(mode==='karigar'?'k-notes':'e-notes').value||'Salary payment'; const msgEl=document.getElementById(mode==='karigar'?'k-msg':'e-msg'); msgEl.innerHTML='<div class="text-muted small">Processing...</div>'; const fd=new FormData(); fd.append('csrf_token',CSRF); fd.append('action','pay_bank'); fd.append('mode',mode); fd.append('person_id',pid); fd.append('amount',net); fd.append('pay_date',pd); fd.append('notes',notes); fd.append('period_to',s.to||pd); fd.append('period_from',s.from||pd); fd.append('slip_json',buildSlipData(mode,s,notes)); fetch('',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{ if(d.success){ if(mode==='karigar'){kPaid=true;kS.slipId=d.slip_id;}else{ePaid=true;eS.slipId=d.slip_id;} document.getElementById(mode==='karigar'?'k-print-btn':'e-print-btn').style.display=''; msgEl.innerHTML='<div class="alert alert-success py-2"><strong>✓ Done!</strong> Bank payment recorded. Deduction me add ho gaya. <strong>Ab Print Slip kar sakte hain.</strong> Excel bhi download ho rahi hai.</div>'; const ef=document.getElementById('bankExportForm'); ef.action=d.export_action; document.getElementById('bef-rows').value=d.export_rows; ef.submit(); } else { msgEl.innerHTML='<div class="alert alert-danger py-2">Error: '+d.error+'</div>'; } }).catch(e=>{ msgEl.innerHTML='<div class="alert alert-danger py-2">Network error: '+e+'</div>'; }); } loadKarigars(); loadEmployees(); </script> <?php require_once __DIR__ . '/partials/footer.php'; ?>