<?php
namespace App\Controller\ward;
use App\Entity\AllocationRemark;
use App\Entity\Bursary;
use App\Entity\CancelledAllocation;
use App\Entity\FundAccount;
use App\Entity\Student;
use App\Entity\StudentAllocation;
use App\Entity\Take;
use App\Entity\Transaction;
use App\Entity\Ward;
use App\Form\AllocationCancelType;
use App\Form\AllocationRemarkType;
use App\Form\AllocationType;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\Persistence\ObjectManager;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerBuilder;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class AllocationController extends AbstractController {
/**
* @Route("/allocations", name="allocationsRoute")
* @IsGranted("ROLE_USER")
* @param Request $request
* @return Response
*/
public function home(Request $request): Response {
$em = $this->getDoctrine()->getManager();
if(!$request->getSession()->has('ward_id') && !$request->getSession()->get('ward_id') ){
return $this->redirectToRoute('wardSelectRoute');
}
return $this->render('ward/allocations.html.twig',[
]);
}
/**
* @Route("/allocations/add/{id}", name="allocationsDateRoute")
* @IsGranted("ROLE_USER")
* @param Request $request
* @param Student $student
* @return Response
*/
public function allocationDetail(Request $request, Student $student):Response {
if(!$this->isGranted("ROLE_WARD_ADMIN") && !$this->isGranted("ROLE_ADMIN")){
return $this->render('ward/others/allocation_detail.html.twig',[
'isAuthorised' => false
]);
}
if(!$request->getSession()->has('ward_id') && !$request->getSession()->get('ward_id') ){
return $this->redirectToRoute('wardSelectRoute');
}
$wardId = $request->getSession()->get('ward_id');
$em = $this->getDoctrine()->getManager();
$wardId = $request->getSession()->get('ward_id');
$ward = $em->getRepository('App:Ward')->findOneBy([
'id' => $wardId
]);
$phase = $em->getRepository('App:Take')->findOneBy([
],['id'=> 'desc']);
if(!$phase->getIsActive() && !$this->isGranted('ROLE_ADMIN')){
$phaseException = $em->getRepository('App:TakeException')->findOneBy([
'ward' => $ward,
'isActive' => 1
]);
if($phaseException && $phaseException->getIsActive()){
// continue
}else{
$this->addFlash('warning', 'The Bursary phase is complete! please contact admin');
return $this->render('ward/others/allocation_detail.html.twig',[
'isAuthorised' => false
]);
}
}
$bursary = $em->getRepository('App:Bursary')->findOneBy([
'county' => $ward->getSubCounty()->getCounty(),
'isCurrent' => true
]);
$take = $em->getRepository('App:Take')->findOneBy([
'bursary' => $bursary
],['id' => 'DESC']);
$institutionType = $student->getInstitution()->getInstitutionType();
$studentAllocation = new StudentAllocation($em);
$studentAllocation->setStudent($student);
$studentAllocation->setWard($ward);
$studentAllocation->setCreatedAt(new \DateTimeImmutable());
$studentAllocation->setIsCancelled(false);
$studentAllocation->setCreatedBy($this->getUser());
$studentAllocation->setTake($take);
// dump($studentAllocation);
$wardFundAccount = $em->getRepository("App:WardFundAccount")->findOneBy([
'ward' => $ward,
'isDefault' => true
],[ 'id' => 'DESC']);
if(!$wardFundAccount){
return $this->render('ward/others/allocation_detail.html.twig',[
'isAuthorised' => true,
'isAllocated' => false
]);
}
$form = $this->createForm(AllocationType::class, $studentAllocation,[
'validation_groups' => [
'Default'
]
]);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$studentAllocation->setWard($ward);
$studentAllocation->setIsCancelled(false);
$studentAllocation->setStudent($student);
$studentAllocation->setCreatedBy($this->getUser());
try {
$oldAllocation = $em->getRepository("App:StudentAllocation")->findVeryRecentAllocationOfStudent($student->getId());
if($oldAllocation){
return $this->render('ward/others/allocation_detail.html.twig',[
"student" => $student,
"allocation" => $studentAllocation,
'isAuthorised' => true,
'institutionType' => $institutionType,
'isSuccessful' => true
]);
}
} catch (NonUniqueResultException $e) {
}
$conn = $em->getConnection();
$conn->beginTransaction();
try {
$this->makeAllocation($ward,$studentAllocation->getAmount(), $em);
$em->persist($studentAllocation);
$em->flush();
$em->getConnection()->commit();
// $this->addFlash('success', 'allocation made Successfully');
return $this->render('ward/others/allocation_detail.html.twig',[
"student" => $student,
"allocation" => $studentAllocation,
'isAuthorised' => true,
'institutionType' => $institutionType,
'isSuccessful' => true
]);
}catch (\PDOException $e){
$em->getConnection()->rollBack();
return $this->render('ward/others/allocation_detail.html.twig',[
"student" => $student,
"allocationForm"=> $form->createView(),
'isAuthorised' => true,
'institutionType' => $institutionType
]);
}
}
return $this->render('ward/others/allocation_detail.html.twig',[
"student" => $student,
"allocationForm"=> $form->createView(),
'isAuthorised' => true,
'institutionType' => $institutionType
]);
}
/**
* @Route("/allocations/reallocate/{id}", name="reallocationRoute")
* @IsGranted("ROLE_USER")
* @param Request $request
* @param Student $student
* @return Response
*/
public function reallocationDetail(Request $request, StudentAllocation $oldStudentAllocation):Response {
if(!$this->isGranted("ROLE_WARD_ADMIN") && !$this->isGranted("ROLE_ADMIN") ){
return $this->render('ward/others/reallocation_detail.html.twig',[
'isAuthorised' => false
]);
}
if(!$request->getSession()->has('ward_id') && !$request->getSession()->get('ward_id') ){
return $this->redirectToRoute('wardSelectRoute');
}
$wardId = $request->getSession()->get('ward_id');
$em = $this->getDoctrine()->getManager();
$wardId = $request->getSession()->get('ward_id');
$ward = $em->getRepository('App:Ward')->findOneBy([
'id' => $wardId
]);
$bursary = $em->getRepository('App:Bursary')->findOneBy([
'county' => $ward->getSubCounty()->getCounty(),
'isCurrent' => true
]);
$phase = $em->getRepository('App:Take')->findOneBy([
'bursary' => $bursary
],['id'=> 'desc']);
if(!$phase->getIsActive() && !$this->isGranted('ROLE_ADMIN')){
$phaseException = $em->getRepository('App:TakeException')->findOneBy([
'ward' => $ward,
'isActive' => 1
]);
if($phaseException && $phaseException->getIsActive()){
// continue
}else{
$this->addFlash('warning', 'The Bursary phase is complete! please contact admin');
return $this->render('ward/others/allocation_detail.html.twig',[
'isAuthorised' => false
]);
}
}
if($phase->getId() != $oldStudentAllocation->getTake()->getId()){
$this->addFlash('warning', 'This allocation was done in a different phase');
return $this->render('ward/others/allocation_detail.html.twig',[
'isAuthorised' => false
]);
}
$student = $oldStudentAllocation->getStudent();
$institutionType = $student->getInstitution()->getInstitutionType();
$studentAllocation = new StudentAllocation($em);
$studentAllocation->setStudent($student);
$studentAllocation->setWard($ward);
$studentAllocation->setCreatedAt(new \DateTimeImmutable());
$studentAllocation->setIsCancelled(false);
$studentAllocation->setCreatedBy($this->getUser());
$studentAllocation->setTake($phase);
$wardFundAccount = $em->getRepository("App:WardFundAccount")->findOneBy([
'ward' => $ward,
'isDefault' => true
],[ 'id' => 'DESC']);
if(!$wardFundAccount){
return $this->render('ward/others/reallocation_detail.html.twig',[
'isAuthorised' => true,
'isAllocated' => false
]);
}
$form = $this->createForm(AllocationType::class, $studentAllocation,[
'validation_groups' => [
'Default'
]
]);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$studentAllocation->setWard($ward);
$studentAllocation->setIsCancelled(false);
$studentAllocation->setStudent($student);
$studentAllocation->setCreatedBy($this->getUser());
/*try {
$oldAllocation = $em->getRepository("App:StudentAllocation")->findVeryRecentAllocationOfStudent($student->getId());
if($oldAllocation){
return $this->render('ward/others/reallocation_detail.html.twig',[
"student" => $student,
"allocation" => $studentAllocation,
"oldAllocation" => $oldStudentAllocation,
'isAuthorised' => true,
'institutionType' => $institutionType,
'isSuccessful' => true
]);
}
} catch (NonUniqueResultException $e) {
}*/
$conn = $em->getConnection();
$conn->beginTransaction();
try {
$cancelledAllocation = new CancelledAllocation();
$cancelledAllocation->setCreatedAt(new \DateTime());
$cancelledAllocation->setAllocation($oldStudentAllocation);
$cancelledAllocation->setCreatedBy($this->getUser());
$cancelledAllocation->setReason("This student was reallocated an amount from ".$oldStudentAllocation->getAmount()." to ".$studentAllocation->getAmount());
$em->persist($cancelledAllocation);
$oldStudentAllocation->setIsCancelled(true);
$this->cancelAllocation($ward, $oldStudentAllocation->getAmount(), $em );
$this->makeAllocation($ward,$studentAllocation->getAmount(), $em);
$em->persist($studentAllocation);
$em->flush();
$em->getConnection()->commit();
return $this->render('ward/others/reallocation_detail.html.twig',[
"student" => $student,
"allocation" => $studentAllocation,
"oldAllocation" => $oldStudentAllocation,
'isAuthorised' => true,
'institutionType' => $institutionType,
'isSuccessful' => true
]);
}catch (\PDOException $e){
$em->getConnection()->rollBack();
return $this->render('ward/others/reallocation_detail.html.twig',[
"student" => $student,
"oldAllocation" => $oldStudentAllocation,
"allocationForm"=> $form->createView(),
'isAuthorised' => true,
'institutionType' => $institutionType
]);
}
}
return $this->render('ward/others/reallocation_detail.html.twig',[
"student" => $student,
"oldAllocation" => $oldStudentAllocation,
"allocationForm"=> $form->createView(),
'isAuthorised' => true,
'institutionType' => $institutionType
]);
}
private function makeAllocation(Ward $ward, $amount, ObjectManager $em){
$currentBursary = $em->getRepository('App:Bursary')->findOneBy([
],['id' => 'DESC']);
$wardFundAccount = $em->getRepository("App:WardFundAccount")->findOneBy([
'ward' => $ward,
'isDefault' => true
],[ 'id' => 'DESC']);
$wardStudentAccount = $em->getRepository("App:WardFundAccount")->findOneBy([
'isStudent' => true,
'ward' => $ward
],[ 'id' => 'DESC']);
/****************************************************************************************************/
// Double entry for allocation transaction 1
/*****************************************************************************************************/
$transaction = new Transaction();
$transaction->setAmount($amount);
$transaction->setCreatedAt(new \DateTimeImmutable());
$transaction->setCreatedBy($this->getUser());
$transaction->setNarration("WARD STUDENT ALLOCATION");
$transaction->setEntryType('DEBIT');
$transaction->setBursary($currentBursary);
$transaction->setBalance($wardFundAccount->getFundAccount()->getBalance());
$transaction->setEndBalance($wardFundAccount->getFundAccount()->getBalance() - $amount);
$transaction->setTransactionType('WARD STUDENT ALLOCATION');
$transaction->setFundAccount($wardFundAccount->getFundAccount());
/****************************************************************************************************/
// Double entry for allocation transaction 2
/*****************************************************************************************************/
$otherTransaction = new Transaction();
$otherTransaction->setAmount($amount);
$otherTransaction->setEntryType('CREDIT');
$otherTransaction->setBalance($wardStudentAccount->getFundAccount()->getBalance());
$otherTransaction->setFundAccount($wardStudentAccount->getFundAccount());
$otherTransaction->setEndBalance($wardStudentAccount->getFundAccount()->getBalance() + $amount);
$otherTransaction->setCreatedAt(new \DateTimeImmutable());
$otherTransaction->setCreatedBy($this->getUser());
$otherTransaction->setNarration("WARD STUDENT ALLOCATION");
$otherTransaction->setBursary($currentBursary);
$otherTransaction->setAmount($amount);
$otherTransaction->setTransactionType("WARD STUDENT ALLOCATION ");
/** SETUP account & transaction references */
$transaction->setReferenceFundAccount($otherTransaction->getFundAccount());
$otherTransaction->setReferenceFundAccount($transaction->getFundAccount());
$transaction->setTransaction($otherTransaction);
$otherTransaction->setTransaction($transaction);
/** UPDATE account balances */
$transaction->getFundAccount()->setBalance($transaction->getEndBalance());
$otherTransaction->getFundAccount()->setBalance($otherTransaction->getEndBalance());
$em->persist($transaction);
$em->persist($otherTransaction);
}
private function cancelAllocation(Ward $ward, $amount, ObjectManager $em){
$currentBursary = $em->getRepository('App:Bursary')->findOneBy([
],['id' => 'DESC']);
$wardFundAccount = $em->getRepository("App:WardFundAccount")->findOneBy([
'ward' => $ward,
'isDefault' => true
],[ 'id' => 'DESC']);
$wardStudentAccount = $em->getRepository("App:WardFundAccount")->findOneBy([
'isStudent' => true,
'ward' => $ward
],[ 'id' => 'DESC']);
/****************************************************************************************************/
// Double entry for allocation transaction 1
/*****************************************************************************************************/
$transaction = new Transaction();
$transaction->setAmount($amount);
$transaction->setCreatedAt(new \DateTimeImmutable());
$transaction->setCreatedBy($this->getUser());
$transaction->setNarration("WARD STUDENT ALLOCATION CANCELLATION");
$transaction->setEntryType('CREDIT');
$transaction->setBursary($currentBursary);
$transaction->setBalance($wardFundAccount->getFundAccount()->getBalance());
$transaction->setEndBalance($wardFundAccount->getFundAccount()->getBalance() + $amount);
$transaction->setTransactionType('WARD STUDENT ALLOCATION CANCELLATION');
$transaction->setFundAccount($wardFundAccount->getFundAccount());
/****************************************************************************************************/
// Double entry for allocation transaction 2
/*****************************************************************************************************/
$otherTransaction = new Transaction();
$otherTransaction->setAmount($amount);
$otherTransaction->setEntryType('DEBIT');
$otherTransaction->setBalance($wardStudentAccount->getFundAccount()->getBalance());
$otherTransaction->setFundAccount($wardStudentAccount->getFundAccount());
$otherTransaction->setEndBalance($wardStudentAccount->getFundAccount()->getBalance() - $amount);
$otherTransaction->setCreatedAt(new \DateTimeImmutable());
$otherTransaction->setCreatedBy($this->getUser());
$otherTransaction->setNarration("WARD STUDENT ALLOCATION CANCELLATION");
$otherTransaction->setBursary($currentBursary);
$otherTransaction->setAmount($amount);
$otherTransaction->setTransactionType("WARD STUDENT ALLOCATION CANCELLATION ");
/** SETUP account & transaction references */
$transaction->setReferenceFundAccount($otherTransaction->getFundAccount());
$otherTransaction->setReferenceFundAccount($transaction->getFundAccount());
$transaction->setTransaction($otherTransaction);
$otherTransaction->setTransaction($transaction);
/** UPDATE account balances */
$transaction->getFundAccount()->setBalance($transaction->getEndBalance());
$otherTransaction->getFundAccount()->setBalance($otherTransaction->getEndBalance());
$em->persist($transaction);
$em->persist($otherTransaction);
}
/**
* @Route("/allocations/cancel/{id}", methods={"POST", "GET"}, name="allocationsCancelRoute")
* @IsGranted("ROLE_USER")
* @param Request $request
* @param StudentAllocation $allocation
* @return Response
*/
public function cancelAllocationAction(Request $request, StudentAllocation $allocation) :Response {
$em = $this->getDoctrine()->getManager();
if(!$this->isGranted("ROLE_WARD_ADMIN")){
return $this->render('ward/others/allocation_cancel.html.twig',[
'isAuthorised' => false
]);
}
$phase = $em->getRepository(Take::class)->findOneBy([
'isActive' => true
],['id' => 'desc']);
if($phase){
if($phase->getId() != $allocation->getTake()->getId()){
$this->addFlash('warning', 'This allocation was done in a different phase');
return $this->render('ward/others/allocation_cancel.html.twig',[
'isAuthorised' => false
]);
}
}else{
$this->addFlash('warning', 'This allocation was done in a different phase');
return $this->render('ward/others/allocation_cancel.html.twig',[
'isAuthorised' => false
]);
}
if(!$request->getSession()->has('ward_id') && !$request->getSession()->get('ward_id') ){
return $this->redirectToRoute('wardSelectRoute');
}
$wardId = $request->getSession()->get('ward_id');
$ward = $em->getRepository('App:Ward')->findOneBy([
'id' => $wardId
]);
$em = $this->getDoctrine()->getManager();
$cancelledAllocation = new CancelledAllocation();
$cancelledAllocation->setCreatedAt(new \DateTime());
$cancelledAllocation->setAllocation($allocation);
$cancelledAllocation->setCreatedBy($this->getUser());
/** @var Student $student */
$student = $allocation->getStudent();
$form = $this->createForm(AllocationCancelType::class, $cancelledAllocation,[
'validation_groups' => [
'Default'
]
]);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$conn = $em->getConnection();
$conn->beginTransaction();
try {
$this->cancelAllocation($ward,$allocation->getAmount(), $em);
$allocation->setIsCancelled(true);
$em->persist($cancelledAllocation);
$em->flush();
$em->getConnection()->commit();
return $this->render('ward/others/allocation_cancel.html.twig',[
'allocation' => $allocation,
'student' => $student,
'form' => $form->createView(),
'isAuthorised' => true,
'isSuccessful' => true
]);
}catch (\PDOException $e){
$em->getConnection()->rollBack();
return $this->render('ward/others/allocation_cancel.html.twig',[
'allocation' => $allocation,
'student' => $student,
'form' => $form->createView(),
'isSuccessful' => false
]);
}
}
return $this->render('ward/others/allocation_cancel.html.twig',[
'allocation' => $allocation,
'student' => $student,
'form' => $form->createView(),
'isAuthorised' => true
]);
}
/**
* @Route("/allocations/json", name="studentsAllocationsJSONRoute")
* @IsGranted("ROLE_USER")
* @return Response
*/
public function studentsAllocationJSON(Request $request){
if(!$request->getSession()->has('ward_id') && !$request->getSession()->get('ward_id') ){
return $this->redirectToRoute('wardSelectRoute');
}
$wardId = $request->getSession()->get('ward_id');
$context = new SerializationContext();
$context->setSerializeNull(true);
$serializer = SerializerBuilder::create()->build();
$em = $this->getDoctrine()->getManager();
$page = $request->request->get('page') > 1 ? $request->request->get('page'): 1;
$rows = $request->request->get('rows') > 1 ? $request->request->get('rows'): 20;
$offset = ($page - 1)*$rows;
$filterRules = $request->request->get('filterRules');
$take = $em->getRepository(Take::class)->findOneBy([
'isActive' => true
]);
$students = $em->getRepository('App:StudentAllocation')->getAllStudentAllocations( $wardId, $filterRules, $offset,$rows, $take->getId());
$studentsCount = $em->getRepository('App:StudentAllocation')->studentsAllocationsCounter( $wardId, $filterRules,$take->getId());
$data = [
'total' => $studentsCount,
'rows' => $students,
];
$data = $serializer->serialize($data, 'json', $context);
return new Response($data, Response::HTTP_OK);
}
}