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 / 47
CRAP
0.00% covered (danger)
0.00%
0 / 813
FeeService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 47
18906.00
0.00% covered (danger)
0.00%
0 / 813
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 3
 __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
 getStudentAssignedFees
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 19
 getStudentAssignedFeeHeads
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 deleteAssignedFeeHead
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 isFeeHeadPaid
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getStudentNotAssignedFeeHeads
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getStudentNotAssignedFineFeeHeads
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 createFeeHead
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getFeeHeadByCode
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 updateFeeHead
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 getFeeHeads
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getFineFeeHeads
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 deleteFeeHead
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 assignFeeHeadsToStudents
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 17
 updateStudentFees
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getStudentPaymentDetailsByBatch
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 23
 getStudentPaymentDetailsByStudentId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 saveStudentPaymentDetails
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 29
 getStudentPendingPaymentDetailsByBatch
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 updatePriority
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 15
 updateStudentAssignedFees
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 22
 searchPaymentHistory
0.00% covered (danger)
0.00%
0 / 1
240.00
0.00% covered (danger)
0.00%
0 / 52
 getBillDetailsByStudent
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 29
 getReceiptDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 51
 getBillDetailsByBillNo
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 51
 addStudentFeeRemittedDetails
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 12
 getFeeCollectionReport
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 getStudentPendingPaymentDetailsStudentId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 addStudentChallanDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getStudentChallanDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 addChallanFeeHeadDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getChallanFeeHeadByChallanId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 verifyStudentChallan
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 40
 isStudentChallan
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 24
 constructStudentRemittedFeesList
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 21
 constructPaymentRequest
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getCountOfNotVerifedChallanByStudent
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getChallanByTranscationId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 initiatePayment
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 53
 getStudentFeeOnlinePaymentReq
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 processStudentOnlineFeePaymentFailure
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 processStudentOnlineFeePaymentSuccess
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 38
 verifyStudentOnlineFeePayment
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 16
 getSupplyExamCommonFees
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getSupplyExamSubjectFees
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
<?php
namespace com\linways\core\ams\professional\service;
use com\linways\core\ams\professional\dto\SettingsConstents;
use com\linways\core\ams\professional\dto\StudentFeeRemittedDetails;
use com\linways\core\ams\professional\dto\StudentRemittedFees;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\mapper\FeeServiceMapper;
use com\linways\core\ams\professional\request\ExecutePaymentRequest;
use com\linways\core\ams\professional\request\SearchPaymentHistoryRequest;
use com\linways\core\ams\professional\response\SearchPaymentHistoryResponse;
use com\linways\core\ams\professional\util\CommonUtil;
use com\linways\core\ams\professional\dto\FeeHead;
use com\linways\core\ams\professional\dto\StudentFees;
use com\linways\core\ams\professional\dto\StudentIssuedChallan;
use com\linways\core\ams\professional\dto\ChallanFeeHeadDetails;
use com\linways\core\ams\professional\dto\fee\StudentFeeOnlinePaymentReq;
use com\linways\base\util\StringUtil;
class FeeService extends BaseService
{
    // private $batchService = BatchService::getInstance();
    // /Condition 1 - Presence of a static member variable
    private static $_instance = null;
    private $mapper = [];
    // /Condition 2 - Locked down the constructor
    private function __construct()
    {
        $this->mapper = FeeServiceMapper::getInstance()->getMapper();
    }
    // Prevent any oustide 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;
    }
    /**
     * get fee assigned students
     *
     * @param int $batchId
     * @param int $semId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentAssignedFees($batchId, $semId, $studentName, $sortBy = 'rollNo', $sortOrder = 'ASC')
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $staffName = $this->realEscapeString($staffName);
        $sortBy = $this->realEscapeString($sortBy);
        $sortOrder = $this->realEscapeString($sortOrder);
        $sql = "SELECT sfs.id as feeId, sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id AS headId, fh.name,fh.code,fh.amount, sfs.batchId, sfs.semID, sfs.fees, (SELECT sum(fees) FROM studentfees_feesasigned_studentwise WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees FROM studentaccount sa INNER JOIN studentfees_feesasigned_studentwise sfs ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId INNER JOIN studentfees_feesasigned_batchwise sfb ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId WHERE sa.batchID=$batchId  AND fh.isFineHead=0 AND sfb.isActive=1 ";
        if ($studentName) {
            $sql .= "AND sa.studentName like '%" . $studentName . "%' ";
        }
        $sql .= "ORDER BY sa.$sortBy $sortOrder, sfs.priority, sfs.feeHeadId";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_STUDENT_FEES]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * get fee assigned students
     *
     * @param int $batchId
     * @param int $semId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentAssignedFeeHeads($batchId, $semId)
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sql = "SELECT distinct fh.id AS headId, fh.name, fh.code, sfb.fees, sfb.priority FROM studentfees_feesasigned_batchwise sfb INNER JOIN feeHead fh ON fh.id=sfb.feeHeadId WHERE sfb.batchID=$batchId AND sfb.semID=$semId AND sfb.isActive=1 AND fh.isFineHead=0 ORDER BY sfb.priority, fh.id";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_FEE_HEADS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * delete assigned fee head from batch(soft delete using active flag)
     *
     * @param int $batchId
     * @param int $semId
     * @param int $headId
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function deleteAssignedFeeHead($batchId, $semId, $headId)
    {
        $sql = "delete from studentfees_feesasigned_batchwise WHERE batchID=$batchId AND semID=$semId AND feeHeadId=$headId";
        $sqlStudentDelete = "delete from studentfees_feesasigned_studentwise where batchID=$batchId AND semID=$semId AND feeHeadId=$headId";
        try {
            $this->executeQueryForObject($sql);
            return $this->executeQueryForObject($sqlStudentDelete);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get count of feehead paid by feeHeadId
     *
     * @param int $batchId
     * @param int $semId
     * @param int $headId
     * @throws ProfessionalException
     * @return boolean
     */
    public function isFeeHeadPaid($batchId, $semId, $headId)
    {
        $paid = true;
        $sql = "SELECT COUNT(sr.remittedfeeID) as totalCount FROM studentfees_remittedfees sr INNER JOIN studentfees_feesasigned_studentwise sfs ON sfs.id = sr.feesId AND sfs.semID=sr.semID WHERE sfs.batchId=$batchId AND sfs.semID=$semId AND sfs.feeHeadId=$headId";
        try {
            $totalCount = $this->executeQueryForObject($sql)->totalCount;
            if (!$totalCount) {
                $paid = false;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $paid;
    }
    /**
     * get fee assigned students
     *
     * @param int $batchId
     * @param int $semId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentNotAssignedFeeHeads($batchId, $semId)
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sql = "SELECT DISTINCT fh.id AS headId, fh.name, fh.code, fh.amount, sfs.feeHeadId  FROM feeHead fh LEFT JOIN studentfees_feesasigned_studentwise sfs ON sfs.feeHeadId=fh.id AND sfs.batchID=$batchId AND sfs.semID=$semId WHERE sfs.feeHeadId IS NULL AND fh.isFineHead=0 ORDER BY sfs.priority, fh.id";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_FEE_HEADS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * get fee assigned students
     *
     * @param int $batchId
     * @param int $semId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentNotAssignedFineFeeHeads($batchId, $semId)
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sql = "SELECT DISTINCT fh.id AS headId, fh.name, fh.code, fh.amount, sfs.feeHeadId  FROM feeHead fh LEFT JOIN studentfees_feesasigned_studentwise sfs ON sfs.feeHeadId=fh.id AND sfs.batchID=$batchId AND sfs.semID=$semId WHERE sfs.feeHeadId IS NULL AND fh.isFineHead=1 ORDER BY sfs.priority, fh.id";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_FEE_HEADS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * create fee heads
     *
     * @param FeeHead $feeHead
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function createFeeHead($feeHead)
    {
        $sql = "INSERT INTO feeHead (name, code, amount, isFineHead, createdBy, createdDate, updatedBy, updatedDate)
VALUES ('$feeHead->name','$feeHead->code',0, $feeHead->isFineHead$feeHead->createdBy,utc_timestamp(),$feeHead->updatedBy,utc_timestamp())";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get fee heads
     *
     * @param FeeHead $feeHead
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function getFeeHeadByCode($feeHeadCode)
    {
        $sql = "select * from feeHead where code = '$feeHeadCode'";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * update fee Heads
     *
     * @param FeeHead $feeHead
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function updateFeeHead($feeHead)
    {
        $sql = "UPDATE feeHead SET name='$feeHead->name', code='$feeHead->code', isFineHead='$feeHead->isFineHead', updatedBy=$feeHead->updatedBy, updatedDate=utc_timestamp() WHERE id=$feeHead->id";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get all fee heads
     *
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getFeeHeads($showFineHead = false)
    {
        $feeHeads = [];
        if (!$showFineHead) {
            $cond = "WHERE isFineHead=0";
        }
        $sql = "SELECT id AS headId, name, code, amount, isFineHead FROM feeHead $cond ORDER BY id";
        try {
            $feeHeads = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_FEE_HEADS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $feeHeads;
    }
    /**
     * get all fine fee heads
     *
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getFineFeeHeads()
    {
        $feeHeads = [];
        $sql = "SELECT id AS headId, name, code, amount, isFineHead FROM feeHead WHERE isFineHead=1 ORDER BY id";
        try {
            $feeHeads = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_FEE_HEADS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $feeHeads;
    }
    /**
     * remove fee heads
     *
     * @param int $feeHeadId
     * @throws ProfessionalException
     */
    public function deleteFeeHead($feeHeadId)
    {
        $sql = "DELETE FROM feeHead WHERE id=$feeHeadId";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     *
     * @param
     *            array of StudentFees $studentFeeList
     * @throws ProfessionalException
     */
    public function assignFeeHeadsToStudents($studentFeeList)
    {
        $studentFeeList = $this->realEscapeArray($studentFeeList);
        try {
            if (!empty($studentFeeList) && $studentFeeList != null) {
                foreach ($studentFeeList as $studentFee) {
                    $sql = "INSERT INTO studentfees_feesasigned_studentwise ( studentID, batchId, semID, feeHeadId, fees, priority) SELECT studentID, batchID, $studentFee->semId,$studentFee->feeHeadId, '$studentFee->fee', '$studentFee->priority' FROM studentaccount WHERE batchID=$studentFee->batchId";
                    $this->executeQueryForObject($sql);
                    $value[] = "($studentFee->batchId$studentFee->semId$studentFee->fee$studentFee->feeHeadId$studentFee->priority)";
                }
                $sql_batch = "INSERT INTO studentfees_feesasigned_batchwise (batchID, semID, fees, feeHeadId, priority) VALUES ";
                $sql_batch .= implode(',', $value);
                $this->executeQueryForObject($sql_batch);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * update student fees
     *
     * @param StudentFees $studentFee
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function updateStudentFees($studentFee)
    {
        $studentFee = $this->realEscapeObject($studentFee);
        $sql = "UPDATE studentfees_feesasigned_studentwise SET fees=$studentFee->fee WHERE id=$studentFee->id";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get student payment details by batch and sem id
     *
     * @param int $batchId
     * @param int $semId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentPaymentDetailsByBatch($batchId, $semId, $studentName=null, $sortBy = 'rollNo', $sortOrder = 'ASC', $admissionNo = '')
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentName = $this->realEscapeString($studentName);
        $sortBy = $this->realEscapeString($sortBy);
        $sortOrder = $this->realEscapeString($sortOrder);
        $admissionNo = $this->realEscapeString($admissionNo);
        $cond = '';
        if ($studentName) {
            $cond = "AND sa.studentName like '%" . $studentName . "%' ";
        }
        if ($admissionNo) {
            $cond .= "AND sa.admissionNo like '%" . $admissionNo . "%' ";
        }
        $sql = "SELECT studentID,studentName,rollNo,admissionNo,headId,name,code,fees,remittedAmt, remittedDate, totalFees, totalPaid, totalRemitted-totalFine,  (totalFees-totalPaid)+totalFine as totalBalance, fees-totalRemitted as feeHeadBalance,remittedfeeID, balanceAmt, priority, feeId, totalFine FROM(SELECT sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id AS headId, fh.name,fh.code,fh.amount, sfs.batchId, sfs.semID, sfs.fees,  sfs.priority,  (SELECT sum(fees) FROM studentfees_feesasigned_studentwise WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees,sfs.id as feeId,if(sr.remittedAmt,sr.remittedAmt,0) as remittedAmt, sr.remittedDate, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID)as totalPaid, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID AND feesId=sfs.id)as totalRemitted, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr INNER JOIN studentfees_feesasigned_studentwise stfs ON stfs.id=sfr.feesId INNER join feeHead fhs ON stfs.feeHeadId=fhs.id WHERE sfr.studentID=sfs.studentID AND sfr.semID=sfs.semID AND fhs.isFineHead=1)as totalFine, sr.remittedfeeID, sr.balanceAmt FROM studentaccount sa INNER JOIN studentfees_feesasigned_studentwise sfs ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId INNER JOIN studentfees_feesasigned_batchwise sfb ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId LEFT JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id WHERE sa.batchID=$batchId AND sfb.isActive=1 AND fh.isFineHead=0 $cond ORDER BY sa.$sortBy $sortOrder ,fh.isFineHead, sfs.priority, fh.id, sr.remittedfeeID)as paymentDetails";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_STUDENT_PAYMENT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * get student payment details by student id
     *
     * @param int $batchId
     * @param int $semId
     * @param int $studentId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentPaymentDetailsByStudentId($batchId, $semId, $studentId)
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sql = "SELECT studentID,studentName,rollNo,admissionNo, headId,name,code,fees,remittedAmt, remittedDate, totalFees, totalPaid , totalRemitted, (totalFees-totalPaid)+totalFine as totalBalance, fees-totalRemitted as feeHeadBalance,remittedfeeID, balanceAmt, priority, feeId, isFineHead, totalFine FROM(SELECT sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id as headId, fh.name,fh.code,fh.amount, sfs.batchId, sfs.semID, sfs.fees,  sfs.priority, fh.isFineHead, sr.billNo,  (SELECT sum(fees) FROM studentfees_feesasigned_studentwise WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees,sfs.id as feeId,if(sr.remittedAmt,sr.remittedAmt,0) as remittedAmt, sr.remittedDate, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID)as totalPaid, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID AND feesId=sfs.id)as totalRemitted, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr INNER JOIN studentfees_feesasigned_studentwise stfs ON stfs.id=sfr.feesId INNER join feeHead fhs ON stfs.feeHeadId=fhs.id WHERE sfr.studentID=sfs.studentID AND sfr.semID=sfs.semID AND fhs.isFineHead=1)as totalFine, sr.remittedfeeID, sr.balanceAmt FROM studentaccount sa INNER JOIN studentfees_feesasigned_studentwise sfs ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId INNER JOIN studentfees_feesasigned_batchwise sfb ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId LEFT JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id WHERE sa.batchID=$batchId AND sfb.isActive=1 AND sa.studentID=$studentId ORDER BY sa.rollNo,fh.isFineHead, sfs.priority, fh.id, sr.remittedfeeID)as paymentDetails";
        try {
            $studentList = $this->executeQueryForObject($sql, false, $this->mapper[FeeServiceMapper::GET_STUDENT_PAYMENT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * save student payment details
     *
     * @param
     *            array of StudentRemittedFees $studentRemittedFeesList
     * @param StudentFeeRemittedDetails $paymentDetails
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function saveStudentPaymentDetails($studentRemittedFeesList, $paymentDetails)
    {
        $paymentDateStr = null;
        $valueStr = null;
        $studentRemittedFeesList = $this->realEscapeArray($studentRemittedFeesList);
        $paymentDetails = $this->realEscapeObject($paymentDetails);
        $billNo = CommonService::getInstance()->getSettings(SettingsConstents::STUDENT_FEES, SettingsConstents::STUDENT_FEES_BILL_NO_LAST);
        $billNo++;
        $billNo = CommonService::getInstance()->appendZero($billNo, 3);
        CommonService::getInstance()->updateSettings(SettingsConstents::STUDENT_FEES, SettingsConstents::STUDENT_FEES_BILL_NO_LAST, $billNo);
        $paymentDetails->billNo = $billNo;
        if (!empty($studentRemittedFeesList)) {
            $value = [];
            $sql = "INSERT INTO studentfees_remittedfees (studentID, semID, remittedAmt, remittedDate, balanceAmt, feesId, billNo, paymentMethod, createdBy, updatedBy, createdDate, updatedDate) VALUES ";
            foreach ($studentRemittedFeesList as $studentRemittedFees) {
                $paymentDateStr = empty($paymentDetails->date) ? 'utc_timestamp()' : "'$paymentDetails->date'";
                $valueStr = "($studentRemittedFees->studentID$studentRemittedFees->semID$studentRemittedFees->remittedAmt, {{paymentDate}},$studentRemittedFees->balanceAmt$studentRemittedFees->feesId, '$billNo','$studentRemittedFees->paymentMethod', $studentRemittedFees->createdBy$studentRemittedFees->updatedBy, utc_timestamp(), utc_timestamp())";
                $tags = ['paymentDate' => $paymentDateStr];
                $valueStr = StringUtil::replace_tags($valueStr, $tags);
                $value[] = $valueStr;
            }
            $sql .= implode(',', $value);
        }
        try {
            $this->executeQueryForObject($sql);
            return $this->addStudentFeeRemittedDetails($paymentDetails);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get student payment details by batch and sem id
     *
     * @param int $batchId
     * @param int $semId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentPendingPaymentDetailsByBatch($batchId, $semId)
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sql = "SELECT studentID,studentName,rollNo,admissionNo,headId,name,code,fees,remittedAmt, remittedDate, totalFees, totalPaid, totalRemitted, (totalFees-totalPaid)+totalFine as totalBalance, fees-totalRemitted as feeHeadBalance,remittedfeeID, balanceAmt, priority, feeId, totalFine FROM(SELECT sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id AS headId, fh.name,fh.code,fh.amount, sfs.batchId, sfs.semID, sfs.fees,  sfs.priority,  (SELECT sum(fees) FROM studentfees_feesasigned_studentwise WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees,sfs.id as feeId,if(sr.remittedAmt,sr.remittedAmt,0) as remittedAmt, sr.remittedDate, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID)as totalPaid, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID AND feesId=sfs.id)as totalRemitted, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr INNER JOIN studentfees_feesasigned_studentwise stfs ON stfs.id=sfr.feesId INNER join feeHead fhs ON stfs.feeHeadId=fhs.id WHERE sfr.studentID=sfs.studentID AND sfr.semID=sfs.semID AND fhs.isFineHead=1)as totalFine, sr.remittedfeeID, sr.balanceAmt FROM studentaccount sa INNER JOIN studentfees_feesasigned_studentwise sfs ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId INNER JOIN studentfees_feesasigned_batchwise sfb ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId LEFT JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id WHERE sa.batchID=$batchId AND sfb.isActive=1 AND fh.isFineHead=0 ORDER BY sa.rollNo, fh.isFineHead, sfs.priority, fh.id, sr.remittedfeeID)as paymentDetails WHERE totalFees !=totalPaid";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_STUDENT_PAYMENT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * update priority
     *
     * @param array $studentFeeList
     * @throws ProfessionalException
     */
    public function updatePriority($studentFeeList)
    {
        $studentFeeList = $this->realEscapeArray($studentFeeList);
        try {
            if (!empty($studentFeeList) && $studentFeeList != null) {
                foreach ($studentFeeList as $studentFee) {
                    $sql = "UPDATE studentfees_feesasigned_studentwise SET priority=$studentFee->priority WHERE batchId=$studentFee->batchId AND semID=$studentFee->semId AND feeHeadId=$studentFee->feeHeadId";
                    $sql_batch = "UPDATE studentfees_feesasigned_batchwise SET priority=$studentFee->priority WHERE batchID=$studentFee->batchId AND semID=$studentFee->semId AND feeHeadId=$studentFee->feeHeadId";
                    $this->executeQueryForObject($sql);
                    $this->executeQueryForObject($sql_batch);
                }
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * update student batch assigned fees
     *
     * @param int $batchId
     * @param int $semId
     * @param int $headId
     * @param float $fees
     * @param float $prevAmount
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function updateStudentAssignedFees($batchId, $semId, $headId, $fees, $prevAmount)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $headId = $this->realEscapeString($headId);
        $fees = $this->realEscapeString($fees);
        $prevAmount = $this->realEscapeString($prevAmount);
        $excess = $fees - $prevAmount;
        $sql = "UPDATE studentfees_feesasigned_studentwise SET fees=$fees WHERE batchId=$batchId AND semID=$semId AND feeHeadId=$headId";
        $sql_batch = "UPDATE studentfees_feesasigned_batchwise SET fees=$fees WHERE batchID=$batchId AND semID=$semId AND feeHeadId=$headId";
        try {
            $this->executeQueryForObject($sql);
            $this->executeQueryForObject($sql_batch);
            $sql_fee = "select group_concat(sfs.id) as feeIds from studentfees_feesasigned_studentwise sfs INNER JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id WHERE sfs.semID=$semId AND sfs.batchId=$batchId AND sfs.feeHeadId=$headId";
            $feeIds = $this->executeQueryForObject($sql_fee)->feeIds;
            if ($feeIds) {
                $sql_balance = "update studentfees_remittedfees sr set sr.balanceAmt=balanceAmt+$excess WHERE sr.feesId IN ($feeIds)";
                return $this->executeQueryForObject($sql_balance);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param SearchPaymentHistoryRequest $request
     * @return SearchPaymentHistoryResponse
     * @throws ProfessionalException
     */
    public function searchPaymentHistory(SearchPaymentHistoryRequest $request)
    {
        $conditions = "";
        $paymentHistory = null;
        $response = new SearchPaymentHistoryResponse();
        $limit = "";
        if (empty($request->studentId))
            throw new ProfessionalException("INVALID_STUDENT_ID", "Select a valid student");
        if (!empty($request->semesters))
            $conditions .= " AND rf.semID IN (" . implode(',', $request->semesters) . ")";
        if ((!empty($request->fromDate) && empty($request->toDate))) {
            $conditions .= " AND rf.remittedDate >= '" . date('Y-m-d H:i:s', strtotime($request->fromDate)) . "'";
        } else if (empty($request->fromDate) && !empty($request->toDate)) {
            $conditions .= " AND rf.remittedDate <= '" . date('Y-m-d H:i:s', strtotime($request->toDate)) . "'";
        } else if (!empty($request->fromDate) && !empty($request->toDate))
            $conditions .= " AND rf.remittedDate BETWEEN '" . date('Y-m-d H:i:s', strtotime($request->fromDate)) . "'
              AND '" . date('Y-m-d H:i:s', strtotime($request->toDate)) . "'";
        if (!empty($request->paymentMode))
            $conditions .= " AND rf.paymentMethod='" . $request->paymentMode . "'";
        /**
         * Payement mode wise filtering
         */
        if ($request->startIndex !== "" || $request->studentId != null)
            $limit = " LIMIT $request->startIndex$request->endIndex";
        $totalRecordsSql = "SELECT COUNT(DISTINCT rf.billNo) as totalRecords
                FROM `studentfees_remittedfees` rf
                INNER JOIN studentaccount sa ON sa.`studentID`= rf.`studentID`
                INNER JOIN semesters s ON s.`semID`=rf.`semID`
                WHERE rf.studentID=$request->studentId " . $conditions;
        $sql = "SELECT SUM(rf.remittedAmt) as amount,sa.studentID, s.`semID`,sa.studentName,
                      DATE_FORMAT(CONVERT_TZ(rf.remittedDate,'+00:00',@@global.time_zone),'%d-%m-%Y %h:%i %p') as remittedDate, 
                      s.semName, sa.admissionNo,sa.rollNo, if(rf.billNo,rf.billNo,'f') as billNo, rf.`paymentMethod`
                FROM `studentfees_remittedfees` rf
                INNER JOIN studentaccount sa ON sa.`studentID`= rf.`studentID`
                INNER JOIN semesters s ON s.`semID`=rf.`semID`
                WHERE rf.studentID=$request->studentId " . $conditions . "  GROUP BY rf.`billNo` 
                ORDER BY rf.remittedDate DESC, rf.billNo DESC" . $limit;
        try {
            $response->totalRecords = $this->executeQueryForObject($totalRecordsSql)->totalRecords;
            $paymentHistory = $this->executeQueryForObject($sql, false, $this->mapper[FeeServiceMapper::GET_ALL_RECEIPTS_OF_STUDENT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        foreach ($paymentHistory->receipts as $receipt) {
            $billPrefix = "";
            try {
                $billPrefix = CommonService::getInstance()->getSettings(SettingsConstents::STUDENT_FEES, SettingsConstents::STUDENT_FEES_BILL_NO_PREFIX);
            } catch (\Exception $e) {
            }
            $billPrefix = str_replace('{{year}}', date('Y', strtotime($receipt->receiptDate)), $billPrefix);
            $receipt->receiptNumber = CommonService::getInstance()->appendZero($receipt->receiptNumber, 3);
            $receipt->receiptNumber = $billPrefix . $receipt->receiptNumber;
        }
        $response->paymentHistory = $paymentHistory;
        return $response;
    }
    public function getBillDetailsByStudent($batchId, $semId, $studentId, $billNo = 0)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $billNo = $this->realEscapeString($billNo);
        $billDetails = null;
        if ($billNo) {
            $cond = "AND sr.billNo = $billNo ";
        }
        $sql = "select sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id, fh.name, sr.remittedfeeID, 
                        CONVERT_TZ(sr.remittedDate,'+00:00',@@global.time_zone) as remittedDate, 
                        if(sr.billNo,sr.billNo,'f') as billNo, sfs.fees, sr.remittedAmt, sr.balanceAmt, 
                        fh.isFineHead, sr.paymentMethod 
                from studentfees_feesasigned_studentwise sfs 
                LEFT JOIN studentfees_remittedfees sr ON sfs.id=sr.feesId AND sr.semID=sfs.semID $cond 
                LEFT JOIN studentfees_feesasigned_batchwise sfb ON sfb.feeHeadId=sfs.feeHeadId 
                      AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID 
                LEFT JOIN feeHead fh ON fh.id=sfs.feeHeadId 
                LEFT JOIN studentaccount sa ON sa.studentID=sfs.studentID AND sa.batchID=sfs.batchId 
                WHERE sfs.studentID=$studentId AND sfs.batchId=$batchId 
                AND sfs.semID=$semId AND sfb.isActive=1 ";
        $sql .= "order by fh.isFineHead, sr.remittedDate, sr.billNo, sfs.priority";
        try {
            $billDetails = $this->executeQueryForObject($sql, FALSE, $this->mapper[FeeServiceMapper::GET_STUDENT_BILL_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $billDetails;
    }
    public function getReceiptDetails($semId, $studentId, $billNo = 0, $billDate)
    {
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $billNo = $this->realEscapeString($billNo);
        $billDate = $this->realEscapeString($billDate);
        $billDate = date('Y-m-d', strtotime($billDate));
        $billDetails = null;
        $sql = "SELECT studentID,studentName,rollNo,admissionNo,if(billNo,billNo,'f') as billNo, paymentMethod, 
                        id,name,code,fees,remittedAmt,totalFees, 
                        CONVERT_TZ(remittedDate,'+00:00',@@global.time_zone) as remittedDate, 
                        (totalPaid-totalFine) as totalPaid , totalRemitted, 
                        (totalFees-totalPaid)+totalFine as totalBalance, fees-totalRemitted as feeHeadBalance,
                        remittedfeeID, balanceAmt, priority, feeId, isFineHead,totalFine ,batchName
                FROM ( SELECT sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id, fh.name,fh.code,fh.amount, 
                              sfs.batchId, sfs.semID, sfs.fees,  sfs.priority, fh.isFineHead, sr.billNo, b.batchName,
                              sr.paymentMethod,  
                              (SELECT sum(fees) 
                                FROM studentfees_feesasigned_studentwise 
                                WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees,
                              sfs.id as feeId, if(sr.remittedAmt,sr.remittedAmt,0) as remittedAmt, sr.remittedDate, 
                              (SELECT if(sum(remittedAmt),sum(remittedAmt),0) 
                                FROM studentfees_remittedfees sfr 
                                WHERE studentID=sfs.studentID AND semID=sfs.semID AND 
                                DATE(sfr.remittedDate) <= '$billDate')as totalPaid, 
                              (SELECT if(sum(remittedAmt),sum(remittedAmt),0) 
                                FROM studentfees_remittedfees sfr 
                                WHERE studentID=sfs.studentID AND semID=sfs.semID AND feesId=sfs.id 
                                AND DATE(sfr.remittedDate) <= '$billDate')as totalRemitted, 
                              (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr 
                                INNER JOIN studentfees_feesasigned_studentwise stfs ON stfs.id=sfr.feesId 
                                INNER join feeHead fhs ON stfs.feeHeadId=fhs.id WHERE sfr.studentID=sfs.studentID 
                                AND sfr.semID=sfs.semID AND DATE(sfr.remittedDate) <= '$billDate
                                AND fhs.isFineHead=1)as totalFine, 
                              sr.remittedfeeID, sr.balanceAmt 
                      FROM studentaccount sa 
                      INNER JOIN studentfees_feesasigned_studentwise sfs 
                          ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId 
                      INNER JOIN studentfees_feesasigned_batchwise sfb 
                          ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID 
                      INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId 
                      INNER JOIN batches b ON b.batchID =sfb.batchID
                      LEFT JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id AND sr.billNo=$billNo 
                      WHERE sfb.isActive=1 
                        AND sa.studentID=$studentId)as paymentDetails";
        try {
            $billDetails = $this->executeQueryForObject($sql, FALSE, $this->mapper[FeeServiceMapper::GET_STUDENT_BILL_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $billDetails;
    }
    public function getBillDetailsByBillNo($batchId, $semId, $studentId, $billNo = 0, $billDate)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $billNo = $this->realEscapeString($billNo);
        $billDate = $this->realEscapeString($billDate);
        $billDate = date('Y-m-d', strtotime($billDate));
        $billDetails = null;
        $sql = "SELECT studentID,studentName,rollNo,admissionNo,if(billNo,billNo,'f') as billNo, paymentMethod, 
                        id,name,code,fees,remittedAmt,totalFees, 
                        CONVERT_TZ(remittedDate,'+00:00',@@global.time_zone) as remittedDate, 
                        (totalPaid-totalFine) as totalPaid , totalRemitted, 
                        (totalFees-totalPaid)+totalFine as totalBalance, fees-totalRemitted as feeHeadBalance,
                        remittedfeeID, balanceAmt, priority, feeId, isFineHead,totalFine 
                FROM ( SELECT sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id, fh.name,fh.code,fh.amount, 
                              sfs.batchId, sfs.semID, sfs.fees,  sfs.priority, fh.isFineHead, sr.billNo, 
                              sr.paymentMethod,  
                              (SELECT sum(fees) 
                                FROM studentfees_feesasigned_studentwise 
                                WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees,
                              sfs.id as feeId, if(sr.remittedAmt,sr.remittedAmt,0) as remittedAmt, sr.remittedDate, 
                              (SELECT if(sum(remittedAmt),sum(remittedAmt),0) 
                                FROM studentfees_remittedfees sfr 
                                WHERE studentID=sfs.studentID AND semID=sfs.semID AND 
                                DATE(sfr.remittedDate) <= '$billDate')as totalPaid, 
                              (SELECT if(sum(remittedAmt),sum(remittedAmt),0) 
                                FROM studentfees_remittedfees sfr 
                                WHERE studentID=sfs.studentID AND semID=sfs.semID AND feesId=sfs.id 
                                AND DATE(sfr.remittedDate) <= '$billDate')as totalRemitted, 
                              (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr 
                                INNER JOIN studentfees_feesasigned_studentwise stfs ON stfs.id=sfr.feesId 
                                INNER join feeHead fhs ON stfs.feeHeadId=fhs.id WHERE sfr.studentID=sfs.studentID 
                                AND sfr.semID=sfs.semID AND DATE(sfr.remittedDate) <= '$billDate
                                AND fhs.isFineHead=1)as totalFine, 
                              sr.remittedfeeID, sr.balanceAmt 
                      FROM studentaccount sa 
                      INNER JOIN studentfees_feesasigned_studentwise sfs 
                          ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId 
                      INNER JOIN studentfees_feesasigned_batchwise sfb 
                          ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID 
                      INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId 
                      LEFT JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id AND sr.billNo=$billNo 
                      WHERE sa.batchID=$batchId AND sfb.isActive=1 
                        AND sa.studentID=$studentId)as paymentDetails";
        try {
            $billDetails = $this->executeQueryForObject($sql, FALSE, $this->mapper[FeeServiceMapper::GET_STUDENT_BILL_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $billDetails;
    }
    /**
     * add student fee details
     *
     * @param StudentFeeRemittedDetails $studentFeeRemittedDetails
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function addStudentFeeRemittedDetails($studentFeeRemittedDetails)
    {
        $studentFeeRemittedDetails = $this->realEscapeObject($studentFeeRemittedDetails);
        $paymentDateStr = empty($studentFeeRemittedDetails->date) ? 'utc_timestamp()' : "'$studentFeeRemittedDetails->date'";
        $tags = ['paymentDate' => $paymentDateStr];
        $sql = "INSERT INTO studentFeeRemittedDetails(studentId, billNo, amount, mode, ddNumber, ddDate, bankName, bankBranch, date, chequeNo, remarks, chequeDate, challanNo, createdBy, createdDate, updatedBy, updatedDate) VALUES($studentFeeRemittedDetails->studentId$studentFeeRemittedDetails->billNo$studentFeeRemittedDetails->amount, '$studentFeeRemittedDetails->mode', '$studentFeeRemittedDetails->ddNumber', '" . date('Y-m-d', strtotime($studentFeeRemittedDetails->ddDate)) . "', '$studentFeeRemittedDetails->bankName', '$studentFeeRemittedDetails->bankBranch',  {{paymentDate}}, '$studentFeeRemittedDetails->chequeNo', '$studentFeeRemittedDetails->remarks', '" . ($studentFeeRemittedDetails->chequeDate ? date('Y-m-d', strtotime($studentFeeRemittedDetails->chequeDate)) : '') . "', '$studentFeeRemittedDetails->challanNo', $studentFeeRemittedDetails->createdBy, utc_timestamp(), $studentFeeRemittedDetails->updatedBy, utc_timestamp())";
        $sql = StringUtil::replace_tags($sql, $tags);
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::QUERY_EXECUTION_FAILED, $e->getMessage());
        }
    }
    public function getFeeCollectionReport($fromDate, $toDate, $paymentMethod)
    {
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $paymentMethod = $this->realEscapeString($paymentMethod);
        if ($paymentMethod) {
            $cond = "AND srf.paymentMethod='$paymentMethod";
        }
        $sql = "select sa.studentID, sa.studentName, sa.admissionNo, b.batchName, sem.semID, sem.semName,sum(srf.remittedAmt) as remittedAmt ,CONVERT_TZ(srf.remittedDate,'+00:00',@@global.time_zone) as remittedDate,srf.paymentMethod, srf.billNo from studentfees_remittedfees srf inner join studentaccount sa on sa.studentID = srf.studentID inner join batches b on b.batchId = sa.batchId inner join semesters sem on sem.semID = srf.semId inner join studentfees_feesasigned_studentwise sfs on sfs.id = srf.feesId inner join feeHead fh on fh.id = sfs.feeHeadId WHERE CAST(srf.remittedDate as date) between '" . date('Y-m-d', strtotime($fromDate)) . "' and '" . date('Y-m-d', strtotime($toDate)) . "$cond group by sa.studentID, srf.semID, srf.billNo order by  srf.remittedDate asc, srf.semID";
        try {
            return $this->executeQueryForList($sql, $this->mapper[FeeServiceMapper::GET_STUDENT_BILL_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get student payment details by batch and sem id
     *
     * @param int $batchId
     * @param int $semId
     * @param int $studentId
     * @throws ProfessionalException
     * @return object|array|\com\linways\base\util\$objectList[]
     */
    public function getStudentPendingPaymentDetailsStudentId($batchId, $semId, $studentId)
    {
        $studentList = [];
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $sql = "SELECT studentID,studentName,rollNo,admissionNo,headId,name,code,fees,remittedAmt, remittedDate, totalFees, totalPaid, totalRemitted, (totalFees-totalPaid)+totalFine as totalBalance, fees-totalRemitted as feeHeadBalance,remittedfeeID, balanceAmt, priority, feeId, totalFine FROM(SELECT sa.studentID, sa.studentName, sa.rollNo, sa.admissionNo, fh.id AS headId, fh.name,fh.code,fh.amount, sfs.batchId, sfs.semID, sfs.fees,  sfs.priority,  (SELECT sum(fees) FROM studentfees_feesasigned_studentwise WHERE batchId=sfs.batchId AND semID=sfs.semID AND studentID=sfs.studentID) as totalFees,sfs.id as feeId,if(sr.remittedAmt,sr.remittedAmt,0) as remittedAmt, sr.remittedDate, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID)as totalPaid, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr WHERE studentID=sfs.studentID AND semID=sfs.semID AND feesId=sfs.id)as totalRemitted, (SELECT if(sum(remittedAmt),sum(remittedAmt),0) FROM studentfees_remittedfees sfr INNER JOIN studentfees_feesasigned_studentwise stfs ON stfs.id=sfr.feesId INNER join feeHead fhs ON stfs.feeHeadId=fhs.id WHERE sfr.studentID=sfs.studentID AND sfr.semID=sfs.semID AND fhs.isFineHead=1)as totalFine, sr.remittedfeeID, sr.balanceAmt FROM studentaccount sa INNER JOIN studentfees_feesasigned_studentwise sfs ON sfs.studentID=sa.studentID AND sa.batchID=sfs.batchId AND sfs.semID=$semId INNER JOIN studentfees_feesasigned_batchwise sfb ON sfb.feeHeadId=sfs.feeHeadId AND sfb.batchID=sfs.batchId AND sfb.semID=sfs.semID INNER JOIN feeHead fh ON fh.id=sfs.feeHeadId LEFT JOIN studentfees_remittedfees sr ON sr.feesId=sfs.id WHERE sa.batchID=$batchId AND sfb.isActive=1 AND fh.isFineHead=0 AND sfs.fees >0 AND sfs.studentID=$studentId ORDER BY sa.rollNo, fh.isFineHead, sfs.priority, fh.id, sr.remittedfeeID)as paymentDetails WHERE totalFees !=totalPaid";
        try {
            $studentList = $this->executeQueryForObject($sql, false, $this->mapper[FeeServiceMapper::GET_STUDENT_PAYMENT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * add student challan details
     *
     * @param StudentIssuedChallan $studentIssuedChallan
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function addStudentChallanDetails($studentIssuedChallan)
    {
        $studentIssuedChallan = $this->realEscapeObject($studentIssuedChallan);
        $sql = "INSERT INTO studentIssuedChallan (studentId, challanNo, amount, semId, createdBy, createdDate, updatedBy, updatedDate) VALUES ($studentIssuedChallan->studentId, '$studentIssuedChallan->challanNo', $studentIssuedChallan->amount$studentIssuedChallan->semId$studentIssuedChallan->createdBy, utc_timestamp(), $studentIssuedChallan->updatedBy, utc_timestamp())";
        try {
            return $this->executeQueryForObject($sql, true);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get student challan details
     *
     * @param int $studentId
     * @param float $amount
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function getStudentChallanDetails($studentId, $amount)
    {
        $studentId = $this->realEscapeString($studentId);
        $amount = $this->realEscapeString($amount);
        $sql = "SELECT * FROM studentIssuedChallan WHERE isVerified=0 AND studentId=$studentId AND AMOUNT=$amount";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * add challan fee head details
     *
     * @param ChallanFeeHeadDetails $challanFeeHeadDetails
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function addChallanFeeHeadDetails($challanFeeHeadDetails)
    {
        $value = [];
        $challanFeeHeadDetails = $this->realEscapeObject($challanFeeHeadDetails);
        foreach ($challanFeeHeadDetails as $feeHead) {
            $value[] = "($feeHead->challanId, '$feeHead->feeHeadId', $feeHead->amount$feeHead->createdBy, utc_timestamp(), $feeHead->updatedBy, utc_timestamp())";
        }
        $sql = "INSERT INTO challanFeeHeadDetails (challanId, feeHeadId, amount, createdBy, createdDate, updatedBy, updatedDate) VALUES " . implode(', ', $value);
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get student challan feehead details
     *
     * @param int $challanId
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function getChallanFeeHeadByChallanId($challanId)
    {
        $challanId = $this->realEscapeString($challanId);
        $sql = "SELECT * FROM challanFeeHeadDetails WHERE challanId=$challanId";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function verifyStudentChallan($dateWisePaymentRequest)
    {
        $dateWisePaymentRequest = $this->realEscapeObject($dateWisePaymentRequest);
        $paymentDetails = BankPaymentService::getInstance()->getDateWisePaymentDetails($dateWisePaymentRequest);
        $StudentDetailsPayment = [];
        try {
            foreach ($paymentDetails as $payment) {
                $challan = $this->isStudentChallan($payment->amount, $payment->bankSID);
                $challanCount = $this->getCountOfNotVerifedChallanByStudent($payment->amount, $payment->bankSID);
                $verifedTransaction = $this->getChallanByTranscationId($payment->transactionId);
                $verified = 'Not Verified';
                if ($challanCount == 1) {
                    $verified = 'Already Verified';
                    if (!$challan->verified && !$verifedTransaction) {
                        $feeHeads = $this->getChallanFeeHeadByChallanId($challan->challanId);
                        $studentPayment = $this->getStudentPendingPaymentDetailsStudentId($challan->batchId, $challan->semId, $challan->studentId);
                        $studentRemittedFeesList = $this->constructStudentRemittedFeesList($feeHeads, $studentPayment, $challan);
                        $otherPaymentDetails = $this->constructPaymentRequest($payment, $challan);
                        $this->saveStudentPaymentDetails($studentRemittedFeesList, $otherPaymentDetails);
                        $sql = "UPDATE studentIssuedChallan SET isVerified=1, responseData='$payment->responseData', transactionId='$payment->transactionId' WHERE id=$challan->challanId";
                        $this->executeQueryForObject($sql);
                        $verified = 'Verified';
                    }
                }
                $studenDetails = StudentService::getInstance()->getStudentDetailsBybankSID($payment->bankSID);
                $studenDetails->amount = $payment->amount;
                $studenDetails->bankSID = $payment->bankSID;
                $studenDetails->challanNo = $challan->challanNo;
                $studenDetails->transactionId = $payment->transactionId;
                $studenDetails->verified = $verified;
                $studenDetails->tranDate = $payment->tranDate;
                $studenDetails->challanCount = $challanCount;
                $studenDetails->responseData = $payment->responseData;
                $studenDetails->semName = $challan->semId ? SemesterService::getInstance()->getSemestersName($challan->semId) : '';
                $StudentDetailsPayment[] = $studenDetails;
            }
            return $StudentDetailsPayment;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    private function isStudentChallan($amount, $bankSID)
    {
        $amount = $this->realEscapeString($amount);
        $bankSID = $this->realEscapeString($bankSID);
        $response = new \stdClass();
        $sql = "select sic.isVerified, sic.id, sic.semId, sic.studentId, sa.batchID, sic.challanNo, sic.transactionId FROM studentIssuedChallan sic INNER JOIN studentaccount sa ON sa.studentID=sic.studentId WHERE sic.amount='$amount' AND sa.bankSID='$bankSID'";
        $response->verified = TRUE;
        $response->isChallan = FALSE;
        try {
            $challanDetails = $this->executeQueryForObject($sql);
            $response->isChallan = $challanDetails->id ? TRUE : FALSE;
            $response->challanId = $challanDetails->id;
            $response->semId = $challanDetails->semId;
            $response->batchId = $challanDetails->batchID;
            $response->studentId = $challanDetails->studentId;
            $response->challanNo = $challanDetails->challanNo;
            $response->transactionId = $challanDetails->transactionId;
            if ($challanDetails->isVerified === '0') {
                $response->verified = FALSE;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $response;
    }
    private function constructStudentRemittedFeesList($feeHeads, $studentPayment, $challan)
    {
        $studentRemittedFeesList = [];
        $feeHeads = $this->realEscapeArray($feeHeads);
        $studentPayment = $this->realEscapeObject($studentPayment);
        $challan = $this->realEscapeObject($challan);
        foreach ($studentPayment->feeHeads as $feeHeadPay) {
            $paidHead = CommonUtil::objArraySearch($feeHeads, 'feeHeadId', $feeHeadPay->id);
            $paidHeadAmount = empty($paidHead) ? 0 : $paidHead->amount;
            $studentRemittedFees = new StudentRemittedFees();
            $studentRemittedFees->studentID = $challan->studentId;
            $studentRemittedFees->feesId = $feeHeadPay->feeId;
            $studentRemittedFees->remittedAmt = $paidHeadAmount;
            $studentRemittedFees->balanceAmt = $feeHeadPay->fees - ($feeHeadPay->paid + $paidHeadAmount);
            $studentRemittedFees->semID = $challan->semId;
            $studentRemittedFees->paymentMethod = 'CHALLAN';
            $studentRemittedFees->createdBy = 1;
            $studentRemittedFees->updatedBy = 1;
            $studentRemittedFeesList[] = $studentRemittedFees;
        }
        return $studentRemittedFeesList;
    }
    private function constructPaymentRequest($payment, $challan)
    {
        $studentFeeRemittedDetails = new StudentFeeRemittedDetails();
        $studentFeeRemittedDetails->studentId = $challan->studentId;
        $studentFeeRemittedDetails->amount = $payment->amount;
        $studentFeeRemittedDetails->mode = 'CHALLAN';
        $studentFeeRemittedDetails->remarks = $payment->remarks;
        $studentFeeRemittedDetails->createdBy = 1;
        $studentFeeRemittedDetails->updatedBy = 1;
        $studentFeeRemittedDetails->challanNo = $challan->challanNo;
        //Setting 11:30:00 for fixing converting utctimestamp
        //From api we will get only date and db saving it as utc format
        //while fetching converting to local time stamp so if we save date only it will show yesterdays date.
        //to fix appending time to 11:30:00 so that we will get date in same day while converting to local
        $studentFeeRemittedDetails->date = empty($payment->tranDate) ? null : $payment->tranDate . " 11:30:00";
        return $studentFeeRemittedDetails;
    }
    private function getCountOfNotVerifedChallanByStudent($amount, $bankSID)
    {
        $amount = $this->realEscapeString($amount);
        $bankSID = $this->realEscapeString($bankSID);
        $sql = "select count(sic.id) as challanCount FROM studentIssuedChallan sic INNER JOIN studentaccount sa ON sa.studentID=sic.studentId WHERE sic.amount='$amount' AND sa.bankSID='$bankSID'";
        try {
            return $this->executeQueryForObject($sql)->challanCount;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    private function getChallanByTranscationId($transactionId)
    {
        $transactionId = $this->realEscapeString($transactionId);
        $sql = "select IF(id,1,0) as verified FROM studentIssuedChallan  WHERE transactionId='$transactionId'";
        try {
            return $this->executeQueryForObject($sql)->id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Make admission payment for a student
     *
     * @param StudentFeeOnlinePaymentReq $studentFeeOnlinePaymentReq
     */
    public function initiatePayment($studentFeeOnlinePaymentReq, $module = 'FEE_MODULE', $category = 'STUDENT')
    {
        $studentFeeOnlinePaymentReq = $this->realEscapeObject($studentFeeOnlinePaymentReq);
        $module = $this->realEscapeString($module);
        $category = $this->realEscapeString($category);
        
        $linwaysTxnId = mt_rand();
        $studentFeeOnlinePaymentReq->linwaysTxnId = $linwaysTxnId;
        $studentFeeOnlinePaymentReqId = null;
        $sqlStudentFeeOnlinePaymentReq = null;
        $sqlStudentFeeOnlinePaymentReqFeeHeads = null;
        $student = null;
        // First Setep - Create FeePaymentRequest
        $sqlStudentFeeOnlinePaymentReq = "INSERT INTO `StudentFeeOnlinePaymentReq`
 (`studentId`, `batchId`, 
`semId`, `totalAmount`, 
`linwaysTxnId`, `paymentGatewayTxnId`,
 `status`, `createdBy`, `createdDate`, 
`updatedBy`, `updatedDate`) 
VALUES ($studentFeeOnlinePaymentReq->studentId$studentFeeOnlinePaymentReq->batchId,
 $studentFeeOnlinePaymentReq->semId, '$studentFeeOnlinePaymentReq->totalAmount', 
$linwaysTxnId, 0, 'IN_PROGRESS',$studentFeeOnlinePaymentReq->createdBy
utc_timestamp(), $studentFeeOnlinePaymentReq->updatedBy, utc_timestamp());
";
        // Second Step - created CurrentFeePayment Request Fee Heads
        try {
            $studentFeeOnlinePaymentReqId = $this->executeQueryForObject($sqlStudentFeeOnlinePaymentReq, true);
            foreach ($studentFeeOnlinePaymentReq->studentFeeOnlinePaymentReqFeeHeads as $feeHead) {
                $sqlStudentFeeOnlinePaymentReqFeeHeads = "INSERT INTO
`StudentFeeOnlinePaymentReqFeeHead` (`studentFeeOnlinePaymentReqId`, `feeId`, `amount`, `createdBy`, `createdDate`, `updatedBy`, `updatedDate`)
VALUES ($studentFeeOnlinePaymentReqId$feeHead->feeId,'$feeHead->amount', $studentFeeOnlinePaymentReq->createdBy,
utc_timestamp(), $studentFeeOnlinePaymentReq->updatedBy, utc_timestamp());";
                $this->executeQueryForObject($sqlStudentFeeOnlinePaymentReqFeeHeads);
            }
            $student = StudentService::getInstance()->getStudentDetailsById($studentFeeOnlinePaymentReq->studentId);
            // Third Step: invoke Payment Gateway
            $exePaymentReq = new ExecutePaymentRequest();
            $exePaymentReq->module = $module;
            $exePaymentReq->category = $category;
            $exePaymentReq->amount = $studentFeeOnlinePaymentReq->totalAmount;
            $exePaymentReq->currency = 'INR';
            $exePaymentReq->returnURL = $studentFeeOnlinePaymentReq->returnURL;
            $exePaymentReq->timeStamp = date("d-m-Y");
            $exePaymentReq->txnId = $linwaysTxnId;
            $exePaymentReq->productInfo = 'Student Fee Collection';
//             $exePaymentReq->email = $student->studentEmail;
            $exePaymentReq->email = 'pradeep.ofc@adishankara.ac.in';
            $exePaymentReq->phone = $student->studentPhone;
            $exePaymentReq->userName = $student->name;;
            $exePaymentReq->userId = $studentFeeOnlinePaymentReq->studentId;
            $userDfParams = [];
            $userDfParams['studentFeeOnlinePaymentReqId'] = $studentFeeOnlinePaymentReqId;
            $userDfParams['semId'] = $studentFeeOnlinePaymentReq->semId;
            $exePaymentReq->userdfParams = $userDfParams;
            PaymentGatewayService::getInstance()->executePayment($exePaymentReq);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get Student Fee Online payment req details
     * @param int $studentFeeOnlinePaymentReqId
     * @throws ProfessionalException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function getStudentFeeOnlinePaymentReq($studentFeeOnlinePaymentReqId)
    {
        $studentFeeOnlinePaymentReqId = $this->realEscapeString($studentFeeOnlinePaymentReqId);
        $studentFeeOnlinePaymentReq = null;
        $sql = "select spr.*,sprfh.id as studentFeeOnlinePaymentReqFeeHeadsId,sprfh.studentFeeOnlinePaymentReqId,sprfh.feeId,sprfh.amount from StudentFeeOnlinePaymentReq spr inner join StudentFeeOnlinePaymentReqFeeHead sprfh
on spr.id = sprfh.studentFeeOnlinePaymentReqId where spr.id=$studentFeeOnlinePaymentReqId;";
        try {
            $studentFeeOnlinePaymentReq = $this->executeQueryForObject($sql, false, $this->mapper[FeeServiceMapper::GET_STUDENT_ONLINE_FEE_PAYMENT_REQ]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentFeeOnlinePaymentReq;
    }
    /**
     * Process student fee online payment failed response
     * @param int $studentFeeOnlinePaymentReqId
     * @param string $paymentGatewayTxnId
     * @throws ProfessionalException
     */
    private function processStudentOnlineFeePaymentFailure($studentFeeOnlinePaymentReqId, $paymentGatewayTxnId)
    {
        $studentFeeOnlinePaymentReqId = $this->realEscapeString($studentFeeOnlinePaymentReqId);
        $paymentGatewayTxnId = $this->realEscapeString($paymentGatewayTxnId);
        $sql = "UPDATE StudentFeeOnlinePaymentReq SET status='FAILED',paymentGatewayTxnId='$paymentGatewayTxnId' WHERE id=$studentFeeOnlinePaymentReqId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Process student fee online payment success response
     * @param int $studentFeeOnlinePaymentReqId
     * @param string $paymentGatewayTxnId
     * @throws ProfessionalException
     */
    private function processStudentOnlineFeePaymentSuccess($studentFeeOnlinePaymentReqId, $paymentGatewayTxnId)
    {
        $studentFeeOnlinePaymentReqId = $this->realEscapeString($studentFeeOnlinePaymentReqId);
        $paymentGatewayTxnId = $this->realEscapeString($paymentGatewayTxnId);
        $sql = "UPDATE StudentFeeOnlinePaymentReq SET status='SUCCESS',paymentGatewayTxnId='$paymentGatewayTxnId' WHERE id=$studentFeeOnlinePaymentReqId";
        try {
            $this->executeQuery($sql);
            $studentFeeOnlinePaymentReq = $this->getStudentFeeOnlinePaymentReq($studentFeeOnlinePaymentReqId);
            $studentRemittedFeesList = [];
            $selectedAssignedFees = $studentFeeOnlinePaymentReq->studentFeeOnlinePaymentReqFeeHeads;
            $studentCurrentFeesDetails = $this->getStudentPendingPaymentDetailsStudentId($studentFeeOnlinePaymentReq->batchId, $studentFeeOnlinePaymentReq->semId, $studentFeeOnlinePaymentReq->studentId);
            $studentRemittedFeesList = [];
            foreach ($studentCurrentFeesDetails->feeHeads as $assignedFee) {
                $paidHead = CommonUtil::objArraySearch($selectedAssignedFees, 'feeId', $assignedFee->feeId);
                $remittedAmt = empty($paidHead) ? 0 : $paidHead->amount;
                $studentRemittedFees = new StudentRemittedFees();
                $studentRemittedFees->studentID = $studentFeeOnlinePaymentReq->studentId;
                $studentRemittedFees->feesId = $assignedFee->feeId;
                $studentRemittedFees->remittedAmt = $remittedAmt;
                $studentRemittedFees->balanceAmt = $assignedFee->fees - ($assignedFee->paid + $remittedAmt);
                $studentRemittedFees->semID = $studentFeeOnlinePaymentReq->semId;
                $studentRemittedFees->paymentMethod = 'ONLINE';
                $studentRemittedFees->createdBy = $studentFeeOnlinePaymentReq->createdBy;
                $studentRemittedFees->updatedBy = $studentFeeOnlinePaymentReq->updatedBy;
                $studentRemittedFeesList[] = $studentRemittedFees;
            }
            $studentFeeRemittedDetails = new StudentFeeRemittedDetails();
            $studentFeeRemittedDetails->studentId = $studentFeeOnlinePaymentReq->studentId;
            $studentFeeRemittedDetails->amount = $studentFeeOnlinePaymentReq->totalAmount;
            $studentFeeRemittedDetails->mode = 'ONLINE';
            $studentFeeRemittedDetails->remarks = "";
            $studentFeeRemittedDetails->createdBy = $studentFeeOnlinePaymentReq->createdBy;
            $studentFeeRemittedDetails->updatedBy = $studentFeeOnlinePaymentReq->createdBy;
            $studentFeeRemittedDetails->linwaysTxnId = $studentFeeOnlinePaymentReq->linwaysTxnId;
            $this->saveStudentPaymentDetails($studentRemittedFeesList, $studentFeeRemittedDetails);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Verify student online fee payment
     * @param int $studentFeeOnlinePaymentReqId
     * @param string $paymentGatewayTxnId
     * @param string $status
     * @throws ProfessionalException
     */
    public function verifyStudentOnlineFeePayment($studentFeeOnlinePaymentReqId, $paymentGatewayTxnId, $status)
    {
        $studentFeeOnlinePaymentReqId = $this->realEscapeString($studentFeeOnlinePaymentReqId);
        $paymentGatewayTxnId = $this->realEscapeString($paymentGatewayTxnId);
        $status = $this->realEscapeString($status);
        switch ($status) {
            case 'SUCCESS':
                $this->processStudentOnlineFeePaymentSuccess($studentFeeOnlinePaymentReqId, $paymentGatewayTxnId);
                break;
            case 'FAILED':
                $this->processStudentOnlineFeePaymentFailure($studentFeeOnlinePaymentReqId, $paymentGatewayTxnId);
                break;
            default:
                throw new ProfessionalException("STUDENT_FEE_ONLINE_PAYMENT_STATUS_NOT_FOUND", "STUDENT_FEE_ONLINE_PAYMENT_STATUS_NOT_FOUND");
                break;
        }
    }
     /**
     * get common fees details
     * @param int $supplyExamRegId
     * @throws ProfessionalException
     */
    public function getSupplyExamCommonFees($supplyExamRegId)
    {
        $supplyExamRegId = $this->realEscapeString($supplyExamRegId);
        $sql = "SELECT eft.examfeesName, sief.supply_feesAmount, sief.improve_feesAmount,eft.examfeesID FROM supply_improve_exam_fees sief INNER JOIN exam_feestype eft ON (eft.examfeesID = sief.examfeesID ) WHERE sief.exam_supplementary_id ='$supplyExamRegId' and eft.everySubject =0";
        try {
            $commonFees = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $commonFees;
    }
    /**
     * get subject fees
     * @param int $supplyExamRegId,examId
     * @throws ProfessionalException
     */
    public function getSupplyExamSubjectFees($request)
    {
        $request = $this->realEscapeObject($request);
        $examIds = implode(",",$request->examIds);
        $studentSubjectFees="";
        $sql = "SELECT supply_subject_amount,improve_subject_amount,examfeesID FROM supply_improve_subject_fees WHERE exam_supplementary_id = '$request->supplyRegId' AND examID IN($examIds)";
        try {
            $studentSubjectFees = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentSubjectFees;
    }
}