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

Download   Open   Back

<?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();
?>

PHP File Manager