src\Controller\Mpesa\MpesaController.php line 65

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Mpesa;
  3. use App\Entity\MpesaAuth;
  4. use App\Entity\MpesaManual;
  5. use App\Entity\MpesaTransaction;
  6. use App\Entity\MpesaTransactionVerification;
  7. use App\Entity\User;
  8. use DateTime;
  9. use Doctrine\Persistence\ManagerRegistry;
  10. use Doctrine\Persistence\ObjectManager;
  11. use JMS\Serializer\SerializationContext;
  12. use JMS\Serializer\SerializerBuilder;
  13. use PDOException;
  14. use Psr\Log\LoggerInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\HttpClient\Exception\ClientException;
  17. use Symfony\Component\HttpFoundation\JsonResponse;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpFoundation\Response;
  20. use Symfony\Component\HttpKernel\KernelInterface;
  21. use Symfony\Component\Routing\Annotation\Route;
  22. use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
  23. use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
  24. use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
  25. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  26. use Symfony\Contracts\HttpClient\HttpClientInterface;
  27. class MpesaController extends AbstractController
  28. {
  29.     private $host 'api.safaricom.co.ke';
  30.     private $callbackUrlRegister '/mpesa/c2b/v2/registerurl';
  31.     private $tokenRequest '/oauth/v1/generate?grant_type=client_credentials';
  32.     private $authType 'PROD';
  33.     private LoggerInterface $logger;
  34.     private ObjectManager $em;
  35.     private HttpClientInterface $client;
  36.     private KernelInterface $kernel;
  37. //Proxy:OAuth2Token - https://api.safaricom.co.ke/oauth/v1/generate
  38. //Proxy:C2B_v1 -      https://api.safaricom.co.ke/mpesa/c2b/v1/registerurl
  39.     public function __construct(ManagerRegistry $managerRegistryLoggerInterface $loggerHttpClientInterface $clientKernelInterface $kernel)
  40.     {
  41.         $this->logger $logger;
  42.         $this->em $managerRegistry->getManager();
  43.         $this->client $client;
  44.         $this->kernel $kernel;
  45.     }
  46. //composer update "symfony/*" --with-all-dependencies
  47. //
  48.     /**
  49.      * @Route("/callback", methods={"POST"}, name="mpesaCallback")
  50.      * @param Request $request
  51.      * @return Response
  52.      */
  53.     public function mpesaCallback(Request $request): Response
  54.     {
  55.         $em $this->em;
  56.         $this->logger->debug('MPESa Callback', [$request->getContent()]);
  57.         $json $request->getContent();
  58.         $response json_decode($jsontrue);
  59. //        20191122063845
  60.         $transactionId $response['TransID'];
  61.         $mpesaTransactionVerification $em->getRepository(MpesaTransactionVerification::class)->findOneBy([
  62.             'transactionId' => $transactionId
  63.         ]);
  64.         if($mpesaTransactionVerification){
  65.             $mpesa = new MpesaTransaction();
  66.             $mpesa->setTransactionId($transactionId);
  67.             $mpesa->setTransactionType($mpesaTransactionVerification->getTransactionType());
  68.             $mpesa->setTransactionTime($mpesaTransactionVerification->getTransactionTime());
  69.             $mpesa->setTransactionAmount($mpesaTransactionVerification->getTransactionAmount());
  70.             $mpesa->setShortCode($mpesaTransactionVerification->getShortCode());
  71.             $mpesa->setBillReferenceNumber($mpesaTransactionVerification->getBillReferenceNumber());
  72.             $mpesa->setAccountBalance($response['OrgAccountBalance']);
  73.             $mpesa->setMsisdn($mpesaTransactionVerification->getMsisdn());
  74.             $mpesa->setFirstName($mpesaTransactionVerification->getFirstName());
  75.             $mpesa->setMiddleName($mpesaTransactionVerification->getMiddleName());
  76.             $mpesa->setLastName($mpesaTransactionVerification->getLastName());
  77.             $mpesa->setIsComplete(true);
  78. //            $mpesa->setCreatedAt(new \DateTime('+3 hours'));
  79.             $mpesa->setCreatedAt(new \DateTime());
  80.             $mpesa->setIsValidated(true);
  81.             $mpesa->setIsSeen(false);
  82.             $mpesa->setIsUsed(false);
  83.             $mpesa->setCompletedMpesaFromIp($request->getClientIp());
  84.             try {
  85.                 $em->persist($mpesa);
  86.                 $em->flush();
  87.                 return new Response('OK'Response::HTTP_OK);
  88.             } catch (\PDOException $exception) {
  89.                 return new Response('OK'Response::HTTP_OK);
  90.             }
  91.         }else{
  92.             $this->logger->debug('MPESa Validation', [$request->getContent()]);
  93.             $json $request->getContent();
  94.             $response json_decode($jsontrue);
  95.             $transactionId $response['TransID'];
  96.             $transactionTime $response['TransTime'];
  97.             $from \DateTime::createFromFormat('YmdHis'$transactionTime);
  98.             $transactionTime $from;
  99.             $transactionType $response['TransactionType'];
  100.             $transactionAmount $response['TransAmount'];
  101.             $shortCode $response['BusinessShortCode'];
  102.             $billRefNumber $response['BillRefNumber'];
  103.             $invoiceNumber $response['InvoiceNumber'];
  104.             $accountBalance $response['OrgAccountBalance'];
  105.             $thirdPartyTransactionId $response['ThirdPartyTransID'];
  106.             $msisdn $response['MSISDN'];
  107.             $firstName $response['FirstName'];
  108.             $secondName = isset($response['MiddleName']) ? $response['MiddleName'] : '-';
  109.             $lastName = isset($response['LastName']) ? $response['LastName'] : '-';
  110.             $mpesa = new MpesaTransaction();
  111.             $mpesa->setTransactionId($transactionId);
  112.             $mpesa->setTransactionType($transactionType);
  113.             $mpesa->setTransactionTime($transactionTime);
  114.             $mpesa->setTransactionAmount($transactionAmount);
  115.             $mpesa->setShortCode($shortCode);
  116.             $mpesa->setBillReferenceNumber($billRefNumber);
  117.             $mpesa->setAccountBalance(($accountBalance $accountBalance 0));
  118.             $mpesa->setThirdPartyTransactionId($thirdPartyTransactionId);
  119.             $mpesa->setMsisdn($msisdn);
  120.             $mpesa->setFirstName($firstName);
  121.             $mpesa->setMiddleName($secondName);
  122.             $mpesa->setLastName($lastName);
  123.             $mpesa->setIsComplete(false);
  124.             $mpesa->setCreatedAt(new \DateTime());
  125.             $mpesa->setIsValidated(false);
  126.             $mpesa->setIsSeen(false);
  127.             $mpesa->setIsUsed(false);
  128.             $mpesa->setCompletedMpesaFromIp($request->getClientIp());
  129.             try {
  130.                 $em->persist($mpesa);
  131.                 $em->flush();
  132. //            return new Response('OK', Response::HTTP_OK);
  133.                 return new JsonResponse([
  134.                     "ResultCode" => '0',
  135.                     "ResultDesc" => "Accepted"
  136.                 ], Response::HTTP_OK);
  137.             } catch (\PDOException $exception) {
  138.                 return new JsonResponse([
  139.                     "ResultCode" => 'C2B00016',
  140.                     "ResultDesc" => "Rejected"
  141.                 ], Response::HTTP_OK);
  142.             }
  143.         }
  144. //        return new Response('OK', Response::HTTP_OK);
  145.     }
  146.     /**
  147.      * @Route("/callback/verify", methods={"POST"}, name="mpesaCallbackVerify")
  148.      * @param Request $request
  149.      * @return Response
  150.      */
  151.     public function mpesaCallbackVerification(Request $request): Response
  152.     {
  153.         $this->logger->debug($request->getContent());
  154.         $jsonData json_decode($request->getContent(), true);
  155.         $result $jsonData['Result'];
  156.         $resultCode $result['ResultCode'];
  157.         if($resultCode == '0') {
  158.             $resultParameters $result['ResultParameters']['ResultParameter'];
  159.             $firstName null;
  160.             $middleName null;
  161.             $lastName null;
  162.             $mpesaTransaction = new MpesaTransaction();
  163.             foreach ($resultParameters as $index => $resultParameter) {
  164.                 if ($index == 0) {
  165.                     $phoneName $resultParameter['Value'];
  166.                     if ($phoneName) {
  167.                         $phoneNameArray explode('-'$phoneName);
  168.                         $phoneNumber trim($phoneNameArray[0]);
  169.                         $name $phoneNameArray[1];
  170.                         $namesArray explode(" "trim($name));
  171.                         foreach ($namesArray as $index => $item) {
  172.                             if ($index == 0) {
  173.                                 $firstName trim($item);
  174.                             } elseif ($index == 1) {
  175.                                 $middleName trim($item);
  176.                             } elseif ($index >= 2) {
  177.                                 $lastName .= trim($item);
  178.                             }
  179.                         }
  180.                         $mpesaTransaction->setMsisdn($phoneNumber);
  181.                         $mpesaTransaction->setFirstName($firstName);
  182.                         $mpesaTransaction->setMiddleName($middleName $middleName '-');
  183.                         $mpesaTransaction->setLastName($lastName $lastName '-');
  184.                     }
  185.                 } else if ($index == 1) {
  186.                     $values explode('-'$resultParameter['Value']);
  187.                     $mpesaTransaction->setShortCode($values[0]);
  188.                 } else if ($index == 3) {
  189.                     $transactionTime explode('-'$resultParameter['Value']);
  190.                     $from \DateTime::createFromFormat('YmdHis'$transactionTime[0]);
  191.                     $mpesaTransaction->setTransactionTime($from);
  192.                 } else if ($index == 10) {
  193.                     $amount $resultParameter['Value'];
  194.                     $mpesaTransaction->setTransactionAmount($amount);
  195.                 } else if ($index == 12) {
  196.                     $transactionID $resultParameter['Value'];
  197.                     $mpesaTransaction->setTransactionId($transactionID);
  198.                 }
  199.             }
  200. //
  201.             $mpesaTransaction->setTransactionType("Paybill");
  202.             $mpesaTransaction->setIsValidated(false);
  203.             $mpesaTransaction->setCreatedAt(new DateTime());
  204.             $mpesaTransaction->setBillReferenceNumber('billReference');
  205.             $mpesaTransaction->setAccountBalance(0);
  206.             $mpesaTransaction->setIsComplete(true);
  207.             $mpesaTransaction->setIsSeen(false);
  208.             $mpesaTransaction->setIsUsed(false);
  209.             $mpesaManual = new MpesaManual();
  210.             $mpesaManual->setMpesaTransaction($mpesaTransaction);
  211.             $mpesaManual->setCreatedBy(null);
  212.             $mpesaManual->setCreatedAt(new DateTime());
  213.             $mpesaAuth $this->em->getRepository(MpesaAuth::class)->findOneBy([
  214.                 'tillNumber' => $mpesaTransaction->getShortCode()
  215.             ]);
  216.             $mpesaManual->setBranch($mpesaAuth->getBranch());
  217.             try {
  218.                 $user $this->em->getRepository(User::class)->findOneBy([
  219.                     'id' => 17
  220.                 ]);
  221.                 $mpesaManual->setCreatedBy($user);
  222.                 $this->em->persist($mpesaTransaction);
  223.                 $this->em->persist($mpesaManual);
  224.                 $this->em->flush();
  225.             } catch (\Exception $error) {
  226.                 $this->logger->debug($error->getMessage());
  227.             }
  228.         }
  229.         return new Response('OK'Response::HTTP_OK);
  230.     }
  231.     /**
  232.      * @Route("/callback/verify/timeout", methods={"POST"}, name="mpesaCallbackVerifyTimeout")
  233.      * @param Request $request
  234.      * @return Response
  235.      */
  236.     public function mpesaCallbackVerificationTimeout(Request $request): Response
  237.     {
  238.         $this->logger->debug($request->getContent());
  239.          
  240.         return new Response('OK'Response::HTTP_OK);
  241.     }
  242.     /**
  243.      * @Route("/callback/validation", methods={"POST"}, name="mpesaCallbackValidation")
  244.      * @param Request $request
  245.      * @return Response
  246.      */
  247.     public function mpesaCallbackValidation(Request $request): JsonResponse|Response
  248.     {
  249.         $em $this->em;
  250.         $this->logger->debug('MPESa Validation', [$request->getContent()]);
  251.         $json $request->getContent();
  252.         $response json_decode($jsontrue);
  253.         $transactionId $response['TransID'];
  254.         $transactionTime $response['TransTime'];
  255.         $from \DateTime::createFromFormat('YmdHis'$transactionTime);
  256.         $transactionTime $from;
  257.         $transactionType $response['TransactionType'];
  258.         $transactionAmount $response['TransAmount'];
  259.         $shortCode $response['BusinessShortCode'];
  260.         $billRefNumber $response['BillRefNumber'];
  261.         $invoiceNumber $response['InvoiceNumber'];
  262.         $accountBalance $response['OrgAccountBalance'];
  263.         $thirdPartyTransactionId $response['ThirdPartyTransID'];
  264.         $msisdn $response['MSISDN'];
  265.         $firstName $response['FirstName'];
  266.         $secondName = isset($response['MiddleName']) ? $response['MiddleName'] : '-';
  267.         $lastName = isset($response['LastName']) ? $response['LastName'] : '-';
  268.         $mpesa = new MpesaTransactionVerification();
  269.         $mpesa->setTransactionId($transactionId);
  270.         $mpesa->setTransactionType($transactionType);
  271.         $mpesa->setTransactionTime($transactionTime);
  272.         $mpesa->setTransactionAmount($transactionAmount);
  273.         $mpesa->setShortCode($shortCode);
  274.         $mpesa->setBillReferenceNumber($billRefNumber);
  275.         $mpesa->setAccountBalance(($accountBalance $accountBalance 0));
  276.         $mpesa->setThirdPartyTransactionId($thirdPartyTransactionId);
  277.         $mpesa->setMsisdn($msisdn);
  278.         $mpesa->setFirstName($firstName);
  279.         $mpesa->setMiddleName($secondName);
  280.         $mpesa->setLastName($lastName);
  281.         $mpesa->setIsComplete(false);
  282.         $mpesa->setCreatedAt(new \DateTime());
  283.         $mpesa->setIsValidated(false);
  284.         $mpesa->setIsSeen(false);
  285.         $mpesa->setIsUsed(false);
  286.         $mpesa->setCompletedMpesaFromIp($request->getClientIp());
  287.         try {
  288.             $em->persist($mpesa);
  289.             $em->flush();
  290. //            return new Response('OK', Response::HTTP_OK);
  291.             return new JsonResponse([
  292.                 "ResultCode" => '0',
  293.                 "ResultDesc" => "Accepted"
  294.             ], Response::HTTP_OK);
  295.         } catch (\PDOException $exception) {
  296.             return new JsonResponse([
  297.                 "ResultCode" => 'C2B00016',
  298.                 "ResultDesc" => "Rejected"
  299.             ], Response::HTTP_OK);
  300.         }
  301.     }
  302.     /**
  303.      * @Route("/callback/register/{shortCode}", name="register_callback_urls")
  304.      * @return Response|null
  305.      */
  306.     function paymentUrlRegister(Request $request$shortCode): ?Response
  307.     {
  308.         $em $this->getDoctrine()->getManager();
  309.         /** @var MpesaAuth $credential */
  310.         $credential $em->getRepository(MpesaAuth::class)->findOneBy([
  311.             'authType' => $this->authType,
  312.             'tillNumber' => $shortCode
  313.         ]);
  314.         if (!$credential) {
  315.             return new Response('Credentials not found'Response::HTTP_OK, [
  316.                 'content-type' => 'application/json'
  317.             ]);
  318.         }
  319.         dump("Get credentials");
  320.         $response = [];
  321.        $data =  [
  322.             'ShortCode' => $credential->getTillNumber(),
  323.             'ResponseType' => 'Completed',
  324.             'ConfirmationURL' => 'https://neema.ohau.co.ke/callback',
  325.             'ValidationURL' => 'https://neema.ohau.co.ke/callback/validation'
  326.         ];
  327.         $url "https://{$this->host}{$this->callbackUrlRegister}";
  328.         try {
  329.             $response $this->client->request(
  330.                 "POST",
  331.                 $url,
  332.                 [
  333.                     'headers' => [
  334.                         "Content-Type:application/json",
  335.                         "Authorization:Bearer {$credential->getToken()}"
  336.                     ],
  337.                     'json' => $data
  338.                 ],
  339.             );
  340.             $responseData $response->getContent();
  341.             $this->logger->debug("ok - {$responseData}_");
  342.             return new Response($response->getContent(), Response::HTTP_OK);
  343.         } catch (ClientExceptionInterface|ClientException|RedirectionExceptionInterface|ServerExceptionInterface|TransportExceptionInterface $e) {
  344.             $this->logger->debug($e->getMessage());
  345.             return new Response($e->getMessage(), Response::HTTP_OK);
  346.         }
  347.     }
  348.     /**
  349.      * @Route("/mpesa/mpesa_credentials/{shortCode}", name="renew_mpesa_authentication")
  350.      */
  351.     function getMpesaAuthentication(Request $request$shortCode)
  352.     {
  353.         $em $this->em;
  354.         $ip $request->getClientIp();
  355.         $date = new \DateTime();
  356.         $date date_format($date'YmdHis');
  357.         /** @var MpesaAuth $credential */
  358.         $credential $em->getRepository(MpesaAuth::class)->findOneBy([
  359.             'authType' => $this->authType,
  360.             'tillNumber' => $shortCode
  361.         ]);
  362.         $date = new \DateTime();
  363.         $date date_format($date'YmdHis');
  364.         $url "https://{$this->host}{$this->tokenRequest}";
  365.         $password base64_encode("{$credential->getConsumerKey()}:{$credential->getConsumerSecret()}");
  366.         try {
  367.             $response $this->client->request(
  368.                 "GET",
  369.                 $url,
  370.                 [
  371.                     'headers' => [
  372.                         "Content-Type:application/json",
  373.                         "Authorization:Basic {$password}"
  374.                     ]
  375.                 ]
  376.             );
  377.             $responseData $response->getContent();
  378. //            dump($responseData); die;
  379.             $responseDataArray json_decode($responseDatatrue);
  380.             $credential->setToken($responseDataArray['access_token']);
  381.             $credential->setTokenUpdatedAt(new \DateTime());
  382.             $em->flush();
  383.             $this->logger->debug("ok - {$responseData}_");
  384.             return new Response($response->getContent(), Response::HTTP_OK);
  385.         } catch (ClientExceptionInterface|ClientException|RedirectionExceptionInterface|ServerExceptionInterface|TransportExceptionInterface $e) {
  386.             $this->logger->debug($e->getMessage());
  387.             return new Response($e->getMessage(), Response::HTTP_OK);
  388.         }
  389.     }
  390.     #[Route('/imports'name'app_admin_imports_k')]
  391.     public function importMpesaTransactions(){
  392.         $path $this->kernel->getProjectDir() .'/reports''/imports' '/mpesa_18_19.csv';
  393.         $rowNo 1;
  394.         $availableStudents 0;
  395.         $sumAllocation 0;
  396.         // $fp is file pointer to file sample.csv
  397.         $count 0;
  398.         $total 0;
  399.         if (($fp fopen($path"r")) !== FALSE) {
  400.             while (($row fgetcsv($fp1000",")) !== FALSE) {
  401.                 $num count($row);
  402.                 // dump("<p> $num fields in line $rowNo: <br /></p>\n");
  403.                 $rowNo++;
  404.                 $mpesaTransaction $this->em->getRepository(MpesaTransaction::class)->findOneBy([
  405.                     'transactionId' => $row[0]
  406.                 ]);
  407.                 if($mpesaTransaction){
  408.                     $mpesaTransaction->setMsisdn($row[7]);
  409.                 }
  410.                 if(!$mpesaTransaction) {
  411.                     $k $row[1].' '.$row[2];
  412. //                    "18-06-2024 14:30:47"
  413. //                    dump($k);
  414.                     $dateTime DateTime::createFromFormat('d-m-Y H:i:s',$k);
  415. //                    $datetime = DateTime::createFromFormat('d/m/Y', $date_str);
  416. //                    dump($dateTime);
  417.                     $mpesaTransaction = new MpesaTransaction();
  418.                     $mpesaTransaction->setCreatedAt(new DateTime());
  419.                     $mpesaTransaction->setTransactionId($row[0]);
  420.                     $mpesaTransaction->setTransactionType($row[6]);
  421.                     $mpesaTransaction->setFirstName($row[8]);
  422.                     $mpesaTransaction->setTransactionTime($dateTime);
  423.                     $mpesaTransaction->setShortCode($row[3]);
  424.                     $mpesaTransaction->setMsisdn($row[7]);
  425.                     $mpesaTransaction->setIsUsed(false);
  426.                     $mpesaTransaction->setIsComplete(true);
  427.                     $mpesaTransaction->setTransactionAmount($row[4]);
  428.                     $mpesaTransaction->setBillReferenceNumber($row[0]);
  429.                     $mpesaTransaction->setAccountBalance($row[4]);
  430.                     $mpesaTransaction->setIsSeen(false);
  431.                     $mpesaTransaction->setIsValidated(false);
  432.                     $this->em->persist($mpesaTransaction);
  433.                     $count++;
  434.                 }
  435.             }
  436.             dump($count);
  437.             dump($total);
  438.             fclose($fp);
  439.             $this->em->flush();
  440.             dump($availableStudents);
  441.             dump($sumAllocation);
  442. //            $this->em->flush();
  443.         }
  444.         die;
  445.     }
  446. }