File "save_bulk.php"
Full path: /home2/santhos2/public_html/bharath-coe.firstmatrix.in.net/api/internal_marks/save_bulk.php
File size: 7.75 KiB (7934 bytes)
MIME-type: text/x-php
Charset: utf-8
<?php
require_once __DIR__ . '/../../config/config.php';
header('Content-Type: application/json');
ob_start();
try {
// Get and validate input data
$raw = file_get_contents('php://input');
$payload = json_decode($raw, true);
if(!$payload){
echo json_encode(['status'=>'error','message'=>'Invalid JSON']);
exit;
}
$academic_year = trim($payload['academic_year'] ?? '');
$course_id = (int)($payload['course_id'] ?? 0);
$semester = (int)($payload['semester'] ?? 0);
$subject_id = (int)($payload['subject_id'] ?? 0);
$rows = $payload['rows'] ?? [];
if(!$academic_year || !$course_id || !$semester || !$subject_id || !is_array($rows)){
echo json_encode(['status'=>'error','message'=>'Missing params']);
exit;
}
global $pdo;
// Get CI settings for validation
$stmt = $pdo->prepare("SELECT ci1_max_marks, ci2_max_marks, ci3_max_marks, calculation_method FROM ci_assessment_settings WHERE course_id=? AND exam_type='Internal' ORDER BY setting_id DESC LIMIT 1");
$stmt->execute([$course_id]);
$ciSettings = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$ciSettings) {
$ciSettings = ['ci1_max_marks' => 10, 'ci2_max_marks' => 10, 'ci3_max_marks' => 10, 'calculation_method' => 'best2_avg'];
}
// Create CI attendance table if it doesn't exist
$pdo->exec("CREATE TABLE IF NOT EXISTS internal_ci_attendance (
id INT NOT NULL AUTO_INCREMENT,
internal_exam_id INT NOT NULL,
student_id INT NOT NULL,
attendance_pct DECIMAL(5,2) NOT NULL DEFAULT 0.00,
PRIMARY KEY (id),
UNIQUE KEY uq_ie_student (internal_exam_id, student_id),
KEY idx_ie (internal_exam_id),
KEY idx_student (student_id),
CONSTRAINT fk_ica_exam FOREIGN KEY (internal_exam_id) REFERENCES internal_exams(internal_exam_id) ON DELETE CASCADE,
CONSTRAINT fk_ica_student FOREIGN KEY (student_id) REFERENCES students(student_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
$pdo->beginTransaction();
// Get or create exam types for CI1, CI2, CI3
$examTypeIds = [];
$ciTypes = ['CI1', 'CI2', 'CI3'];
foreach($ciTypes as $index => $typeName){
$stmt = $pdo->prepare("SELECT exam_type_id FROM exam_types WHERE type_name=? LIMIT 1");
$stmt->execute([$typeName]);
$examTypeId = $stmt->fetchColumn();
if(!$examTypeId){
$stmt = $pdo->prepare("INSERT INTO exam_types (type_name, description) VALUES (?, ?)");
$stmt->execute([$typeName, 'Internal component']);
$examTypeId = (int)$pdo->lastInsertId();
}
$examTypeIds[$index + 1] = (int)$examTypeId;
}
// Get or create internal exam records for CI1, CI2, CI3
$examIds = [];
// Fix the academic year format to match what's stored in internal_exams table
// Ensure the format matches what's in internal_exams table: "2025-2026 - Even"
// If it doesn't have the dash before Even/Odd, add it
$ay_term = $academic_year;
if (preg_match('/^(\d{4}-\d{4})\s+(Even|Odd)$/', $ay_term, $matches)) {
$ay_term = $matches[1] . ' - ' . $matches[2];
}
for($i = 1; $i <= 3; $i++){
$stmt = $pdo->prepare("SELECT internal_exam_id FROM internal_exams WHERE exam_type_id=? AND subject_id=? AND academic_year=? AND semester=? LIMIT 1");
$stmt->execute([$examTypeIds[$i], $subject_id, $ay_term, $semester]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if($row){
$examIds[$i] = (int)$row['internal_exam_id'];
} else {
// Get default settings
$max_marks = 20;
$pass_marks = 10;
$stmt = $pdo->prepare("SELECT max_marks, pass_marks FROM subject_assessment_settings WHERE subject_id=? AND exam_type='Internal' ORDER BY setting_id DESC LIMIT 1");
$stmt->execute([$subject_id]);
$settings = $stmt->fetch(PDO::FETCH_ASSOC);
if($settings){
$max_marks = (int)$settings['max_marks'];
$pass_marks = (int)$settings['pass_marks'];
}
$stmt = $pdo->prepare("INSERT INTO internal_exams (exam_type_id, subject_id, academic_year, semester, max_marks, pass_marks) VALUES (?,?,?,?,?,?)");
$stmt->execute([$examTypeIds[$i], $subject_id, $ay_term, $semester, $max_marks, $pass_marks]);
$examIds[$i] = (int)$pdo->lastInsertId();
}
}
// Prepare SQL statements for saving marks and attendance
$marksSql = "INSERT INTO internal_marks (internal_exam_id, student_id, marks_obtained, attendance_status) VALUES (?,?,?,?)
ON DUPLICATE KEY UPDATE marks_obtained=VALUES(marks_obtained), attendance_status=VALUES(attendance_status)";
$marksStmt = $pdo->prepare($marksSql);
$attendanceSql = "INSERT INTO internal_ci_attendance (internal_exam_id, student_id, attendance_pct) VALUES (?,?,?)
ON DUPLICATE KEY UPDATE attendance_pct=VALUES(attendance_pct)";
$attendanceStmt = $pdo->prepare($attendanceSql);
// Process each student's marks and attendance
foreach($rows as $row){
$student_id = (int)($row['student_id'] ?? 0);
if(!$student_id) continue;
// Extract CI marks and attendance percentages
$ci1 = is_numeric($row['ci1'] ?? null) ? (float)$row['ci1'] : null;
$ci2 = is_numeric($row['ci2'] ?? null) ? (float)$row['ci2'] : null;
$ci3 = is_numeric($row['ci3'] ?? null) ? (float)$row['ci3'] : null;
$ci1_att = is_numeric($row['ci1_att'] ?? null) ? (float)$row['ci1_att'] : null;
$ci2_att = is_numeric($row['ci2_att'] ?? null) ? (float)$row['ci2_att'] : null;
$ci3_att = is_numeric($row['ci3_att'] ?? null) ? (float)$row['ci3_att'] : null;
// Validate CI marks against settings
if ($ci1 !== null && $ci1 > $ciSettings['ci1_max_marks']) {
echo json_encode(['status'=>'error','message'=>"CI1 mark ({$ci1}) exceeds maximum allowed ({$ciSettings['ci1_max_marks']})"]);
exit;
}
if ($ci2 !== null && $ci2 > $ciSettings['ci2_max_marks']) {
echo json_encode(['status'=>'error','message'=>"CI2 mark ({$ci2}) exceeds maximum allowed ({$ciSettings['ci2_max_marks']})"]);
exit;
}
if ($ci3 !== null && $ci3 > $ciSettings['ci3_max_marks']) {
echo json_encode(['status'=>'error','message'=>"CI3 mark ({$ci3}) exceeds maximum allowed ({$ciSettings['ci3_max_marks']})"]);
exit;
}
// Save CI marks
$ciMarks = [$ci1, $ci2, $ci3];
for($i = 1; $i <= 3; $i++){
if($ciMarks[$i-1] !== null){
$marksStmt->execute([$examIds[$i], $student_id, $ciMarks[$i-1], 'Present']);
}
}
// Save attendance percentages
$attendance = [$ci1_att, $ci2_att, $ci3_att];
for($i = 1; $i <= 3; $i++){
if($attendance[$i-1] !== null){
$clampedAttendance = max(0, min(100, $attendance[$i-1]));
$attendanceStmt->execute([$examIds[$i], $student_id, $clampedAttendance]);
}
}
}
// Commit transaction
if($pdo->inTransaction()) {
$pdo->commit();
}
echo json_encode(['status'=>'success','message'=>'Marks saved successfully']);
} catch (Throwable $e) {
// Rollback transaction on error
if(isset($pdo) && $pdo->inTransaction()) {
try {
$pdo->rollBack();
} catch (Throwable $e2) {
// Ignore rollback errors
}
}
error_log('save_bulk error: '.$e->getMessage());
http_response_code(500);
echo json_encode(['status'=>'error','message'=>$e->getMessage()]);
}
ob_end_flush();
?>