/**
  * Tests Services_Paymill_Clients->create()
  */
 public function testCreate()
 {
     $email = '*****@*****.**';
     $client = $this->_clients->create(array('email' => $email));
     $this->assertArrayHasKey('email', $client);
     $this->assertEquals($email, $client['email']);
     return $client['id'];
 }
Beispiel #2
0
 public function onAKPaymentCallback($paymentmethod, $data)
 {
     JLoader::import('joomla.utilities.date');
     // Check if we're supposed to handle this
     if ($paymentmethod != $this->ppName) {
         return false;
     }
     $isValid = true;
     // Load the relevant subscription row
     $id = $data['sid'];
     $subscription = null;
     // CHECK: Is this a valid subscription record?
     if ($id > 0) {
         $subscription = F0FModel::getTmpInstance('Subscriptions', 'AkeebasubsModel')->setId($id)->getItem();
         if ($subscription->akeebasubs_subscription_id <= 0 || $subscription->akeebasubs_subscription_id != $id) {
             $subscription = null;
             $isValid = false;
         }
     } else {
         $isValid = false;
     }
     if (!$isValid) {
         $data['akeebasubs_failure_reason'] = 'The subscription ID is invalid';
     }
     // CHECK: Is the amount correct?
     $isPartialRefund = false;
     if ($isValid) {
         $mc_gross = $data['amount'];
         // Remember: the amount is in cents, e.g. 400 means 4.00 Euros
         $gross = (int) ($subscription->gross_amount * 100);
         $isValid = $gross - $mc_gross < 0.01;
         if (!$isValid) {
             $data['akeebasubs_failure_reason'] = 'Paid amount does not match the subscription amount';
         }
     }
     // CHECK: Is this transaction valid?
     // Log the IPN data
     $this->logIPN($data, $isValid, 'CALLBACK');
     // Fraud attempt? Do nothing more!
     if (!$isValid) {
         $level = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->setId($subscription->akeebasubs_level_id)->getItem();
         $error_url = 'index.php?option=' . JRequest::getCmd('option') . '&view=level&slug=' . $level->slug . '&layout=' . JRequest::getCmd('layout', 'default');
         $error_url = JRoute::_($error_url, false);
         JFactory::getApplication()->redirect($error_url, $data['akeebasubs_failure_reason'], 'error');
         return false;
     }
     // ACTION: Initialise common variables
     if ($isValid) {
         $apiKey = $this->getPrivateKey();
         $apiEndpoint = 'https://api.paymill.de/v2/';
         $db = JFactory::getDbo();
     }
     // CHECK: Do we have a user already defined in PayMill?
     $user = JFactory::getUser($subscription->user_id);
     $clientsObject = new Services_Paymill_Clients($apiKey, $apiEndpoint);
     $filters = array('email' => $user->email);
     $clients = $clientsObject->get($filters);
     // ACTION: Get the client ID or create and save a new user in PayMill if necessary
     if (count($clients)) {
         $clientRecord = array_pop($clients);
     } else {
         $params = array('email' => $user->email, 'description' => $user->name . ' [' . $user->username . ']');
         try {
             $clientRecord = $clientsObject->create($params);
         } catch (Exception $exc) {
             $isValid = false;
             $params['akeebasubs_failure_reason'] = $exc->getMessage();
         }
         if (!array_key_exists('id', $clientRecord) || empty($clientRecord['id'])) {
             // Apparently the client creation failed
             $isValid = false;
             $params['akeebasubs_failure_reason'] = JText::_('PLG_AKPAYMENT_PAYMILL_ERROR_CLIENT');
         }
         // Log the user creation data
         $this->logIPN($data, $isValid, 'USER');
         // Fraud attempt? Do nothing more!
         if (!$isValid) {
             $level = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->setId($subscription->akeebasubs_level_id)->getItem();
             $error_url = 'index.php?option=' . JRequest::getCmd('option') . '&view=level&slug=' . $level->slug . '&layout=' . JRequest::getCmd('layout', 'default');
             $error_url = JRoute::_($error_url, false);
             JFactory::getApplication()->redirect($error_url, $params['akeebasubs_failure_reason'], 'error');
             return false;
         }
     }
     $client = $clientRecord['id'];
     // CHECK: Do we already have a payment for this subscription?
     // -- Load the processor key from database. This prevents race conditions.
     $query = $db->getQuery(true)->select($db->qn('processor_key'))->from('#__akeebasubs_subscriptions')->where($db->qn('akeebasubs_subscription_id') . ' = ' . $db->q($subscription->akeebasubs_subscription_id));
     $db->setQuery($query);
     $payment_id = $db->loadResult();
     // ACTION: Create and save a new payment for this subscription if there is no payment or transaction yet
     if (substr($payment_id, 0, 4) != 'pay_' && substr($payment_id, 0, 5) != 'tran_') {
         $params = array('client' => $client, 'token' => $data['token']);
         $paymentsObject = new Services_Paymill_Payments($apiKey, $apiEndpoint);
         try {
             $creditcard = $paymentsObject->create($params);
         } catch (Exception $exc) {
             $isValid = false;
             $params['akeebasubs_failure_reason'] = $exc->getMessage();
         }
         if (!array_key_exists('id', $creditcard) || empty($creditcard['id'])) {
             // Apparently the credit card capture creation failed
             $isValid = false;
             $params['akeebasubs_failure_reason'] = JText::_('PLG_AKPAYMENT_PAYMILL_ERROR_CC') . '<br/>Tech info: <tt>' . htmlentities($creditcard['error']) . '</tt>';
         }
         // Log the payment creation data
         $this->logIPN($data, $isValid, 'PAYMENT');
         // Fraud attempt? Do nothing more!
         if (!$isValid) {
             $level = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->setId($subscription->akeebasubs_level_id)->getItem();
             $error_url = 'index.php?option=' . JRequest::getCmd('option') . '&view=level&slug=' . $level->slug . '&layout=' . JRequest::getCmd('layout', 'default');
             $error_url = JRoute::_($error_url, false);
             JFactory::getApplication()->redirect($error_url, $params['akeebasubs_failure_reason'], 'error');
             return false;
         }
         $subscription->processor_key = $creditcard['id'];
         $payment_id = $creditcard['id'];
         // Save the payment information WITHOUT using the table (skips the plugins)
         // This prevents double payments from being recorded
         $oUpdate = (object) array('akeebasubs_subscription_id' => $subscription->akeebasubs_subscription_id, 'processor_key' => $subscription->processor_key, 'state' => 'P');
         JFactory::getDbo()->updateObject('#__akeebasubs_subscriptions', $oUpdate, 'akeebasubs_subscription_id');
     }
     // CHECK: Do we already have a transaction for this subscription?
     // -- Load the processor key from database. This prevents race conditions.
     $query = $db->getQuery(true)->select($db->qn('processor_key'))->from('#__akeebasubs_subscriptions')->where($db->qn('akeebasubs_subscription_id') . ' = ' . $db->q($subscription->akeebasubs_subscription_id));
     $db->setQuery($query);
     $payment_id = $db->loadResult();
     // ACTION: Create a transaction if necessary
     if (substr($payment_id, 0, 5) != 'tran_') {
         // First update the object with a fake transaction
         $subscription->processor_key = 'tran_in_progress';
         // Save the payment information WITHOUT using the table (skips the plugins)
         // This prevents double payments from being recorded
         $oUpdate = (object) array('akeebasubs_subscription_id' => $subscription->akeebasubs_subscription_id, 'processor_key' => $subscription->processor_key, 'state' => 'P');
         JFactory::getDbo()->updateObject('#__akeebasubs_subscriptions', $oUpdate, 'akeebasubs_subscription_id');
         // Create the transaction
         $params = array('amount' => $data['amount'], 'currency' => $data['currency'], 'client' => $client, 'payment' => $payment_id, 'description' => $data['description']);
         try {
             $transactionsObject = new Services_Paymill_Transactions($apiKey, $apiEndpoint);
             $transaction = $transactionsObject->create($params);
         } catch (Exception $exc) {
             $isValid = false;
             $params['akeebasubs_failure_reason'] = $exc->getMessage();
         }
         if (!array_key_exists('id', $transaction) || empty($transaction['id'])) {
             // Apparently the transaction creation failed
             $isValid = false;
             $params['akeebasubs_failure_reason'] = JText::_('PLG_AKPAYMENT_PAYMILL_ERROR_TRANS');
         }
         // Log the payment creation data
         $this->logIPN($data, $isValid, 'TRANSACTION');
         if (!$isValid) {
             $transaction_id = $payment_id;
         } else {
             $transaction_id = $transaction['id'];
         }
         // First update the object
         $subscription->processor_key = $transaction_id;
         // Save the payment information WITHOUT using the table (skips the plugins)
         // This prevents double payments from being recorded
         $oUpdate = (object) array('akeebasubs_subscription_id' => $subscription->akeebasubs_subscription_id, 'processor_key' => $subscription->processor_key);
         JFactory::getDbo()->updateObject('#__akeebasubs_subscriptions', $oUpdate, 'akeebasubs_subscription_id');
         // Fraud attempt? Do nothing more!
         if (!$isValid) {
             $level = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->setId($subscription->akeebasubs_level_id)->getItem();
             $error_url = 'index.php?option=' . JRequest::getCmd('option') . '&view=level&slug=' . $level->slug . '&layout=' . JRequest::getCmd('layout', 'default');
             $error_url = JRoute::_($error_url, false);
             JFactory::getApplication()->redirect($error_url, $params['akeebasubs_failure_reason'], 'error');
             return false;
         }
     } else {
         // ACTION: If no transaction is necessary, show an error
         $level = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->setId($subscription->akeebasubs_level_id)->getItem();
         $error_url = 'index.php?option=' . JRequest::getCmd('option') . '&view=level&slug=' . $level->slug . '&layout=' . JRequest::getCmd('layout', 'default');
         $error_url = JRoute::_($error_url, false);
         JFactory::getApplication()->redirect($error_url, 'Cannot process the transaction twice. Wait to receive your subscription confirmation email and do not retry submitting the payment form again.', 'error');
         return false;
     }
     if ($isValid) {
         if ($this->params->get('sandbox') == $transaction['livemode']) {
             $isValid = false;
             $data['akeebasubs_failure_reason'] = "Transaction done in wrong mode.";
         }
     }
     // Payment status
     // Check the payment_status
     switch ($transaction['status']) {
         case 'closed':
         case 'partial_refunded':
             $newStatus = 'C';
             break;
         case 'open':
         case 'pending':
         case 'preauthorize':
             $newStatus = 'P';
             break;
         case 'failed':
         case 'refunded':
             $newStatus = 'X';
             break;
     }
     // Update subscription status (this also automatically calls the plugins)
     $updates = array('akeebasubs_subscription_id' => $id, 'processor_key' => $transaction_id, 'state' => $newStatus, 'enabled' => 0);
     JLoader::import('joomla.utilities.date');
     if ($newStatus == 'C') {
         $this->fixDates($subscription, $updates);
     }
     $subscription->save($updates);
     // Run the onAKAfterPaymentCallback events
     JLoader::import('joomla.plugin.helper');
     JPluginHelper::importPlugin('akeebasubs');
     $app = JFactory::getApplication();
     $jResponse = $app->triggerEvent('onAKAfterPaymentCallback', array($subscription));
     // Redirect the user to the "thank you" page
     $level = F0FModel::getTmpInstance('Levels', 'AkeebasubsModel')->setId($subscription->akeebasubs_level_id)->getItem();
     $thankyouUrl = JRoute::_('index.php?option=com_akeebasubs&view=message&slug=' . $level->slug . '&layout=order&subid=' . $subscription->akeebasubs_subscription_id, false);
     JFactory::getApplication()->redirect($thankyouUrl);
     return true;
 }