Source of file DPSPayment.php
Size: 14,729 Bytes - Last Modified: 2021-12-23T10:33:28+00:00
/var/www/docs.ssmods.com/process/src/code/DPSPayment/DPSPayment.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 | <?php /** * Payment type to support credit-card payments through DPS. * * @package payment */ class DPSPayment extends Payment { public static $db = array( 'TxnRef' => 'Varchar(1024)', 'TxnType' => "Enum('Purchase,Auth,Complete,Refund,Validate', 'Purchase')", 'AuthCode' => 'Varchar(22)', 'MerchantReference' => 'Varchar(64)', 'DPSHostedRedirectURL' => 'Text', // This field is stored for only when the payment is made thru merchant-hosted DPS gateway (PxPost); 'SettlementDate' => 'Date', // We store the whole raw response xml in case that tracking back the payment is needed in a later stage for whatever the reason. 'ResponseXML' => "Text", 'CardNumberTruncated' => 'Varchar(32)', // The first six and two last digits of the CC 'CardHolderName' => 'Varchar(255)', 'DateExpiry' => 'Varchar(4)', // four digits (mm/yy) 'TimeOutDate' => 'SS_Datetime' ); public static $indexes = array( 'TxnRef' => true, ); public static $has_one = array( //in case that TxnType is Complete, the DPSPayment could have one Auth DPSPayment 'AuthPayment' => 'DPSPayment', //in case that TxnType is Refund, the DPSPayment could have one Refunded DPSPayment 'RefundedFor' => 'DPSPayment' ); private static $input_elements = array( 'Amount', 'CardHolderName', 'CardNumber', 'BillingId', 'Cvc2', 'DateExpiry', 'DpsBillingId', 'DpsTxnRef', 'EnableAddBillCard', 'InputCurrency', 'MerchantReference', 'Opt', 'PostUsername', 'PostPassword', 'TxnType', 'TxnData1', 'TxnData2', 'TxnData3', 'TxnId', 'EnableAvsData', 'AvsAction', 'AvsPostCode', 'AvsStreetAddress', 'DateStart', 'IssueNumber', 'Track2', ); private static $dpshosted_input_elements = array( 'PxPayUserId', 'PxPayKey', 'AmountInput', 'CurrencyInput', 'EmailAddress', 'EnableAddBillCard', 'MerchantReference', 'TxnData1', 'TxnData2', 'TxnData3', 'TxnType', 'TxnId', 'UrlFail', 'UrlSuccess', ); public static $default_sort = "ID DESC"; /** * Cached {@link SimpleXMLElement} object, containing ResponseXML. Indexed by Payment record ID. * @var SimpleXMLElement|null */ protected $cacheResponseXML = null; public function getPaymentFormFields() { $adapter = $this->getDPSAdapter(); return $adapter->getPaymentFormFields(); } /** * Returns the required fields to add to the order form, when using this payment method. */ public function getPaymentFormRequirements() { $adapter = $this->getDPSAdapter(); return $adapter->getPaymentFormRequirements(); } //This function is hooked with OrderForm/E-commerce at the moment, so we need to keep it as it is. public function processPayment($data, $form) { $inputs['Amount'] = $this->Amount->Amount; $inputs['InputCurrency'] = $this->Amount->Currency; $inputs['TxnData1'] = $this->ID; $inputs['TxnType'] = 'Purchase'; $inputs['CardHolderName'] = $data['CardHolderName']; $inputs['CardNumber'] = implode('', $data['CardNumber']); $inputs['DateExpiry'] = $data['DateExpiry']; if (self::$cvn_mode) { $inputs['Cvc2'] = $data['Cvc2'] ? $data['Cvc2'] : ''; } $adapter = $this->getDPSAdapter(); $responseFields = $adapter->doPayment($inputs); $adapter->ProcessResponse($this, $responseFields); if ($this->Status == 'Success') { $result = new Payment_Success(); } else { $result = new Payment_Failure(); } return $result; } public function auth($data) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionStart(); } try { $this->TxnType = "Auth"; $this->write(); $adapter = $this->getDPSAdapter(); $inputs = $this->prepareAuthInputs($data); $adapter->doPayment($inputs, $this); if (DPSAdapter::$using_transaction) { DB::getConn()->transactionEnd(); } } catch (Exception $e) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionRollback(); } $this->handleError($e); } } private function prepareAuthInputs($data) { //never put this loop after $inputs['AmountInput'] = $this->Amount->Amount;, since it will change it to an array. foreach ($data as $element => $value) { if (in_array($element, self::$input_elements)) { $inputs[$element] = $value; } } $inputs['TxnData1'] = $this->ID; $inputs['TxnType'] = $this->TxnType; $inputs['Amount'] = $this->Amount->Amount; $inputs['InputCurrency'] = $this->Amount->Currency; //special element $inputs['CardNumber'] = implode('', $data['CardNumber']); return $inputs; } public function complete() { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionStart(); } try { $auth = $this->AuthPayment(); $this->TxnType = "Complete"; $this->MerchantReference = "Complete: ".$auth->MerchantReference; $this->write(); $adapter = $this->getDPSAdapter(); $inputs = $this->prepareCompleteInputs(); $adapter->doPayment($inputs, $this); if (DPSAdapter::$using_transaction) { DB::getConn()->transactionEnd(); } } catch (Exception $e) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionRollback(); } $this->handleError($e); } } private function prepareCompleteInputs() { $auth = $this->AuthPayment(); $inputs['TxnData1'] = $this->ID; $inputs['TxnType'] = $this->TxnType; $inputs['Amount'] = $this->Amount->Amount; $inputs['InputCurrency'] = $this->Amount->Currency; $inputs['DpsTxnRef'] = $auth->TxnRef; //$inputs['AuthCode'] = $auth->AuthCode; return $inputs; } public function purchase($data) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionStart(); } try { $this->TxnType = "Purchase"; $this->write(); $adapter = $this->getDPSAdapter(); $inputs = $this->prepareAuthInputs($data); $adapter->doPayment($inputs, $this); if (DPSAdapter::$using_transaction) { DB::getConn()->transactionEnd(); } } catch (Exception $e) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionRollback(); } $this->handleError($e); } } public function refund() { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionStart(); } try { $refunded = $this->RefundedFor(); $this->TxnType = "Refund"; $this->MerchantReference = "Refund for: ".$refunded->MerchantReference; $this->write(); $adapter = $this->getDPSAdapter(); $inputs = $this->prepareRefundInputs(); $adapter->doPayment($inputs, $this); if (DPSAdapter::$using_transaction) { DB::getConn()->transactionEnd(); } } catch (Exception $e) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionRollback(); } $this->handleError($e); return false; } return true; } private function prepareRefundInputs() { $refundedFor = $this->RefundedFor(); $inputs['TxnData1'] = $this->ID; $inputs['TxnType'] = $this->TxnType; $inputs['Amount'] = $this->Amount->Amount; $inputs['InputCurrency'] = $this->Amount->Currency; $inputs['DpsTxnRef'] = $refundedFor->TxnRef; $inputs['MerchantReference'] = $this->MerchantReference; return $inputs; } public function dpshostedPurchase($data = array()) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionStart(); } try { $this->TxnType = "Purchase"; $this->write(); $adapter = $this->getDPSAdapter(); $inputs = $this->prepareDPSHostedRequest($data); return $adapter->doDPSHostedPayment($inputs, $this); } catch (Exception $e) { if (DPSAdapter::$using_transaction) { DB::getConn()->transactionRollback(); } $this->handleError($e); } } public function prepareDPSHostedRequest($data = array()) { //never put this loop after $inputs['AmountInput'] = $amount, since it will change it to an array. foreach ($data as $element => $value) { if (in_array($element, self::$dpshosted_input_elements)) { $inputs[$element] = $value; } } $inputs['TxnData1'] = $this->ID; $inputs['TxnType'] = $this->TxnType; $amount = (float) ltrim($this->Amount->Amount, '$'); $inputs['AmountInput'] = $amount; $inputs['InputCurrency'] = $this->Amount->Currency; $inputs['MerchantReference'] = $this->MerchantReference; if (isset($this->TimeOutDate)) { $inputs['Opt'] = $this->TimeOutDate; } $postProcess_url = Director::absoluteBaseURL() ."DPSAdapter/processDPSHostedResponse"; $inputs['UrlFail'] = $postProcess_url; $inputs['UrlSuccess'] = $postProcess_url; return $inputs; } public function payAsRecurring() { $adapter = $this->getDPSAdapter(); $inputs = $this->prepareAsRecurringPaymentInputs(); $adapter->doPayment($inputs, $this); } public function prepareAsRecurringPaymentInputs() { $reccurringPayment = DataObject::get_by_id('DPSRecurringPayment', $this->RecurringPaymentID); $inputs['DpsBillingId'] = $reccurringPayment->DPSBillingID; $inputs['TxnData1'] = $this->ID; $inputs['TxnType'] = 'Purchase'; $amount = (float) ltrim($reccurringPayment->Amount->Amount, '$'); $inputs['Amount'] = $amount; $inputs['InputCurrency'] = $reccurringPayment->Amount->Currency; $inputs['MerchantReference'] = $reccurringPayment->MerchantReference; return $inputs; } public function CanComplete() { $successComplete = $this->successCompletePayment(); return !($successComplete && $successComplete->ID) && $this->TxnType == 'Auth' && $this->Status = 'Success'; } public function successCompletePayment() { return DataObject::get_one( "DPSPayment", "\"Status\" = 'Success' AND \"TxnType\" = 'Complete' AND \"AuthPaymentID\" = '".(int)$this->ID."'" ); } public function onAfterWrite() { if ($this->isChanged('Status') && $this->Status == 'Success') { $this->sendReceipt(); } parent::onAfterWrite(); } public function sendReceipt() { $member = $this->PaidBy(); if ($member->exists() && $member->Email) { $from = DPSAdapter::get_receipt_from(); if ($from) { $body = $this->renderWith($this->ClassName."_receipt"); $body .= $member->ReceiptMessage(); $email = new Email($from, $member->Email, "Payment receipt (Ref no. #".$this->ID.")", $body); $email->send(); } } } protected function parsedResponseXML($cached = true) { if (!$this->cacheResponseXML || !$cached) { $this->cacheResponseXML = simplexml_load_string($this->ResponseXML, 'SimpleXMLElement', LIBXML_NOWARNING); } return $this->cacheResponseXML; } /** * From the ResponseXML, retrieve the AmountSettlement value. * CAUTION: Only works for transactions created through PXPay, not PXPost! * * @return bool|string */ public function getAmountSettlement() { $xml = $this->parsedResponseXML(); return ($xml) ? (string) $xml->AmountSettlement : false; } /** * From the ResponseXML, retrieve the CardName value. * @return bool|string */ public function getCardName() { $xml = $this->parsedResponseXML(); if (!$xml) { return false; } return ($xml->Transaction) ? (string)$xml->Transaction->CardName : (string)$xml->CardName; } /** * From the ResponseXML, retrieve the CardHolderName value. * @return bool|string */ public function getCardHolderName() { $xml = $this->parsedResponseXML(); if (!$xml) { return false; } return ($xml->Transaction) ? (string)$xml->Transaction->CardHolderName : (string)$xml->CardHolderName; } /** * From the ResponseXML, retrieve the DateExpiry value. * @return bool|string */ public function getDateExpiry() { $xml = $this->parsedResponseXML(); if (!$xml) { return false; } return ($xml->Transaction) ? (string)$xml->Transaction->DateExpiry : (string)$xml->DateExpiry; } /** * From the ResponseXML, retrieve the CardNumber value. * @return bool|string */ public function getCardNumber() { $xml = $this->parsedResponseXML(); if (!$xml) { return false; } return ($xml->Transaction) ? (string)$xml->Transaction->CardNumber : (string)$xml->CardNumber; } protected $dpsAdapter; public function getDPSAdapter() { if (!$this->dpsAdapter) { $this->dpsAdapter = new DPSAdapter(); } return $this->dpsAdapter; } public function setDPSAdapter($adapter) { $this->dpsAdapter = $adapter; } } |