src/Payment/MpesaPaymentController.php line 355

Open in your IDE?
  1. <?php
  2. namespace App\Payment;
  3. use App\Controller\SendSms;
  4. use App\Entity\Mpesa;
  5. use App\Entity\MpesaAuth;
  6. use App\Entity\MpesaMessage;
  7. use App\Entity\MpesaPaybill;
  8. use App\Entity\MpesaPayment;
  9. use App\Entity\MpesaPaymentRequest;
  10. use App\Entity\MpesaResponse;
  11. use App\Entity\MpesaTransaction;
  12. use App\Entity\Transaction;
  13. use App\Entity\WayBill;
  14. use DateTime;
  15. use Doctrine\DBAL\Driver\PDO\Exception;
  16. use Doctrine\ORM\EntityRepository;
  17. use Doctrine\Persistence\ManagerRegistry;
  18. use Doctrine\Persistence\ObjectManager;
  19. use http\Message;
  20. use JMS\Serializer\SerializationContext;
  21. use JMS\Serializer\SerializerBuilder;
  22. use NumberFormatter;
  23. use Psr\Log\LoggerInterface;
  24. use Symfony\Bridge\Doctrine\Form\Type\EntityType;
  25. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  26. use Symfony\Component\Form\Extension\Core\Type\FormType;
  27. use Symfony\Component\Form\Extension\Core\Type\NumberType;
  28. use Symfony\Component\Form\Extension\Core\Type\TextType;
  29. use Symfony\Component\HttpFoundation\JsonResponse;
  30. use Symfony\Component\HttpFoundation\Request;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\Routing\Annotation\Route;
  33. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  34. use Symfony\Component\Validator\Constraints\Length;
  35. use Symfony\Component\Validator\Constraints\NotBlank;
  36. class MpesaPaymentController extends AbstractController
  37. {
  38.     private $logger;
  39.     private $host 'api.safaricom.co.ke';
  40.     private $stkpushUrl '/mpesa/stkpush/v1/processrequest';
  41. //    private $callbackUrlRegister = '/mpesa/c2b/v2/registerurl';
  42.     private $callbackUrlRegister '/mpesa/c2b/v1/registerurl';
  43.     private $tokenRequest '/oauth/v1/generate?grant_type=client_credentials';
  44.     private $authType 'PROD';
  45.     private $sms;
  46.     private ObjectManager $manager;
  47. //    private $url = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
  48.     public function __construct(LoggerInterface $loggerManagerRegistry $managerRegistry)
  49.     {
  50.         $this->sms = new SendSms();
  51.         $this->logger $logger;
  52.         $this->manager $managerRegistry->getManager();
  53.     }
  54.     /**
  55.      * @Route("/request/mpesa/{waybill_id}", methods={"POST"}, name="request_mpesa_express_payment")
  56.      * @param $waybill_id
  57.      * @return Response
  58.      */
  59.     public function requestMpesaExpressPayment(Request $request$waybill_id)
  60.     {
  61.         $this->logger->info("Start creating request");
  62.         $em $this->getDoctrine()->getManager();
  63.         /** @var WayBill $waybill */
  64.         $waybill $em->getRepository(WayBill::class)
  65.             ->findOneBy([
  66.                 'id' => $waybill_id
  67.             ]);
  68. //        /** @var Transaction $transaction */
  69. //        $transaction = $em->getRepository(Transaction::class)->findOneBy([
  70. //            'wayBill' => $waybill
  71. //        ]);
  72.         if (!$waybill) {
  73.             return $this->redirectToRoute('payment_request_view', ['waybill'$waybill_id]);
  74.         }
  75.         $requestSenderPhoneForm $this->postMpesaPaymentPhoneNumber($waybill_id'sender_form');
  76.         $requestSenderPhoneForm->handleRequest($request);
  77.         $requestReceiverPhoneForm $this->postMpesaPaymentPhoneNumber($waybill_id'receiver_form');
  78.         $requestReceiverPhoneForm->handleRequest($request);
  79.         $requestOtherPhoneForm $this->postMpesaPaymentPhoneNumber($waybill_id'other_form');
  80.         $requestOtherPhoneForm->handleRequest($request);
  81.         $data '';
  82.         if ($requestSenderPhoneForm->isSubmitted() || $requestReceiverPhoneForm->isSubmitted() || $requestOtherPhoneForm->isSubmitted()) {
  83. //          $requestForm->getData('phone');
  84. //          $requestForm->get('field');
  85. //            dump($requestSenderPhoneForm);
  86. //            dump($requestReceiverPhoneForm);
  87. //            dump($requestOtherPhoneForm);
  88.             $data null;
  89.             if ($requestSenderPhoneForm->isSubmitted()) {
  90.                 dump($requestSenderPhoneForm);
  91. //                $requestForm = $requestSenderPhoneForm;
  92.                 $data $requestSenderPhoneForm->getData();
  93.             } else if ($requestReceiverPhoneForm->isSubmitted()) {
  94.                 dump($requestReceiverPhoneForm);
  95. //                $requestForm = $requestSenderPhoneForm;
  96.                 $data $requestReceiverPhoneForm->getData();
  97.             } else if ($requestOtherPhoneForm->isSubmitted()) {
  98. //                $requestForm = $requestOtherPhoneForm;
  99.                 dump($requestOtherPhoneForm);
  100.                 $data $requestOtherPhoneForm->getData();
  101.             }
  102. //            dump($data);
  103. //            die;
  104.             $this->logger->info('payment data'$data);
  105.             $phone str_replace(' '''$data['phone']);
  106.             $phone substr_replace($phone''01);
  107.             $phone '254' $phone;
  108.             $field $data['field'];
  109.             $waybill->getTransaction()->setPaymentMethod('MPESA');
  110.             $waybill->getTransaction()->setMpesaPaymentPhone($phone);
  111.             $waybill->getTransaction()->setPaidBy($field);
  112.             $em->flush();
  113.             $amount $waybill->getTransaction()->getAmount();
  114.             $date $waybill->getCreatedAt();
  115.             $date date_format($date'YmdHis');
  116.             $this->logger->info("Create formatted Date{$date}");
  117.             /** @var MpesaAuth $credentials */
  118.             $credentials $em->getRepository(MpesaAuth::class)->findOneBy([
  119.                 'station' => $request->getSession()->get('STATION'),
  120.                 'authType' => $this->authType
  121.             ]);
  122.             $this->logger->info("Get credentials");
  123.             $url "https://{$this->host}{$this->stkpushUrl}";
  124. //        dump($authKey);
  125.             if ($credentials) {
  126.                 $curl curl_init();
  127.                 curl_setopt($curlCURLOPT_URL$url);
  128.                 curl_setopt($curlCURLOPT_HTTPHEADER, [
  129.                         "Content-Type:application/json",
  130.                         "Authorization:Bearer {$credentials->getToken()}"
  131.                     ]
  132.                 );
  133.                 //setting custom header
  134. //                'CallBackURL' => $this->generateUrl("receive_mpesa_express_callback",['waybill_id' => $waybill->getId()], UrlGeneratorInterface::ABSOLUTE_URL),
  135.                 $curl_post_data = array(
  136.                     //Fill in the request parameters with valid values
  137.                     'BusinessShortCode' => "{$credentials->getPaybill()}",
  138.                     'Password' => base64_encode("{$credentials->getPaybill()}{$credentials->getPassKey()}{$date}"),
  139.                     'Timestamp' => "{$date}",
  140.                     'TransactionType' => 'CustomerPayBillOnline',
  141.                     'Amount' => $amount,
  142.                     'PartyA' => $phone,
  143.                     'PartyB' => "{$credentials->getPaybill()}",
  144.                     'PhoneNumber' => $phone,
  145.                     'CallBackURL' => "https://sys.nenocourier.co.ke/payment/callback/express/{$waybill->getId()}",
  146.                     'AccountReference' => $waybill->getId(),
  147.                     'TransactionDesc' => "Request to {$phone} to pay for waybill {$waybill->getId()}"
  148.                 );
  149. //                dump($curl_post_data);
  150.                 $data_string json_encode($curl_post_data);
  151.                 curl_setopt($curlCURLOPT_RETURNTRANSFERtrue);
  152.                 curl_setopt($curlCURLOPT_POSTtrue);
  153.                 curl_setopt($curlCURLOPT_POSTFIELDS$data_string);
  154.                 $curl_response curl_exec($curl);
  155.                 $this->logger->info("Request response");
  156.                 $this->logger->info($curl_response);
  157.                 $curlResponse json_decode($curl_responsetrue);
  158.                 if (isset($curlResponse['errorCode'])) {
  159.                     $response = [
  160.                         'message' => 'Error occurred during request',
  161.                         'error' => $curlResponse['errorMessage']
  162.                     ];
  163.                     $jsonResponse json_encode($response);
  164.                     $this->logger->error("payment_request_error"$curlResponse);
  165.                     $this->addFlash('success''Payment request sent to ' $phone);
  166.                     return $this->redirectToRoute('payment_request_view', ['waybill' => $waybill_id]);
  167. //
  168. //                        return new Response($jsonResponse, Response::HTTP_NOT_ACCEPTABLE,[
  169. //                            'content-type' => 'text/json'
  170. //                        ]);
  171.                 } elseif (isset($curlResponse['ResponseCode'])) {
  172.                     $response = [
  173.                         'message' => 'Request sent'
  174.                     ];
  175.                     $this->addFlash('success''Payment request sent to ' $phone);
  176.                     return $this->redirectToRoute('payment_request_view', ['waybill' => $waybill_id]);
  177. //
  178. //                        $response = json_encode($response);
  179. //                        return new Response($response, Response::HTTP_OK,[
  180. //                            'content-type' => 'text/json'
  181. //                        ]);
  182.                 }
  183.             }
  184.         }
  185.     }
  186.     /**
  187.      * @Route("/callback/express/awesome/{waybill_id}",  name="receive_mpesa_express_callback_testing")
  188.      * @param Request $request
  189.      * @param $waybill_id
  190.      * @return Response
  191.      */
  192.     public function receiveMpesaExpressCallbackTesting(Request $request$waybill_id)
  193.     {
  194. //        dump($request->getContent());
  195. //        $this->logger->info('Printed: ', $request->getContent());
  196.         return new Response("OK"Response::HTTP_OK, [
  197.             'content-type' => 'text/html'
  198.         ]);
  199.     }
  200.     /**
  201.      * @Route("/callback/express/{waybill_id}",  name="receive_mpesa_express_callback")
  202.      * @param Request $request
  203.      * @param $waybill_id
  204.      * @return Response
  205.      */
  206.     public function receiveMpesaExpressCallback(Request $request$waybill_id)
  207.     {
  208.         $em $this->getDoctrine()->getManager();
  209.         /** @var WayBill $waybill */
  210.         $waybill $em->getRepository("App:WayBill")->findOneBy([
  211.             'id' => $waybill_id
  212.         ]);
  213.         $transaction $waybill->getTransaction();
  214.         $json $request->getContent();
  215.         $this->logger->info("Gotten response mpesa");
  216.         $this->logger->info($json);
  217.         $response json_decode($jsontrue);
  218.         $mpesaPayment = new MpesaPayment();
  219.         $mpesaResponse = new MpesaResponse();
  220.         $merchantRequestId $response['Body']['stkCallback']['MerchantRequestID'];
  221.         $checkoutRequestID $response['Body']['stkCallback']['CheckoutRequestID'];
  222.         $resultCode $response['Body']['stkCallback']['ResultCode'];
  223.         $resultDesc $response['Body']['stkCallback']['ResultDesc'];
  224.         $mpesaResponse->setMerchantRequestId($merchantRequestId);
  225.         $mpesaResponse->setCheckoutRequestId($checkoutRequestID);
  226.         $mpesaResponse->setCode($resultCode);
  227.         $mpesaResponse->setDescription($resultDesc);
  228.         $mpesaResponse->setCreatedAt(new \DateTime());
  229.         $mpesaResponse->setWaybill($waybill);
  230.         $em->persist($mpesaResponse);
  231.         if ($resultCode == 0) {
  232.             $items $response['Body']['stkCallback']['CallbackMetadata']['Item'];
  233.             $amount $items[0]['Value'];
  234.             $receiptNumber $items[1]['Value'];
  235.             $transactionDate '';
  236.             $phoneNumber '';
  237.             if (count($items) == 5) {
  238.                 $transactionDate $items[3]['Value'];
  239.                 $phoneNumber $items[4]['Value'];
  240.             } else {
  241.                 $transactionDate $items[2]['Value'];
  242.                 $phoneNumber $items[3]['Value'];
  243.             }
  244.             $mpesaPayment->setAmount($amount);
  245.             $mpesaPayment->setMpesaPaymentType("MPESA_EXPRESS");
  246.             $mpesaPayment->setWaybill($waybill);
  247.             $mpesaPayment->setPhone($phoneNumber);
  248.             $mpesaPayment->setResponse($mpesaResponse);
  249.             $mpesaPayment->setTransactionId($receiptNumber);
  250.             $mpesaPayment->setCreatedAt(new \DateTime());
  251.             $em->persist($mpesaPayment);
  252.             $transaction->setPaymentMethod('MPESA');
  253.         }
  254.         $conn $em->getConnection();
  255.         $conn->beginTransaction();
  256.         try {
  257.             $em->flush();
  258.             $em->getConnection()->commit();
  259.         } catch (\PDOException $exception) {
  260.             $em->getConnection()->rollBack();
  261.         }
  262.         return new Response("OK"Response::HTTP_OK, [
  263.             'content-type' => 'text/html'
  264.         ]);
  265.     }
  266.     /**
  267.      * @Route("/callback/paybill", methods={"POST"}, name="receive_mpesa_paybill_callback")
  268.      * @param Request $request
  269.      * @return Response
  270.      */
  271.     public function receiveMpesaPaybillCallback(Request $request)
  272.     {
  273.         $em $this->getDoctrine()->getManager();
  274.         $json $request->getContent();
  275.         $this->logger->debug('mpesa-paybill response' $json);
  276.         $this->logger->error('');
  277.         $response json_decode($jsontrue);
  278.         $transactionType $response['TransactionType'];
  279.         $transactionId $response['TransID'];
  280.         $transactionTime $response['TransTime'];
  281.         $transactionAmount $response['TransAmount'];
  282.         $shortCode $response['BusinessShortCode'];
  283.         $billRefNumber $response['BillRefNumber'];
  284.         $invoiceNumber $response['InvoiceNumber'];
  285.         $accountBalance $response['OrgAccountBalance'];
  286.         $thirdPartyTransactionId $response['ThirdPartyTransID'];
  287.         $msisdn $response['MSISDN'];
  288.         $firstName $response['FirstName'];
  289.         $secondName '-';
  290.         $lastName '-';
  291.         if ($shortCode != 4022957 && $shortCode != 726614) {
  292.             $secondName $response['MiddleName'];
  293.             $lastName $response['LastName'];
  294.         }
  295.         $mpesa = new Mpesa();
  296.         $mpesa->setTransactionId($transactionId);
  297.         $mpesa->setTransactionType($transactionType);
  298.         $mpesa->setTransactionTime($transactionTime);
  299.         $mpesa->setTransactionAmount($transactionAmount);
  300.         $mpesa->setShortCode($shortCode);
  301.         $mpesa->setRefNumber($billRefNumber);
  302.         $mpesa->setBalance(($accountBalance $accountBalance 0));
  303.         $mpesa->setMsisdn($msisdn);
  304.         $mpesa->setFirstName(($firstName $firstName ''));
  305.         $mpesa->setMiddleName($secondName $secondName '');
  306.         $mpesa->setLastName($lastName $lastName '');
  307.         $mpesa->setCreatedAt(new \DateTime());
  308.         $mpesa->setIsUsed(false);
  309.         $conn $em->getConnection();
  310.         $conn->beginTransaction();
  311.         try {
  312.             /** @var Mpesa $availableMpesa */
  313.             $availableMpesa $em->getRepository(Mpesa::class)->findOneBy([
  314.                 'transactionId' => $transactionId
  315.             ]);
  316.             if($availableMpesa){
  317.                 $availableMpesa->setTransactionType('PAYBILL_PHONE_AV');
  318.             }else{
  319.                 $em->persist($mpesa);
  320.             }
  321.             $em->getConnection()->commit();
  322.             $em->flush();
  323.             return new Response("OK"Response::HTTP_OK, [
  324.                 'content-type' => 'text/html'
  325.             ]);
  326.         } catch (\PDOException $exception) {
  327.             $em->getConnection()->rollBack();
  328.             $this->logger->error($exception->getMessage(), []);
  329.             $date = new \DateTime();
  330.             $date date_format($date'Y/m/d H:i:s');
  331.             $this->sms->sendOutSms('254716308459'"HELLO Samuel A payment mpesa error occurred during COMMIT at {$date}");
  332.             return new Response("NOT OK"Response::HTTP_INTERNAL_SERVER_ERROR, [
  333.                 'content-type' => 'text/html'
  334.             ]);
  335.         }
  336.         /*return new Response("NOT OK", Response::HTTP_INTERNAL_SERVER_ERROR, [
  337.             'content-type' => 'text/html'
  338.         ]);*/
  339.     }
  340.     /**
  341.      * @Route("/callback/paybill/validation", methods={"POST"}, name="receive_mpesa_paybill_callback_validation")
  342.      * @param Request $request
  343.      * @return Response
  344.      */
  345.     public function receiveMpesaPaybillCallbackValidation(Request $request)
  346.     {
  347.         $json $request->getContent();
  348.         $this->logger->log('MPESA VALIDATION: ',$json);
  349.         return new JsonResponse([
  350.             "ResultCode" => '0',
  351.             "ResultDesc" => "Accepted"
  352.         ], Response::HTTP_OK);
  353.     }
  354.     /**
  355.      * @Route("/response/mpesa/{waybill_id}", name="payment_response_verification")
  356.      * @param $waybill_id
  357.      * @return Response
  358.      */
  359.     public function paymentResponseVerification($waybill_id)
  360.     {
  361.         $em $this->getDoctrine()->getManager();
  362.         /** @var WayBill $waybill */
  363.         $waybill $em->getRepository("App:WayBill")->findOneBy([
  364.             'id' => $waybill_id
  365.         ]);
  366. //        dump($waybill);
  367.         if ($waybill) {
  368.             /** @var MpesaPaymentRequest $mpesaRequest */
  369.             $mpesaRequest $em->getRepository("App:MpesaPaymentRequest")
  370.                 ->findBy([
  371.                     'waybill' => $waybill
  372.                 ]);
  373.             /** @var MpesaResponse $mpesaResponse */
  374.             $mpesaResponses $em->getRepository("App:MpesaResponse")
  375.                 ->findBy([
  376.                     'waybill' => $waybill
  377.                 ]);
  378.             /** @var MpesaPayment $mpesaPayment */
  379.             $mpesaPayments $em->getRepository("App:MpesaPayment")
  380.                 ->findBy([
  381.                     'waybill' => $waybill
  382.                 ]);
  383.             if ($mpesaResponses) {
  384.                 return $this->render('fos/parcels/mpesa_payment.html.twig', [
  385.                     'mpesa_responses' => $mpesaResponses,
  386.                     'mpesa_payments' => $mpesaPayments,
  387.                     'waybill' => $waybill,
  388.                     'isAvailable' => true,
  389.                     'mpesa_requests' => $mpesaRequest
  390.                 ]);
  391.             }
  392.             return $this->render('fos/parcels/mpesa_payment.html.twig', [
  393.                 'isAvailable' => false,
  394.                 'waybill' => $waybill
  395.             ]);
  396.         }
  397.         return $this->render('fos/parcels/mpesa_payment.html.twig', [
  398.             'isAvailable' => false,
  399.         ]);
  400.     }
  401.     /**
  402.      * @Route("/renew/mpesa_credentials", name="renew_mpesa_authentication")
  403.      */
  404.     function getMpesaAuthentication(Request $request)
  405.     {
  406.         $em $this->getDoctrine()->getManager();
  407.         $ip $request->getClientIp();
  408.         $date = new \DateTime();
  409.         $date date_format($date'YmdHis');
  410.         $this->logger->info("Create formatted Date{$date}");
  411.         /** @var MpesaAuth $credentials */
  412.         $credentials $em->getRepository(MpesaAuth::class)->findBy([
  413.             'authType' => $this->authType
  414.         ]);
  415.         $this->logger->info("Get credentials");
  416.         dump($credentials);
  417. //        die;
  418. //        dump($credentials->getConsumerSecret().' '.$credentials->getConsumerKey());
  419. //        ips: [35.180.247.100]
  420.         $errors '';
  421.         foreach ($credentials as $index => $credential) {
  422.             if ($credential) {
  423.                 $url "https://{$this->host}{$this->tokenRequest}";
  424.                 $password base64_encode("{$credential->getConsumerKey()}:{$credential->getConsumerSecret()}");
  425.                 $curl curl_init();
  426.                 curl_setopt($curlCURLOPT_URL$url);
  427.                 curl_setopt($curlCURLOPT_HTTPHEADER, [
  428.                         "Content-Type:application/json",
  429.                         "Authorization:Basic {$password}"
  430.                     ]
  431.                 );
  432.                 curl_setopt($curlCURLOPT_RETURNTRANSFERtrue);
  433.                 curl_setopt($curlCURLOPT_HTTPGETtrue);
  434. //            curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
  435.                 $curl_response curl_exec($curl);
  436.                 dump($curl_response);
  437.                 $this->logger->info("Request response");
  438.                 $this->logger->info($curl_response);
  439.                 $curlResponse json_decode($curl_responsetrue);
  440.                 if ($curlResponse) {
  441.                     $response json_decode($curl_responsetrue);
  442.                     $credential->setToken($response['access_token']);
  443.                     $credential->setTokenUpdatedAt(new \DateTime());
  444.                     $em->flush();
  445. //                    $date = new \DateTime();
  446. //                    $date = date_format($date, 'Y/m/d H:i:s');
  447. //                    $this->sms->sendOutSms('254716308459', "HELLO Samuel MPESA TOKEN GENERATION SUCCEEDED at {$date}");
  448.                 } else {
  449.                     $date = new \DateTime();
  450.                     $date date_format($date'Y/m/d H:i:s');
  451.                     $this->sms->sendOutSms('254716308459'"HELLO Samuel MPESA TOKEN GENERATION FAILED at {$date} pleae check it out");
  452.                     $errors .= $credential->getPaybill() . ' Could not create credentials';
  453. //                    return new Response("error", Response::HTTP_OK, [
  454. //                        'content-type'=>'text/html'
  455. //                    ]);
  456.                 }
  457.             }
  458.         }
  459.         die;
  460.         return new Response("AWESOME {$errors}_" $ipResponse::HTTP_OK, [
  461.             'content-type' => 'text/html'
  462.         ]);
  463. //        $sms = new SendSms();
  464. //        $sms->sendOutSms('254716308459', "HELLO CRON WORKED");
  465.         return new Response("error"Response::HTTP_OK, [
  466.             'content-type' => 'text/html'
  467.         ]);
  468.     }
  469. //    private function getMSISDN($phone){
  470. //        $code = '254';
  471. //        if(substr($phone, 1) == 0){
  472. //            return $phone;
  473. //        }
  474. //       return $code.substr($phone, 1);
  475. //    }
  476.     /**
  477.      * @Route("/request_view/{waybill}", methods={"POST", "GET"}, name="payment_request_view")
  478.      */
  479.     function paymentRequestView($waybillRequest $request){
  480.         $em $this->getDoctrine()->getManager();
  481.         @ini_set("memory_limit", -1);
  482.         @ini_set("max_duration", -1);
  483.         /** @var Transaction $transaction */
  484.         $transaction $em->getRepository(Transaction::class)->findOneBy([
  485.             'wayBill' => $waybill
  486.         ]);
  487.         if (!$transaction) {
  488.             $this->addFlash('warning''this transaction has been paid fully');
  489.             return $this->redirectToRoute('new-parcel');
  490.         }
  491.         /** @var MpesaAuth $credentials */
  492.         $credentials $em->getRepository(MpesaAuth::class)->findOneBy([
  493.             'station' => $request->getSession()->get('STATION'),
  494.             'authType' => $this->authType
  495.         ]);
  496.         $requestSenderPhoneForm $this->postMpesaPaymentPhoneNumber($waybill'sender_form');
  497.         $requestReceiverPhoneForm $this->postMpesaPaymentPhoneNumber($waybill'receiver_form');
  498.         $requestOtherPhoneForm $this->postMpesaPaymentPhoneNumber($waybill'other_form');
  499.         $mpesaPaymentSelection $this->postMpesaPaymentSelection($waybill$credentials'mpesa_payment_selection');
  500.         $mpesaCashPaymentSelection $this->postMpesaCashPaymentSelection($waybill$credentials'mpesa_cash_payment_selection');
  501.         $mpesaCashPaymentSelection->handleRequest($request);
  502.         $mpesaPaymentSelection->handleRequest($request);
  503.         $conn $em->getConnection();
  504.         if ($mpesaCashPaymentSelection->isSubmitted()) {
  505.             $data $mpesaCashPaymentSelection->getData();
  506.             if (!$data) {
  507.                 $this->addFlash('warning''error transaction data not available please select again');
  508.                 return $this->redirectToRoute('payment_request_view', ['id' => $waybill]);
  509.             }
  510. //            dump($data);
  511. //            die;
  512.             if ($transaction->getIsPaid()) {
  513.                 if (!$transaction->getPaymentMethod() == 'CASH') {
  514.                     $this->addFlash('warning''this transaction has been paid fully');
  515.                     return $this->redirectToRoute('one_way_bill', ['id' => $waybill]);
  516.                 }
  517.             }
  518.             try {
  519.                 $conn->beginTransaction();
  520.                 $amount 0;
  521.                 $mpesa null;
  522.                 foreach ($data['mpesa'] as $index => $datum) {
  523.                     $mpesaPayment = new MpesaTransaction();
  524.                     $mpesaPayment->setCreatedAt(new \DateTime());
  525.                     $mpesaPayment->setCreatedBy($this->getUser());
  526.                     $mpesaPayment->setMpesa($datum);
  527.                     $mpesaPayment->setTransaction($transaction);
  528.                     $datum->setIsUsed(true);
  529.                     $em->persist($mpesaPayment);
  530.                     $mpesa $datum;
  531.                     $amount += $datum->getTransactionAmount();
  532.                 }
  533. //              $transaction->getDailyAccount()->setMpesa($transaction->getDailyAccount()->getMpesa() + $mpesa->getTransactionAmount());
  534.                 $transaction->setPaymentMethod('MPESA_CASH');
  535.                 $transaction->setMpesaAmount($amount);
  536.                 $transaction->setCashAmount(0);
  537.                 if ($transaction->getAmount() > $amount) {
  538.                     $transaction->setCashAmount($transaction->getAmount() - $amount);
  539.                 }
  540.                 $transaction->setPaidBy('OTHER');
  541.                 $transaction->setIsPaid(true);
  542.                 $transaction->setIsComplete(true);
  543.                 $em->getConnection()->commit();
  544.                 $em->flush();
  545. //                $this->sms->sendOutSms($mpesa->getMsisdn(), "HELLO {$mpesa->getFirstName()} your M-PESA payment {$mpesa->getTransactionId()} has been received for waybill: {$transaction->getWayBill()->getId()}
  546. //                            STAY SAFE & Travel SAFE WITH NENO SACCO Matatus during this festive season, You can also save and grow with NENO SACCO BOSA Account. Merry Christmas And A Happy New Year From all of us At NENO FRATERNITY");
  547.                 $this->sms->sendOutSms($mpesa->getMsisdn(), "HELLO {$mpesa->getFirstName()} your M-PESA payment {$mpesa->getTransactionId()} has been received for waybill: {$transaction->getWayBill()->getId()}
  548.                                             STAY SAFE & Travel SAFE WITH NENO SACCO Matatus, You can also save and grow with NENO SACCO BOSA Account.");
  549.                 $this->addFlash('success''Mpesa transaction successful');
  550.                 return $this->redirectToRoute('one_way_bill', ['id' => $waybill]);
  551.             } catch (\PDOException $exception) {
  552.                 $em->getConnection()->rollBack();
  553.                 $this->logger->error($exception->getMessage(), []);
  554.                 $this->addFlash('error''Error Occurred please contact admin');
  555.                 return $this->redirectToRoute('payment_request_view', ['waybill' => $waybill]);
  556.             }
  557.         }
  558.         if ($mpesaPaymentSelection->isSubmitted()) {
  559.             $data $mpesaPaymentSelection->getData();
  560. //            $id = $data['id'];
  561. //            $amount = $data['id'];
  562. //            dump($data);
  563. //
  564. //            die;
  565.             if (!$data) {
  566.                 $this->addFlash('warning''error transaction data not available please select again');
  567.                 return $this->redirectToRoute('payment_request_view', ['id' => $waybill]);
  568.             }
  569.             if ($transaction->getIsPaid()) {
  570.                 if (!$transaction->getPaymentMethod() == 'CASH') {
  571.                     $this->addFlash('warning''this transaction has been paid fully');
  572.                     return $this->redirectToRoute('one_way_bill', ['id' => $waybill]);
  573.                 }
  574.             }
  575.             try {
  576.                 $conn->beginTransaction();
  577.                 $amount 0;
  578.                 $mpesa null;
  579.                 foreach ($data['mpesa'] as $index => $datum) {
  580.                     $datumMpesa $em->getRepository(Mpesa::class)->findOneBy([
  581.                         'id' => $datum->getId()
  582.                     ]);
  583.                     $mpesaPayment = new MpesaTransaction();
  584.                     $mpesaPayment->setCreatedAt(new \DateTime());
  585.                     $mpesaPayment->setCreatedBy($this->getUser());
  586.                     $mpesaPayment->setMpesa($datum);
  587.                     $mpesaPayment->setTransaction($transaction);
  588.                     $datum->setIsUsed(true);
  589.                     $em->persist($mpesaPayment);
  590.                     $mpesa $datum;
  591.                     $amount += $datumMpesa->getTransactionAmount();
  592.                 }
  593. //              $transaction->getDailyAccount()->setMpesa($transaction->getDailyAccount()->getMpesa() + $mpesa->getTransactionAmount());
  594.                 $transaction->setPaymentMethod('MPESA');
  595.                 $transaction->setCashAmount(0);
  596.                 $transaction->setMpesaAmount($amount);
  597.                 $transaction->setIsComplete(true);
  598.                 $transaction->setPaidBy('OTHER');
  599.                 $transaction->setIsPaid(true);
  600.                 $transaction->setIsComplete(true);
  601.                 $em->getConnection()->commit();
  602.                 $em->flush();
  603. //                $this->sms->sendOutSms($mpesa->getMsisdn(), "HELLO {$mpesa->getFirstName()} your M-PESA payment {$mpesa->getTransactionId()} has been received for waybill: {$transaction->getWayBill()->getId()}
  604. //                            STAY SAFE WITH Neno Courier Services");
  605. //                $this->sms->sendOutSms($mpesa->getMsisdn(), "HELLO {$mpesa->getFirstName()} your M-PESA payment {$mpesa->getTransactionId()} has been received for waybill: {$transaction->getWayBill()->getId()}
  606. //                            STAY SAFE & Travel SAFE WITH NENO SACCO Matatus, You can also save and grow with NENO SACCO BOSA Account.");
  607.                 $this->addFlash('success''Mpesa transaction successful');
  608.                 return $this->redirectToRoute('one_way_bill', ['id' => $waybill]);
  609.             } catch (\PDOException $exception) {
  610.                 $em->getConnection()->rollBack();
  611.                 $this->logger->error($exception->getMessage(), []);
  612.                 $this->addFlash('error''Error Occurred please contact admin');
  613.                 return $this->redirectToRoute('payment_request_view', ['waybill' => $waybill]);
  614.             }
  615.         }
  616.         return $this->render('payment/payment.html.twig', [
  617.             'transaction' => $transaction,
  618.             'senderForm' => $requestSenderPhoneForm->createView(),
  619.             'receiverForm' => $requestReceiverPhoneForm->createView(),
  620.             'otherForm' => $requestOtherPhoneForm->createView(),
  621.             'mpesaSelectionForm' => $mpesaPaymentSelection->createView(),
  622.             'mpesaCashSelectionForm' => $mpesaCashPaymentSelection->createView()
  623.         ]);
  624.     }
  625.     /**
  626.      * @Route("/callback/register/{paybill}", name="register_callback_urls")
  627.      * @return Response|null
  628.      */
  629.     function paymentUrlRegister(Request $request$paybill)
  630.     {
  631.         $em $this->getDoctrine()->getManager();
  632.         /** @var MpesaAuth $credentials */
  633.         $credentials $em->getRepository(MpesaAuth::class)->findBy([
  634.             'authType' => $this->authType,
  635.             'paybill' => $paybill
  636.         ]);
  637. //        dump($credentials);
  638. //        die;
  639.         $this->logger->debug("Get credentials");
  640.         $response = [];
  641.         foreach ($credentials as $index => $credential) {
  642.             $url "https://{$this->host}{$this->callbackUrlRegister}";
  643.             $curl curl_init();
  644.             curl_setopt($curlCURLOPT_URL$url);
  645.             curl_setopt($curlCURLOPT_HTTPHEADER, [
  646.                     "Content-Type:application/json",
  647.                     "Authorization:Bearer {$credential->getToken()}"
  648.                 ]
  649.             );
  650.             dump($credential->getStation());
  651.             $curl_post_data = [
  652.                 'ShortCode' => $credential->getPaybill(),
  653.                 'ResponseType' => 'Cancelled',
  654.                 'ConfirmationURL' => 'https://courier.ohau.co.ke/payment/callback/paybill',
  655.                 'ValidationURL' => 'https://courier.ohau.co.ke/payment/callback/paybill/validation'
  656.             ];
  657. //            dump($curl_post_data);
  658.             $data_string json_encode($curl_post_data);
  659.             curl_setopt($curlCURLOPT_RETURNTRANSFERtrue);
  660.             curl_setopt($curlCURLOPT_POSTtrue);
  661.             curl_setopt($curlCURLOPT_POSTFIELDS$data_string);
  662.             $curl_response curl_exec($curl);
  663.             dump($curl_response); die;
  664.             $this->logger->info("Request response");
  665.             $this->logger->info($curl_response);
  666.             $curlResponse json_decode($curl_responsetrue);
  667.             $this->logger->error('Url registration '$curlResponse);
  668.             dump($curl_response);
  669.         }
  670.         return new Response('awesome'Response::HTTP_OK, [
  671.             'content-type' => 'text/html'
  672.         ]);
  673.     }
  674.     /**
  675.      * @Route("/list", methods={"POST"}, name="mpesa_payment_list")
  676.      * @param Request $request
  677.      * @return Response
  678.      */
  679.     public function unUsedtransactions(Request $request)
  680.     {
  681.         $em $this->getDoctrine()->getManager();
  682.         $context = new SerializationContext();
  683.         $context->setSerializeNull(true);
  684.         $serializer SerializerBuilder::create()->build();
  685.         /** @var MpesaAuth $credentials */
  686.         $credentials $em->getRepository(MpesaAuth::class)->findOneBy([
  687.             'station' => $request->getSession()->get('STATION'),
  688.             'authType' => $this->authType
  689.         ]);
  690.         $em $this->getDoctrine()->getManager();
  691. //        /** @var Mpesa[] $transactions */
  692. //        $transactions = $em->getRepository('App:Mpesa')->findBy([
  693. //            'isUsed' => false,
  694. //            'shortCode' => $credentials->getPaybill()
  695. //        ]);
  696.         /** @var Mpesa[] $transactions */
  697.         $transactions $em->getRepository('App\Entity\Mpesa')->findTransactions('false'$credentials->getPaybill());
  698.         $data = [
  699.             'rows' => $transactions,
  700.             'total' => count($transactions)
  701.         ];
  702.         $data $serializer->serialize($data'json'$context);
  703.         return new Response($dataResponse::HTTP_OK);
  704.     }
  705.     private function postMpesaPaymentPhoneNumber($waybill$formName)
  706.     {
  707.         $fb $this->get('form.factory')
  708.             ->createNamedBuilder($formName);
  709.         $fb->add('phone'TextType::class, [
  710.             'constraints' => [
  711.                 new NotBlank(['message' => 'phone number should be available']),
  712.                 new Length(['min' => 12'max' => 12'maxMessage' => 'Phone number is incorrect''minMessage' => 'Phone number is incorrect'])
  713.             ]
  714.         ])
  715.             ->add('field'TextType::class, [
  716.                 'constraints' => [
  717.                     new NotBlank(['message' => 'please key in the field'])
  718.                 ]
  719.             ]);
  720.         return $fb
  721.             ->setAction($this->generateUrl('request_mpesa_express_payment', ['waybill_id' => $waybill]))
  722.             ->setMethod('POST')
  723.             ->getForm();
  724.     }
  725.     private function postMpesaPaymentSelection($waybill$credentials$formName)
  726.     {
  727.         $fb $this->get('form.factory')
  728.             ->createNamedBuilder($formName);
  729.         $fb->add('mpesa'EntityType::class, [
  730.             'constraints' => [
  731.                 new NotBlank(['message' => 'Please select mpesa transaction'])
  732.             ],
  733.             'class' => 'App\Entity\Mpesa',
  734.             'expanded' => true,
  735.             'multiple' => true,
  736.             'query_builder' => function (EntityRepository $er) use ($credentials) {
  737.                 return $er->createQueryBuilder('m')
  738.                     ->andWhere('m.isUsed = false')
  739.                     ->andWhere('m.shortCode = ' $credentials->getPaybill());
  740.             }
  741.         ]);
  742.         return $fb
  743.             ->setAction($this->generateUrl('payment_request_view', ['waybill' => $waybill]))
  744.             ->setMethod('POST')
  745.             ->getForm();
  746.     }
  747.     private function postMpesaCashPaymentSelection($waybill$credentials$formName)
  748.     {
  749.         $fb $this->get('form.factory')
  750.             ->createNamedBuilder($formName);
  751.         $fb->add('mpesa'EntityType::class, [
  752.             'constraints' => [
  753.                 new NotBlank(['message' => 'Please select mpesa transaction'])
  754.             ],
  755.             'class' => 'App\Entity\Mpesa',
  756.             'expanded' => true,
  757.             'multiple' => true,
  758.             'query_builder' => function (EntityRepository $er) use ($credentials) {
  759.                 return $er->createQueryBuilder('m')
  760.                     ->andWhere('m.isUsed = false')
  761.                     ->andWhere('m.shortCode = ' $credentials->getPaybill());
  762.             }
  763.         ]);
  764.         return $fb
  765.             ->setAction($this->generateUrl('payment_request_view', ['waybill' => $waybill]))
  766.             ->setMethod('POST')
  767.             ->getForm();
  768.     }
  769.     /**
  770.      * @Route("/sms", methods={"GET"}, name="send_sms")
  771.      * @param Request $request
  772.      * @return Response
  773.      */
  774.     public function sendSms(Request $request)
  775.     {
  776.         $results $this->sms->sendOutSms('254716308459',
  777.             "HELLO samuel your test sms STAY SAFE WITH Neno Courier Services");
  778.         dump($results);
  779.         die;
  780.     }
  781.     /**
  782.      * @Route("/transponder", methods={"POST", "GET"}, name="mpesaTransponder")
  783.      * @param Request $request
  784.      * @return JsonResponse
  785.      */
  786.     public function mpesaTransponder(Request $request): JsonResponse
  787.     {
  788.         $em $this->manager;
  789.         $data json_decode($request->getContent(), true);
  790.         $SMSMessage $data['message'];
  791.         $shortCode $data['short_code'];
  792.         if ($shortCode == 174379) {
  793.             $shortCode 4022961;
  794.         }
  795. //        $text = $SMSMessage;
  796. //        $SMSMessage = "RJJ2XSAA1K Confirmed. on 19/10/23 at 6:13 PM Ksh300.00 received from EUNICE      NJIRU 254720781207.  Account Number Wanja Ali New Utility balance is Ksh32,050.00";
  797. //        $SMSMessage = "RJJ2XUWIE0 Confirmed. on 19/10/23 at 6:29 PM Ksh250.00 received from Nickson   Akhura 254719172781.  Account Number nickson  New Utility balance is Ksh33,000.00";
  798.         $text $SMSMessage;
  799.         /**
  800.          * (\d{12}): This part of the regular expression is a capturing group. It's designed to match and capture exactly 12 consecutive digits (0-9). Here's a breakdown of this part:
  801.          *
  802.          * \d: Matches any digit from 0 to 9.
  803.          * {12}: Specifies that the preceding \d should occur exactly 12 times, which means it matches 12 digits in a row.
  804.          * \.: This part matches a literal period (dot) character (.).
  805.          *
  806.          * So, when you put the entire expression together, (\d{12})\. matches and captures
  807.          * a sequence of exactly 12 digits followed by a period in the input text.
  808.          * This is useful for extracting a 12-digit number followed by a period,
  809.          * which is often used for various purposes, such as account numbers or identifiers.
  810.          */
  811.         $patternSenderPhone '/(\d{12})\./';
  812.         /**
  813.          * 1. `^`: The caret symbol at the beginning of the regular expression denotes the start of a line or string. It ensures that the pattern matches at the very beginning of the text.
  814.          *
  815.          * 2. `(\w+)`: This is a capturing group. It matches one or more word characters, which typically include letters (both uppercase and lowercase), digits, and underscores. Here's the breakdown of this part:
  816.          * - `\w`: Matches any word character (letters, digits, or underscores).
  817.          * - `+`: Specifies that the preceding `\w` should occur one or more times.
  818.          *
  819.          * 3. `Confirmed\.`: This part of the regular expression matches the literal text "Confirmed." followed by a period (dot).
  820.          *
  821.          * So, when you put the entire expression together, `/^(\w+) Confirmed\./` matches and captures a sequence of word
  822.          * characters (e.g., a word or alphanumeric code) followed by the exact text "Confirmed."
  823.          * and a period at the beginning of a line or string. This is useful for extracting specific information,
  824.          * such as a transaction ID, that is followed by "Confirmed." in the input text.
  825.          */
  826.         $patternTransactionId '/^(\w+) Confirmed\./';
  827.         /**
  828.          *
  829.          * 1. `received from`: This part of the regular expression matches the literal text "received from".
  830.          *
  831.          * 2. `([A-Z\s]+)`: This is a capturing group, and it's designed to match and capture one or more uppercase letters (A to Z) or
  832.          * whitespace characters (space or tab). Here's the breakdown of this part:
  833.          * - `[A-Z\s]`: This is a character class that matches any uppercase letter (A to Z) or a whitespace character.
  834.          * - `+`: Specifies that the preceding character class `[A-Z\s]` should occur one or more times in a row.
  835.          *
  836.          * 3. `\d{12}`: This part matches exactly 12 consecutive digits (0-9). It's used to match a 12-digit number.
  837.          *
  838.          * 4. `\.`: This part matches a literal period (dot) character (`.`).
  839.          *
  840.          * So, when you put the entire expression together, `/received from ([A-Z\s]+) \d{12}\./`
  841.          * matches the text "received from" followed by a sequence of one or more uppercase letters or spaces,
  842.          * then a 12-digit number, and finally a period. This pattern is useful for extracting the sender's
  843.          * name and their associated 12-digit number, often found in transaction descriptions or logs.
  844.          */
  845. //        $patternSenderName = '/received from ([A-Z\s]+) \d{12}\./';
  846. //        $patternSenderName = '/received from ([A-Z][A-Z\s]+?) \d{12}\./';
  847.         $patternSenderName '/received from ([A-Z][A-Z\s]+?) \d{12}\./i';
  848.         /**
  849.          * The regular expression `/on (\d{1,2}\/\d{1,2}\/\d{2} at \d{1,2}:\d{2} [APM]{2})/` is used to match and capture a specific date and time format in a text. Here's the breakdown of this expression:
  850.          *
  851.          * 1. `on`: This part of the regular expression matches the literal text "on".
  852.          *
  853.          * 2. `(\d{1,2}\/\d{1,2}\/\d{2} at \d{1,2}:\d{2} [APM]{2})`: This is a capturing group that matches a date and time format with the following components:
  854.          * - `\d{1,2}\/\d{1,2}\/\d{2}`: This part matches a date in the format of one or two digits for the day, one or two digits for the month, and two digits for the year (e.g., "10/10/23").
  855.          * - ` at `: This matches the space and the text " at ".
  856.          * - `\d{1,2}:\d{2}`: This part matches a time in the format of one or two digits for the hour, a colon, and two digits for the minutes (e.g., "7:52").
  857.          * - `[APM]{2}`: This matches either "AM" or "PM," which represents the time of day.
  858.          *
  859.          *   So, when you apply this regular expression to a text, it captures and extracts a specific date and time format,
  860.          *    including the day, month, year, hour, and minute, often found in date and time descriptions.
  861.          *
  862.          */
  863.         $patternTransactionDate '/on (\d{1,2}\/\d{1,2}\/\d{2} at \d{1,2}:\d{2} [APM]{2})/';
  864.         /**
  865.          * The regular expression /Ksh(\d+\.\d{2}) received from/ is used to match and capture a specific currency amount format in a text. Here's the breakdown of this expression:
  866.          *
  867.          * Ksh: This part of the regular expression matches the literal text "Ksh".
  868.          *
  869.          * (\d+\.\d{2}): This is a capturing group that matches a currency amount format with the following components:
  870.          *
  871.          * \d+: This matches one or more digits (0-9). It captures the digits before the decimal point, allowing for any number of digits in the integer part of the currency amount.
  872.          * \.: This matches the literal decimal point (dot).
  873.          * \d{2}: This matches exactly two digits, which are typically used for the cents or fractional part of the currency amount.
  874.          * received from: This part matches the literal text " received from".
  875.          *
  876.          * So, when you apply this regular expression to a text, it captures and extracts a currency amount formatted as
  877.          * "Ksh" followed by one or more digits for the whole part, a decimal point,
  878.          * and exactly two digits for the cents part, often found in financial or transaction descriptions.
  879.          */
  880.         $patternAmount '/Ksh([\d,]+.\d{2}) received from/';
  881.         $patternAmount '/Ksh([\d,]+.\d{2}) received/';
  882.         $patternBalance '/Ksh([\d,]+.\d{2})/';
  883.         $patternAccountNumber '/Account Number ([A-Z\s]+) New/';
  884.         $phoneNumber 0;
  885.         $transactionId 0;
  886.         $senderName 0;
  887.         $transactionDate 0;
  888.         $transactionAmount 0;
  889.         $transactionBalance 0;
  890.         $transactionAccountNumber 0;
  891.         $fmt = new NumberFormatter'en_US'NumberFormatter::DECIMAL );
  892.         if (preg_match($patternSenderPhone$text$matches)) {
  893.             $phoneNumber $matches[1];
  894.         }
  895.         if (preg_match($patternTransactionId$text$matches)) {
  896.             $transactionId $matches[1];
  897.         }
  898.         if (preg_match($patternSenderName$text$matches)) {
  899.             $senderName $matches[1];
  900.             dump($senderName);
  901.         }
  902.         if (preg_match($patternTransactionDate$text$matches)) {
  903.             $transactionDate $matches[1];
  904.         }
  905.         if (preg_match($patternAmount$text$matches)) {
  906.             $transactionAmount $matches[1];
  907.             $transactionAmount $fmt->parse($transactionAmount);
  908.         }
  909.         if (preg_match($patternBalance$text$matches)) {
  910.             $transactionBalance $matches[1];
  911.             $transactionBalance $fmt->parse($transactionBalance);
  912.         }
  913.         if (preg_match($patternAccountNumber$text$matches)) {
  914.             $transactionAccountNumber $matches[1];
  915.         }
  916.         /**
  917.          * We use DateTime::createFromFormat to convert the captured date and time string into a
  918.          * DateTime PHP object. The format 'd/m/y \a\t h:i A' matches the format of the captured date and time string.
  919.          * It specifies the day, month, year, hour, minute, and AM/PM format.
  920.          */
  921.         $dateTimeObject DateTime::createFromFormat('d/m/y \a\t h:i A'$transactionDate);
  922.         if (!$transactionId) {
  923.             $resp = [
  924.                 'sms' => $text,
  925.                 'message' => "Invalid SMS Message the message should an M-Pesa notification message"
  926.             ];
  927.             return new JsonResponse($respResponse::HTTP_OK);
  928.         }
  929.         $firstName "-";
  930.         $middleName "-";
  931.         $thirdName "-";
  932.         // Explode the senderName into an array using space as a separator
  933.         $names explode(' '$senderName);
  934. // Assign the first name to $firstName
  935.         $firstName = isset($names[0]) ? $names[0] : '-';
  936. // Assign the second name to $middleName
  937.         $middleName = isset($names[1]) ? $names[1] : '-';
  938. // Initialize $thirdName as an empty string
  939.         $thirdName '';
  940. // Loop through the array starting from the third name
  941.         for ($i 2$i count($names); $i++) {
  942.             $thirdName .= $names[$i] . ' ';
  943.         }
  944. // Trim any trailing space
  945.         $thirdName trim($thirdName);
  946.         $availableMpesa $em->getRepository(Mpesa::class)->findOneBy([
  947.             'transactionId' => $transactionId
  948.         ]);
  949.         $message = new MpesaMessage();
  950.         $message->setMessage($SMSMessage);
  951.         $message->setShortCode($shortCode);
  952.         $message->setCallbackAvailable(true);
  953.         $message->setCreatedAt(new \DateTime());
  954.         if(!$availableMpesa){
  955.             $mpesa = new Mpesa();
  956.             $mpesa->setCreatedAt(new DateTime());
  957.             $mpesa->setShortCode($shortCode);
  958.             $mpesa->setBalance($transactionBalance);
  959.             $mpesa->setMsisdn($phoneNumber);
  960.             $mpesa->setFirstName($firstName);
  961.             $mpesa->setMiddleName($middleName);
  962.             $mpesa->setLastName($thirdName);
  963.             $mpesa->setTransactionType("PAYBILL_PHONE");
  964.             $mpesa->setTransactionTime($dateTimeObject->format('YmdHis'));
  965.             $mpesa->setTransactionAmount($transactionAmount);
  966.             $mpesa->setIsUsed(0);
  967.             $mpesa->setTransactionId($transactionId);
  968.             $mpesa->setRefNumber($transactionAccountNumber);
  969.             $em->persist($mpesa);
  970.             $message->setCallbackAvailable(false);
  971.         }
  972. //        dump($mpesa);
  973. //        die;
  974.         $em->persist($message);
  975.         $em->flush();
  976.         $resp = [
  977.             'phone_number' => $phoneNumber,
  978.             'transaction_id' => $transactionId,
  979.             'sender_name' => $senderName,
  980.             'transaction_date' => $dateTimeObject,
  981.             'transaction_amount' => $transactionAmount,
  982.             'transaction_balance' => $transactionBalance
  983.         ];
  984.         return new JsonResponse($respResponse::HTTP_OK);
  985.     }
  986. }