src/Controller/PaymentController.php line 363
- <?php
- /*
- * The Payment controller contains methods for the following payment gateways:
- * BarclaysSmart Pay - http://www.barclaycard.com/smartpay/documentation/pdf/SmartPay_HPP_IntegrationGuide.pdf
- * Authorize.net - https://developer.authorize.net/guides/DPM/wwhelp/wwhimpl/js/html/wwhelp.htm
- */
- namespace App\Controller;
- use Doctrine\Persistence\ManagerRegistry;
- use Symfony\Bridge\Twig\Mime\TemplatedEmail;
- use Symfony\Bridge\Twig\Mime\WrappedTemplatedEmail;
- use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
- use Symfony\Component\HttpFoundation\RedirectResponse;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\Mailer\Mailer;
- use Symfony\Component\Mailer\MailerInterface;
- use Symfony\Component\Mailer\Transport;
- use Symfony\Component\Mime\Email;
- use Symfony\Component\Routing\Annotation\Route;
- use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
- use Symfony\Contracts\Translation\TranslatorInterface;
- use Psr\Log\LoggerInterface;
- use Twig\Environment;
- use App\Entity\Booking as Booking;
- class PaymentController extends AbstractController
- {
- private $loggedUser;
- public function __construct(private ManagerRegistry $doctrine, private LoggerInterface $logger, private TranslatorInterface $trans, private MailerInterface $mailer, private Environment $twig)
- {
- }
- #[\Symfony\Component\Routing\Attribute\Route('/customer/booking-confirmation/{ref}', name: 'bookingLink')]
- public function confirmAction($ref)
- {
- $em = $this->doctrine->getManager();
- $booking = $this->decodeRef(urldecode($ref));
- $this->loggedUser = $this->getUser();
- $this->logger->info('confirmAction: Confirm booking for ref '.$ref);
- if ($booking)
- {
- $this->logger->info('confirmAction: Found booking Id: '.$booking->getBookingid());
- $paid = false;
- $payment = $this->getPayment($em, $booking, $paid);
- $this->logger->info("confirmAction: paid: ".$paid);
- if (!$payment)
- {
- $payment = new Payment();
- $payment->setPaymentgateway($booking->getBookingoffice()->getPaymentgateway());
- $payment->setBooking($booking);
- $payment->setUpdated( new \DateTime() );
- $em->persist($payment);
- $em->flush();
- $paymentArray = $em->getRepository('App\Entity\Payment')->findByBooking($booking->getBookingid());
- $payment = array_pop($paymentArray);
- }
- else if ($paid)
- {
- $redirect = $this->generateUrl('successPayment', array('payment' => $this->createPaymentRef($payment)), UrlGeneratorInterface::ABSOLUTE_URL);
- return new RedirectResponse($redirect);
- }
- $paymentTemplate = $booking->getBookingoffice()->getPaymentgateway()->getTemplate();
- $this->logger->info('confirmAction: paymentTemplate: '.$paymentTemplate);
- $func = 'appendData_'.$paymentTemplate;
- $this->logger->info("confirmAction: Looking for appendData func: ".$func);
- if (method_exists($this, $func))
- $data = $this->$func($booking, $payment);
- else
- $data = array();
- $this->logger->info('confirmAction: Got payment Id: '.$payment->getPaymentid());
- $data['bookingRef'] = $ref;
- $data['booking'] = $booking;
- $data['payment'] = $payment;
- $data['user'] = $this->loggedUser;
- $data['resURL'] = $this->generateURL('processBooking', array('gateway' => $payment->getPaymentgateway()->getPaymentgatewayid()), UrlGeneratorInterface::ABSOLUTE_URL);
- $data['paid'] = $paid;
- $data['footer'] = 'booking.confirmation.footer.'.$paymentTemplate;
- $data['template'] = $paymentTemplate;
- $response = $this->render('booking/confirm.html.twig', $data);
- $date = new \DateTime(); // Set expire date to +2 seconds to prevent caching
- $date->modify('+2 seconds');
- $response->setExpires($date);
- return $response;
- }
- else
- return $this->render('booking/notfound.html.twig', array("user" => $this->loggedUser));
- }
- #[\Symfony\Component\Routing\Attribute\Route('/customer/payment-failure/{payment}', name: 'failurePayment')]
- public function failureAction($payment, Request $request)
- {
- $payment = $this->decodePaymentRef($payment);
- if ($payment)
- {
- $notificationData = explode('\n', $payment->getNotification());
- $this->logger->info('$notificationData: '.end($notificationData));
- $notificationData = json_decode(end($notificationData));
- return $this->render('payment/failure.html.twig', array('payment' => $payment, 'failureReason' => $notificationData->code.': '.$notificationData->status));
- }
- else
- return $this->render('booking/notfound.html.twig', array("user"=>$this->loggedUser ));
- }
- #[\Symfony\Component\Routing\Attribute\Route('/customer/worldpay/getRedirectUrl/{ref}', name: 'getWorldpayRedirectUrl')]
- public function getWorldpayRedirectUrlAction($ref)
- {
- //BE 190702: this is for Worldpay XML payments only
- $em = $this->doctrine->getManager();
- $booking = $this->decodeRef(urldecode($ref));
- $this->loggedUser = $this->getUser();
- $this->logger->info("getWorldpayRedirectUrlAction: getRedirectUrlAction for ref ".$ref);
- if ($booking)
- {
- $this->logger->info("getWorldpayRedirectUrlAction: Found booking Id: ".$booking->getBookingid());
- $paid = false;
- $payment = $this->getPayment($em, $booking, $paid);
- $this->logger->info("getWorldpayRedirectUrlAction: Found payment Id: ".$payment->getPaymentid());
- $office = $booking->getBookingoffice();
- //$data = $this->appendData_worldpay($booking, $payment);
- $cost = number_format($booking->getTotalprice(), 2, '', '');
- $currency = $booking->getBookingcurrency()->getCode();
- $officeSalt = $office->getMerchantsalt();
- $merchantCode = $this->decrypt($office->getMerchantcode(), $officeSalt).$currency;
- //$merchantCode = $office->getMerchantcode().$currency;
- $xml = '<?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE paymentService PUBLIC "-//Worldpay//DTD Worldpay PaymentService v1//EN" "http://dtd.worldpay.com/paymentService_v1.dtd">
- <paymentService version="1.4" merchantCode="'.$merchantCode.'">
- <submit>
- <order orderCode="'.$payment->getPaymentid().'" installationId="1356990">
- <description>'.$booking->__toString().'</description>
- <amount currencyCode="'.$currency.'" exponent="2" value="'.$cost.'" />
- <orderContent><![CDATA[]]></orderContent>
- <paymentMethodMask>
- <include code="ALL" />
- </paymentMethodMask>
- <shopper>
- <shopperEmailAddress>'.$booking->getCustomer()->getEmail().'</shopperEmailAddress>
- </shopper>
- <billingAddress>
- <address>
- <address1>'.$booking->getCustomer()->getAddress().'</address1>
- <address2></address2>
- <address3></address3>
- <postalCode>'.$booking->getCustomer()->getPostcode().'</postalCode>
- <city>'.$booking->getCustomer()->getCity().'</city>
- <state>'.$booking->getCustomer()->getState().'</state>
- <countryCode>'.$booking->getCustomer()->getCustomercountry()->getCountry2Code().'</countryCode>
- </address>
- </billingAddress>
- </order>
- </submit>
- </paymentService>';
- $this->logger->info("getWorldpayRedirectUrlAction: Xml: ".$xml);
- $username = $merchantCode;//$this->decrypt($office->getMerchantusername(), $officeSalt);
- $pwd = $this->decrypt($office->getMerchantpassword(), $officeSalt);
- $test_mode = $this->getParameter('app.worldpayxml_test_mode') == 'TRUE';
- $basicAuth = $username . ':' . $pwd;
- //$this->logger->info("Using Auth: ".$basicAuth);
- $basicAuthBase64 = base64_encode($basicAuth);
- $basicAuthUrlEncoded = urlencode($username) . ":" . urlencode($pwd);
- if ($test_mode)
- $url = "https://secure-test.worldpay.com/jsp/merchant/xml/paymentService.jsp";
- else
- $url = "https://secure.worldpay.com/jsp/merchant/xml/paymentService.jsp";
- $this->logger->info("Using Url: ".$url);
- //$this->logger->info("Using Url: ".str_replace($basicAuth, "user:pwd", $url));
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- curl_setopt($ch, CURLOPT_USERPWD, $basicAuth);
- //curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Authorization: ' . $basicAuthBase64));
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300);
- $response = curl_exec($ch);
- if ($response == false)
- {
- $this->logger->error('Error code: '.curl_error($ch));
- $url = $this->generateUrl('failurePayment', array('payment'=>$this->createPaymentRef($payment)), UrlGeneratorInterface::ABSOLUTE_URL);
- $err = array('date' => date('Y-m-d H:i:s'),'code' => 999, 'status' => 'XML Response empty - contact Support');
- $payment->setNotification($payment->getNotification().'\n'.json_encode($err));
- $em->persist($payment);
- $em->flush();
- $this->mailSalesFailure($payment);
- //$this->logger->info("failurePayment: ".$serializedData);
- return new RedirectResponse($url);
- }
- else
- {
- $this->logger->info("getWorldpayRedirectUrlAction: response: ".$response);
- $responseXml = simplexml_load_string($response);
- //$this->logger->info("responseXml: ".print_r($responseXml, true));
- if (property_exists($responseXml->reply, 'error') || strpos($response, '<html') !== false)
- {
- $url = $this->generateUrl('failurePayment', array('payment'=>$this->createPaymentRef($payment)), UrlGeneratorInterface::ABSOLUTE_URL);
- if (property_exists($responseXml->reply, 'error'))
- {
- $code = (int)$responseXml->reply->error['code'];
- $error = (string)$responseXml->reply->error;
- if ($error == 'Order has already been paid')
- $status = $error;
- else
- $status = 'There was an unknown problem with the gateway - Contact Support, and give them this info: '.(string)$responseXml->reply->error;
- }
- else if (strpos($response, '<html') !== false && strpos($response, 'Status: 401') !== false)
- {
- $code = '401';
- $status = 'There was an authentication problem with the gateway - contact Support, and give them this info: Status 401: Authentication Problem';
- }
- else
- {
- $code = '?';
- $status = 'There was an unknown problem with the gateway - Contact Support, and give them this info: '.htmlentities($response);
- }
- $err = array('date' => date('Y-m-d H:i:s'), 'code' => $code, 'status' => $status);
- $payment->setNotification($payment->getNotification().'\n'.json_encode($err));
- $em->persist($payment);
- $em->flush();
- $this->mailSalesFailure($payment);
- //$this->logger->info("failurePayment: ".$serializedData);
- return new RedirectResponse($url);
- }
- else if (property_exists($responseXml->reply, 'orderStatus') && property_exists($responseXml->reply->orderStatus, 'reference'))
- {
- $refUrl = (string)$responseXml->reply->orderStatus->reference[0];
- $this->logger->info("getWorldpayRedirectUrlAction: reference: ".$refUrl);
- //$this->logger->info("reference: ".print_r($refUrl, true));
- //$this->logger->info("reference type: ".gettype($refUrl));
- //return $this->redirect($refUrl);
- $successURL = urlencode($this->generateURL("processWorldpay", array("pid" => $payment->getPaymentID() ), UrlGeneratorInterface::ABSOLUTE_URL));
- $refUrl .= '&successURL='.$successURL.'&failureURL='.$successURL.'&cancelURL='.$successURL.'&errorURL='.$successURL;
- $this->logger->info("getWorldpayRedirectUrlAction: reference: ".$refUrl);
- return new RedirectResponse($refUrl);
- }
- }
- curl_close($ch);
- }
- else
- $this->logger->info("getWorldpayRedirectUrlAction: No booking found!");
- }
- public function paymentNotificationAction($template, Request $request)
- {
- $this->logger->info("PaymentController.paymentNotificationAction started template:$template");
- if ($template == "barclays")
- {
- $dataChk=array();
- $dataChk['live'] = $request->get("live"); // live or test
- $dataChk["eventCode"] = $request->get("eventCode"); // event code - will be AUTHORISATION
- $dataChk["pspReference"] = $request->get("pspReference"); // Barclay ref code
- $dataChk["originalReference"] = $request->get("originalReference"); // blank
- $dataChk["merchantReference"] = $request->get("merchantReference"); // Our ref code
- $dataChk["merchantAccountCode"] = $request->get("merchantAccountCode"); // Merchant account code
- $dataChk["success"] = $request->get("success");
- $dataChk["paymentMethod"] = $request->get("paymentMethod");
- $dataChk["operations"] = $request->get("operations");
- $dataChk["reason"] = $request->get("reason");
- $dataChk["amount"] = $request->get("amount");
- $this->logger->info("PaymentController.paymentNotificationAction Request Data: ".print_r($dataChk,true));
- $em = $this->doctrine->getManager();
- $payment = false;
- if ($dataChk["merchantReference"] > 0)
- {
- $this->logger->info("PaymentController.paymentNotificationAction Retrieving Payment: ".$dataChk['merchantReference']);
- $payment = $em->getRepository('App\Entity\Payment')->find($dataChk["merchantReference"]);
- } else {
- $this->logger->info("PaymentController.paymentNotificationAction No Asscociated Payment");
- }
- if ($payment)
- {
- $this->logger->info("PaymentController.paymentNotificationAction Payment Successfully Retreived: ".$dataChk['merchantReference']);
- $payment->setNotification(serialize($dataChk));
- $em->persist($payment);
- $em->flush();
- if ($dataChk["success"]=='false')
- {
- $this->logger->info("PaymentController.paymentNotificationAction Payment Unsuccessful, Mailing Sales Rep: ".$dataChk['merchantReference']);
- $this->mailSalesFailure($payment);
- } else
- {
- $this->logger->info("PaymentController.paymentNotificationAction Payment Successful: ".$dataChk['merchantReference']);
- }
- }
- $this->logger->info("PaymentController.paymentNotificationAction Returning 200 Response");
- return new Response('[accepted]',200,array('content-type' => 'text/html'));
- }
- }
- #[\Symfony\Component\Routing\Attribute\Route('/customer/worldpay/redirect/{pid}', name: 'processWorldpay')]
- public function processWorldpayAction($pid, MailerInterface $mailer, Request $request)
- {
- $em = $this->doctrine->getManager();
- $payment = $this->saveReturnData_worldpay($pid, $request);
- $msg = 'NONE';
- if ($payment)
- {
- $paymentRef = $this->createPaymentRef($payment);
- $booking = $payment->getBooking();
- if ($payment->getSuccessful() == 1)
- {
- $redirect = $this->generateUrl('successPayment', array("payment"=>$paymentRef), UrlGeneratorInterface::ABSOLUTE_URL);
- $this->mailCustomerConfirmation($booking, $payment);
- $this->mailSalesConfirmation($booking, $payment, $request);
- $booking->setPaid(1);
- $em->persist($booking);
- $em->flush();
- } else {
- $redirect = $this->generateUrl('failurePayment', array("payment"=>$paymentRef), UrlGeneratorInterface::ABSOLUTE_URL);
- $this->mailSalesFailure($payment);
- }
- } else
- $redirect = $this->generateUrl('failurePayment', array("payment"=>$paymentRef), UrlGeneratorInterface::ABSOLUTE_URL);
- //$redirect = $redirect===false ? $request->get("MC_failure") : $redirect;
- //$params = $request->query->all();
- //return $this->render("ACSBundle:Payment:process_worldpay.html.twig", array("redirect"=>$redirect, "payment"=>$payment, 'params'=>$params, 'msg'=>$msg) );
- //return new Response("done");
- return new RedirectResponse($redirect);
- }
- #[\Symfony\Component\Routing\Attribute\Route('/customer/payment-success/{payment}', name: 'successPayment')]
- public function successAction($payment)
- {
- $payment = $this->decodePaymentRef($payment);
- if ($payment)
- return $this->render("payment/success.html.twig", array('payment' => $payment));
- else
- return $this->render("booking/notfound.html.twig", array("user"=>$this->loggedUser ));
- }
- public function testAction()
- {
- $test = 'MYADMINCODE^MYMERCHANT^T0211010:1400:GBP:AUTHORISED';
- $result = hash_hmac('sha256', $test, '@p-p1epie');
- return new Response($result);
- /*$em = $this->getDoctrine()->getManager();
- $payment = $em->getRepository('App\Entity\Payment')->find(57);
- $booking = $payment->getBooking();
- $this->mailCustomerConfirmation($booking, $payment);
- $customer = $booking->getCustomer();
- $user = $booking->getCreatedby();
- $recipient = trim($customer->getFirstname()." ".$customer->getSurname());
- $sender = trim($user->getFirstname()." ".$user->getSurname());
- return $this->render("emails/CustomerConfirmation.html.twig",
- array(
- 'recipient' => $recipient,
- 'sender'=> $sender,
- 'booking'=>$booking,
- 'payment'=>$payment,
- ));*/
- }
- /*** PRIVATE HELPER METHODS ***/
- private function appendData_worldpay($booking, $payment)
- {
- // See docs for implementation : https://beta.developer.worldpay.com/docs/wpg/hostedintegration/quickstart
- $test_mode = $this->getParameter('app.worldpayxml_test_mode') == 'TRUE';
- // MD5 hash params may be chosen from the merchant interface. Currently set to
- // md5_secret:instId:currency:amount:paymentid
- $cost = number_format($booking->getTotalprice(), 2, '.', '');
- $currency = $booking->getBookingcurrency()->getCode();
- $sig_params = array();
- $sig_params[] = null; //$md5_secret;
- $sig_params[] = null; //$instId;
- $sig_params[] = $currency;
- $sig_params[] = $cost;
- $sig_params[] = $payment->getPaymentid();
- $bookingOffice = $booking->getBookingoffice();
- $bookingAgentEmail = $booking->getCreatedby()->getEmail();
- $bookingAgentName = trim($booking->getCreatedby()->getFirstname()." ".$booking->getCreatedby()->getSurname());
- $contactDetails = $bookingOffice->getAddress()."<br />".$bookingOffice->getCity()."<br />".$bookingOffice->getZipcode()."<br />".$bookingOffice->getOfficecountry()->getName()."<br />Reg. No.: ".$bookingOffice->getRegnumber()."<br />Phone: ".$bookingOffice->getPhone()."<br />Booking agent: ".$bookingAgentName." - <a href='mailto:".$bookingAgentEmail."'>".$bookingAgentEmail."</a>";
- $data = array(
- "orderId" => $payment->getPaymentid(),
- "testMode" => $test_mode,
- "orderCurrency" => $currency,
- "orderAmount" => $cost,
- "description" => $booking->__toString(),
- "shopperEmail" => $booking->getCustomer()->getEmail(),
- "name" => $booking->getCustomer()->getFirstname()." ".$booking->getCustomer()->getSurname(),
- "address" => $booking->getCustomer()->getAddress(),
- "city" => $booking->getCustomer()->getCity(),
- "zip" => $booking->getCustomer()->getPostcode(),
- "state" => $booking->getCustomer()->getState(),
- "country" => $booking->getCustomer()->getCustomercountry()->getCountry2Code(),
- "phone" => preg_replace("/^![0-9]$/","",$booking->getCustomer()->getPhone()),
- "successURL" => $this->generateURL("successPayment", array( "payment"=>$payment->getPaymentID() ), UrlGeneratorInterface::ABSOLUTE_URL),
- "failureURL" => $this->generateURL("failurePayment", array( "payment"=>$payment->getPaymentID() ), UrlGeneratorInterface::ABSOLUTE_URL),
- // Following fields required by VISA for payments in GBP
- "shopperAdditionalAccountNumber" => "",
- "shopperAdditionalLastName" => "",
- "shopperAdditionalBirthDate" => "",
- "shopperAdditionalPostalCode" => "",
- "contactDetails" => $contactDetails
- );
- $data['MD5sig'] = md5(implode(":", $sig_params));
- return $data;
- }
- private function createPaymentRef($payment)
- {
- $booking = $payment->getBooking();
- $ref=array();
- $ref[]=$payment->getPaymentid();
- $ref[]=$booking->getBookingid();
- $ref[]=$booking->getCustomer()->getCustomerid();
- $ref[]=$booking->getBookingoffice()->getOfficeid();
- /*$finalRef = $ref[0].$ref[1].$ref[2].$ref[3];
- $next = $this->getEverySecondDigit($finalRef);
- $finalRef = $finalRef / $next;
- $next = $this->getEverySecondDigit($finalRef);
- $finalRef = $finalRef / $next;
- $next = $this->getEverySecondDigit($finalRef);
- $finalRef = $finalRef * $next;
- $decimalPos = strrpos($finalRef, '.');
- $finalRef = str_replace('.', '', $finalRef);
- $finalRef .= $decimalPos;
- $this->logger->info('$finalRef: '.$finalRef);
- return urlencode($finalRef);*/
- return urlencode(bin2hex(implode(Booking::URL_SECRET, $ref)));
- }
- private function decodePaymentRef($ref)
- {
- $this->logger->info('decodePaymentRef: '.$ref);
- //$decimalPos = (string)$ref[strlen((string)$ref) - 1];
- //$this->logger->info('decimalPos: '.$decimalPos);
- $data = explode(Booking::URL_SECRET, pack("H*", $ref));
- $this->logger->info('Data: '.print_r($data, true));
- $id = array_shift($data);
- $em = $this->doctrine->getManager();
- $payment = $em->getRepository('App\Entity\Payment')->find($id);
- if ($payment)
- {
- $this->logger->info('Got payment: '.$payment->getPaymentid());
- $booking = $payment->getBooking();
- if ($booking->getBookingid() == $data[0] && $booking->getCustomer()->getCustomerid() == $data[1] && $booking->getBookingoffice()->getOfficeid() == $data[2])
- return $payment;
- else {
- $this->logger->info('Did not match criteria: bid: '.$booking->getBookingid().' $data[0]: '.$data[0].', cid: '.$booking->getCustomer()->getCustomerid().' $data[1]: '.$data[1].', oid: '.$booking->getBookingoffice()->getOfficeid().' $data[2]: '.$data[2]);
- return false;
- }
- } else {
- $this->logger->info('Could not find payment from id: '.$id);
- return false;
- }
- }
- private function decodeRef($ref)
- {
- $data = explode(Booking::URL_SECRET, pack("H*", $ref));
- //$decimalPos = (string)$ref[(strlen($ref) - 1];
- $id = array_shift($data);
- $em = $this->doctrine->getManager();
- $booking = $em->getRepository('App\Entity\Booking')->find($id);
- if ($booking)
- {
- if ($booking->getCustomer()->getCustomerid() == $data[0] && $booking->getBookingoffice()->getOfficeid()==$data[1])
- return $booking;
- else
- return false;
- } else
- return false;
- }
- private function decrypt($encrypted, $salt) {
- //https://www.the-art-of-web.com/php/two-way-encryption/
- $encKey = $this->getParameter('app.worldpayxml_enckey').$salt;
- $method = 'AES-256-CTR';
- list($encrypted, $encIV) = explode("::", $encrypted);
- $decrypted = openssl_decrypt($encrypted, $method, $encKey, 0, hex2bin($encIV));
- return $decrypted;
- }
- private function encrypt($token, $salt) {
- //https://www.the-art-of-web.com/php/two-way-encryption/
- $encKey = $this->getParameter('app.worldpayxml_enckey').$salt;
- $method = 'AES-256-CTR';
- $encIV = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
- $encrypted = openssl_encrypt($token, $method, $encKey, 0, $encIV) . "::" . bin2hex($encIV);
- return $encrypted;
- }
- public static function getEverySecondDigit($input) {
- //$this->logger = Logger::getLogger(__CLASS__);
- $input = (string)$input;
- $len = strlen($input);
- //$this->logger->info('Length of '.$input.' is '.$len);
- $final = '';
- for ($x = 0; $x < $len; $x++) {
- if ($input[$x] != '.') {
- if (($x + 1) % 2 === 0) {
- $final .= $input[$x];
- }
- } else {
- $final .= '.';
- }
- }
- //$this->logger->info('From $input: '.$input.', calculated: '.$final);
- return $final;
- }
- private function getPayment($em, $booking, &$paid)
- {
- $this->logger->info('getPayment for booking: '.$booking->getBookingid());
- $paymentArray = $em->getRepository('App\Entity\Payment')->findByBooking($booking->getBookingid());
- $payment = false;
- foreach ($paymentArray as $p)
- {
- $this->logger->info('Found payment: '.$p->getPaymentid().', is successful: '.($p->getSuccessful() == 1));
- $payment = $p;
- if ($p->getSuccessful() == 1)
- {
- $paid = true;
- break;
- }
- //else if ($p->getResulttoken() == null && $p->getAuthcode() == null && $p->getSuccessful() == null) {
- // $payment = $p;
- // break;
- //}
- }
- return $payment;
- }
- private function mailCustomerConfirmation($booking, $payment)
- {
- $customer = $booking->getCustomer();
- $user = $booking->getCreatedby();
- $office = $booking->getBookingoffice();
- $recipient = trim($customer->getFirstname().' '.$customer->getSurname());
- $sender = trim($user->getFirstname().' '.$user->getSurname());
- $from = $office->getEmailaddress();
- $message = (new TemplatedEmail())
- ->subject('Booking Payment Received')
- ->from($from)
- ->to($customer->getEmail());
- //https://github.com/symfony/symfony/issues/42407#issuecomment-1006995400
- $html = $this->render('emails/CustomerConfirmation.html.twig',
- [
- 'recipient' => $recipient,
- 'sender' => $sender,
- 'booking' => $booking,
- 'payment' => $payment,
- 'email' => new WrappedTemplatedEmail($this->twig, $message),
- ])
- ->getContent();
- $message->html($html);
- $this->mailer = new Mailer(Transport::fromDsn('sendmail://default'));
- $sent = $this->mailer->send($message);
- //https://stackoverflow.com/q/71496164/206852
- // if ($sent !== null)
- // dd($sent->getDebug());
- }
- private function mailSalesConfirmation($booking, $payment, $request) {
- $customer = $booking->getCustomer();
- $user = $booking->getCreatedby();
- $office = $booking->getBookingoffice();
- $recipient = trim($user->getFirstname().' '.$user->getSurname());
- $sender = 'System';
- $from = $office->getEmailaddress();
- $message = (new TemplatedEmail())
- ->subject('Booking Payment Received')
- ->from($from)
- ->to($user->getEmail())
- ->cc($this->getParameter('app.accountsemail'));
- //https://github.com/symfony/symfony/issues/42407#issuecomment-1006995400
- $html = $this->render('emails/SalesConfirmation.txt.twig',
- [
- 'recipient' => $recipient,
- 'sender' => $sender,
- 'booking' => $booking,
- 'payment' => $payment,
- 'cardUsed' => $request->get('cardType'),
- 'email' => new WrappedTemplatedEmail($this->twig, $message),
- ])
- ->getContent();
- $message->html($html);
- $this->mailer = new Mailer(Transport::fromDsn('sendmail://default'));
- $sent = $this->mailer->send($message);
- //https://stackoverflow.com/q/71496164/206852
- // if ($sent !== null)
- // dd($sent->getDebug());
- }
- private function mailSalesFailure($payment)
- {
- $this->logger->info('mailSalesFailure');
- if ($payment)
- {
- $booking = $payment->getBooking();
- $customer = $booking->getCustomer();
- $user = $booking->getCreatedby();
- $office = $booking->getBookingoffice();
- $recipient = trim($user->getFirstname().' '.$user->getSurname());
- $sender = 'System';
- $name = trim($customer->getFirstname().' '.$customer->getSurname());
- $from = $office->getEmailaddress();
- $template = $booking->getBookingoffice()->getPaymentgateway()->getTemplate();
- $notificationData = explode('\n', $payment->getNotification());
- $notificationData = json_decode(end($notificationData));
- //$this->logger->info('$payment->getNotification(): '.$payment->getNotification());
- $this->logger->info('$notificationData: '.print_r($notificationData, true));
- $this->logger->info('json_last_error: '.json_last_error());
- switch ($template)
- {
- case 'authorize':
- $reason = $notificationData->response_reason_text;
- break;
- case 'barclays':
- $reason = $notificationData['reason'];
- break;
- case 'worldpay':
- $reason = 'Error code: '.$notificationData->code.', Error message: '.$notificationData->status;
- break;
- }
- $message = (new TemplatedEmail())
- ->subject('Booking Payment Failed')
- ->from($from)
- ->to($user->getEmail());
- //https://github.com/symfony/symfony/issues/42407#issuecomment-1006995400
- $html = $this->render('emails/Failure.txt.twig',
- [
- 'recipient' => $recipient,
- 'sender' => $sender,
- 'booking' => $booking,
- 'payment' => $payment,
- 'name' => $name,
- 'reason' => $reason,
- 'email' => new WrappedTemplatedEmail($this->twig, $message),
- ])
- ->getContent();
- $message->html($html);
- $this->mailer = new Mailer(Transport::fromDsn('sendmail://default'));
- $sent = $this->mailer->send($message);
- //https://stackoverflow.com/q/71496164/206852
- // if ($sent !== null)
- // dd($sen
- }
- }
- private function saveReturnData_worldpay($pid, Request $request)
- {
- $this->logger->info('saveReturnData_worldpay');
- $em = $this->doctrine->getManager();
- $payment = $em->getRepository('App\Entity\Payment')->find($pid);
- if ($payment)
- {
- $this->logger->info("Found payment with id ".$pid);
- if ($request->query->has('errorRefNumber') && $request->query->has('errors'))
- {
- $err = array('date' => date('Y-m-d H:i:s'), 'code' => $request->get('errorRefNumber'), 'status' => 'Worldpay error: '.$request->get('errors'));
- $payment->setNotification($payment->getNotification().'\n'.json_encode($err));
- $payment->setSuccessful(0);
- $em->persist($payment);
- $em->flush();
- return $payment;
- }
- //AUTHORISED EXAMPLE
- //https://dev.onlinepayments.aircharterservice.com/customer/worldpay/redirect/296?orderKey=AIRCHARTERSERVICES%5EAIRCHARTERUKECOMGBP%5E296&paymentStatus=AUTHORISED&paymentAmount=1234565&paymentCurrency=GBP&mac2=c975417ba3d7b63a29c1457802379b4f6b799a67750d9aab590dd277622ff92e
- //CANCELLED EXAMPLE
- //https://dev.onlinepayments.aircharterservice.com/customer/worldpay/redirect/309?orderKey=AIRCHARTERSERVICES%5EAIRCHARTERUKECOMGBP%5E309&orderAmount=65421&orderCurrency=GBP&mac2=5e3ee235214f9906c3869bb916f49477f126d076cb11c6497472f07b2528fdbf
- //REFUSED EXAMPLE
- //https://dev.onlinepayments.aircharterservice.com/customer/worldpay/redirect/309?orderKey=AIRCHARTERSERVICES%5EAIRCHARTERUKECOMGBP%5E309&paymentStatus=REFUSED&paymentAmount=65421&paymentCurrency=GBP&mac2=8911c0e65ad5d7bbd219db86581c84fe63a532a34023b2ac670e44f0d6e6c677
- //ERROR EXAMPLE
- //https://dev.onlinepayments.aircharterservice.com/customer/worldpay/redirect/309?orderKey=AIRCHARTERSERVICES%5EAIRCHARTERUKECOMGBP%5E309&errorRefNumber=D190710-T154806-M001-43&errors=Gateway+error
- //BE 190708: documentation at https://beta.developer.worldpay.com/docs/wpg/hostedintegration/securingpayments
- $booking = $payment->getBooking();
- $office = $booking->getBookingoffice();
- $officeSalt = $office->getMerchantsalt();
- $macSecret = $this->decrypt($office->getMerchantmacsecret(), $officeSalt);
- $test_mode = $this->getParameter('app.worldpayxml_test_mode') == 'TRUE';
- $currency = $booking->getBookingcurrency()->getCode();
- $merchantCode = $this->decrypt($office->getMerchantcode(), $officeSalt).$currency;
- // status can be "AUTHORISED" or "REFUSED"
- $status = $request->get('paymentStatus');
- $sig_params = array();
- $sig_params[] = $request->get('orderKey');
- $sig_params[] = $request->get('paymentAmount');
- $sig_params[] = $request->get('paymentCurrency');
- if ($status)
- $sig_params[] = $status;
- $sig_check = array();
- $sig_check[] = 'AIRCHARTERSERVICES^'.$merchantCode.'^'.$payment->getPaymentId();
- $sig_check[] = ltrim((string)number_format($booking->getTotalprice(), 2, '', ''), '0');
- $sig_check[] = $currency;
- if ($status)
- $sig_check[] = $status;
- $sigSent = implode(":", $sig_params);
- $sigCalculated = implode(":", $sig_check);
- $calculated_hash = hash_hmac('sha256', $sigCalculated, $macSecret);
- //$this->logger->info('Using secret: '.$macSecret);
- $hash_check = $calculated_hash == $request->get('mac2');
- $retVal = false;
- if ($hash_check)
- {
- $statusCode = 1;
- if (!$status || $status == 'CANCELLED')
- $statusCode = 3;
- else if ($status == 'AUTHORISED')
- $statusCode = 1;
- else if ($status == 'REFUSED')
- $statusCode = 2;
- else
- $statusCode = 99;
- $this->logger->info('Hash check succeeded!');
- $payment->setResulttoken($request->get('mac2'));
- $payment->setAuthcode($request->get('mac2'));
- $payment->setSuccessful($statusCode == 1);
- $payment->setNotification($payment->getNotification().'\n'.json_encode(array('date' => date('Y-m-d H:i:s'), 'code' => $statusCode, 'status' => $status, 'params' => $request->query->all())));
- $retVal = $payment;
- }
- else
- {
- $this->logger->info('Sig params sent: '.$sigSent.', Sig params calculated: '.$sigCalculated.', are equal = '.($sigSent == $sigCalculated));
- $this->logger->info('Failed Hash Check: Calculated Value: '.$calculated_hash.', Sent Value (mac): '.$request->get('mac').', Sent Value (mac2): '.$request->get('mac2'));
- $payment->setNotification($payment->getNotification().'\n'.json_encode(array('date' => date('Y-m-d H:i:s'), 'code' => 4, 'status' => 'Failed Auth Hash Check - contact Support', 'params' => $request->query->all())));
- $retVal = $payment;
- }
- $em->persist($payment);
- $em->flush();
- return $retVal;
- } else {
- $this->logger->info("Payment with id ".$pid." was NOT found.");
- return false;
- }
- }
- /*** OLD CODE - KEPT FOR REFERENCE IF REQUIRED IN THE FUTURE ***/
- private function appendData_barclays($booking, $payment) {
- $hmac_key = $this->getParameter('barclays_hmac_key');
- $skin_code = $this->getParameter('barclays_skin_code');
- $merchant_acc = $this->getParameter('barclays_merchant_acc');
- $time = $payment->getUpdated()->format("U") + 60*60*24*30;
- $paymentexpires = gmdate("Y-m-d", $time) . 'T' . gmdate("H:i:s", $time) ."Z";
- //$paymentexpires=gmdate(DATE_ISO8601,$expTimestamp);
- $data = array(
- 'paymentAmount' => $booking->getTotalprice()*100,
- 'currencyCode' => $booking->getBookingcurrency()->getCode(),
- 'shipBeforeDate' => $payment->getUpdated()->format('Y-m-d'),
- 'merchantReference' => $payment->getPaymentid(),
- 'skinCode' => $skin_code,
- 'merchantAccount' => $merchant_acc,
- 'sessionValidity' => $paymentexpires,
- 'shopperEmail' => $booking->getCustomer()->getEmail(),
- 'shopperReference' => $booking->getCustomer()->getCustomerid(),
- 'allowedMethods' => '',
- 'blockedMethods' => '',
- 'shopperStatement' => '',
- 'billingAddressType'=> '',
- );
- $summary = implode("",$data);
- $merchantSig = base64_encode(hash_hmac('sha1',$summary,$hmac_key,true));
- $data['orderData'] = base64_encode($booking->__toString());
- $data['merchantSig'] = $merchantSig;
- return $data;
- }
- private function appendData_authorize($booking,$payment) {
- $hmac_key = $this->getParameter('authorize_hmac_key');
- $api_login = $this->getParameter('authorize_api_login');
- /*added by vazquel on 2014-02-19*/
- $md5_hash = $this->getParameter('authorize_md5_hash');
- $gateway = new \Authorizenet_Authorizenet($api_login, $md5_hash);
- $response = $gateway->AuthorizeSIM;
- $fp_timestamp = gmdate("U");
- $fingerprint = \AuthorizeNetSIM_Form::getFingerprint($api_login, $hmac_key, $booking->getTotalprice(), $payment->getPaymentid(), $fp_timestamp, $booking->getBookingcurrency()->getCode());
- $data['x_login'] = $api_login;
- $data['x_test_request'] = $this->getParameter('authorize_test_mode');
- $data['x_fp_sequence'] = $payment->getPaymentid();
- $data['x_fp_timestamp'] = $fp_timestamp;
- $data['x_amount'] = $booking->getTotalprice();
- $data['x_currency_code']= $booking->getBookingcurrency()->getCode();
- $data['x_fp_hash'] = $fingerprint;
- $data['x_description'] = $booking->__toString();
- $data['x_first_name'] = $booking->getCustomer()->getFirstname();
- $data['x_last_name'] = $booking->getCustomer()->getSurname();
- $data['x_address'] = $booking->getCustomer()->getAddress();
- $data['x_city'] = $booking->getCustomer()->getCity();
- $data['x_zip'] = $booking->getCustomer()->getPostcode();
- $data['x_state'] = $booking->getCustomer()->getState();
- $data['x_country'] = $booking->getCustomer()->getCustomercountry()->getName();
- $data['x_phone'] = preg_replace("/^![0-9]$/","",$booking->getCustomer()->getPhone());
- $data['x_email'] = $booking->getCustomer()->getEmail();
- $data['booking'] = $booking;
- $data['payment'] = $payment;
- return $data;
- }
- private function appendData_moneyswap($booking, $payment) {
- $moneyswap_aid = $this->getParameter('moneyswap_aid');
- $moneyswap_md5_signature = $this->getParameter('moneyswap_md5_signature');
- $data = array(
- "acqID" => $moneyswap_aid,
- //"acqID" => "04020826",
- "backURL" => $this->generateURL("processBooking", array( "gateway"=>$payment->getPaymentgateway()->getPaymentgatewayid() ), UrlGeneratorInterface::ABSOLUTE_URL),
- "charSet" => "UTF-8",
- "frontURL" => $this->generateURL("processBooking", array( "gateway"=>$payment->getPaymentgateway()->getPaymentgatewayid() ), UrlGeneratorInterface::ABSOLUTE_URL),
- "merID" => "846084045110001",
- "merReserve" => $booking->__toString(),
- "orderAmount" => number_format($booking->getTotalprice(), 2, '.', ''),
- "orderCurrency" => $booking->getBookingcurrency()->getCode(),
- "orderNum" => $payment->getPaymentid(),
- "paymentSchema" => "UP",
- "transTime" => date("YmdHis"),
- "transType" => "PURC",
- "signType" => "MD5",
- "version" => "VER000000002",
- );
- $signature = MoneySwapHelper::createSignature($moneyswap_md5_signature, $data);
- $data['signature'] = $signature;
- return $data;
- }
- private function getRelayResponseSnippet($redirect_url) {
- return "<html><head><script language=\"javascript\">
- <!--
- window.location1=\"{$redirect_url}\";
- //-->
- </script>
- </head><body><noscript><meta http-equiv=\"refresh\" content=\"1;url={$redirect_url}\"></noscript>Test</body></html>";
- }
- #[\Symfony\Component\Routing\Attribute\Route('/customer/process/{gateway}', name: 'processBooking')]
- public function processAction($gateway, MailerInterface $mailer, Request $request)
- {
- $em = $this->getDoctrine()->getManager();
- $paymentGateway = $em->getRepository('App\Entity\Paymentgateway')->find($gateway);
- $func = "saveReturnData_".$paymentGateway->getTemplate();
- $api_login = $this->getParameter('authorize_api_login');
- $md5_hash = $this->getParameter('authorize_md5_hash');
- $fullDomain = ($request->server->get("https") ? "https://" : "http://") . $request->getHost();
- if (method_exists($this, $func))
- $payment = $this->$func($request);
- if ($payment)
- {
- $booking=$payment->getBooking();
- if ($payment->getSuccessful()==1)
- {
- if ($gateway == 3) {
- if (!$booking->getPaid()) {
- $this->mailCustomerConfirmation($booking,$payment);
- $this->mailSalesConfirmation($booking,$payment,$request);
- }
- } else {
- $this->mailCustomerConfirmation($booking,$payment);
- $this->mailSalesConfirmation($booking,$payment,$request);
- }
- $booking->setPaid(1);
- $em->persist($booking);
- $em->flush();
- //$this->mailCustomerConfirmation($booking,$payment);
- //$this->mailSalesConfirmation($booking,$payment);
- $fail = 0;
- $url = $this->generateUrl('successPayment', array("payment"=>$payment->getPaymentid()), UrlGeneratorInterface::ABSOLUTE_URL);
- if ($gateway == 2)
- {
- //added by vazquel on 2014-02-19
- $auth_controller = new \Authorizenet_Authorizenet($api_login, $md5_hash);
- $response = $auth_controller->AuthorizeSIM;
- //added by vazquel on 2014-02-19 (Redirect to the payment success page)
- if ($response->isAuthorizeNet())
- return new Response($this->getRelayResponseSnippet($fullDomain.$url));
- else
- return $this->redirect($url);
- }
- else
- return $this->redirect($url);
- } else
- $fail=1;
- } else
- $fail=2;
- if ($fail == 1)
- {
- $url = $this->generateUrl('failurePayment', array("payment"=>$payment->getPaymentid()), UrlGeneratorInterface::ABSOLUTE_URL);
- if ($gateway == 2)
- {
- $this->mailSalesFailure($payment);
- $auth_controller = new \Authorizenet_Authorizenet($api_login, $md5_hash);
- $response = $auth_controller->AuthorizeSIM;
- if ($response->isAuthorizeNet())
- return new Response($this->getRelayResponseSnippet($fullDomain.$url));
- else
- return $this->redirect($url);
- }
- else
- return $this->redirect($url);
- }
- }
- private function saveReturnData_barclays(Request $request) {
- $hmac_key = $this->getParameter('barclays_hmac_key');
- $em = $this->getDoctrine()->getManager();
- $payment = $em->getRepository('App\Entity\Payment')->find($request->get("merchantReference"));
- if ($payment)
- {
- $booking = $payment->getBooking();
- $data = $this->appendData_barclays($booking, $payment);
- $dataChk = array();
- $dataChk[] = $request->get("authResult");
- $dataChk[] = $request->get("pspReference");
- $dataChk[] = $request->get("merchantReference");
- $dataChk[] = $request->get("skinCode");
- $dataChk[] = $request->get("merchantReturnData");
- $sig = base64_encode(hash_hmac('sha1',implode("", $dataChk),$hmac_key,true));
- if ($sig==$request->get("merchantSig"))
- {
- $payment->setResulttoken($request->get("pspReference"));
- $payment->setAuthcode($request->get("authResult"));
- $payment->setSuccessful("AUTHORISED"==$request->get("authResult"));
- $em->persist($payment);
- $em->flush();
- return $payment;
- }
- else
- return false;
- }
- else
- return false;
- }
- private function saveReturnData_authorize(Request $request) {
- $hmac_key = $this->getParameter('authorize_hmac_key');
- $api_login = $this->getParameter('authorize_api_login');
- $md5_hash = $this->getParameter('authorize_md5_hash');
- $em = $this->doctrine->getManager();
- $payment = $em->getRepository('App\Entity\Payment')->find($request->get("x_invoice_num"));
- $gateway = new \Authorizenet_Authorizenet($api_login, $md5_hash);
- $response = $gateway->AuthorizeSIM;
- if ($response->isAuthorizeNet() && $payment instanceof Payment)
- {
- $payment->setResulttoken($response->authorization_code);
- $payment->setAuthcode($response->response_reason_code);
- $payment->setSuccessful($response->approved*1);
- $payment->setNotification(serialize($response));
- $em->persist($payment);
- $em->flush();
- return $payment;
- }
- else
- die( "Error. Check your MD5 Setting.<br>Received: $response->md5_hash<br>Calculated: ".$response->generateHash());
- }
- private function saveReturnData_moneyswap(Request $request) {
- $moneyswap_aid = $this->getParameter('moneyswap_aid');
- $moneyswap_md5_signature = $this->getParameter('moneyswap_md5_signature');
- $em = $this->getDoctrine()->getManager();
- $payment = $em->getRepository('App\Entity\Payment')->find($request->get("orderNum"));
- if ($payment)
- {
- $booking = $payment->getBooking();
- $query = "version=".$request->get("version");
- $query .= "&charSet=".$request->get("charSet");
- $query .= "&transType=".$request->get("transType");
- $query .= "&orderNum=".$request->get("orderNum");
- $query .= "&orderAmount=".$request->get("orderAmount");
- $query .= "&orderCurrency=".$request->get("orderCurrency");
- $query .= "&settAmount=".$request->get("settAmount");
- $query .= "&settCurrency=".$request->get("settCurrency");
- $query .= "&rate=".$request->get("rate");
- $query .= "&merReserve=".$request->get("merReserve");
- $query .= "&transID=".$request->get("transID");
- $query .= "&merID=".$request->get("merID");
- $query .= "&acqID=".$request->get("acqID");
- $query .= "&paymentSchema=".$request->get("paymentSchema");
- $query .= "&RespCode=".$request->get("RespCode");
- $query .= "&RespMsg=".$request->get("RespMsg");
- $query .= "&transTime=".$request->get("transTime");
- $query .= "&GWTime=".$request->get("GWTime");
- $query .= "&signType=".$request->get("signType");
- $query .= "&signature=".$request->get("signature");
- $isValid = MoneySwapHelper::verifySignature($moneyswap_md5_signature, $query);
- if ($isValid)
- {
- $payment->setResulttoken($request->get("RespMsg"));
- $payment->setAuthcode($request->get("RespCode"));
- $payment->setSuccessful("00"==$request->get("RespCode"));
- $payment->setNotification(serialize($query));
- $em->persist($payment);
- $em->flush();
- return $payment;
- }
- else
- return false;
- }
- else
- return false;
- }
- }