Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 809
ModerationRuleService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 18
10712.00
0.00% covered (danger)
0.00%
0 / 809
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 4
 saveModerationRule
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 35
 validateSaveModerationRule
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 4
 insertModeration
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 updateModerationRule
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 17
 deleteModerationRule
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 26
 getAllModerationRules
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 17
 getBatchModerationEntryCheck
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 20
 getModerationRules
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 51
 assignAndUnAssignBatches
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 20
 unAssignBatchesForModeration
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 assignBatchesForModeration
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 21
 getPreviewTemplateForApplyModeration
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 75
 getStudentModerationDetails
0.00% covered (danger)
0.00%
0 / 1
1482.00
0.00% covered (danger)
0.00%
0 / 152
 getAllFailedStudentsDetails
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 126
 getActiveBatchesForAssignModerationRule
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 53
 applyModerationMarkByRule
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 35
 getModerationAppliedPassedStudents
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 123
<?php
namespace com\linways\ec\core\service;
use com\linways\base\util\MakeSingletonTrait;
use com\linways\base\util\SecurityUtils;
use com\linways\ec\core\constant\StatusConstants;
use com\linways\ec\core\exception\ExamControllerException;
use com\linways\ec\core\mapper\ModerationRuleServiceMapper;
use com\linways\ec\core\dto\ModerationRule;
use com\linways\ec\core\logging\Events;
use com\linways\ec\core\logging\entities\Staff;
use com\linways\core\ams\professional\logging\AMSLogger;
use com\linways\base\util\TwigRenderer;
use com\linways\core\ams\professional\util\PdfUtil;
use com\linways\oe\core\service\ExamUserMarkService;
use com\linways\ec\core\service\StudentsOverAllMarkReportService;
use com\linways\ec\core\service\GradeSchemeService;
use com\linways\ec\core\service\CommonExamService;
use com\linways\ec\core\service\MarksCardService;
use com\linways\ec\core\request\SearchRuleRequest;
use com\linways\ec\core\service\RuleService;
class ModerationRuleService extends BaseService
{
    use MakeSingletonTrait;
    private function __construct()
    {
        $this->logger = AMSLogger::getLogger('exam-controller-log');
        $this->mapper = ModerationRuleServiceMapper::getInstance()->getMapper();
    }
    /**
     * Save Moderation Rule
     * @param ModerationRule $moderationRule
     * @return $id
     */
    public function saveModerationRule(ModerationRule $moderationRule)
    {
        $moderationRule = $this->realEscapeObject($moderationRule);
        $moderationRule->createdBy = $GLOBALS['userId'] ?? $moderationRule->createdBy;
        $moderationRule->updatedBy = $GLOBALS['userId'] ?? $moderationRule->updatedBy;
        $staffId = $GLOBALS['userId'];
        try {
            $this->validateSaveModerationRule($moderationRule);
            if (!empty($moderationRule->id)) {
                $moderationRule->id = $this->updateModerationRule($moderationRule);
            } else {
                $moderationRule->id = $this->insertModeration($moderationRule);
            }
            AMSLogger::log_info($this->logger,Events::EC_SAVE_MODERATION_RULE, [
                "staff" => new Staff(["id" => $staffId]),
                "request" => $moderationRule,
                "status" => StatusConstants::SUCCESS
            ]);
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::EC_SAVE_MODERATION_RULE, [
                "staff" => new Staff(["id" => $staffId]),
                "request" => $moderationRule,
                "errorCode" => $e->getCode(),
                "errorMessage" => $e->getMessage(),
                "status" => StatusConstants::FAILED
            ]);
            if ($e->getCode() !== ExamControllerException::INVALID_PARAMETERS && $e->getCode() !== ExamControllerException::EMPTY_PARAMETERS && $e->getCode() !== "DUPLICATE_ENTRY") {
                throw new ExamControllerException($e->getCode(), "Failed to save Exam Registration! Please try again");
            } else if ($e->getCode() === ExamControllerException::DUPLICATE_ENTRY) {
                throw new ExamControllerException(ExamControllerException::DUPLICATE_ENTRY_MODERATION_RULE, "Cannot create moderation rule.This rule already created");
            } else {
                throw new ExamControllerException($e->getCode(), $e->getMessage());
            }
        }
        return $moderationRule->id;
    }
    /**
     * Validate Moderation Rule Request Before Saving
     * @param ModerationRule $moderationRule
     * @return NULL
     */
    private function validateSaveModerationRule(ModerationRule $moderationRule)
    {
        if (empty($moderationRule->name))
            throw new ExamControllerException(ExamControllerException::EMPTY_PARAMETERS, " Moderation name is  empty! Please fill name ");
    }
    /**
     * Insert Moderation Rule
     * @param ModerationRule $moderationRule
     * @return  $id
     */
    private function insertModeration(ModerationRule $moderationRule)
    {
        $properties = !empty($moderationRule->properties) ? "'" . json_encode($moderationRule->properties) . "'" : "NULL";
        $id = SecurityUtils::getRandomString();
        $query = "INSERT INTO ec_moderation_rule
                  (id,name,properties,created_by,updated_by)
                  VALUES
                  ('$id','$moderationRule->name',$properties,'$moderationRule->createdBy','$moderationRule->updatedBy')";
        try {
            $this->executeQuery($query);
            $moderationRule->id = $id;
            return $moderationRule->id;
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Update Moderation Rule
     * @param ModerationRule $moderationRule
     * @return String $moderationRule->id
     */
    private function updateModerationRule(ModerationRule $moderationRule)
    {
        $properties = !empty($moderationRule->properties) ? "'" . json_encode($moderationRule->properties) . "'" : "NULL";
        $query = "UPDATE
                    ec_moderation_rule
                SET
                    name = '$moderationRule->name',
                    properties = $properties,
                    updated_by = '$moderationRule->updatedBy'
                WHERE
                    id = '$moderationRule->id'";
        try {
            $this->executeQuery($query);
            return $moderationRule->id;
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
    }
     /**
     * Delete Moderation Rule 
     * @param String $id
     * @return NULL
     */
    public function deleteModerationRule($id){
        $id = $this->realEscapeString($id);
        $staffId = $GLOBALS['userId'];
        $moderationRule = new \stdClass();
        $moderationRule->id = $id;
        $currentModerationDetails = reset($this->getModerationRules($moderationRule));
        if(empty($currentModerationDetails)){
            throw new ExamControllerException(ExamControllerException::EMPTY_PARAMETERS,"Can't delete ! Moderation rule missing.");
        }
        if(count($currentModerationDetails->batches) > 0){
            throw new ExamControllerException(ExamControllerException::HAVE_RELATION,"Can't delete moderation rule! Batch(s) already assigned.");
        }
        $query = "DELETE FROM
                    ec_moderation_rule
                WHERE
                    id = '$id'";
        try {
            $this->executeQuery($query);
             // LOGGING
            AMSLogger::log_info($this->logger,Events::EC_DELETE_MODERATION_RULE,[
                "staff" => new Staff(["id" => $staffId]),
                "request" => $currentModerationDetails,
                "status" => StatusConstants::SUCCESS
            ]);
        }catch (\Exception $e) {
            throw new ExamControllerException(ExamControllerException::HAVE_RELATION,"Error deleting mderation rule! Please try again");
        }
    }
    /**
     * get All moderation Rule 
     * @param $searchRequest
     * @return $moderationRules
     */
    public function getAllModerationRules($searchRequest){
        try {
            $moderationRules = $this->getModerationRules($searchRequest);
            foreach($moderationRules as $moderationRule){
                foreach($moderationRule->batches as $batch){
                    $batch->name = $batch->groupName.'-'.$batch->academicTermName;
                    $request = new \stdClass;
                    $request->examRegistrationBatchId = $batch->id;
                    $entryCheck = $this->getBatchModerationEntryCheck($request);
                    $batch->isDisableEdit = $entryCheck ? true : false;
                    $moderationRule->isDisableEdit = $moderationRule->isDisableEdit ? $moderationRule->isDisableEdit : $batch->isDisableEdit;
                }
            }
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
        return $moderationRules;
    }
    /**
     * get Batch Moderation Entry Check
     * @params examRegistrationId
     * @return studentList
     */
    public function getBatchModerationEntryCheck($request){
        $request = $this->realEscapeObject($request);
        $limitQuerry = "Limit 1";
        $whereQuery = '';
        $query = " SELECT 
            ostm.student_id as studentId,
            ostm.am_assessment_id as assessmentId
        FROM
            ec_exam_registration_batch eerb
        INNER JOIN ec_exam_registration_subject eers ON
            eers.ec_exam_registration_batch_id = eerb.id 
        INNER JOIN oe_student_total_mark ostm ON
            ostm.am_assessment_id = eers.am_assessment_id AND ostm.valuation_type = 'MODERATION'
        WHERE eerb.id = '$request->examRegistrationBatchId'";
        try {
            $studentList = $this->executeQueryForList($query. $whereQuery.$limitQuerry);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        return $studentList;
    }
    /**
     * get Moderation Rules 
     * @param $searchRequest
     * @return $moderationRules
     */
    public function getModerationRules($searchRequest)
    {
        $searchRequest = $this->realEscapeObject($searchRequest);
        try {
            $whereQuery = null;
            $orderBy = " ORDER BY mr.created_date ASC ";
            $whereQuery = "";
            if (!empty($searchRequest->id)) {
                $moderationIdString = is_array($searchRequest->id) ? "'" . implode("','", $searchRequest->id) . "'" : "'" . $searchRequest->id . "'";
                $whereQuery .= " AND mr.id IN ( $moderationIdString )";
            }
            $query = "SELECT
                            DISTINCT mr.id AS id,
                            mr.name AS ruleName,
                            mr.properties AS ruleProperties,
                            eerb.id AS examRegistrationBatchId,
                            g.id AS groupsId,
                            g.name AS groupName,
                            eerb.properties AS batchProperties,
                            eer.name AS examRegistrationName,
                            eer.properties AS examRegistrationProperties,
                            act.id AS academicTermId,
                            act.name AS academicTermName,
                            eers.am_assessment_id AS assessmentId,
                            eers.properties->>'$.moderationMark' AS moderationMark,
                            aps.properties->>'$.classType' AS subjectPropertyType,
                            s.code AS subjectCode,
                            s.name AS subjectName
                        FROM
                            ec_moderation_rule mr
                        LEFT JOIN ec_exam_registration_subject eers ON
                            eers.properties->>'$.moderationRuleId' = mr.id
                        LEFT JOIN ec_exam_registration_batch eerb ON 
                            eerb.id = eers.ec_exam_registration_batch_id
                        LEFT JOIN `groups` g ON
                            g.id = eerb.groups_id
                        LEFT JOIN ec_exam_registration eer ON
                            eer.id = eerb.ec_exam_registration_id
                        LEFT JOIN academic_term act ON
                            act.id = CAST(eerb.properties ->> '$.academicTermId'AS CHAR) 
                        LEFT JOIN  cm_academic_paper_subjects aps ON 
                            aps.id = eers.cm_academic_paper_subjects_id
                        LEFT JOIN v4_ams_subject s ON 
                            s.id = aps.ams_subject_id
                        WHERE
                            1 = 1 ";
            $moderationRules =  $this->executeQueryForList($query . $whereQuery . $orderBy, $this->mapper[ModerationRuleServiceMapper::GET_MODERATION_RULE]);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
        return $moderationRules;
    }
    /**
     * Assign / Un Assign Batches for Moderation
     * @param $moderationRule
     * @return NULL
     */
    public function assignAndUnAssignBatches($moderationRule)
    {
        if (!empty($moderationRule->unAssignBatchIds)) {
            $updateRequest = new \stdClass();
            $updateRequest->moderationRuleId = $moderationRule->id;
            $updateRequest->batchIds = $moderationRule->unAssignBatchIds;
            $this->unAssignBatchesForModeration($updateRequest);
        }
        if (!empty($moderationRule->assignBatches)) {
            foreach ($moderationRule->assignBatches as $batch) {
                foreach ($batch->subjects as $subject) {
                    $updateRequest = new \stdClass();
                    $updateRequest->moderationRuleId = $moderationRule->id;
                    $updateRequest->batchId = $batch->id;
                    $updateRequest->assessmentId = $subject->assessmentId;
                    $updateRequest->moderationMark = $subject->moderationMark;
                    $this->assignBatchesForModeration($updateRequest);
                }
            }
        }
    }
    /**
     * Un Assign Batches For Moderation
     * @param $request
     */
    private function unAssignBatchesForModeration($request)
    {
        $batchIdString = is_array($request->batchIds) ? "'" . implode("','", $request->batchIds) . "'" : "'" . $request->batchIds . "'";
        $query = "UPDATE
                    ec_exam_registration_subject
                SET
                    properties = JSON_REMOVE(properties,'$.moderationRuleId'),
                    properties = JSON_REMOVE(properties,'$.moderationMark')
                WHERE
                    ec_exam_registration_batch_id IN ($batchIdString)";
        try {
            $this->executeQuery($query);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Assign Batches For Moderation
     * @param $request
     */
    private function assignBatchesForModeration($request)
    {
        $query = "UPDATE
                    ec_exam_registration_subject
                SET
                    properties = JSON_SET(properties,'$.moderationRuleId','$request->moderationRuleId'),
                    properties = JSON_SET(properties,'$.moderationMark','$request->moderationMark')
                WHERE
                    ec_exam_registration_batch_id = '$request->batchId' AND am_assessment_id = '$request->assessmentId' AND  properties IS NOT NULL";
        $query1 = "UPDATE
                    ec_exam_registration_subject
                SET
                    properties = JSON_OBJECT('moderationRuleId','$request->moderationRuleId','moderationMark','$request->moderationMark')
                WHERE
                    ec_exam_registration_batch_id = '$request->batchId' AND am_assessment_id = '$request->assessmentId' AND  properties IS NULL";
        try {
            $this->executeQuery($query);
            $this->executeQuery($query1);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get Preview Template For Apply Moderation
     * @param $moderationRule
     * @return $programResult
     */
    public function getPreviewTemplateForApplyModeration($moderationRule){
        $moderationResponse = $this->getStudentModerationDetails($moderationRule);
        $failedStudentSubjectsAfterModeration = $moderationResponse->failedStudentSubjectsAfterModeration;
        $passedStudentSubjectsAfterModeration = $moderationResponse->passedStudentSubjectsAfterModeration;
        $examType = 'EC_MODERATION_PREVIEW_TEMPLATE';
        $template = MarksCardService::getInstance()->getMarkCardTemplate($examType);
       
        if($template == 'Template_5'){
            if(empty($passedStudentSubjectsAfterModeration)){
                throw new ExamControllerException(ExamControllerException::NO_DETAILS_FOUND, "No Moderation Student(s) !");
            }
            $batchList = [];
            $additionalInfo->collegeData = CommonExamService::getInstance()->getCollegeDetails();
            $additionalInfo->examRegistrationName =  reset($student->examRegistrationName);
            foreach($passedStudentSubjectsAfterModeration as $student){
                $passedStudentsBatchList[$student->groupId]->id = $student->groupId;
                $passedStudentsBatchList[$student->groupId]->name = $student->batchName;
                $passedStudentsBatchList[$student->groupId]->students[] = $student;
            }
            $templateName = $template == 'Template_5' ? "preview-apply-moderation-details-template-5" :"preview-apply-moderation-details";
            $responseHtml = TwigRenderer::renderTemplateFileToHtml(realpath(DOCUMENT_ROOT . "../examcontroller-api/src/com/linways/web/templates/moderation/$templateName.twig"), ['passedStudentsBatchList' => $passedStudentsBatchList,'failedStudentsBatchList' => $failedStudentsBatchList, 'additionalInfo' => $additionalInfo,'passedStudents' => $passedStudentSubjectsAfterModeration]);
            $prtContent = NULL;
            $prtContent .= '<html><head>'; 
            $prtContent .= "<style>
                    
                    </style>";
            $prtContent .= '</head><title>Preview Moderation</title><body>';
            $prtContent .= $responseHtml;
            $prtContent .= '</body></html>';
            $options = array(
                'page-width'     => "297mm",
                'page-height'    => "210mm",
                'dpi'            => 96,
                'margin-top' => "3mm",
                'margin-left' => "10mm",
                'margin-right' => "10mm",
                'margin-bottom' => "5mm",
                // 'binary' => "/usr/local/bin/wkhtmltopdf", // For Mac
                'user-style-sheet' => realpath(DOCUMENT_ROOT . "/libcommon/bootstrap/css/bootstrap.min.css")
            );
            $programResult = new \stdClass;
            $programResult->displayData = $responseHtml;
            $programResult->pdf = PdfUtil::renderPdf($prtContent, $options);
            $programResult->isModerationAlreadyApplied = $moderationResponse->isModerationAlreadyApplied;
            return  $programResult;
        }
        else{
                $searchRuleRequest = new SearchRuleRequest;
                $searchRuleRequest->name = "EXAM_MODERATION_RULE";
                $moderationRule = reset(RuleService::getInstance()->searchRule($searchRuleRequest))->rule;
                $previewTemplate = $moderationRule->previewTemplate;
                $templateName = $previewTemplate == 'Template_5' ? "preview-apply-moderation-details-template-5" :"preview-apply-moderation-details";
                $responseHtml = TwigRenderer::renderTemplateFileToHtml(realpath(DOCUMENT_ROOT . "../examcontroller-api/src/com/linways/web/templates/moderation/$templateName.twig"), ['failedStudents' => $failedStudentSubjectsAfterModeration, 'passedStudents' => $passedStudentSubjectsAfterModeration]);
                $prtContent = NULL;
                $prtContent .= '<html><head>';
                $prtContent .= "<style>
                        </style>";
                $prtContent .= '</head><title>Preview Moderation</title><body>';
                $prtContent .= $responseHtml;
                $prtContent .= '</body></html>';
                $totalWidth = 210;
                $totalHeight = 297;
                $options = array(
                    'page-width'     => $totalWidth . "mm",
                    'page-height'    => $totalHeight . "mm",
                    'dpi'            => 96,
                    'margin-top' => "9mm",
                    'margin-left' => "1mm",
                    'margin-right' => "1mm",
                    'margin-bottom' => "9mm",
                    // 'binary' => "/usr/local/bin/wkhtmltopdf", // For Mac
                    'user-style-sheet' => realpath(DOCUMENT_ROOT . "/libcommon/bootstrap/css/bootstrap.min.css")
                );
            
            $programResult = new \stdClass;
            $programResult->displayData = $responseHtml;
            $programResult->pdf = PdfUtil::renderPdf($prtContent, $options);
            $programResult->isModerationAlreadyApplied = $moderationResponse->isModerationAlreadyApplied;
            return  $programResult;
        }
    }
    /**
     * Get Student Moderation Details
     * @param $moderationRule
     * @return $studentModerationDetails
     */
    public function getStudentModerationDetails($moderationRule){
        $failedStudentSubjectsAfterModeration = [];
        $passedStudentSubjectsAfterModeration = [];
        $response = new \stdClass();
        $response->isModerationAlreadyApplied = false;
        $moderationRule = $this->realEscapeObject($moderationRule);
        $currentModerationDetails = reset($this->getAllModerationRules($moderationRule));
        if (empty($currentModerationDetails)) {
            throw new ExamControllerException(ExamControllerException::NO_DETAILS_FOUND, "Moderation rule not found !");
        }
        $request = new \stdClass();
        $request->examRegistrationBatchId = $moderationRule->batchIds;
        $failedStudentDetails = (array)$this->getAllFailedStudentsDetails($request);
        $moderationAppliedPassedStudents = (array)$this->getModerationAppliedPassedStudents($request);
        if ( $moderationAppliedPassedStudents ){
            $failedStudentDetails = array_values(array_merge( $failedStudentDetails, $moderationAppliedPassedStudents));
        }
        if (empty($currentModerationDetails)) {
            throw new ExamControllerException(ExamControllerException::NO_DETAILS_FOUND, "No student found !");
        }
        foreach ($failedStudentDetails as $student) {
            foreach ($student->examBatches as $batch) {
                foreach ($batch->subjects as $subject) {
                    $searchRequestForGradeScheme = new \stdClass();
                    $searchRequestForGradeScheme->groupId = $batch->groupId;
                    $searchRequestForGradeScheme->academicTermId = $batch->academicTermId;
                    $searchRequestForGradeScheme->academicPaperSubjectId = $subject->academicPaperSubjectId;
                    $subjectGradeSchemeArray = GradeSchemeService::getInstance()->getAllSubjectGradeSchemesByRequest($searchRequestForGradeScheme);
                    $subjectGradeKey = array_search($subject->id, array_column( $subjectGradeSchemeArray, "id"));
                    $gradeDetails = [];
                    if($subjectGradeKey || $subjectGradeKey === 0){
                        $gradeDetails = $subjectGradeSchemeArray[$subjectGradeKey]->grades;
                    }
                    $maxGradePercent =  max(array_column($gradeDetails,"rangeTo"));
                    $schemeType = "PERCENTAGE";
                    $passCriteriaArray[$subject->academicPaperSubjectId] = GradeSchemeService::getInstance()->getSubjectPassCriteriaByAcademicPaperSubject($subject->academicPaperSubjectId, $schemeType);
                    $checkPassPercentCriteria = new \stdClass();
                    $checkPassPercentCriteria->courseTypeMethod = $student->courseTypeMethod;
                    $checkPassPercentCriteria->schemeType = $subjectGradeSchemeArray[$subjectGradeKey]->schemeType ? $subjectGradeSchemeArray[$subjectGradeKey]->schemeType : "PERCENTAGE";
                    $checkPassPercentCriteria->isInternal = $subject->isInternal;
                    $checkPassPercentCriteria->internalMaxMark = $subject->internalMaxMark;
                    $checkPassPercentCriteria->isExternal = $subject->isExternal;
                    $checkPassPercentCriteria->externalMaxMark = $subject->externalMaxMark;
                    $checkPassPercentCriteria->internalMark = round($subject->internalMark, 2 );
                    $checkPassPercentCriteria->passPercentConfig = $passCriteriaArray[$subject->academicPaperSubjectId];
                    $checkPassPercentCriteria->externalMark = round ( $subject->externalMark, 2 );
                    $checkPassPercentCriteria->maxGradePercent = $maxGradePercent;
                    $checkPassPercentCriteria->gradeDetails = $gradeDetails;
                    $subjectPassCriteria = CommonExamService::getInstance()->checkIsFailedByPassPercentCreditCriteria ( $checkPassPercentCriteria );
                    $subject->markNeededToPass = $subjectPassCriteria->overAllMarkNeededToPass >  $subjectPassCriteria->externalMarkNeededToPass ? (int)ceil($subjectPassCriteria->overAllMarkNeededToPass) : (int)ceil($subjectPassCriteria->externalMarkNeededToPass);
                    $subject->markNeededToPassInSemester += $subjectObj->markNeededToPass;
                }
                $moderationRuleBatch = reset(array_filter($currentModerationDetails->batches, function ($moderationBatch) use ($batch) {
                    return $moderationBatch->id == $batch->id;
                }));
                if(!$moderationRuleBatch->isDisableEdit){
                    if ($currentModerationDetails->properties->applicableByExamRegistrationType == 'ALL' || $currentModerationDetails->properties->applicableByExamRegistrationType == $batch->examRegistrationType) {
                        if (count($batch->subjects) == 1 && $currentModerationDetails->properties->maximumModerationAwardedWhenCandidateFailedInOneSubject) {
                            if ($currentModerationDetails->properties->applicableBySubjectClassType == 'ALL' || $currentModerationDetails->properties->applicableBySubjectClassType == $batch->subjects[0]->classType) {
                                $batch->subjects[0]->newFailedStatus = 'FAILED';
                                if ($batch->subjects[0]->markNeededToPass <= $currentModerationDetails->properties->maximumModerationAwardedWhenCandidateFailedInOneSubject && !$batch->subjects[0]->hasModerationMark && $batch->subjects[0]->markNeededToPass > 0 ) {
                                    $batch->subjects[0]->moderationMark = $currentModerationDetails->properties->moderationMarkNotExceedPassMark == '1' ? $batch->subjects[0]->markNeededToPass : $currentModerationDetails->properties->maximumModerationAwardedWhenCandidateFailedInOneSubject;
                                    $batch->subjects[0]->newExternalMark = $batch->subjects[0]->moderationMark + $batch->subjects[0]->markObtained;
                                    $batch->subjects[0]->externalMarkAftMod = $batch->subjects[0]->moderationMark + (int)$batch->subjects[0]->externalMark;
                                    $batch->subjects[0]->newFailedStatus = 'PASSED';
                                }
                            }
                        } else {
                            $batch->addedModerationMark = 0;
                            foreach ($batch->subjects as $subject) {
                                $subject->newFailedStatus = 'FAILED';
                                if($subject->studentAttendanceStatus == 'FE'){
                                    $subject->newFailedStatus = 'FAILED';
                                }
                                else{
                                    if ($currentModerationDetails->properties->applicableBySubjectClassType == 'ALL' || $currentModerationDetails->properties->applicableBySubjectClassType == $subject->classType) {
                                        $moderationRuleSubject = reset(array_filter($moderationRuleBatch->subjects, function ($moderationSubject) use ($subject) {
                                            return $moderationSubject->id == $subject->assessmentId;
                                        }));
                                        if ((int)$subject->markNeededToPass <= (int)$moderationRuleSubject->moderationMark && (int)$batch->addedModerationMark < (int)$currentModerationDetails->properties->maximumModerationAwardedInSemester && !$subject->hasModerationMark && (int)$subject->markNeededToPass > 0 ) {
                                            $subject->moderationMark = $currentModerationDetails->properties->moderationMarkNotExceedPassMark == '1' ? $subject->markNeededToPass : $currentModerationDetails->properties->maximumModerationAwardedInSubject;
                                            $subject->newExternalMark = $subject->moderationMark + $subject->markObtained;
                                            $subject->externalMarkAftMod = $subject->moderationMark + (int)$subject->externalMark;
                                            $batch->addedModerationMark += $subject->moderationMark;
                                            $subject->newFailedStatus = 'PASSED';
                                            if ($batch->addedModerationMark > $currentModerationDetails->properties->maximumModerationAwardedInSemester) {
                                                $batch->addedModerationMark = $batch->addedModerationMark - $subject->moderationMark;
                                                $subject->moderationMark = 0;
                                                $subject->newExternalMark = $subject->moderationMark + $subject->markObtained;
                                                $subject->externalMarkAftMod = $subject->moderationMark + (int)$subject->externalMark;
                                                $subject->newFailedStatus = 'FAILED';
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if ($currentModerationDetails->properties->modereationAwardedIfCandidatePassInAllPapersInSemester == 1) {
                            $failedSubjects = array_filter($batch->subjects, function ($subject) {
                                return $subject->newFailedStatus == 'FAILED';
                            });
                            if (count($failedSubjects) > 0) {
                                array_walk($batch->subjects, function ($subject) {
                                    $subject->moderationMark = 0;
                                    $subject->newExternalMark = $subject->moderationMark + $subject->markObtained;
                                    $subject->externalMarkAftMod = $subject->moderationMark + (int)$subject->externalMark;
                                    $subject->newFailedStatus = 'FAILED';
                                });
                            }
                        }
                    }
                }
                else{
                    array_walk($batch->subjects, function ($subject) {
                        if($subject->hasModerationMark){
                            $subject->newFailedStatus =  "PASSED";
                            $subject->newExternalMark = $subject->moderationMark + $subject->markObtained;
                            $subject->externalMarkAftMod = $subject->moderationMark + (int)$subject->externalMark;
                        }
                        else{
                            $subject->newFailedStatus =  $subject->failedStatus;
                        }
                    });
                    $response->isModerationAlreadyApplied = true;
                }
                foreach ($batch->subjects as $subject) {
                    $studentSubjectDetails = new \stdClass;
                    $studentSubjectDetails->studentId = $student->id;
                    $studentSubjectDetails->studentName = $student->name;
                    $studentSubjectDetails->registerNo = $student->registerNo;
                    $studentSubjectDetails->groupId = $batch->groupId;
                    $studentSubjectDetails->batchName = $batch->groupName;
                    $studentSubjectDetails->academicTermId = $batch->academicTermId;
                    $studentSubjectDetails->academicTermName = $batch->academicTermName;
                    $studentSubjectDetails->examRegistrationName = $batch->examRegistrationName;
                    $studentSubjectDetails->assessmentId = $subject->assessmentId;
                    $studentSubjectDetails->oeExamId = $subject->oeExamId;
                    $studentSubjectDetails->subjectCode = $subject->code;
                    $studentSubjectDetails->subjectName = $subject->name;
                    $studentSubjectDetails->hasModerationMark = $subject->hasModerationMark;
                    $studentSubjectDetails->moderationMark = $subject->moderationMark;
                    $studentSubjectDetails->markObtained = $subject->markObtained;
                    $studentSubjectDetails->newExternalMark = $subject->newExternalMark;
                    $studentSubjectDetails->externalMark = $subject->externalMark;
                    $studentSubjectDetails->externalMarkAftMod = $subject->externalMarkAftMod;
                    $studentSubjectDetails->markNeededToPass = $subject->markNeededToPass;
                    if ($subject->newFailedStatus == 'FAILED') {
                        $failedStudentSubjectsAfterModeration[] = $studentSubjectDetails;
                    } elseif ($subject->newFailedStatus == 'PASSED') {
                        $passedStudentSubjectsAfterModeration[] = $studentSubjectDetails;
                    }
                }
                
            }
        }
        $response->failedStudentSubjectsAfterModeration = $failedStudentSubjectsAfterModeration;
        $response->passedStudentSubjectsAfterModeration = $passedStudentSubjectsAfterModeration;
        return ($response);
    }
    /**
     * Get Failed Student Details
     * @param $searchRequest
     * @return $failedStudentDetails
     */
    public function getAllFailedStudentsDetails($searchRequest)
    {
        $searchRequest = $this->realEscapeObject($searchRequest);
        try {
            $whereQuery = "";
            $orderBy = " ORDER BY spa.properties->>'$.registerNumber' ASC ";
            if (!empty($searchRequest->examRegistrationBatchId)) {
                $examRegistrationBatchIdString = is_array($searchRequest->examRegistrationBatchId) ? "'" . implode("','", $searchRequest->examRegistrationBatchId) . "'" : "'" . $searchRequest->examRegistrationBatchId . "'";
                $whereQuery .= " AND eerb.id IN ( $examRegistrationBatchIdString )";
            }
            $query = "SELECT DISTINCT
                        sa.studentID AS id,
                        sa.studentID AS studentId,
                        sa.studentName,
                        spa.properties->>'$.registerNumber' AS regNo,
                        spa.properties->>'$.rollNumber' AS rollNo,
                        g.id AS groupId,
                        g.name AS groupName,
                        eer.id AS examRegistrationId,
                        eer.name AS examRegistrationName,
                        eer.type AS examRegistrationType,
                        eerb.id AS examRegistrationBatchId,
                        act.id AS academicTermId,
                        act.name AS academicTermName,
                        dept.deptID,
                        deg.name AS degreeName,
                        deg.id AS degreeId,
                        dept.deptName,
                        ct.courseTypeID,
                        ct.typeName AS courseTypeName,
                        ct.course_Type AS courseTypeMethod, 
                        esmdsem.mark_details ->>'$.percentage' AS semesterPercentage,
                        esmdsem.mark_details ->>'$.markObtained' AS semesterMarkObtained,
                        esmdsem.mark_details ->>'$.totalMarks' AS semesterTotalMarks,
                        esmdsem.mark_history AS semesterMarkHistory,
                        s.code AS subjectCode,
                        aps.properties ->> '$.syllabusName' AS syllabusName,
                        s.name AS subjectName,
                        eers.am_assessment_id AS assessmentId,
                        oe.id AS oeExamId,
                        ostmmod.mark_obtained  as moderationMark,
                        ostmmod.mark_obtained  as hasModerationMark,
                        ostmmod.properties as moderationMarkproperties,
                        ostmmod.properties ->> '$.moderationMarkRemarks'  as moderationMarkRemarks,
                        aps.properties ->>'$.classType' AS subjectClassType,
                        eers.id AS examRegistrationSubjectId,
                        eers.cm_academic_paper_subjects_id AS academicPaperSubjectId,
                        esmdsub.mark_details ->>'$.markObtained' AS subjectMarkObtained,
                        esmdsub.mark_details ->>'$.isExternalFailed' AS isExternalFailed,
                        esmdsub.mark_details ->>'$.internalMark' AS internalMark,
                        esmdsub.percentage AS subjectPercentage,
                        esmdsub.failed_status AS subjectFailedStatus,
                        CAST(esmdsub.mark_details ->>'$.externalMark' AS DECIMAL(8,2)) AS externalMark,
                        esmdsub.mark_details ->>'$.markNeededToPass' AS markNeededToPass,
                        esmdsub.mark_details ->>'$.studentAttendanceStatus' AS studentAttendanceStatus,
                        
                        esmdsubcon.mark_details ->>'$.internalResultStatus' AS subjectInternalResultStatus,
                        esmdsubcon.mark_details ->>'$.externalMaxMark' AS externalMaxMark,
                        esmdsubcon.mark_details ->>'$.internalMaxMark' AS internalMaxMark,
                        esmdsubcon.mark_details ->>'$.totalMarks' AS subjectTotalMarks,
                        esmdsubcon.mark_details ->>'$.isExternal' AS isExternal,
                        esmdsubcon.mark_details ->>'$.isInternal' AS isInternal,
                        esmdsubcon.mark_details ->>'$.isInternalFailed' AS isInternalFailed,
                        esmdsubcon.mark_details ->>'$.internalPassPercentage' AS subjectInternalPassPercentage,
                        esmdsubcon.mark_details ->>'$.externalPassPercentage' AS subjectExternalPassPercentage,
                        esmdsubcon.mark_details ->>'$.aggregatePassPercentage' AS subjectAggregatePassPercentage
                       
                    FROM
                        `groups` g
                    INNER JOIN ec_exam_registration_batch eerb ON
                        eerb.groups_id = g.id
                    INNER JOIN ec_exam_registration_subject eers ON
                        eers.ec_exam_registration_batch_id = eerb.id
                    INNER JOIN oe_exams oe ON
                        oe.assessment_id = eers.am_assessment_id AND oe.is_deleted = 0
                    INNER JOIN  cm_academic_paper_subjects aps ON 
                        eers.cm_academic_paper_subjects_id = aps.id
                    INNER JOIN  v4_ams_subject s ON 
                        aps.ams_subject_id = s.id
                    INNER JOIN ec_exam_registration eer ON
                        eer.id = eerb.ec_exam_registration_id
                    INNER JOIN ec_student_assessment_registration esar ON
                        esar.am_assessment_id = eers.am_assessment_id AND 
                        esar.ec_exam_registration_type = eer.type AND
                        ((CAST(esar.properties ->> '$.registrationStatus' AS CHAR) = 'REGISTERED' AND 
                        CAST(esar.properties ->> '$.feeStatus' AS CHAR) = 'PAID' ) OR 
                        CAST(esar.properties->>'$.studentAttendanceStatus' AS CHAR) = 'FE' AND
                        CAST(esar.properties->>'$.registrationStatus' AS CHAR) ='NOT_REGISTERED')
                    INNER JOIN studentaccount sa ON 
                        sa.studentID = esar.student_id
                    INNER JOIN department dept ON
                        dept.deptID = g.properties ->> '$.departmentId'
                    INNER JOIN program p ON
                        p.id = g.properties ->> '$.programId'
                    INNER JOIN student_program_account spa ON 
                        spa.current_program_id = p.id AND 
                        spa.student_id = esar.student_id 
                    INNER JOIN degree deg ON
                        deg.id = p.degree_id
                    INNER JOIN `course_type` ct ON
                        ct.courseTypeID = p.course_type_id
                    INNER JOIN ec_subject_mark_details esmdsub ON
                        esmdsub.ec_exam_registration_id = eerb.ec_exam_registration_id AND 
                        esmdsub.groups_id = eerb.groups_id AND 
                        esmdsub.cm_academic_paper_subjects_id = eers.cm_academic_paper_subjects_id AND 
                        esmdsub.student_id = sa.studentID AND 
                        esmdsub.failed_status = 'FAILED'
                    INNER JOIN ec_consolidated_subject_mark_details esmdsubcon ON
                        esmdsubcon.groups_id = eerb.groups_id AND 
                        esmdsubcon.cm_academic_paper_subjects_id = eers.cm_academic_paper_subjects_id AND 
                        esmdsubcon.student_id = sa.studentID 
                    INNER JOIN  academic_term act ON 
                        act.id = CAST(eerb.properties ->> '$.academicTermId'AS CHAR) AND 
                        act.type = 'SEMESTER'
                    INNER JOIN ec_semester_mark_details esmdsem ON
                        esmdsem.groups_id = eerb.groups_id AND 
                        esmdsem.academic_term_id = act.id AND 
                        esmdsem.student_id = sa.studentID 
                    LEFT JOIN oe_student_total_mark ostmmod ON 
                            ostmmod.student_id = sa.studentID AND 
                            ostmmod.am_assessment_id = esar.am_assessment_id AND 
                            ostmmod.valuation_type = 'MODERATION'
                    WHERE 1=1";
            $failedStudentDetails = $this->executeQueryForList($query . $whereQuery.$orderBy, $this->mapper[ModerationRuleServiceMapper::FAILED_STUDENT_DETAILS]);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
        return $failedStudentDetails;
    }
    /**
     * get Active Batch For Assign Moderation Rule
     * @param  $request
     * @return examRegistration
     */
    public function getActiveBatchesForAssignModerationRule($request){
        $request = $this->realEscapeObject($request);
        $whereQuery = "";
        $limitQuery = "";
        if(!empty($request->examRegistrationId)) {
            $whereQuery .= " AND eerb.ec_exam_registration_id='$request->examRegistrationId";
        }
        if(!empty($request->moderationRuleId)) {
            $whereQuery .= " AND (eers.properties->>'$.moderationRuleId' IS NULL OR eers.properties->>'$.moderationRuleId' = '$request->moderationRuleId') ";
        }
        $query = "SELECT DISTINCT
            eerb.id AS examRegistrationBatchId,
            eerb.groups_id AS groupsId,
            eerb.ec_exam_registration_id AS examRegistrationId,        
            eerb.properties AS batchProperties,            
            act.id AS academicTermId,
            act.name AS academicTermName,
            g.name AS groupName,
            eer.name AS examRegistrationName,
            eer.type AS examRegistrationType,
            eer.properties AS examRegistrationProperties,
            aps.id AS academicPaperSubjectId,
            aps.properties->>'$.classType' AS subjectPropertyType,
            eers.properties->>'$.moderationMark' AS moderationMark,
            eers.properties AS ecSubjectProperties,
            eers.id AS examRegistrationSubjectId,
            eers.am_assessment_id AS assessmentId,
            s.code AS subjectCode,
            s.name AS subjectName
        FROM
            ec_exam_registration_batch eerb
        INNER JOIN `groups` g ON
            g.id = eerb.groups_id
        INNER JOIN program p ON
            p.id = CONVERT(g.properties ->> '$.programId',CHAR)
        INNER JOIN `academic_term` act ON
            act.id = CONVERT(eerb.properties ->> '$.academicTermId',CHAR)
        INNER JOIN ec_exam_registration eer ON
            eer.id = eerb.ec_exam_registration_id
        INNER JOIN ec_exam_registration_subject eers ON
            eers.ec_exam_registration_batch_id = eerb.id
        INNER JOIN  cm_academic_paper_subjects aps ON 
            eers.cm_academic_paper_subjects_id = aps.id
        INNER JOIN  v4_ams_subject s ON 
            aps.ams_subject_id = s.id
        WHERE
            1 = 1";
        try {
            $examRegistrationBatches = $this->executeQueryForList($query.$whereQuery.$limitQuery, $this->mapper[ModerationRuleServiceMapper::SEARCH_ACTIVE_BATCH]);
        } catch (\Exception $e) {
            throw new ExamControllerException(ExamControllerException::ERROR_FETCHING_EXAM_REGISTRATION_BATCH,"Cannot fetch Exam Registration Batch details! Please try again.");
        }
        return $examRegistrationBatches;
    }
    /**
     * Apply Moderation Mark by rule
     * @param $moderationRule
     */
    public function applyModerationMarkByRule($moderationRule){
        $moderationResponse = $this->getStudentModerationDetails($moderationRule);
        $passedStudentSubjectsAfterModeration = $moderationResponse->passedStudentSubjectsAfterModeration;
        if(empty($passedStudentSubjectsAfterModeration)){
            throw new ExamControllerException(ExamControllerException::NO_DETAILS_FOUND, "Nothing to moderate !!");
        }
        $passedStudentAfterModeration =  array_filter($passedStudentSubjectsAfterModeration, function ($studentSubject) {
            return $studentSubject->hasModerationMark == false;
        });
        if(empty($passedStudentAfterModeration)){
            throw new ExamControllerException(ExamControllerException::NO_DETAILS_FOUND, "Already Moderated !!");
        }
        $studentModerationMarkArray = [];
        $editHistoryLog = [];
        foreach($passedStudentAfterModeration as $studentSubject){
            $moderationObj = new \stdClass();
            $moderationObj->studentId = $studentSubject->studentId;
            $moderationObj->assessmentId = $studentSubject->assessmentId;
            $moderationObj->oeExamsId = $studentSubject->oeExamId;
            $moderationObj->markObtained = $studentSubject->moderationMark;
            $moderationMarkproperties = new \stdClass();
            $moderationMarkproperties->moderationBy = "MODERATION_RULE";
            $moderationObj->properties  = $moderationMarkproperties;
            $moderationObj->valuationType = "MODERATION";
            $studentModerationMarkArray[] = $moderationObj;
            // for high lighting edit changes in import mark
            $editRequest = new \stdClass();
            $editRequest->groupId = $studentSubject->groupId;
            $editRequest->studentId = $studentSubject->studentId;
            $editRequest->isDirty = 1;
            $editRequest->staffId = $GLOBALS['userId'];
            $editHistoryLog[] = $editRequest;
        }
        ExamUserMarkService::getInstance()->saveExamUserTotalMark($studentModerationMarkArray);
        if(! empty($editHistoryLog)){
            StudentsOverAllMarkReportService::getInstance()->insertStudentEditStatus($editHistoryLog);
        }
    }
    /**
     * Get Failed Student Details
     * @param $searchRequest
     * @return $failedStudentDetails
     */
    public function getModerationAppliedPassedStudents($searchRequest)
    {
        $searchRequest = $this->realEscapeObject($searchRequest);
        try {
            $whereQuery = "";
            $orderBy = " ORDER BY spa.properties->>'$.registerNumber' ASC ";
            if (!empty($searchRequest->examRegistrationBatchId)) {
                $examRegistrationBatchIdString = is_array($searchRequest->examRegistrationBatchId) ? "'" . implode("','", $searchRequest->examRegistrationBatchId) . "'" : "'" . $searchRequest->examRegistrationBatchId . "'";
                $whereQuery .= " AND eerb.id IN ( $examRegistrationBatchIdString )";
            }
            $query = "SELECT DISTINCT
                        sa.studentID AS id,
                        sa.studentID AS studentId,
                        sa.studentName,
                        spa.properties->>'$.registerNumber' AS regNo,
                        spa.properties->>'$.rollNumber' AS rollNo,
                        g.id AS groupId,
                        g.name AS groupName,
                        eer.id AS examRegistrationId,
                        eer.name AS examRegistrationName,
                        eer.type AS examRegistrationType,
                        eerb.id AS examRegistrationBatchId,
                        act.id AS academicTermId,
                        act.name AS academicTermName,
                        dept.deptID,
                        deg.name AS degreeName,
                        deg.id AS degreeId,
                        dept.deptName,
                        ct.courseTypeID,
                        ct.typeName AS courseTypeName,
                        ct.course_Type AS courseTypeMethod, 
                        esmdsem.mark_details ->>'$.percentage' AS semesterPercentage,
                        esmdsem.mark_details ->>'$.markObtained' AS semesterMarkObtained,
                        esmdsem.mark_details ->>'$.totalMarks' AS semesterTotalMarks,
                        esmdsem.mark_history AS semesterMarkHistory,
                        s.code AS subjectCode,
                        aps.properties ->> '$.syllabusName' AS syllabusName,
                        s.name AS subjectName,
                        eers.am_assessment_id AS assessmentId,
                        oe.id AS oeExamId,
                        ostmmod.mark_obtained  as moderationMark,
                        ostmmod.mark_obtained  as hasModerationMark,
                        ostmmod.properties as moderationMarkproperties,
                        ostmmod.properties ->> '$.moderationMarkRemarks'  as moderationMarkRemarks,
                        aps.properties ->>'$.classType' AS subjectClassType,
                        eers.id AS examRegistrationSubjectId,
                        eers.cm_academic_paper_subjects_id AS academicPaperSubjectId,
                        esmdsub.mark_details ->>'$.markObtained' AS subjectMarkObtained,
                        esmdsub.mark_details ->>'$.isExternalFailed' AS isExternalFailed,
                        esmdsub.mark_details ->>'$.internalMark' AS internalMark,
                        esmdsub.percentage AS subjectPercentage,
                        esmdsub.failed_status AS subjectFailedStatus,
                        CAST(esmdsub.mark_details ->>'$.externalMarkObtainedInExam' AS DECIMAL(8,2)) AS externalMark,
                        esmdsub.mark_details ->>'$.markNeededToPass' AS markNeededToPass,
                        
                        esmdsubcon.mark_details ->>'$.internalResultStatus' AS subjectInternalResultStatus,
                        esmdsubcon.mark_details ->>'$.externalMaxMark' AS externalMaxMark,
                        esmdsubcon.mark_details ->>'$.internalMaxMark' AS internalMaxMark,
                        esmdsubcon.mark_details ->>'$.totalMarks' AS subjectTotalMarks,
                        esmdsubcon.mark_details ->>'$.isExternal' AS isExternal,
                        esmdsubcon.mark_details ->>'$.isInternal' AS isInternal,
                        esmdsubcon.mark_details ->>'$.isInternalFailed' AS isInternalFailed,
                        esmdsubcon.mark_details ->>'$.internalPassPercentage' AS subjectInternalPassPercentage,
                        esmdsubcon.mark_details ->>'$.externalPassPercentage' AS subjectExternalPassPercentage,
                        esmdsubcon.mark_details ->>'$.aggregatePassPercentage' AS subjectAggregatePassPercentage
                       
                    FROM
                        `groups` g
                    INNER JOIN ec_exam_registration_batch eerb ON
                        eerb.groups_id = g.id
                    INNER JOIN ec_exam_registration_subject eers ON
                        eers.ec_exam_registration_batch_id = eerb.id
                    INNER JOIN oe_exams oe ON
                        oe.assessment_id = eers.am_assessment_id AND oe.is_deleted = 0
                    INNER JOIN  cm_academic_paper_subjects aps ON 
                        eers.cm_academic_paper_subjects_id = aps.id
                    INNER JOIN  v4_ams_subject s ON 
                        aps.ams_subject_id = s.id
                    INNER JOIN ec_exam_registration eer ON
                        eer.id = eerb.ec_exam_registration_id
                    INNER JOIN ec_student_assessment_registration esar ON
                        esar.am_assessment_id = eers.am_assessment_id AND 
                        esar.ec_exam_registration_type = eer.type AND
                        CAST(esar.properties ->> '$.registrationStatus' AS CHAR) = 'REGISTERED' AND 
                        CAST(esar.properties ->> '$.feeStatus' AS CHAR) = 'PAID'
                    INNER JOIN studentaccount sa ON 
                        sa.studentID = esar.student_id
                    INNER JOIN department dept ON
                        dept.deptID = g.properties ->> '$.departmentId'
                    INNER JOIN program p ON
                        p.id = g.properties ->> '$.programId'
                    INNER JOIN student_program_account spa ON 
                        spa.current_program_id = p.id AND 
                        spa.student_id = esar.student_id 
                    INNER JOIN degree deg ON
                        deg.id = p.degree_id
                    INNER JOIN `course_type` ct ON
                        ct.courseTypeID = p.course_type_id
                    INNER JOIN ec_subject_mark_details esmdsub ON
                        esmdsub.ec_exam_registration_id = eerb.ec_exam_registration_id AND 
                        esmdsub.groups_id = eerb.groups_id AND 
                        esmdsub.cm_academic_paper_subjects_id = eers.cm_academic_paper_subjects_id AND 
                        esmdsub.student_id = sa.studentID AND 
                        esmdsub.failed_status = 'PASSED'
                    INNER JOIN ec_consolidated_subject_mark_details esmdsubcon ON
                        esmdsubcon.groups_id = eerb.groups_id AND 
                        esmdsubcon.cm_academic_paper_subjects_id = eers.cm_academic_paper_subjects_id AND 
                        esmdsubcon.student_id = sa.studentID 
                    INNER JOIN  academic_term act ON 
                        act.id = CAST(eerb.properties ->> '$.academicTermId'AS CHAR) AND 
                        act.type = 'SEMESTER'
                    INNER JOIN ec_semester_mark_details esmdsem ON
                        esmdsem.groups_id = eerb.groups_id AND 
                        esmdsem.academic_term_id = act.id AND 
                        esmdsem.student_id = sa.studentID 
                    INNER JOIN oe_student_total_mark ostmmod ON 
                            ostmmod.student_id = sa.studentID AND 
                            ostmmod.am_assessment_id = esar.am_assessment_id AND 
                            ostmmod.valuation_type = 'MODERATION'
                    WHERE 1=1";
            $failedStudentDetails = $this->executeQueryForList($query . $whereQuery.$orderBy, $this->mapper[ModerationRuleServiceMapper::FAILED_STUDENT_DETAILS]);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(), $e->getMessage());
        }
        return $failedStudentDetails;
    }
    
}