コード例 #1
0
ファイル: PaypalBatch.class.php プロジェクト: alcf/chms
 /**
  * This will process a report text file as taken from PayPal.  This will create any applicable PaypalBatch entries
  * and correlate with existing CreditCardPayment records.  This will *only* process "Delayed Capture" transactions,
  * since that's all we actually care about.  This will create "as unlinked" any CreditCardPayment records that had
  * to be created because it didn't exist (which means that this is a bad thing -- we should not have any of those).
  * 
  * If there are any issues with importing, this will throw an error
  * 
  * @param string $strReportText the text of the report itself from paypal
  * @param integer $intEntriesModified return value of the number of entries that were modified
  * @param integer $intEntriesAdded return value of the number of entries that were created (hopefully shouuld be zero)
  * @throws QCallerException
  */
 public static function ProcessReport($strReportText, &$intEntriesModified, &$intEntriesAdded)
 {
     $intEntriesModified = 0;
     $intEntriesAdded = 0;
     // Cleanup Linebreaks
     $strReportText = str_replace("\r", "\n", $strReportText);
     while (strpos($strReportText, "\n\n") !== false) {
         $strReportText = str_replace("\n\n", "\n", $strReportText);
     }
     $strReportText = trim($strReportText);
     // Pull out the First Line (column headers) from the rest of the report
     $intPosition = strpos($strReportText, "\n");
     $strFirstLine = substr($strReportText, 0, $intPosition);
     $strReportText = substr($strReportText, $intPosition + 1);
     // Calculate the tokens
     $strTokenArray = array();
     $intColumnIndex = 0;
     foreach (explode("\t", $strFirstLine) as $strToken) {
         if (array_key_exists($strToken, $strTokenArray)) {
             throw new QCallerException('Report has a duplicate column: ' . $strToken);
         }
         $strTokenArray[$strToken] = $intColumnIndex;
         $intColumnIndex++;
     }
     // Ensure that the required fields exist
     foreach (self::$RequiredFields as $strRequiredToken) {
         if (!array_key_exists($strRequiredToken, $strTokenArray)) {
             throw new QCallerException('Report is missing required column: ' . $strRequiredToken);
         }
     }
     // Go through each line of the report
     foreach (explode("\n", $strReportText) as $strLine) {
         // Break out all cells, and then create a specific Values array that contain only the cells we care about, indexed by name
         $strCellArray = explode("\t", $strLine);
         $strValuesArray = array();
         foreach (self::$RequiredFields as $strRequiredToken) {
             $strValuesArray[$strRequiredToken] = $strCellArray[$strTokenArray[$strRequiredToken]];
         }
         // Only process "Delayed Capture"
         if ($strValuesArray['Type'] == 'Delayed Capture') {
             if (strlen(trim($strValuesArray[self::PayPalOriginalTransactionId])) == 0) {
                 throw new QCallerException('Transaction ' . $strValuesArray[self::PayPalTransactionId] . ' does not have an Original Transaction Id');
             }
             // Can we find the linked CCPayment Record?
             $objCreditCardPayment = CreditCardPayment::LoadByTransactionCode($strValuesArray[self::PayPalOriginalTransactionId]);
             if (!$objCreditCardPayment) {
                 // No -- let's create this as an UNLINKED one
                 $intEntriesAdded++;
                 $objCreditCardPayment = new CreditCardPayment();
                 $objCreditCardPayment->TransactionCode = $strValuesArray[self::PayPalOriginalTransactionId];
                 $objCreditCardPayment->CreditCardStatusTypeId = CreditCardStatusType::Captured;
                 $objCreditCardPayment->CreditCardLastFour = substr($strValuesArray[self::PayPalAccountNumber], strlen($strValuesArray[self::PayPalAccountNumber]) - 4);
                 foreach (CreditCardType::$NameArray as $intId => $strName) {
                     if (strtolower($strName) == strtolower($strValuesArray[self::PayPalTenderType])) {
                         $objCreditCardPayment->CreditCardTypeId = $intId;
                     }
                 }
                 if (!$objCreditCardPayment->CreditCardTypeId) {
                     throw new QCallerException('Unlinked transaction contains an unknown credit card type: ' . $strValuesArray[self::PayPalTenderType]);
                 }
                 $objCreditCardPayment->UnlinkedFlag = true;
                 // Setup Fields
                 $objCreditCardPayment->AuthorizationCode = $strValuesArray[self::PayPalAuthCode];
                 $objCreditCardPayment->AmountCharged = $strValuesArray[self::PayPalAmount];
             }
             // Link in the Pay Pal Batch Info (if applicable)
             //					if (SERVER_INSTANCE == 'dev') $strValuesArray[self::PayPalBatchId] = 789;
             if ($intBatchNumber = trim($strValuesArray[self::PayPalBatchId])) {
                 $objPayPalBatch = PaypalBatch::LoadByNumber($intBatchNumber);
                 if (!$objPayPalBatch) {
                     $objPayPalBatch = new PaypalBatch();
                     $objPayPalBatch->Number = $intBatchNumber;
                     $objPayPalBatch->DateReceived = new QDateTime($strValuesArray[self::PayPalSettledDate]);
                     $objPayPalBatch->ReconciledFlag = false;
                     $objPayPalBatch->Save();
                 }
                 if ($objCreditCardPayment->PaypalBatchId != $objPayPalBatch->Id) {
                     $objCreditCardPayment->PaypalBatch = $objPayPalBatch;
                     if ($objCreditCardPayment->Id) {
                         $intEntriesModified++;
                     }
                 }
             } else {
                 if (!is_null($objCreditCardPayment->PaypalBatchId)) {
                     $objCreditCardPayment->PaypalBatch = null;
                     if ($objCreditCardPayment->Id) {
                         $intEntriesModified++;
                     }
                 }
             }
             // TODO: How do we account fo a "reconciled" PayPal batch that unexpectatly received another transaction not previously accounted for?
             // Check Fields to ensure match
             if ($objCreditCardPayment->AuthorizationCode != $strValuesArray[self::PayPalAuthCode]) {
                 throw new QCallerException(sprintf('Mismatch AuthCode for Transaction %s: %s vs. %s', $strValuesArray[self::PayPalOriginalTransactionId], $strValuesArray[self::PayPalAuthCode], $objCreditCardPayment->AuthorizationCode));
             }
             if ($objCreditCardPayment->AmountCharged != str_replace(',', '', $strValuesArray[self::PayPalAmount])) {
                 throw new QCallerException(sprintf('Mismatch Amount for Transaction %s: %s vs. %s', $strValuesArray[self::PayPalOriginalTransactionId], $strValuesArray[self::PayPalAmount], $objCreditCardPayment->AmountCharged));
             }
             // Update Fields
             $objCreditCardPayment->DateCaptured = new QDateTime($strValuesArray[self::PayPalTime]);
             $objCreditCardPayment->Save();
         }
     }
 }
コード例 #2
0
ファイル: CreditCardPayment.class.php プロジェクト: alcf/chms
 /**
  * The following will synchronously perform an "Authorization" for an UNSAVED PaymentObject against
  * a given Name, Address, Cc Credentials and Amount.  If the authorization succeeds, a valid
  * CreditCardPayment object is returned.  Otherwise, an error message is presented in String form.
  * 
  * The actual "Capture" will be performed asynchronously by a separate cron-based CLI process.
  * 
  * @param mixed $objPaymentObject this should be either an OnlineDonation or a SignupPayment object
  * @param array $arrPaymentObjectSaveChildrenCallback a callback to a method that will perform any children-save to the PaymentObject sent in
  * @param string $strFirstName
  * @param string $strLastName
  * @param Address $objAddress does not have to be linked to an actual db row
  * @param float $fltAmount
  * @param string $strCcNumber
  * @param string $strCcExpiration four digits, MMYY format
  * @param string $strCcCsc
  * @param integer $intCreditCardTypeId
  * @return mixed a CreditCardPayment object if authorization successful, otherwise a string-based message on why it failed
  */
 public static function PerformAuthorization($objPaymentObject, $arrPaymentObjectSaveChildrenCallback, $strFirstName, $strLastName, Address $objAddress, $fltAmount, $strCcNumber, $strCcExpiration, $strCcCsc, $intCreditCardTypeId)
 {
     // Ensure a "Valid" PaymentObject
     if (!$objPaymentObject instanceof SignupPayment && !$objPaymentObject instanceof OnlineDonation) {
         throw new QCallerException('Supplied PaymentObject is not an instance of SignupPayment or OnlineDonation');
     }
     if ($objPaymentObject->Id) {
         throw new QCallerException('Supplied PaymentObject has already been saved');
     }
     if ($objPaymentObject->CreditCardPaymentId) {
         throw new QCallerException('Supplied PaymentObject already has a linked CCPayment object');
     }
     CreditCardPayment::GetDatabase()->TransactionBegin();
     try {
         // Save the PaymentObject itself
         $objPaymentObject->Save();
         // Make a call to save children (if applicable)
         call_user_func($arrPaymentObjectSaveChildrenCallback, $objPaymentObject);
         $strClassName = get_class($objPaymentObject);
         switch ($strClassName) {
             case 'SignupPayment':
                 $strComment1 = 'Signup Payment ' . $objPaymentObject->Id;
                 $strComment2 = 'SE' . $objPaymentObject->SignupEntry->Id . ' - ' . 'SF' . $objPaymentObject->SignupEntry->SignupFormId . ' - ' . 'P' . $objPaymentObject->SignupEntry->PersonId;
                 $strInvoiceNumber = 'SP' . $objPaymentObject->Id;
                 break;
             case 'OnlineDonation':
                 $strComment1 = 'Online Donation ' . $objPaymentObject->Id;
                 $strComment2 = 'P' . $objPaymentObject->PersonId;
                 $strInvoiceNumber = 'OD' . $objPaymentObject->Id;
                 break;
             default:
                 throw new Exception('Unsupported: ' . $strClassName);
         }
         $strNvpRequestArray = self::PaymentGatewayGenerateAuthorizationPayload($strFirstName, $strLastName, $objAddress, $fltAmount, $strCcNumber, $strCcExpiration, $strCcCsc, $strComment1, $strComment2, $strInvoiceNumber);
         $strNvpResponseArray = self::PaymentGatewaySubmitRequest($strNvpRequestArray);
         if (!is_array($strNvpResponseArray)) {
             CreditCardPayment::GetDatabase()->TransactionRollBack();
             return 'Could Not Connect to Payment Gateway';
         }
         // Analyze the ResponseArray
         if (!array_key_exists('RESULT', $strNvpResponseArray)) {
             CreditCardPayment::GetDatabase()->TransactionRollBack();
             return 'Missing Result Code from Payment Gateway';
         }
         if (!array_key_exists('RESPMSG', $strNvpResponseArray)) {
             CreditCardPayment::GetDatabase()->TransactionRollBack();
             return 'Missing Response from Payment Gateway';
         }
         if (!array_key_exists('PNREF', $strNvpResponseArray)) {
             CreditCardPayment::GetDatabase()->TransactionRollBack();
             return 'Missing Reference ID from Payment Gateway';
         }
         // Fill in the blanks
         if (!array_key_exists('CVV2MATCH', $strNvpResponseArray)) {
             $strNvpResponseArray['CVV2MATCH'] = '';
         }
         if (!array_key_exists('AVSADDR', $strNvpResponseArray)) {
             $strNvpResponseArray['AVSADDR'] = '?';
         }
         if (!array_key_exists('AVSZIP', $strNvpResponseArray)) {
             $strNvpResponseArray['AVSZIP'] = '?';
         }
         if (!array_key_exists('IAVS', $strNvpResponseArray)) {
             $strNvpResponseArray['IAVS'] = '?';
         }
         if (!array_key_exists('AUTHCODE', $strNvpResponseArray)) {
             $strNvpResponseArray['AUTHCODE'] = '';
         }
         // If Failure, cleanup and then report
         if ($strNvpResponseArray['RESULT'] != 0) {
             CreditCardPayment::GetDatabase()->TransactionRollBack();
             return sprintf('%s (%s)', $strNvpResponseArray['RESPMSG'], $strNvpResponseArray['RESULT']);
         }
         // If CVV2 Failed, then Report
         if ($strNvpResponseArray['CVV2MATCH'] == 'N') {
             CreditCardPayment::GetDatabase()->TransactionRollBack();
             $strNvpRequestArray = self::PaymentGatewayGenerateVoidPayload($strNvpResponseArray['PNREF']);
             $strNvpResponseArray = self::PaymentGatewaySubmitRequest($strNvpRequestArray);
             return 'The CVV2 code entered is invalid.  Please double check the 3-digit CVV2 code on the back of your card. (' . $strNvpResponseArray['RESULT'] . ')';
         }
         // If we are here, we had a successful authorization!
         $objCreditCardPayment = new CreditCardPayment();
         $objCreditCardPayment->CreditCardStatusTypeId = CreditCardStatusType::Authorized;
         $objCreditCardPayment->CreditCardLastFour = substr($strCcNumber, strlen($strCcNumber) - 4);
         $objCreditCardPayment->CreditCardTypeId = $intCreditCardTypeId;
         $objCreditCardPayment->TransactionCode = $strNvpResponseArray['PNREF'];
         $objCreditCardPayment->AuthorizationCode = $strNvpResponseArray['AUTHCODE'];
         $objCreditCardPayment->AddressMatchCode = $strNvpResponseArray['AVSADDR'] . $strNvpResponseArray['AVSZIP'] . $strNvpResponseArray['IAVS'];
         $objCreditCardPayment->DateAuthorized = QDateTime::Now();
         $objCreditCardPayment->AmountCharged = $fltAmount;
         $objCreditCardPayment->UnlinkedFlag = false;
         // Save, Commit and Return
         $objCreditCardPayment->Save();
         $objPaymentObject->CreditCardPayment = $objCreditCardPayment;
         $objPaymentObject->Save();
         CreditCardPayment::GetDatabase()->TransactionCommit();
     } catch (Exception $objExc) {
         CreditCardPayment::GetDatabase()->TransactionRollBack();
         throw $objExc;
     }
     $objPaymentObject->RefreshDetailsWithCreditCardPayment();
     return $objCreditCardPayment;
 }