/** * Save transaction data. * * @param array $transactionData * * @throws \RuntimeException * @throws \InvalidArgumentException * @throws \UnexpectedValueException * * @return Transaction|null */ protected function storeTransaction($transactionData) { // Get transaction object by transaction ID $keys = array('txn_id' => ArrayHelper::getValue($transactionData, 'txn_id')); $transaction = new Transaction(JFactory::getDbo()); $transaction->load($keys); // DEBUG DATA JDEBUG ? $this->log->add(JText::_($this->textPrefix . '_DEBUG_TRANSACTION_OBJECT'), $this->debugType, $transaction->getProperties()) : null; // Check for existed transaction // If the current status if completed, stop the payment process. if ($transaction->getId() and $transaction->isCompleted()) { return null; } // Add extra data. if (array_key_exists('extra_data', $transactionData)) { if (!empty($transactionData['extra_data'])) { $transaction->addExtraData($transactionData['extra_data']); } unset($transactionData['extra_data']); } // IMPORTANT: It must be before ->bind(); $options = array('old_status' => $transaction->getStatus(), 'new_status' => $transactionData['txn_status']); // Create the new transaction record if there is not record. // If there is new record, store new data with new status. // Example: It has been 'pending' and now is 'completed'. // Example2: It has been 'pending' and now is 'failed'. $transaction->bind($transactionData); // Start database transaction. $db = JFactory::getDbo(); $db->transactionStart(); try { $transactionManager = new TransactionManager($db); $transactionManager->setTransaction($transaction); $transactionManager->process('com_crowdfunding.payment', $options); } catch (Exception $e) { $db->transactionRollback(); $this->log->add(JText::_($this->textPrefix . '_ERROR_TRANSACTION_PROCESS'), $this->errorType, $e->getMessage()); return null; } // Commit database transaction. $db->transactionCommit(); return $transaction; }
/** * Pre-processor for $transactionManager->process($context, $options) * * @param string $context * @param Transaction $transaction * @param array $options * * @throws \RuntimeException * @throws \InvalidArgumentException * @throws \UnexpectedValueException * @throws \OutOfBoundsException * * @return void */ public function onAfterProcessTransaction($context, Transaction $transaction, array $options = array()) { // Check for allowed context. if (!in_array($context, $this->allowedContext, true)) { return; } $completedOrPending = Constants::PAYMENT_STATUS_COMPLETED | Constants::PAYMENT_STATUS_PENDING; $canceledOrRefundedOrFialed = Constants::PAYMENT_STATUS_CANCELED | Constants::PAYMENT_STATUS_REFUNDED | Constants::PAYMENT_STATUS_FAILED; $statuses = array('completed' => Constants::PAYMENT_STATUS_COMPLETED, 'pending' => Constants::PAYMENT_STATUS_PENDING, 'canceled' => Constants::PAYMENT_STATUS_CANCELED, 'refunded' => Constants::PAYMENT_STATUS_REFUNDED, 'failed' => Constants::PAYMENT_STATUS_FAILED); $oldStatus = ArrayHelper::getValue($options, 'old_status'); $newStatus = ArrayHelper::getValue($options, 'new_status'); $oldStatusBit = ($oldStatus and array_key_exists($oldStatus, $statuses)) ? $statuses[$oldStatus] : null; $newStatusBit = ($newStatus and array_key_exists($newStatus, $statuses)) ? $statuses[$newStatus] : null; // Check if it is new record. $isNew = false; if ($oldStatusBit === null and $newStatusBit !== null) { $isNew = true; } $container = Container::getContainer(); $containerHelper = new Helper(); // Add funds when create new transaction record, and it is completed and pending. if ($isNew and $transaction->getProjectId() > 0 and ($transaction->isCompleted() or $transaction->isPending())) { $project = $containerHelper->fetchProject($container, $transaction->getProjectId()); $project->addFunds($transaction->getAmount()); $project->storeFunds(); if ($transaction->getRewardId()) { $reward = $containerHelper->fetchReward($container, $transaction->getRewardId(), $transaction->getProjectId()); $this->increaseDistributedReward($transaction, $reward); } } else { // If someone change the status from completed/pending to another one, remove funds. if ($completedOrPending & $oldStatusBit and $canceledOrRefundedOrFialed & $newStatusBit) { $project = $containerHelper->fetchProject($container, $transaction->getProjectId()); $project->removeFunds($transaction->getAmount()); $project->storeFunds(); if ($transaction->getRewardId()) { $reward = $containerHelper->fetchReward($container, $transaction->getRewardId(), $transaction->getProjectId()); $this->decreaseDistributedReward($transaction, $reward); } } elseif ($canceledOrRefundedOrFialed & $oldStatusBit and $completedOrPending & $newStatusBit) { $project = $containerHelper->fetchProject($container, $transaction->getProjectId()); $project->addFunds($transaction->getAmount()); $project->storeFunds(); if ($transaction->getRewardId()) { $reward = $containerHelper->fetchReward($container, $transaction->getRewardId(), $transaction->getProjectId()); $this->increaseDistributedReward($transaction, $reward); } } } }