public function execute()
 {
     $logger = Logger::getTaggedLogger("corr_id-adyen-{$this->merchantReference}");
     $logger->info("Recording successful capture on account '{$this->account}' with authorization reference " . "'{$this->originalReference}' and order ID '{$this->merchantReference}'.");
     $config = Configuration::getDefaultConfig();
     // Find the details from the payment site in the pending database.
     $logger->debug('Attempting to locate associated message in pending database');
     $db = PendingDatabase::get();
     $dbMessage = $db->fetchMessageByGatewayOrderId('adyen', $this->merchantReference);
     if ($dbMessage && isset($dbMessage['order_id'])) {
         $logger->debug('A valid message was obtained from the pending queue');
         // Add the gateway transaction ID and send it to the completed queue
         $dbMessage['gateway_txn_id'] = $this->originalReference;
         $queueMessage = DonationInterfaceMessage::fromValues($dbMessage);
         SourceFields::addToMessage($queueMessage);
         $config->object('data-store/verified')->push($queueMessage);
         // Remove it from the pending database
         $logger->debug('Removing donor details message from pending database');
         $db->deleteMessage($dbMessage);
     } else {
         // Sometimes we don't have a pending db row because the donor made
         // multiple attempts with the same order ID. It would be nice if
         // Adyen could prevent that, but let's not send a failmail since
         // we'll eventually get the donor details from the payments log
         // when we parse the audit.
         $logger->warning("Could not find donor details for authorization Reference '{$this->originalReference}' " . "and order ID '{$this->merchantReference}'.", $dbMessage);
     }
     return true;
 }
 /**
  * @param array $post_fields Associative array of fields posted to listener
  * @return bool
  */
 function validate($post_fields = array())
 {
     $url = Configuration::getDefaultConfig()->val('postback-url');
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_URL, $url);
     curl_setopt($ch, CURLOPT_HEADER, 0);
     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
     curl_setopt($ch, CURLOPT_POST, 1);
     // TODO we can put VERIFIED in config and generalize this
     // Always capture the cURL output
     $curlDebugLog = fopen('php://temp', 'r+');
     curl_setopt($ch, CURLOPT_VERBOSE, true);
     curl_setopt($ch, CURLOPT_STDERR, $curlDebugLog);
     $response = $this->curl($ch, $post_fields);
     // Read the logging output
     rewind($curlDebugLog);
     $logged = fread($curlDebugLog, 8192);
     fclose($curlDebugLog);
     Logger::debug("cURL verbose logging: {$logged}");
     if ($response === 'VERIFIED') {
         return true;
     } elseif ($response === 'INVALID') {
         return false;
     } else {
         // TODO: Log txn_id. This is annoying because of the random document formats.
         Logger::debug("Unknown response from PayPal IPN PB: [{$response}].\n" . "Verbose logging: {$logged}");
         // FIXME: The same thing happens for "INVALID" and totally broken
         // responses. Differentiate.
         return false;
     }
 }
 protected function getAstroPaySignature($pendingMessage, $result)
 {
     $c = Configuration::getDefaultConfig();
     $login = $c->val('login');
     $secret = $c->val('secret');
     $signed = $login . $result . $pendingMessage['gross'] . $pendingMessage['order_id'];
     return strtoupper(hash_hmac('sha256', pack('A*', $signed), pack('A*', $secret)));
 }
 /**
  * MultiQueueWriter constructor.
  *
  * @param array $backends list of config keys under data-store
  */
 public function __construct($backends)
 {
     $config = Configuration::getDefaultConfig();
     foreach ($backends as $configKey) {
         $path = 'data-store/' . $configKey;
         $this->queues[] = $config->object($path);
     }
 }
 public function execute(ListenerMessage $msg)
 {
     $tl = new TaggedLogger('CaptureResponseAction');
     if ($msg instanceof Capture) {
         if ($msg->success) {
             $tl->info("Adding record capture job for {$msg->currency} {$msg->amount} with id {$msg->correlationId} and psp reference {$msg->pspReference}.");
             $recordJob = RecordCaptureJob::factory($msg);
             $jobQueue = Configuration::getDefaultConfig()->object('data-store/jobs-adyen');
             $jobQueue->push(json_decode($recordJob->toJson(), true));
         } else {
             $tl->warning("Capture failed for payment with reference {$msg->pspReference} and correlation id {$msg->correlationId}.", $msg);
         }
     }
     return true;
 }
 public function execute(ListenerMessage $msg)
 {
     $tl = new TaggedLogger('PaymentCaptureAction');
     if ($msg instanceof Authorisation) {
         $jobQueueObj = Configuration::getDefaultConfig()->object('data-store/jobs-adyen');
         if ($msg->success) {
             // Here we need to capture the payment, the job runner will collect the
             // orphan message
             $tl->info("Adding Adyen capture job for {$msg->currency} {$msg->amount} " . "with id {$msg->correlationId} and psp reference {$msg->pspReference}.");
             $job = ProcessCaptureRequestJob::factory($msg);
             $jobQueueObj->push(json_decode($job->toJson(), true));
         } else {
             // And here we just need to destroy the orphan
             $tl->info("Adyen payment with correlation id {$msg->correlationId} " . "reported status failed: '{$msg->reason}'. " . 'Queueing job to delete pending records.');
             $job = DeletePendingJob::factory('adyen', $msg->merchantReference, $msg->correlationId);
             $jobQueueObj->push(json_decode($job->toJson(), true));
         }
     }
     return true;
 }
 public function execute(Request $request, Response $response)
 {
     $this->config = Configuration::getDefaultConfig();
     $requestValues = $request->getValues();
     // Don't store blank messages.
     if (empty($requestValues)) {
         return;
     }
     // Don't store invalid messages.
     $valid = $this->config->object('api')->validate($requestValues);
     if (!$valid) {
         // This will tell them to resend later.
         $response->setStatusCode(403, 'Failed verification');
         return false;
     }
     // Dump the request right into the queue with no validation.
     $job = new Job();
     $job->payload = $requestValues;
     $this->config->object('data-store/jobs-paypal')->push($job);
     Logger::info('Pushed new message to jobs-paypal: ' . print_r($requestValues, true));
 }
 /**
  * Do the actual work of the script.
  */
 public function execute()
 {
     $this->damagedDatabase = DamagedDatabase::get();
     $messages = $this->damagedDatabase->fetchRetryMessages($this->getOption('max-messages'));
     $stats = array();
     $config = Configuration::getDefaultConfig();
     foreach ($messages as $message) {
         $queueName = $message['original_queue'];
         // FIXME: getting it by alias, this will be annoying cos -new
         $queue = BaseQueueConsumer::getQueue($queueName);
         unset($message['original_queue']);
         $queue->push($message);
         $this->damagedDatabase->deleteMessage($message);
         if (isset($stats[$queueName])) {
             $stats[$queueName]++;
         } else {
             $stats[$queueName] = 1;
         }
     }
     foreach ($stats as $queueName => $count) {
         Logger::info("Requeued {$count} messages to {$queueName}.");
     }
 }
 /**
  * Gets the configuration object associated with the current context.
  *
  * Set the configuration using init()
  *
  * Use this instead of Configuration::getDefaultConfig();
  *
  * @return null|Configuration
  */
 public function getConfiguration()
 {
     if ($this->config) {
         return $this->config;
     } else {
         Logger::notice('Context returning default configuration. Probably missing a setConfiguration().', debug_backtrace(null));
         return Configuration::getDefaultConfig();
     }
 }
 public function execute()
 {
     $this->config = Configuration::getDefaultConfig();
     if ($this->is_reject()) {
         // Returning false would cause it to go to the damaged queue, we
         // just want to forget about these.
         return true;
     }
     // XXX Why does everything get made into objects?
     $request = (array) $this->payload;
     // Determine message type.
     if (isset($request['txn_type'])) {
         $txn_type = $request['txn_type'];
     } elseif (isset($request['payment_status']) && in_array($request['payment_status'], array('Reversed', 'Refunded'))) {
         // refund, chargeback, or reversal
         $txn_type = 'refund';
     } else {
         throw new Exception('Invalid PayPal message: ' . json_encode($request));
     }
     $msg_type = null;
     foreach ($this->config->val('messages') as $type => $conf) {
         if (in_array($txn_type, $conf['txn_types'])) {
             $msg_type = $type;
         }
     }
     if (!$msg_type) {
         throw new Exception('Invalid PayPal message type: ' . $txn_type);
     }
     // Transform into new message.
     // FIXME this could just be an array, but we need compat with
     // keyedopaque* until activemq goes away
     $new_msg = new Message();
     // FIXME hacks because the recurring consumer doesn't want
     // a normalized message
     if ($msg_type === 'recurring') {
         foreach ($request as $key => $val) {
             $new_msg->{$key} = $val;
         }
     } else {
         $map = $this->config->val('var_map');
         foreach ($map as $rx => $tx) {
             if (array_key_exists($rx, $request)) {
                 $new_msg->{$tx} = $request[$rx];
             }
         }
         // FIXME: var map can't put one thing in two places
         if (isset($new_msg->contribution_tracking_id)) {
             $new_msg->order_id = $new_msg->contribution_tracking_id;
         }
         // FIXME represent special case as var_map config override?
         if ($msg_type === 'refund') {
             $new_msg->gateway_refund_id = $request['txn_id'];
             $new_msg->gross_currency = $request['mc_currency'];
             if (isset($new_msg->type) && $new_msg->type === 'chargeback_settlement') {
                 $new_msg->type = 'chargeback';
             } else {
                 $new_msg->type = $msg_type;
             }
         }
         // FIXME once recurring uses normalized msg it needs this too
         $new_msg->date = strtotime($new_msg->date);
     }
     $new_msg->gateway = 'paypal';
     SourceFields::addToMessage($new_msg);
     // Save to appropriate queue.
     $this->config->object('data-store/' . $msg_type)->push($new_msg);
     // FIXME random document formats
     if (substr($txn_type, 0, 7) === 'subscr_') {
         $log_id = "subscr_id:{$request['subscr_id']}";
     } else {
         $log_id = "txn_id:{$request['txn_id']}";
     }
     Logger::info("Message {$log_id} pushed to {$msg_type} queue.");
     // TODO It would be nice if push() returned something useful so we
     // could return something here too
     return true;
 }
 /**
  * Using an AtomicReadBuffer implementation for the backend means that
  * if this throws an exception, the message will remain on the queue.
  *
  * @param array $message
  * @param Exception $ex
  */
 protected function handleError($message, Exception $ex)
 {
     if ($ex instanceof RetryableException) {
         $now = UtcDate::getUtcTimestamp();
         if (!isset($message['source_enqueued_time'])) {
             $message['source_enqueued_time'] = UtcDate::getUtcTimestamp();
         }
         $expirationDate = $message['source_enqueued_time'] + Configuration::getDefaultConfig()->val('requeue-max-age');
         if ($now < $expirationDate) {
             $retryDate = $now + Configuration::getDefaultConfig()->val('requeue-delay');
             $this->sendToDamagedStore($message, $ex, $retryDate);
             return;
         }
     }
     $this->sendToDamagedStore($message, $ex);
 }
 /**
  * @return \SmashPig\PaymentProviders\Adyen\AdyenPaymentsInterface
  */
 protected function getApi()
 {
     $api = Configuration::getDefaultConfig()->object('payment-provider/adyen/api');
     $api->setAccount($this->account);
     return $api;
 }