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 / 51
CRAP
0.00% covered (danger)
0.00%
0 / 1298
AdditionalCreditService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 51
42230.00
0.00% covered (danger)
0.00%
0 / 1298
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 4
 __clone
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
 getInstance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 5
 getApplicationStatus
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 getApplicationCode
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 getAllAdditionalCreditItemIdByName
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getAllAdditionalCreditItems
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 getAdditionalCreditApplicationById
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 33
 getAllAdditionalCreditApplications
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 29
 getAllPendingApplicationsAssignedToStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 41
 searchAdditionalCreditApplications
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 50
 getAllSupportingDocumentIdsByApplicationId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 createAdditionalCreditItems
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 25
 createAchievementDetail
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 createAchievementMonthAndYear
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 createAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 54
 addAdditionalCreditApplicationCredits
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 19
 addAdditionalCreditSupportingDocuments
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 17
 createAdditionalCreditWorkFlowInstance
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 createAdditionalCreditApplicationLog
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 UpdateAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 96
 updateAllRemovedAdditionalCreditItems
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 updateAdditionalCreditApplicationCredits
0.00% covered (danger)
0.00%
0 / 1
210.00
0.00% covered (danger)
0.00%
0 / 48
 updateAdditionalCreditSupportingDocuments
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 editAdditionalCreditApplicationCredit
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 reApplyAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 27
 updateAdditionalCreditApplicationLog
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 updateAchieveMentmonthandyear
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 updateAchievementDetail
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 deleteAllAdditionalCreditSupportingDocumentsByApplicationCreditId
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 removeAdditionalCreditSupportingDocuments
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 16
 deleteApplication
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 29
 deleteAdditionalCreditApplicationCreditByApplicationId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 deleteAdditionalCreditSupportingDocumentsByApplicationId
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 25
 deleteAdditionalCreditApplicationLog
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 approveOrRejectApplication
0.00% covered (danger)
0.00%
0 / 1
552.00
0.00% covered (danger)
0.00%
0 / 79
 processAdditionCreditReject
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 60
 processAdditionalCreditApproval
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 60
 approveAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 rejectAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 approveAllCreditsInsideAnAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 19
 rejectAllCreditsInsideAnAdditionalCreditApplication
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 19
 getStudentSemesterwiseTotalAdditionalCredit
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 29
 updateStudentSemesterwiseTotalAdditionalCredit
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 67
 addStudentSemesterwiseAdditionalCredit
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 31
 removeStudentSemesterwiseAdditionalCredit
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 17
 createSecCreditItems
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 55
 getSecApplication
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 21
 deleteSecApplication
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 36
 getSecApplicationsBySecBatchId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 28
 updateSecStudentStatus
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
<?php
namespace com\linways\core\ams\professional\service;
use com\linways\core\ams\professional\constant\CreatedWorkFlows;
use com\linways\core\ams\professional\constant\Messages;
use com\linways\core\ams\professional\constant\StatusConstants;
use com\linways\core\ams\professional\constant\UserType;
use com\linways\core\ams\professional\constant\AdditionalCredit;
use com\linways\core\ams\professional\dto\AdditionalCreditApplication;
use com\linways\core\ams\professional\dto\AdditionalCreditLog;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\logging\AMSLogger;
use com\linways\core\ams\professional\logging\entities\AdditionalCreditItem;
use com\linways\core\ams\professional\logging\entities\SecCreditItem;
use com\linways\core\ams\professional\logging\entities\Staff;
use com\linways\core\ams\professional\logging\Events;
use com\linways\core\ams\professional\mapper\AdditionalCreditServiceMapper;
use com\linways\core\ams\professional\request\AddAdditionalCreditItemsRequest;
use com\linways\core\ams\professional\request\AddAchievementDetailRequest;
use com\linways\core\ams\professional\request\AddAchievementMonthAndYearRequest;
use com\linways\core\ams\professional\request\AdditionalCreditApplicationLogRequest;
use com\linways\core\ams\professional\request\AddSecCreditItemsRequest;
use com\linways\core\ams\professional\request\ApproveAdditionalCreditApplicationRequest;
use com\linways\core\ams\professional\request\ApproveAllAdditionalCreditsRequest;
use com\linways\core\ams\professional\request\ApproveOrRejectAdditionalCreditsApplicationRequest;
use com\linways\core\ams\professional\request\CreateAdditionalCreditApplicationCreditsRequest;
use com\linways\core\ams\professional\request\CreateAdditionalCreditApplicationRequest;
use com\linways\core\ams\professional\request\DeleteAdditionalCreditApplicationRequest;
use com\linways\core\ams\professional\request\ReApplyAdditionalCreditApplicationRequest;
use com\linways\core\ams\professional\request\RejectAdditionalCreditApplicationRequest;
use com\linways\core\ams\professional\request\RejectAllAdditionalCreditsRequest;
use com\linways\core\ams\professional\request\RemoveResourceRequest;
use com\linways\core\ams\professional\request\SearchAdditionalCreditApplicationRequest;
use com\linways\core\ams\professional\request\UpdateAdditionalCreditApplicationCreditsRequest;
use com\linways\core\ams\professional\request\UpdateAdditionalCreditApplicationLogRequest;
use com\linways\core\ams\professional\request\UpdateAdditionalCreditApplicationRequest;
use com\linways\workflow\api\constants\WorkflowActions;
use com\linways\workflow\api\request\MoveToNextStateApiRequest;
use com\linways\workflow\api\Workflow;
use com\linways\workflow\api\WorkflowInstance;
use com\linways\core\ams\professional\request\SearchAdditionalCreditRequest;
class AdditionalCreditService extends BaseService
{
    // /Condition 1 - Presence of a static member variable
    private static $_instance = null;
    private $mapper = [];
    private $logger = null;
    // /Condition 2 - Locked down the constructor
    private function __construct()
    {
        $this->logger = AMSLogger::getLogger();
        $this->mapper = AdditionalCreditServiceMapper::getInstance()->getMapper();
    }
    // Prevent any outside instantiation of this class
    // /Condition 3 - Prevent any object or instance of that class to be cloned
    private function __clone()
    {
    }
    // Prevent any copy of this object
    // /Condition 4 - Have a single globally accessible static method
    public static function getInstance()
    {
        if (!is_object(self::$_instance)) // or if( is_null(self::$_instance) ) or if( self::$_instance == null )
            self::$_instance = new self ();
        return self::$_instance;
    }
    /***************************************************************************************************************
     *                                                                                                             *
     *                                  FETCHING APPLICATION DETAILS SECTIONS                                      *
     *                                                                                                             *
     ***************************************************************************************************************/
    /**
     * @param $applicationId
     * @return string
     * @throws ProfessionalException
     */
    public function getApplicationStatus($applicationId)
    {
        $sql = "SELECT status FROM additional_credit_application WHERE id = $applicationId";
        try {
            return $this->executeQueryForObject($sql)->status;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $applicationId
     * @return string
     * @throws ProfessionalException
     */
    public function getApplicationCode($applicationId)
    {
        $sql = "SELECT application_type_code FROM additional_credit_application WHERE id = $applicationId";
        try {
            return $this->executeQueryForObject($sql)->application_type_code;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $name
     * @return Object
     * @throws ProfessionalException
     */
    public function getAllAdditionalCreditItemIdByName($name)
    {
        $name = $this->realEscapeString($name);
        $sql = "SELECT id FROM additional_credit_items 
                WHERE  REPLACE(UPPER(name),' ','') =REPLACE(UPPER('$name'),' ','')";
        try {
            return $this->executeQueryForObject($sql)->id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @return Object
     * @throws ProfessionalException
     */
    public function getAllAdditionalCreditItems()
    {
        $sql = "SELECT id,name FROM additional_credit_items";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $applicationId
     * @return Object|AdditionalCreditApplication
     * @throws ProfessionalException
     */
    public function getAdditionalCreditApplicationById($applicationId)
    {
        $applicationId = $this->realEscapeString($applicationId);
        if (empty($applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application credit details given");
        }
        $sql = "SELECT aca.*,
                acac.id as application_credit_id,acac.updated_date as credit_updated_date,
                acac.created_date as credit_created_date,acac.credit,acac.updated_by as credit_updated_by,
                acac.created_by as credit_created_by,acac.remarks as credit_remarks,acac.processed_by as credit_processed_by,
                acac.status as credit_status,
                aci.id as credit_item_id,aci.name as credit_item_name,
                acasd.id as supporting_document_id,acasd.additional_credit_application_credit_id,acasd.resource_id,
                acasd.created_by as document_created_by,acasd.created_date as document_created_date,
                acasd.updated_date as document_updated_date,acasd.updated_by as document_updated_by,
                acal.id as log_id,acal.updated_by as log_updated_by,acal.updated_date as log_updated_date,
                acal.created_date as log_created_date,acal.created_by as log_created_by,acal.log,
                applicationProcessedStaff.staffName as application_processed_staff_name,
                creditProcessedStaff.staffName as credit_processed_staff_name
                FROM additional_credit_application aca
                INNER JOIN application_types at ON at.code = aca.application_type_code
                LEFT JOIN additional_credit_application_credits acac on aca.id = acac.application_id
                LEFT JOIN additional_credit_items aci ON aci.id = acac.additional_credit_item_id
                LEFT JOIN additional_credit_application_supporting_documents acasd ON acac.id = acasd.additional_credit_application_credit_id
                LEFT JOIN additional_credit_application_log acal ON aca.id = acal.application_id
                LEFT JOIN staffaccounts as creditProcessedStaff ON creditProcessedStaff.staffID = acac.processed_by
                LEFT JOIN staffaccounts as applicationProcessedStaff ON applicationProcessedStaff.staffID = aca.processed_by
                WHERE aca.id = $applicationId";
        try {
            return $this->executeQueryForObject($sql, false, $this->mapper[AdditionalCreditServiceMapper::GET_ADDITIONAL_CREDIT_APPLICATION]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Returns all additional credit application
     * @return Object|AdditionalCreditApplication
     * @throws ProfessionalException
     */
    public function getAllAdditionalCreditApplications()
    {
        $sql = "SELECT aca.*,
                acac.id as application_credit_id,acac.updated_date as credit_updated_date,
                acac.created_date as credit_created_date,acac.credit,acac.updated_by as credit_updated_by,
                acac.created_by as credit_created_by,acac.remarks as credit_remarks,acac.processed_by as credit_processed_by,
                acac.status as credit_status,
                aci.id as credit_item_id,aci.name as credit_item_name,
                acasd.id as supporting_document_id,acasd.additional_credit_application_credit_id,acasd.resource_id,
                acasd.created_by as document_created_by,acasd.created_date as document_created_date,
                acasd.updated_date as document_updated_date,acasd.updated_by as document_updated_by,
                acal.id as log_id,acal.updated_by as log_updated_by,acal.updated_date as log_updated_date,
                acal.created_date as log_created_date,acal.created_by as log_created_by,
                applicationProcessedStaff.staffName as application_processed_staff_name,
                creditProcessedStaff.staffName as credit_processed_staff_name
                FROM additional_credit_application aca
                INNER JOIN application_types at on at.code = aca.application_type_code
                LEFT JOIN additional_credit_application_credits acac on aca.id = acac.application_id
                LEFT JOIN additional_credit_items aci ON aci.id = acac.additional_credit_item_id
                LEFT JOIN additional_credit_application_supporting_documents acasd ON acac.id = acasd.additional_credit_application_credit_id
                LEFT JOIN additional_credit_application_log acal ON aca.id = acal.application_id
                LEFT JOIN staffaccounts as creditProcessedStaff ON creditProcessedStaff.staffID = acac.processed_by
                LEFT JOIN staffaccounts as applicationProcessedStaff ON applicationProcessedStaff.staffID = aca.processed_by
                WHERE 1=1";
        try {
            return $this->executeQueryForObject($sql, false, $this->mapper[AdditionalCreditServiceMapper::GET_ADDITIONAL_CREDIT_APPLICATION]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Returns all pending application list
     * @param $staffId
     * @return Object|AdditionalCreditApplication[]
     * @throws ProfessionalException
     */
    public function getAllPendingApplicationsAssignedToStaff($staffId, $applicationCode)
    {
        $sql = "SELECT aca.id,aca.semester_id,aca.student_id,aca.status,aca.created_by,aca.updated_by,aca.remarks,aca.remarks,
                aca.processed_by,
                DATE_FORMAT(CONVERT_TZ(aca.created_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as created_date,
                DATE_FORMAT(CONVERT_TZ(aca.updated_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as updated_date,
                acac.id as application_credit_id,
                DATE_FORMAT(CONVERT_TZ(acac.updated_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %') as credit_updated_date,
                DATE_FORMAT(CONVERT_TZ(acac.created_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as credit_created_date,
                acac.credit,acac.updated_by as credit_updated_by,
                acac.created_by as credit_created_by,acac.remarks as credit_remarks,acac.processed_by as credit_processed_by,
                acac.status as credit_status,
                aci.id as credit_item_id,aci.name as credit_item_name,
                acasd.id as supporting_document_id,acasd.additional_credit_application_credit_id,acasd.resource_id,
                acasd.created_by as document_created_by,acasd.created_date as document_created_date,
                acasd.updated_date as document_updated_date,acasd.updated_by as document_updated_by,
                acal.id as log_id,acal.updated_by as log_updated_by,acal.updated_date as log_updated_date,
                acal.created_date as log_created_date,acal.created_by as log_created_by,acal.log,
                applicationProcessedStaff.staffName as application_processed_staff_name,
                creditProcessedStaff.staffName as credit_processed_staff_name,
                s.semName,s2.studentName,s2.regNo,b.batchID,b.batchName,am.monthandyear as achievement_date,ad.detail as achievement_details
                FROM additional_credit_application aca
                INNER JOIN application_types at ON at.code = \"" . $applicationCode . "\" 
                INNER JOIN studentaccount s2 on aca.student_id = s2.studentID
                INNER JOIN batches b ON b.batchID = s2.batchID
                INNER JOIN batch_tutor bt ON bt.batchID  =b.batchID AND aca.semester_id = bt.semID
                LEFT JOIN additional_credit_application_credits acac on aca.id = acac.application_id
                LEFT JOIN additional_credit_items aci ON aci.id = acac.additional_credit_item_id
                LEFT JOIN additional_credit_application_supporting_documents acasd ON acac.id = acasd.additional_credit_application_credit_id
                LEFT JOIN additional_credit_application_log acal ON aca.id = acal.application_id
                LEFT JOIN staffaccounts as creditProcessedStaff ON creditProcessedStaff.staffID = acac.processed_by
                LEFT JOIN staffaccounts as applicationProcessedStaff ON applicationProcessedStaff.staffID = aca.processed_by
                LEFT JOIN semesters s ON s.semID  =aca.semester_id
                LEFT JOIN achievement_monthandyear am on am.id = acac.achievement_monthandyear_id
                LEFT JOIN achievement_details ad on ad.id = acac.achievement_details_id
                WHERE 1=1 AND bt.staffID = $staffId and aca.application_type_code = at.code ORDER BY aca.created_date DESC";
        try {
            return $this->executeQueryForList($sql, $this->mapper[AdditionalCreditServiceMapper::GET_PENDING_APPLICATIONS_LIST]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * TODO:  Add pagination queries and search filter queries
     * Searching additional credit applications
     * @param SearchAdditionalCreditApplicationRequest $request
     * @return Object|AdditionalCreditApplication[]
     * @throws ProfessionalException
     */
    public function searchAdditionalCreditApplications(SearchAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "SELECT aca.id,aca.semester_id,aca.student_id,aca.status,aca.created_by,aca.updated_by,aca.remarks,aca.remarks,
                aca.processed_by,
                DATE_FORMAT(CONVERT_TZ(aca.created_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as created_date,
                DATE_FORMAT(CONVERT_TZ(aca.updated_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as updated_date,
                acac.id as application_credit_id,
                DATE_FORMAT(CONVERT_TZ(acac.updated_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as credit_updated_date,
                DATE_FORMAT(CONVERT_TZ(acac.created_date,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as credit_created_date,
                acac.credit,acac.updated_by as credit_updated_by,
                acac.created_by as credit_created_by,acac.remarks as credit_remarks,acac.processed_by as credit_processed_by,
                acac.status as credit_status,
                aci.id as credit_item_id,aci.name as credit_item_name,
                acasd.id as supporting_document_id,acasd.additional_credit_application_credit_id,acasd.resource_id,
                acasd.created_by as document_created_by,acasd.created_date as document_created_date,
                acasd.updated_date as document_updated_date,acasd.updated_by as document_updated_by,
                acal.id as log_id,acal.updated_by as log_updated_by,acal.updated_date as log_updated_date,
                acal.created_date as log_created_date,acal.created_by as log_created_by,acal.log,
                applicationProcessedStaff.staffName as application_processed_staff_name,
                creditProcessedStaff.staffName as credit_processed_staff_name,
                s.semName,lr.storage_object,ad.id as achievement_details_id,ad.detail as achievement_details,am.id as achievement_date_id,am.monthandyear as achievement_date
                FROM additional_credit_application aca
                INNER JOIN application_types at on at.code = aca.application_type_code and at.code = \"" . $request->applicationTypeCode . "\"
                LEFT JOIN additional_credit_application_credits acac on aca.id = acac.application_id
                LEFT JOIN additional_credit_items aci ON aci.id = acac.additional_credit_item_id
                LEFT JOIN additional_credit_application_supporting_documents acasd ON acac.id = acasd.additional_credit_application_credit_id
                LEFT JOIN additional_credit_application_log acal ON aca.id = acal.application_id
                LEFT JOIN staffaccounts as creditProcessedStaff ON creditProcessedStaff.staffID = acac.processed_by
                LEFT JOIN staffaccounts as applicationProcessedStaff ON applicationProcessedStaff.staffID = aca.processed_by
                LEFT JOIN semesters s ON s.semID  =aca.semester_id
                LEFT JOIN lin_resource lr on acasd.resource_id = lr.id
                LEFT JOIN achievement_details ad on ad.id = acac.achievement_details_id
                LEFT JOIN achievement_monthandyear am on am.id = acac.achievement_monthandyear_id
                WHERE 1=1 ";
        if (!empty($request->studentId)) {
            $sql .= " AND aca.student_id  =$request->studentId";
        }
        if (!empty($request->applicationId)) {
            $sql .= " AND aca.id = $request->applicationId";
        }
        if (!empty($request->status)) {
            $sql .= " AND aca.status = '$request->status'";
        }
        $sql .= " ORDER BY aca.created_date DESC";
        try {
            return $this->executeQueryForList($sql, $this->mapper[AdditionalCreditServiceMapper::GET_ADDITIONAL_CREDIT_APPLICATION]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Returns all the additional credit application supporting document ids
     * @param $applicationId
     * @return Object
     * @throws ProfessionalException
     */
    private function getAllSupportingDocumentIdsByApplicationId($applicationId)
    {
        $sql = "SELECT resource_id as id FROM additional_credit_application_credits acac
                INNER JOIN additional_credit_application aca on acac.application_id = aca.id
                LEFT JOIN  additional_credit_application_supporting_documents acasd on acac.id = acasd.additional_credit_application_credit_id
                WHERE aca.id = $applicationId";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /***************************************************************************************************************
     *                                                                                                             *
     *                                              CREATE SECTIONS                                                *
     *                                                                                                             *
     ***************************************************************************************************************/
    /**
     * @param AddAdditionalCreditItemsRequest $request
     * @return Object
     * @throws ProfessionalException
     */
    public function createAdditionalCreditItems(AddAdditionalCreditItemsRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "INSERT INTO additional_credit_items (name, created_by, created_date, updated_by, updated_date) 
                VALUES ('$request->name',$request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,UTC_TIMESTAMP())";
        try {
            $id = $this->executeQueryForObject($sql, true);
            $this->logger->info(Events::ADDITIONAL_CREDIT_ITEM_CREATION, [
                "userId" => $request->createdBy,
                "userType" => UserType::STUDENT,
                "additionCreditItem" => new AdditionalCreditItem(["id" => $id]),
                "status" => StatusConstants::SUCCESS
            ]);
            return $id;
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::ADDITIONAL_CREDIT_ITEM_CREATION, [
                "userId" => $request->createdBy,
                "userType" => UserType::STUDENT,
                "itemName" => $request->name,
                "status" => StatusConstants::FAILED,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param AddAchievementDetailRequest $request
     * @return Object
     * @throws ProfessionalException
     */
    public function createAchievementDetail(AddAchievementDetailRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "INSERT INTO achievement_details (detail, created_by, created_date, updated_by, updated_date) 
                VALUES ('$request->detail',$request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,UTC_TIMESTAMP())";
        try {
            $id = $this->executeQueryForObject($sql, true);
            return $id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param AddAchievementMonthAndYearRequest $request
     * @return Object
     * @throws ProfessionalException
     */
    public function createAchievementMonthAndYear(AddAchievementMonthAndYearRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "INSERT INTO achievement_monthandyear (monthandyear, created_by, created_date, updated_by, updated_date) 
                VALUES ('$request->monthAndYear',$request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,UTC_TIMESTAMP())";
        try {
            $id = $this->executeQueryForObject($sql, true);
            return $id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param CreateAdditionalCreditApplicationRequest $request
     * @return Object
     * @throws ProfessionalException
     */
    public function createAdditionalCreditApplication(CreateAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $status = StatusConstants::PENDING;
        if (empty($request->semesterId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_SEMESTER_ID, "Semester details not given");
        }
        if (empty($request->studentId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_STUDENT_ID, "Invalid operation performed");
        }
        try {
            /**
             * Creating workflow instance
             */
            $workFlowInstanceId = $this->createAdditionalCreditWorkFlowInstance($request->createdBy);
            /**
             * Creating additional credit application
             */
            $sql = "INSERT INTO additional_credit_application (student_id, semester_id, workflow_instance_id, application_type_code,
                            created_by, created_date, status, updated_by, updated_date) 
                    VALUES ($request->studentId,$request->semesterId,$workFlowInstanceId,\"" . $request->applicationTypeCode . "\",$request->createdBy,UTC_TIMESTAMP(),
                        '$status',$request->updatedBy,UTC_TIMESTAMP())";
            $request->id = $this->executeQueryForObject($sql, true);
            $this->addAdditionalCreditApplicationCredits($request);
            $additionalCreditLog = new AdditionalCreditLog();
            $additionalCreditLog->status = "PENDING";
            $additionalCreditLog->updatedBy = $request->updatedBy;
            $additionalCreditLog->createdBy = $request->createdBy;
            $additionalCreditLog->actionTakenTime = date("Y-m-d h:i A");
            $additionalCreditLog->appliedStudentName = StudentService::getInstance()->getStudentNameById($request->createdBy);
            if ($request->applicationTypeCode == AdditionalCredit::ACHIEVEMENTS) {
                $additionalCreditLog->message = Messages::ACHIEVEMENT_APPLICATION_CREATED;
            } else {
                $additionalCreditLog->message = Messages::ADDITIONAL_CREDIT_APPLICATION_CREATED;
            }
            $additionalCreditLog->appliedBy = $request->createdBy;
            $createAdditionalCreditLog = new AdditionalCreditApplicationLogRequest();
            $createAdditionalCreditLog->log = json_encode([$additionalCreditLog]);
            $createAdditionalCreditLog->applicationId = $request->id;
            $createAdditionalCreditLog->createdBy = $request->createdBy;
            $createAdditionalCreditLog->updatedBy = $request->updatedBy;
            $this->createAdditionalCreditApplicationLog($createAdditionalCreditLog);
            /**
             * Ams Logger
             */
            $this->logger->info(Events::ADDITIONAL_CREDIT_APPLICATION_CREATION, [
                "userId" => $request->createdBy,
                "userType" => UserType::STUDENT,
                "additionCreditApplication" => new AdditionalCreditApplication(["id" => $request->id]),
                "status" => StatusConstants::SUCCESS
            ]);
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::ADDITIONAL_CREDIT_APPLICATION_CREATION, [
                "userId" => $request->createdBy,
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::FAILED,
                "request" => $request,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $request->id;
    }
    /**
     * @param CreateAdditionalCreditApplicationRequest $request
     * @return void
     * @throws ProfessionalException
     */
    public function addAdditionalCreditApplicationCredits(CreateAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (count($request->additionalCreditApplicationCredits) === 0) {
            throw new ProfessionalException(ProfessionalException::ADDITIONAL_CREDITS_NOT_ADDED, "No additional credits added in this application");
        }
        $status = StatusConstants::PENDING;
        try {
            foreach ($request->additionalCreditApplicationCredits as $credit) {
                $sql = "INSERT INTO additional_credit_application_credits (application_id, additional_credit_item_id,achievement_monthandyear_id,achievement_details_id, 
                        credit, status, created_by, updated_by, created_date, updated_date) 
                        VALUES ($request->id,$credit->additionalCreditItemId,$credit->achievementMonthandyearId,$credit->achievementDetailsId,$credit->credit,'$status',$request->createdBy,
                                $request->updatedBy,UTC_TIMESTAMP(),UTC_TIMESTAMP())";
                $credit->id = $this->executeQueryForObject($sql, true);
                $this->addAdditionalCreditSupportingDocuments($credit);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param CreateAdditionalCreditApplicationCreditsRequest $request
     * @throws ProfessionalException
     */
    public function addAdditionalCreditSupportingDocuments(CreateAdditionalCreditApplicationCreditsRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->id)) {
            throw new ProfessionalException(ProfessionalException::INTERNAL_SERVICE_FAILURE, "Internal server error occurred. Contact system administrator");
        }
        try {
            foreach ($request->supportingDocuments as $supportDocuments) {
                $sql = "INSERT INTO additional_credit_application_supporting_documents (additional_credit_application_credit_id, 
                        resource_id, updated_by, updated_date, created_by, created_date) 
                        VALUES ($request->id,'$supportDocuments->resourceId',$request->updatedBy,UTC_TIMESTAMP(),
                                $request->createdBy,UTC_TIMESTAMP())";
                $this->executeQuery($sql);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $createdUser
     * @return int|void
     * @throws ProfessionalException
     */
    protected function createAdditionalCreditWorkFlowInstance($createdUser)
    {
        $codeOrId = CreatedWorkFlows::ADDITIONAL_CREDIT_APPLICATION_WORKFLOW;
        $requesterUserType = UserType::STUDENT;
        try {
            $workflow = new Workflow($codeOrId);
            if (empty($workflow->getId())) {
                return fault("Additional credit application creation failed. Faculties not assigned for this application approval. Contact your class tutor/mentor");
            }
            $workflowInstance = new WorkflowInstance(WorkflowActions::CREATE, $codeOrId, $createdUser, $requesterUserType);
            return $workflowInstance->getId();
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Creating additional credit application log.
     * TODO : This can be used to show the application tracking and history in future
     * @param AdditionalCreditApplicationLogRequest $request
     * @throws ProfessionalException
     */
    public function createAdditionalCreditApplicationLog(AdditionalCreditApplicationLogRequest $request)
    {
        $request->applicationId = $this->realEscapeString($request->applicationId);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid additional credit application details given");
        }
        $request->log = addslashes($request->log);
        $sql = "INSERT INTO additional_credit_application_log (application_id, log, created_by, created_date, 
                updated_by, updated_date) 
                VALUES ($request->applicationId,'$request->log',$request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,UTC_TIMESTAMP())";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /***************************************************************************************************************
     *                                                                                                             *
     *                                          UPDATE APPLICATION SECTIONS                                        *
     *                                                                                                             *
     ***************************************************************************************************************/
    /**
     * Update Additional Credit Application
     * Step 1:
     *
     * Finding removed additional credit application credit items and updating other details
     * @param UpdateAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    public function UpdateAdditionalCreditApplication(UpdateAdditionalCreditApplicationRequest $request)
    {
        $status = "";
        $request = $this->realEscapeObject($request);
        try {
            /**
             * Checking additional credit application available in the database, if available finding removed application
             * credit items
             */
            $applicationDetails = $this->getAdditionalCreditApplicationById($request->id);
            if (empty($applicationDetails)) {
                throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Application doesn't found");
            }
//            TODO: Use this code when multiple additional credit item added to the application in the future
//            DONT REMOVE THIS CODE, THIS MAY USE FULL IN FUTURE
//            $removedCreditItems = [];
//            foreach ($applicationDetails->applicationCredits as $credit) {
//                $isFound = false;
//                foreach ($request->additionalCreditApplicationCredits as $updatedCredit) {
//                    if ($credit->additionalCreditItemId == $updatedCredit->additionalCreditItemId) {
//                        $isFound = true;
//                    }
//                }
//                if (!$isFound) {
//                    array_push($removedCreditItems, $credit->additionalCreditItemId);
//                }
//            }
//            /**
//             * Removing user removed additional credit items from the application
//             */
//            $this->updateAllRemovedAdditionalCreditItems($removedCreditItems, $request->id);
            /**
             * Updating existing application credit item id and credit values
             */
            $this->updateAdditionalCreditApplicationCredits($applicationDetails, $request->additionalCreditApplicationCredits, $request);
            if ($applicationDetails->status === StatusConstants::REJECTED) {
                $status = StatusConstants::RE_APPLIED;
            } elseif ($applicationDetails->status === StatusConstants::RE_APPLIED) {
                $status = StatusConstants::RE_APPLIED;
            } else {
                $status = StatusConstants::PENDING;
            }
            /**
             * Updating basic details of the additional credit application
             */
            $sql = "UPDATE additional_credit_application 
                    SET semester_id  =$request->semesterId,status='$status',
                    updated_date = UTC_TIMESTAMP(),updated_by=$request->updatedBy 
                    WHERE id = $request->id";
            $this->executeQuery($sql);
            $applicationTypeCode = $this->getApplicationCode($request->id);
            /**
             * If student edited the application after tutor reject, we need to change the application status to Re-Applied
             */
            if ($applicationDetails->status === StatusConstants::REJECTED) {
                $reApplyRequest = new ReApplyAdditionalCreditApplicationRequest();
                $reApplyRequest->applicationId = $request->id;
                $reApplyRequest->userType = $request->userType;
                $reApplyRequest->reAppliedBy = $request->updatedBy;
                $this->reApplyAdditionalCreditApplication($reApplyRequest);
                /**
                 * Adding database log
                 */
                $log = json_decode($applicationDetails->applicationLog->log);
                $additionalCreditLog = new AdditionalCreditLog();
                $additionalCreditLog->status = StatusConstants::RE_APPLIED;
                $additionalCreditLog->updatedBy = $request->updatedBy;
                $additionalCreditLog->createdBy = $request->createdBy;
                $additionalCreditLog->actionTakenTime = date("Y-m-d h:i A");
                $additionalCreditLog->appliedStudentName = StudentService::getInstance()->getStudentNameById($request->createdBy);
                $additionalCreditLog->updatedByUserType = $request->userType;
                if ($applicationTypeCode == AdditionalCredit::ACHIEVEMENTS) {
                    $additionalCreditLog->message = Messages::ACHIEVEMENT_APPLICATION_RE_APPLIED;
                } else {
                    $additionalCreditLog->message = Messages::ADDITIONAL_CREDIT_APPLICATION_RE_APPLIED;
                }
                $additionalCreditLog->appliedBy = $request->processedBy;
                $additionalCreditLog->remarks = $request->remarks;
                array_push($log, $additionalCreditLog);
                $updateLog = new UpdateAdditionalCreditApplicationLogRequest();
                $updateLog->log = json_encode($log);
                $updateLog->applicationId = $applicationDetails->id;
                $updateLog->updatedBy = $request->updatedBy;
                $this->updateAdditionalCreditApplicationLog($updateLog);
                $this->logger->info(Events::ADDITIONAL_CREDIT_APPLICATION_RE_SUBMISSION, [
                    "userId" => $request->createdBy,
                    "userType" => UserType::STUDENT,
                    "request" => $request,
                    "status" => StatusConstants::SUCCESS
                ]);
            } else {
                /**
                 * Adding the additional credit application log
                 */
                $log = json_decode($applicationDetails->applicationLog->log);
                $additionalCreditLog = new AdditionalCreditLog();
                $additionalCreditLog->status = StatusConstants::PENDING;
                $additionalCreditLog->updatedBy = $request->updatedBy;
                $additionalCreditLog->createdBy = $request->createdBy;
                $additionalCreditLog->actionTakenTime = date("Y-m-d h:i A");
                $additionalCreditLog->appliedStudentName = StudentService::getInstance()->getStudentNameById($request->createdBy);
                $additionalCreditLog->updatedByUserType = $request->userType;
                if ($applicationTypeCode == AdditionalCredit::ACHIEVEMENTS) {
                    $additionalCreditLog->message = Messages::ACHIEVEMENT_APPLICATION_UPDATED;
                } else {
                    $additionalCreditLog->message = Messages::ADDITIONAL_CREDIT_APPLICATION_UPDATED;
                }
                $additionalCreditLog->appliedBy = $request->processedBy;
                $additionalCreditLog->remarks = $request->remarks;
                array_push($log, $additionalCreditLog);
                $updateLog = new UpdateAdditionalCreditApplicationLogRequest();
                $updateLog->log = json_encode($log);
                $updateLog->applicationId = $applicationDetails->id;
                $updateLog->updatedBy = $request->updatedBy;
                $this->updateAdditionalCreditApplicationLog($updateLog);
                $this->logger->info(Events::ADDITIONAL_CREDIT_APPLICATION_UPDATION, [
                    "userId" => $request->createdBy,
                    "userType" => UserType::STUDENT,
                    "request" => $request,
                    "status" => StatusConstants::SUCCESS
                ]);
            }
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::ADDITIONAL_CREDIT_APPLICATION_UPDATION, [
                "userId" => $request->createdBy,
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::FAILED,
                "request" => $request,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Update Additional Credit Application
     * Step 2:
     *
     * Updating additional credit application credits by removing user removed credit items from the application
     * @param $removedItems
     * @param $applicationId
     * @throws ProfessionalException
     */
    private function updateAllRemovedAdditionalCreditItems($removedItems, $applicationId)
    {
        if (empty($applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Application doesn't exist");
        }
        try {
            $sql = "DELETE acac.*,acasd.* FROM additional_credit_application_credits acac,
                    INNER JOIN additional_credit_application_supporting_documents as acasd 
                        ON acasd.additional_credit_application_credit_id = acac.id
                    WHERE acac.application_id= $applicationId AND acac.id IN (" . implode(",", $removedItems) . ")";
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Update Additional Credit Application
     * STEP 3:
     * @param AdditionalCreditApplication $applicationDetails
     * @param UpdateAdditionalCreditApplicationCreditsRequest[] $credits
     * @param UpdateAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    private function updateAdditionalCreditApplicationCredits($applicationDetails, array $credits, UpdateAdditionalCreditApplicationRequest $request)
    {
        if (empty($applicationDetails->id)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application details given");
        }
        if ($applicationDetails->status === StatusConstants::REJECTED) {
            $status = StatusConstants::RE_APPLIED;
        } elseif ($applicationDetails->status === StatusConstants::RE_APPLIED) {
            $status = StatusConstants::RE_APPLIED;
        } else {
            $status = StatusConstants::PENDING;
        }
        try {
            $removedSupportingDocuments = [];
            foreach ($credits as $credit) {
                $isCreditFound = 0;
                /*
                 * Finding user removed files from the previously added supporting documents, and then it will be removed from the database
                 */
                foreach ($applicationDetails->applicationCredits as $applicationCredit) {
                    if ($credit->id === $applicationCredit->id) {
                        $isCreditFound = 1;
                        foreach ($applicationCredit->additionalCreditSupportingDocuments as $supportingDocument) {
                            $isNotFound = 1;
                            foreach ($credit->previouslyUploadedFiles as $previouslyUploadedFile) {
                                if ($previouslyUploadedFile['resourceId'] === $supportingDocument->resourceId) {
                                    $isNotFound = 0;
                                    break;
                                }
                            }
                            if ($isNotFound) {
                                array_push($removedSupportingDocuments, $supportingDocument);
                            }
                        }
                    }
                }
                if ($isCreditFound) {
                    $sql = "UPDATE additional_credit_application_credits SET credit =$credit->credit,
                         status='$status', additional_credit_item_id =$credit->additionalCreditItemId,
                         updated_date =UTC_TIMESTAMP(),updated_by = $credit->updatedBy
                         WHERE id= $credit->id AND application_id = $applicationDetails->id";
                    $this->executeQuery($sql);
                    if (count($removedSupportingDocuments) > 0) {
                        /*
                         * Removing user removed support documents from the database
                         */
                        $this->removeAdditionalCreditSupportingDocuments($removedSupportingDocuments, $request);
                    }
                    /*
                     * Adding user newly added support documents to the database
                     */
                    $this->updateAdditionalCreditSupportingDocuments($credit->id, $credit->supportingDocuments);
                }
//                else{
//                    TODO: Use when multiple additional credit items implementing in the application form
//                }
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $applicationCreditId
     * @param AddAdditionalCreditSupportDocuments[] $documents
     * @return void
     * @throws ProfessionalException
     */
    public function updateAdditionalCreditSupportingDocuments($applicationCreditId, array $documents)
    {
        if (empty($applicationCreditId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_CREDIT_ID, "Invalid application credit details given");
        }
        try {
            foreach ($documents as $document) {
                $sql = "INSERT INTO additional_credit_application_supporting_documents (additional_credit_application_credit_id, 
                        resource_id, updated_by, updated_date, created_by, created_date) 
                        VALUES ($applicationCreditId,'$document->resourceId',$document->updatedBy,UTC_TIMESTAMP(),$document->createdBy,UTC_TIMESTAMP())";
                $document->id = $this->executeQueryForObject($sql, true);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Update Additional Credit Application
     * STEP 4:
     * Updating additional credit application credits
     * @param UpdateAdditionalCreditApplicationCreditsRequest $requests []
     * @throws ProfessionalException
     */
    public function editAdditionalCreditApplicationCredit(UpdateAdditionalCreditApplicationCreditsRequest $requests)
    {
        $status = StatusConstants::PENDING;
        try {
            foreach ($requests as $request) {
                $sql = "UPDATE additional_credit_application_credits 
                        SET status ='$status',updated_by = $request->updatedBy,updated_date = UTC_TIMESTAMP(),
                            credit=$request->credit
                        WHERE id = $request->id AND application_id =$request->applicationId";
                $this->executeQuery($sql);
                $this->deleteAllAdditionalCreditSupportingDocumentsByApplicationCreditId($request->id);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param ReApplyAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    public function reApplyAdditionalCreditApplication(ReApplyAdditionalCreditApplicationRequest $request)
    {
        try {
            $applicationDetails = $this->getAdditionalCreditApplicationById($request->applicationId);
            if (empty($applicationDetails)) {
                throw new ProfessionalException(ProfessionalException::APPLICATION_NOT_FOUND, "Application doesn't exist");
            }
            $workflowInstance = new WorkflowInstance(WorkflowActions::GET, $applicationDetails->workflowInstanceId, $request->reAppliedBy, $request->userType);
            if (empty($workflowInstance)) {
                throw new ProfessionalException(ProfessionalException::INTERNAL_SERVICE_FAILURE, "Error occurred while re-applying application. Contact the system administrator");
            }
            /**
             * this will work only if workflow state is rejected. Otherwise workflow stated will not change
             */
            if (strtoupper($workflowInstance->getCurrentState()->name) === strtoupper(StatusConstants::REJECTED)) {
                $possibleNextStates = $workflowInstance->getAllPossibleNextStates();
                foreach ($possibleNextStates as $state) {
                    if (strtoupper($state->name) === StatusConstants::RE_APPLIED) {
                        $moveToNextStateApiRequest = new MoveToNextStateApiRequest();
                        $moveToNextStateApiRequest->approverId = $request->reAppliedBy;
                        $moveToNextStateApiRequest->approverType = $request->userType;
                        $moveToNextStateApiRequest->nextStateId = $state->id;
                        $workflowInstance->moveToNextState($moveToNextStateApiRequest);
                        break;
                    }
                }
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Updating additional credit application log by application id,only json an audit field will be updated
     * @param UpdateAdditionalCreditApplicationLogRequest $request
     * @throws ProfessionalException
     */
    public function updateAdditionalCreditApplicationLog(UpdateAdditionalCreditApplicationLogRequest $request)
    {
        $request->applicationId = $this->realEscapeString($request->applicationId);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid additional credit application details given");
        }
        $request->log = addslashes($request->log);
        $sql = "UPDATE additional_credit_application_log SET log='$request->log', 
                updated_by=$request->updatedBy,updated_date = UTC_TIMESTAMP()
                WHERE application_id = $request->applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Updating monthandyear value in achievement_monthandyear table
     * @param id
     * @param string
     * @param int
     * @throws ProfessionalException
     */
    public function updateAchieveMentmonthandyear($monthandyearId, $monthandyear, $updatedBy)
    {
        $monthandyearId = $this->realEscapeString($monthandyearId);
        $monthandyear = $this->realEscapeString($monthandyear);
        if (empty($monthandyearId) || empty($monthandyear)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ACHIEVEMENT_DETAILS, "Invalid achievement application details given");
        }
        $sql = "UPDATE achievement_monthandyear SET monthandyear='$monthandyear', 
                updated_by=$updatedBy,updated_date = UTC_TIMESTAMP()
                WHERE id = $monthandyearId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Updating details value in achievements_details table
     * @param id
     * @param string
     * @param int
     * @throws ProfessionalException
     */
    public function updateAchievementDetail($detailId, $detail, $updatedBy)
    {
        $detailId = $this->realEscapeString($detailId);
        $monthandyear = $this->realEscapeString($detail);
        if (empty($detailId) || empty($detail)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ACHIEVEMENT_DETAILS, "Invalid achievement application details given");
        }
        $sql = "UPDATE achievement_details SET detail='$detail', 
               updated_by=$updatedBy,updated_date = UTC_TIMESTAMP()
               WHERE id = $detailId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /***************************************************************************************************************
     *                                                                                                             *
     *                                              DELETE SECTIONS                                                *
     *                                                                                                             *
     ***************************************************************************************************************/
    /**
     * Update Additional Credit Application
     * STEP 5:
     * Deleting all additional credit supporting documents
     * @param integer $additionalCreditId
     * @throws ProfessionalException
     */
    public function deleteAllAdditionalCreditSupportingDocumentsByApplicationCreditId($additionalCreditId)
    {
        $supportingDocuments = $this->getAllSupportingDocumentIdsByApplicationId($additionalCreditId);
        /**
         * Removing supporting Documents from the additional credit application
         */
        $sql = "DELETE FROM additional_credit_application_supporting_documents
                WHERE additional_credit_application_credit_id=$additionalCreditId";
        try {
            $this->executeQuery($sql);
            /**
             * Deleting supporting documents from the lin_resources
             */
            foreach ($supportingDocuments as $document) {
                ResourceService::getInstance()->removeResource($document->id);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Deleting supporting documents by ids
     * @param AdditionalCreditSupportingDocuments[] $documents
     * @param UpdateAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    private function removeAdditionalCreditSupportingDocuments(array $documents, UpdateAdditionalCreditApplicationRequest $request)
    {
        try {
            foreach ($documents as $document) {
                $sql = "DELETE FROM additional_credit_application_supporting_documents WHERE id =$document->id";
                $this->executeQuery($sql);
                /**
                 * Removing files from the backend storage
                 */
                $removeRequest = new RemoveResourceRequest();
                $removeRequest->resourceId = $document->resourceId;
                $removeRequest->secretKey = $request->secretKey;
                $removeRequest->accessKey = $request->accessKey;
                $removeRequest->userType = $request->userType;
                ResourceService::getInstance()->removeResource($removeRequest);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Deleting additional credit applications by application id. This wil delete entire application details without
     * checking the application is approved or not
     * @param DeleteAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    public function deleteApplication(DeleteAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid additional credit application or application doesn't exist");
        }
        $sql = "DELETE FROM additional_credit_application WHERE  id = $request->applicationId";
        try {
            $this->deleteAdditionalCreditApplicationLog($request->applicationId);
            $this->deleteAdditionalCreditSupportingDocumentsByApplicationId($request);
            $this->deleteAdditionalCreditApplicationCreditByApplicationId($request->applicationId);
            $this->executeQuery($sql);
            $this->logger->info(Events::ADDITIONAL_CREDIT_APPLICATION_DELETION, [
                "userId" => $request->updatedBy,
                "userType" => UserType::STUDENT,
                "request" => $request,
                "status" => StatusConstants::SUCCESS
            ]);
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::ADDITIONAL_CREDIT_APPLICATION_DELETION, [
                "userId" => $request->updatedBy,
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::FAILED,
                "request" => $request,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Deleting additional credit application credits by application id
     * @param $applicationId
     * @throws ProfessionalException
     */
    private function deleteAdditionalCreditApplicationCreditByApplicationId($applicationId)
    {
        $sql = "DELETE FROM additional_credit_application_credits WHERE application_id = $applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Deleting additional credit suporting documents by application id
     * @param DeleteAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    private function deleteAdditionalCreditSupportingDocumentsByApplicationId(DeleteAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $applicationId = $request->applicationId;
        if (empty($applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid additional credit application details given");
        }
        try {
            $applicationDocuments = $this->getAllSupportingDocumentIdsByApplicationId($applicationId);
            $sql = "DELETE acasd.* FROM  additional_credit_application_supporting_documents acasd 
                    INNER JOIN additional_credit_application_credits  acac ON acac.id = acasd.additional_credit_application_credit_id
                    WHERE acac.application_id  =$applicationId";
            $this->executeQuery($sql);
            foreach ($applicationDocuments as $document) {
                if ($document->id) {
                    $removeResourceRequest = new RemoveResourceRequest();
                    $removeResourceRequest->accessKey = $request->accessKey;
                    $removeResourceRequest->secretKey = $request->secretKey;
                    $removeResourceRequest->resourceId = $document->id;
                    ResourceService::getInstance()->removeResource($removeResourceRequest);
                }
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Deleting additional credit application log
     * @param $applicationId
     * @throws ProfessionalException
     */
    private function deleteAdditionalCreditApplicationLog($applicationId)
    {
        $sql = "DELETE FROM additional_credit_application_log WHERE application_id=$applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /***************************************************************************************************************
     *                                                                                                             *
     *                                 APPLICATION APPROVE/REJECT SECTIONS                                         *
     *                                                                                                             *
     ***************************************************************************************************************/
    /**
     * @param ApproveOrRejectAdditionalCreditsApplicationRequest $request
     * @throws ProfessionalException
     */
    public function approveOrRejectApplication(ApproveOrRejectAdditionalCreditsApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application or application doesn't exist");
        }
        if (count($request->approvedAdditionalCreditApplicationCredits) === 0) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Application doesn't contain any credit items");
        }
        if (empty($request->status)) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Couldn't process application request");
        }
        try {
            $isTutor = StaffService::getInstance()->staffIsOrWasTutor($request->processedBy);
            if (!$isTutor) {
                throw new ProfessionalException(ProfessionalException::UNAUTHENTICATED_OPERATION_PERFORMED, "Un-authenticated operation performed");
            }
            $applicationDetails = null;
            /**
             * Fetching additional credit application details
             */
            $applicationDetails = $this->getAdditionalCreditApplicationById($request->applicationId);
            if (empty($applicationDetails)) {
                throw new ProfessionalException(ProfessionalException::ADDITIONAL_CREDIT_APPLICATION_NOT_FOUND, "Application doesn't exist");
            }
            $user = $request->processedBy;
            $userType = $request->processedUserType;
            $workFlowObject = new WorkflowInstance(WorkflowActions::GET, $applicationDetails->workflowInstanceId, $user, $userType);
            $currentState = $workFlowObject->getCurrentState()->name;
            switch (strtoupper($currentState)) {
                /**
                 * If current state is approved state, then tutor can move this application to rejected state
                 */
                case StatusConstants::APPROVED:
                    if ($request->status === StatusConstants::REJECTED) {
                        $possibleNextStates = $workFlowObject->getAllPossibleNextStates();
                        foreach ($possibleNextStates as $state) {
                            if (strtoupper($state->name) === StatusConstants::REJECTED) {
                                $this->processAdditionCreditReject($applicationDetails, $state, $workFlowObject, $request);
                                break;
                            }
                        }
                    } else {
                        throw new ProfessionalException(ProfessionalException::APPLICATION_ALREADY_APPROVED, "Application already approved by " . $applicationDetails->processedStaffName);
                    }
                    break;
                /**
                 * If current state is rejected, then next state is approved state
                 */
                case StatusConstants::REJECTED:
                    /**
                     * Checking requested transition state is approved state,else throwing errors
                     */
                    if ($request->status === StatusConstants::APPROVED) {
                        $possibleNextStates = $workFlowObject->getAllPossibleNextStates();
                        foreach ($possibleNextStates as $state) {
                            if (strtoupper($state->name) === StatusConstants::APPROVED) {
                                $this->processAdditionalCreditApproval($applicationDetails, $state, $workFlowObject, $request);
                                break;
                            }
                        }
                    } else {
                        throw new ProfessionalException(ProfessionalException::APPLICATION_ALREADY_REJECTED, "Application already rejected by " . $applicationDetails->processedStaffName);
                    }
                    break;
                /**
                 * If current state is applied or re-applied state, then tutor can moe this
                 * application to rejected/approved state only
                 */
                case StatusConstants::APPLIED:
                case StatusConstants::RE_APPLIED:
                    if ($request->status === StatusConstants::REJECTED) {
                        $possibleNextStates = $workFlowObject->getAllPossibleNextStates();
                        foreach ($possibleNextStates as $state) {
                            if (strtoupper($state->name) === StatusConstants::REJECTED) {
                                $this->processAdditionCreditReject($applicationDetails, $state, $workFlowObject, $request);
                                break;
                            }
                        }
                    } else if ($request->status === StatusConstants::APPROVED) {
                        $possibleNextStates = $workFlowObject->getAllPossibleNextStates();
                        foreach ($possibleNextStates as $state) {
                            if (strtoupper($state->name) === StatusConstants::APPROVED) {
                                $this->processAdditionalCreditApproval($applicationDetails, $state, $workFlowObject, $request);
                                break;
                            }
                        }
                    }
                    break;
                default:
                    throw new ProfessionalException(ProfessionalException::INVALID_OPERATION, "You performed an invalid operation. You cannot do this action try again with valid credentials");
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $applicationDetails
     * @param $state
     * @param $workFlowObject
     * @param ApproveOrRejectAdditionalCreditsApplicationRequest $request
     * @throws ProfessionalException
     */
    private function processAdditionCreditReject($applicationDetails, $state, $workFlowObject, ApproveOrRejectAdditionalCreditsApplicationRequest $request)
    {
        try {
            $moveToNextStateApiRequest = new MoveToNextStateApiRequest();
            $moveToNextStateApiRequest->approverId = $request->processedBy;
            $moveToNextStateApiRequest->approverType = $request->processedUserType;
            $moveToNextStateApiRequest->nextStateId = $state->id;
            $workFlowObject->moveToNextState($moveToNextStateApiRequest);
            
            $userType = $request->processedUserType;
            $approveAllCreditRequest = new RejectAllAdditionalCreditsRequest();
            $approveAllCreditRequest->applicationId = $request->applicationId;
            $approveAllCreditRequest->processedBy = $request->processedBy;
            $approveAllCreditRequest->remarks = $request->remarks;
            $approveAllCreditRequest->updatedBy = $request->updatedBy;
            $this->rejectAllCreditsInsideAnAdditionalCreditApplication($approveAllCreditRequest);
            $approveApplication = new RejectAdditionalCreditApplicationRequest();
            $approveApplication->applicationId = $request->applicationId;
            $approveApplication->remarks = $request->remarks;
            $approveApplication->processedBy = $request->processedBy;
            $approveApplication->updatedBy = $request->updatedBy;
            $this->rejectAdditionalCreditApplication($approveApplication);
            
            $applicationTypeCode = $this->getApplicationCode($request->applicationId);
            /**
             * Adding the additional credit application log
             */
            $log = json_decode($applicationDetails->applicationLog->log);
            $additionalCreditLog = new AdditionalCreditLog();
            $additionalCreditLog->status = StatusConstants::REJECTED;
            $additionalCreditLog->updatedBy = $request->updatedBy;
            $additionalCreditLog->createdBy = $request->createdBy;
            $additionalCreditLog->processedByStaffName = StaffService::getInstance()->getStaffNameById($request->processedBy);
            $additionalCreditLog->actionTakenTime = date("Y-m-d h:i A");
            $additionalCreditLog->updatedByUserType = $userType;
            if ($applicationTypeCode == AdditionalCredit::ACHIEVEMENTS) {
                $additionalCreditLog->message = Messages::ACHIEVEMENT_APPLICATION_REJECTED;
            } else {
                $additionalCreditLog->message = Messages::ADDITIONAL_CREDIT_APPLICATION_REJECTED;
            }
            $additionalCreditLog->appliedBy = $request->processedBy;
            $additionalCreditLog->remarks = $request->remarks;
            array_push($log, $additionalCreditLog);
            $updateLog = new UpdateAdditionalCreditApplicationLogRequest();
            $updateLog->log = json_encode($log);
            $updateLog->applicationId = $request->applicationId;
            $updateLog->updatedBy = $request->processedBy;
            $this->updateAdditionalCreditApplicationLog($updateLog);
            $this->logger->info(Events::ADDITIONAL_CREDIT_APPLICATION_REJECTION, [
                "userId" => $request->updatedBy,
                "userType" => UserType::STAFF,
                "request" => $request,
                "status" => StatusConstants::SUCCESS
            ]);
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::ADDITIONAL_CREDIT_APPLICATION_REJECTION, [
                "userId" => $request->updatedBy,
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::FAILED,
                "request" => $request,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $applicationDetails
     * @param $state
     * @param $workFlowObject
     * @param ApproveOrRejectAdditionalCreditsApplicationRequest $request
     * @throws ProfessionalException
     */
    private function processAdditionalCreditApproval($applicationDetails, $state, $workFlowObject, ApproveOrRejectAdditionalCreditsApplicationRequest $request)
    {
        $userType = $request->processedUserType;
        try {
            $moveToNextStateApiRequest = new MoveToNextStateApiRequest();
            $moveToNextStateApiRequest->approverId = $request->processedBy;
            $moveToNextStateApiRequest->approverType = $request->processedUserType;
            $moveToNextStateApiRequest->nextStateId = $state->id;
            $workFlowObject->moveToNextState($moveToNextStateApiRequest);
            $approveAllCreditRequest = new ApproveAllAdditionalCreditsRequest();
            $approveAllCreditRequest->applicationId = $request->applicationId;
            $approveAllCreditRequest->processedBy = $request->processedBy;
            $approveAllCreditRequest->remarks = $request->remarks;
            $approveAllCreditRequest->updatedBy = $request->updatedBy;
            $this->approveAllCreditsInsideAnAdditionalCreditApplication($approveAllCreditRequest);
            $approveApplication = new ApproveAdditionalCreditApplicationRequest();
            $approveApplication->applicationId = $request->applicationId;
            $approveApplication->remarks = $request->remarks;
            $approveApplication->processedBy = $request->processedBy;
            $approveApplication->updatedBy = $request->updatedBy;
            $this->approveAdditionalCreditApplication($approveApplication);
            
            $applicationTypeCode = $this->getApplicationCode($request->applicationId);
            /**
             * Adding the additional credit application log
             */
            $log = json_decode($applicationDetails->applicationLog->log);
            $additionalCreditLog = new AdditionalCreditLog();
            $additionalCreditLog->status = StatusConstants::APPROVED;
            $additionalCreditLog->updatedBy = $request->updatedBy;
            $additionalCreditLog->createdBy = $request->createdBy;
            $additionalCreditLog->processedByStaffName = StaffService::getInstance()->getStaffNameById($request->processedBy);
            $additionalCreditLog->actionTakenTime = date("Y-m-d h:i A");
            $additionalCreditLog->updatedByUserType = $userType;
            if ($applicationTypeCode == AdditionalCredit::ACHIEVEMENTS) {
                $additionalCreditLog->message = Messages::ACHIEVEMENT_APPLICATION_APPROVED;
            } else {
                $additionalCreditLog->message = Messages::ADDITIONAL_CREDIT_APPLICATION_APPROVED;
            }
            $additionalCreditLog->appliedBy = $request->processedBy;
            $additionalCreditLog->remarks = $request->remarks;
            array_push($log, $additionalCreditLog);
            $updateLog = new UpdateAdditionalCreditApplicationLogRequest();
            $updateLog->log = json_encode($log);
            $updateLog->applicationId = $request->applicationId;
            $updateLog->updatedBy = $request->processedBy;
            $this->updateAdditionalCreditApplicationLog($updateLog);
            $this->logger->info(Events::ADDITIONAL_CREDIT_APPLICATION_APPROVAL, [
                "userId" => new Staff($request->updatedBy),
                "userType" => UserType::STAFF,
                "request" => $request,
                "status" => StatusConstants::SUCCESS
            ]);
        } catch (\Exception $e) {
            AMSLogger::log_error($this->logger,Events::ADDITIONAL_CREDIT_APPLICATION_APPROVAL, [
                "userId" => new Staff($request->updatedBy),
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::FAILED,
                "request" => $request,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param ApproveAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    public function approveAdditionalCreditApplication(ApproveAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application or application doesn't exist");
        }
        $status = StatusConstants::APPROVED;
        $sql = "UPDATE additional_credit_application 
                SET status= '$status',remarks='$request->remarks', updated_by =$request->updatedBy,
                    updated_date=UTC_TIMESTAMP(),processed_by=$request->processedBy WHERE id =$request->applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param RejectAdditionalCreditApplicationRequest $request
     * @throws ProfessionalException
     */
    public function rejectAdditionalCreditApplication(RejectAdditionalCreditApplicationRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application or application doesn't exist");
        }
        $status = StatusConstants::REJECTED;
        $sql = "UPDATE additional_credit_application 
                SET status= '$status',remarks='$request->remarks', updated_by =$request->updatedBy,
                    updated_date=UTC_TIMESTAMP(), processed_by=$request->processedBy WHERE id =$request->applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param ApproveAllAdditionalCreditsRequest $request
     * @throws ProfessionalException
     */
    public function approveAllCreditsInsideAnAdditionalCreditApplication(ApproveAllAdditionalCreditsRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application or application doesn't exist");
        }
        $status = StatusConstants::APPROVED;
        if (empty($request->processedBy) || empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Invalid approval request sent");
        }
        $sql = "UPDATE additional_credit_application_credits 
                SET status ='$status',remarks ='$request->remarks', updated_date=UTC_TIMESTAMP(),updated_by = $request->updatedBy,
                processed_by = $request->processedBy
                WHERE application_id  =$request->applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param RejectAllAdditionalCreditsRequest $request
     * @throws ProfessionalException
     */
    public function rejectAllCreditsInsideAnAdditionalCreditApplication(RejectAllAdditionalCreditsRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid application or application doesn't exist");
        }
        $status = StatusConstants::REJECTED;
        if (empty($request->processedBy) || empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Invalid approval request sent");
        }
        $sql = "UPDATE additional_credit_application_credits 
                SET status ='$status',remarks ='$request->remarks', updated_date=UTC_TIMESTAMP(),updated_by = $request->updatedBy,
                processed_by = $request->processedBy
                WHERE application_id  =$request->applicationId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /***************************************************************************************************************
     *                                                                                                             *
     *                                SEMESTER WISE ADDITIONAL CREDIT SECTIONS                                     *
     *                                                                                                             *
     ***************************************************************************************************************/
    /**
     * @param SearchAdditionalCreditRequest $request
     * @return Object|semwiseAdditionalCredits[]
     * @throws ProfessionalException
     */
    public function getStudentSemesterwiseTotalAdditionalCredit(SearchAdditionalCreditRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sqlConditions = "";
        if (empty($request->studentId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Invalid student or student doesn't exist");
        }
        if (!empty($request->semId)) {
            $sqlConditions .= " AND sac.semester_id = '$request->semId'";
        }
        $sql = "SELECT
            sac.semester_id AS semId,
            s.semName,
            sac.student_id AS studentId,
            sac.additional_credit AS credit,
            s.orderNo
        FROM
            semester_additional_credit sac
        INNER JOIN semesters s ON
            s.semID = sac.semester_id
        WHERE
            sac.student_id = '$request->studentId'
            $sqlConditions
        ORDER BY s.orderNo";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $request
     * @throws ProfessionalException
     */
    public function updateStudentSemesterwiseTotalAdditionalCredit($request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "";
        $sqlUpdate = "";
        if (empty($request->studentId) || empty($request->semId) || empty($request->staffId) || empty($request->status) || empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Invalid request sent");
        }
        try {
            $applicationIdArrayJson = '["' . $request->applicationId . '"]';
            $sql = "SELECT
                id,
                additional_credit AS additionalCredit
            FROM
                semester_additional_credit
            WHERE
                student_id = '$request->studentId'
                AND semester_id = '$request->semId'";
            $additionalCreditDetails = $this->executeQueryForObject($sql);
            if ($additionalCreditDetails->id) {
                if ($request->status == StatusConstants::APPROVED) {
                    $sqlUpdate = "UPDATE
                        semester_additional_credit sac
                    INNER JOIN additional_credit_application aca ON
                        aca.semester_id = sac.semester_id
                        AND aca.student_id = sac.student_id
                    INNER JOIN additional_credit_application_credits acac ON
                        acac.application_id = aca.id
                    SET sac.additional_credit =    sac.additional_credit+acac.credit,
                        sac.application_ids = JSON_ARRAY_APPEND(sac.application_ids,'$','$request->applicationId'),
                        sac.updated_by = '$request->staffId'
                    WHERE
                        aca.student_id = '$request->studentId'
                        AND aca.semester_id = '$request->semId'
                        AND acac.status = '$request->status'
                        AND acac.application_id = '$request->applicationId'
                        AND NOT JSON_CONTAINS(application_ids,'$applicationIdArrayJson')";
                } else if ($request->status == StatusConstants::REJECTED) {
                    $sqlUpdate = "UPDATE
                        semester_additional_credit sac
                    INNER JOIN additional_credit_application aca ON
                        aca.semester_id = sac.semester_id
                        AND aca.student_id = sac.student_id
                    INNER JOIN additional_credit_application_credits acac ON
                        acac.application_id = aca.id
                    SET sac.additional_credit =    sac.additional_credit-acac.credit,
                        sac.application_ids = JSON_REMOVE(application_ids,JSON_UNQUOTE(JSON_SEARCH(application_ids,'one','$request->applicationId'))),
                        sac.updated_by = '$request->staffId'
                    WHERE
                        aca.student_id = '$request->studentId'
                        AND aca.semester_id = '$request->semId'
                        AND acac.status = '$request->status'
                        AND acac.application_id = '$request->applicationId'
                        AND JSON_CONTAINS(application_ids,'$applicationIdArrayJson')";
                }
                $this->executeQuery($sqlUpdate);
                $additionalCreditDetailsAfterUpdation = $this->executeQueryForObject($sql);
                if ($additionalCreditDetailsAfterUpdation->additionalCredit <= 0) {
                    $request->semAdditionalCreditDetailsId = $additionalCreditDetailsAfterUpdation->id;
                    $this->removeStudentSemesterwiseAdditionalCredit($request);
                }
            } else if ($request->status == StatusConstants::APPROVED) {
                $this->addStudentSemesterwiseAdditionalCredit($request);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $request
     * @throws ProfessionalException
     */
    public function addStudentSemesterwiseAdditionalCredit($request)
    {
        $request = $this->realEscapeObject($request);
        $approvedStatusConstants = StatusConstants::APPROVED;
        if (empty($request->studentId) || empty($request->semId) || empty($request->staffId) || empty($request->applicationId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Invalid request sent");
        }
        $applicationIdArrayJson = '["' . $request->applicationId . '"]';
        $sql = "INSERT INTO semester_additional_credit(
            semester_id,
            student_id,
            additional_credit,
            application_ids,
            created_by
        )
        SELECT
            $request->semId,
            $request->studentId,
            acac.credit,
            '$applicationIdArrayJson',
            $request->staffId
        FROM
            additional_credit_application_credits acac 
        WHERE
            acac.status = '$approvedStatusConstants'
            AND acac.application_id = '$request->applicationId'";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $request
     * @throws ProfessionalException
     */
    public function removeStudentSemesterwiseAdditionalCredit($request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->semAdditionalCreditDetailsId)) {
            if (empty($request->studentId) || empty($request->semId)) {
                throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Invalid request sent");
            } else {
                $sql = "DELETE FROM semester_additional_credit WHERE semester_id = '$request->semId' AND student_id = '$request->studentId'";
            }
        } else {
            $sql = "DELETE FROM semester_additional_credit WHERE id = '$request->semAdditionalCreditDetailsId'";
        }
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $studentId, $secbid, $resourceId
     * @return Object
     * @throws ProfessionalException
     */
    public function createSecCreditItems($studentId, $secbid, $resourceId, $itemName)
    {
        $studentId = $this->realEscapeString($studentId);
        $secbid = $this->realEscapeString($secbid);
        $resourceId = $this->realEscapeString($resourceId);
        $itemName = $this->realEscapeString($itemName);
        $duplicateAvoidance = "SELECT id FROM sec_students WHERE sec_batch_id =$secbid  and  student_id = $studentId";
        $entries = $this->executeQueryForList($duplicateAvoidance);
        if( count($entries) > 0){
            foreach ($entries as $entry) {
                $sqlDeleteExecute = "DELETE FROM sec_students WHERE id = $entry->id";
                $this->executeQuery($sqlDeleteExecute);
            }
        }
        $sql = "INSERT INTO `sec_students` (`student_id`,
                                             `sec_batch_id`,
                                             `created_by`,
                                             `updated_by`,
                                             `created_date`,
                                             `status`,
                                             `item_name`,
                                             `resource_id`,
                                             `remarks`,
                                             `updated_date`) 
                                             VALUES 
                                                ($studentId,
                                                 $secbid,
                                                 $studentId,
                                                 NULL,
                                                 NOW(),
                                                 0,
                                                 '$itemName',
                                                 '$resourceId',
                                                 '',
                                                 NULL)";
        try {
            $id = $this->executeQueryForObject($sql, true);
            $this->logger->info(Events::SEC_CREDIT_ITEM_CREATION, [
                "userId" => $studentId,
                "userType" => UserType::STUDENT,
                "additionCreditItem" => new SecCreditItem(["id" => $id]),
                "status" => StatusConstants::SUCCESS
            ]);
            return $id;
        } catch (\Exception $e) {
            $this->logger->error(Events::SEC_CREDIT_ITEM_CREATION, [
                "userId" => $studentId,
                "userType" => UserType::STUDENT,
                "itemName" => $itemName,
                "status" => StatusConstants::FAILED,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getSecApplication($secBatchId, $studentID)
    {
        $secBatchId = $this->realEscapeString($secBatchId);
        $studentID = $this->realEscapeString($studentID);
        try{
            $sql = "SELECT id,
                        item_name,
                        resource_id,
                        updated_date,
                        created_date,
                        status,
                        remarks 
                        from sec_students 
                        WHERE student_id = '$studentID
                            and resource_id != ''
                        and item_name != ''
                        ORDER BY created_date DESC";
            return $this->executeQueryForList($sql);
        }
        catch (\Exception $e) {
           
        }
    }
    /**
     * Deleting additional credit applications by application id. This wil delete entire application details without
     * checking the application is approved or not
     * @param $id, $secretKey, $accessKey
     * @throws ProfessionalException
     */
    public function deleteSecApplication($id,$resourseId, $secretKey, $accessKey)
    {
        $id = $this->realEscapeString($id);
        $resourseId = $this->realEscapeString($resourseId);
        $secretKey = $this->realEscapeString($secretKey);
        $accessKey = $this->realEscapeString($accessKey);
        $studentID = $_SESSION['studentID'];
        if (empty($id)) {
            throw new ProfessionalException(ProfessionalException::INVALID_ADDITIONAL_CREDIT_APPLICATION_ID, "Invalid additional credit application or application doesn't exist");
        }
        try {
            $sql = "DELETE FROM sec_students WHERE  id = $id";
            $this->executeQuery($sql);
            if($resourseId)
            {
                $removeResourceRequest = new RemoveResourceRequest();
                $removeResourceRequest->accessKey = $accessKey;
                $removeResourceRequest->secretKey = $secretKey;
                $removeResourceRequest->resourceId = $resourseId;
                ResourceService::getInstance()->removeResource($removeResourceRequest);
            }
            $this->logger->info(Events::SEC_CREDIT_ITEM_DELETION, [
                "userId" => $studentID,
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::SUCCESS
            ]);
        } catch (\Exception $e) {
            $this->logger->error(Events::SEC_CREDIT_ITEM_DELETION, [
                "userId" => $studentID,
                "userType" => UserType::STUDENT,
                "status" => StatusConstants::FAILED,
                "error" => $e->getCode(),
                "message" => $e->getMessage()
            ]);
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getSecApplicationsBySecBatchId($secBatchId)
    {
        $secBatchId = $this->realEscapeString($secBatchId);
        try{
            $sql = "SELECT
                        s.studentID ,
                        s.studentName ,
                        s.regNo ,
                        ss.id as resourceEntry,
                        ss.item_name ,
                        ss.resource_id ,
                        ss.remarks ,
                        ss.updated_date ,
                        ss.student_id as sec_student_id,
                        ss.status
                    from
                        studentaccount s
                    inner join sec_batches sb on
                        sb.batch_id = s.batchID
                    left join sec_students ss on ss.student_id = s.studentID  
                    WHERE
                        s.batchID = sb.batch_id
                        and sb.id = $secBatchId
                        ORDER BY s.studentName ASC,ss.created_date DESC";
            return $this->executeQueryForList($sql);
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function updateSecStudentStatus($resourceEntry, $status,$remarks)
    {
        $resourceEntry = $this->realEscapeString($resourceEntry);
        $status = (Int) $this->realEscapeString($status);
        $remarks = $this->realEscapeString($remarks);
        $staffID = $_SESSION['staffID'];
        try{
            $sql = "UPDATE sec_students SET updated_by = '$staffID',status ='$status',remarks ='$remarks',updated_date = NOW() WHERE id = '$resourceEntry";
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        $this->executeQuery($sql);
    }
}