<?php
namespace Payum\Stripe\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Stripe\Keys;
use Payum\Stripe\Request\Api\CreatePlan;
use Stripe\Error;
use Stripe\Plan;
use Stripe\Stripe;

/**
 * @param Keys $keys
 * @param Keys $api
 */
class CreatePlanAction implements ActionInterface, GatewayAwareInterface, ApiAwareInterface
{
    use ApiAwareTrait {
        setApi as _setApi;
    }
    use GatewayAwareTrait;

    /**
     * @deprecated BC will be removed in 2.x. Use $this->api
     *
     * @var Keys
     */
    protected $keys;

    public function __construct()
    {
        $this->apiClass = Keys::class;
    }

    /**
     * {@inheritDoc}
     */
    public function setApi($api)
    {
        $this->_setApi($api);

        // BC. will be removed in 2.x
        $this->keys = $this->api;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request CreatePlan */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        try {
            Stripe::setApiKey($this->keys->getSecretKey());

            $plan = Plan::create($model->toUnsafeArrayWithoutLocal());

            $model->replace($plan->__toArray(true));
        } catch (Error\Base $e) {
            $model->replace($e->getJsonBody());
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof CreatePlan &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php

namespace Payum\Core\Storage;

use Payum\Core\Security\CryptedInterface;
use Payum\Core\Security\CypherInterface;

final class CryptoStorageDecorator implements StorageInterface
{
    /**
     * @var StorageInterface
     */
    private $decoratedStorage;

    /**
     * @var CypherInterface
     */
    private $crypto;

    /**
     * @param StorageInterface $decoratedStorage
     * @param CypherInterface $crypto
     */
    public function __construct(StorageInterface $decoratedStorage, CypherInterface $crypto)
    {
        $this->decoratedStorage = $decoratedStorage;
        $this->crypto = $crypto;
    }

    /**
     * {@inheritdoc}
     */
    public function create()
    {
        $model = $this->decoratedStorage->create();

        $this->assertCrypted($model);

        return $model;
    }

    /**
     * {@inheritdoc}
     */
    public function support($model)
    {
        return $this->decoratedStorage->support($model);
    }

    /**
     * {@inheritdoc}
     */
    public function update($model)
    {
        $this->assertCrypted($model);

        $model->encrypt($this->crypto);

        $this->decoratedStorage->update($model);
    }

    /**
     * {@inheritdoc}
     */
    public function delete($model)
    {
        $this->decoratedStorage->delete($model);
    }

    /**
     * {@inheritdoc}
     */
    public function find($id)
    {
        $model = $this->decoratedStorage->find($id);

        $this->assertCrypted($model);

        $model->decrypt($this->crypto);

        return $model;
    }

    /**
     * {@inheritdoc}
     */
    public function findBy(array $criteria)
    {
        $models = $this->decoratedStorage->findBy($criteria);

        foreach ($models as $model) {
            $this->assertCrypted($model);

            $model->decrypt($this->crypto);
        }

        return $models;
    }

    /**
     * {@inheritdoc}
     */
    public function identify($model)
    {
        return $this->decoratedStorage->identify($model);
    }

    /**
     * @param object $model
     */
    private function assertCrypted($model)
    {
        if (false == $model instanceof  CryptedInterface) {
            throw new \LogicException(sprintf(
                'The model %s must implement %s interface. It is required for this decorator.',
                get_class($model),
                CryptedInterface::class
            ));
        }
    }
}


<?php
namespace Payum\AuthorizeNet\Aim\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\AuthorizeNet\Aim\Bridge\AuthorizeNet\AuthorizeNetAIM;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Capture;
use Payum\Core\Request\ObtainCreditCard;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Security\SensitiveValue;

/**
 * @property AuthorizeNetAIM $api
 */
class CaptureAction implements ActionInterface, GatewayAwareInterface, ApiAwareInterface
{
    use ApiAwareTrait;
    use GatewayAwareTrait;

    public function __construct()
    {
        $this->apiClass = AuthorizeNetAIM::class;
    }

    /**
     * {@inheritDoc}
     *
     * @param Capture $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if (null != $model['response_code']) {
            return;
        }

        if (false == $model->validateNotEmpty(array('card_num', 'exp_date'), false)) {
            try {
                $obtainCreditCard = new ObtainCreditCard($request->getToken());
                $obtainCreditCard->setModel($request->getFirstModel());
                $obtainCreditCard->setModel($request->getModel());
                $this->gateway->execute($obtainCreditCard);
                $card = $obtainCreditCard->obtain();

                $model['exp_date'] = SensitiveValue::ensureSensitive($card->getExpireAt()->format('m/y'));
                $model['card_num'] = SensitiveValue::ensureSensitive($card->getNumber());
                $model['card_code'] = SensitiveValue::ensureSensitive($card->getSecurityCode());
            } catch (RequestNotSupportedException $e) {
                throw new LogicException('Credit card details has to be set explicitly or there has to be an action that supports ObtainCreditCard request.');
            }
        }

        $api = clone $this->api;
        $api->ignore_not_x_fields = true;
        $api->setFields(array_filter($model->toUnsafeArray()));

        $response = $api->authorizeAndCapture();

        $model->replace(get_object_vars($response));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Capture &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Paypal\ProCheckout\Nvp\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Paypal\ProCheckout\Nvp\Api;
use Payum\Core\Request\GetStatusInterface;
use Payum\Core\Exception\RequestNotSupportedException;

/**
 * @author Ton Sharp <Forma-PRO@66ton99.org.ua>
 */
class StatusAction implements ActionInterface
{
    /**
     * {@inheritDoc}
     *
     * @param GetStatusInterface $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = new ArrayObject($request->getModel());

        if (null === $model['RESULT']) {
            $request->markNew();

            return;
        }

        if (false == is_numeric($model['RESULT'])) {
            $request->markUnknown();

            return;
        }

        if ($model['RESULT'] > 0) {
            $request->markFailed();

            return;
        }

        if ($model['ORIGID'] && Api::TRXTYPE_CREDIT == $model['TRXTYPE'] && Api::RESULT_SUCCESS == $model['RESULT']) {
            $request->markRefunded();

            return;
        }

        if (Api::TRXTYPE_SALE == $model['TRXTYPE'] && Api::RESULT_SUCCESS == $model['RESULT']) {
            $request->markCaptured();

            return;
        }

        $request->markUnknown();
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetStatusInterface &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Core\Storage;

use Payum\Core\Exception\InvalidArgumentException;

abstract class AbstractStorage implements StorageInterface
{
    /**
     * @var string
     */
    protected $modelClass;

    /**
     * @param $modelClass
     */
    public function __construct($modelClass)
    {
        $this->modelClass = $modelClass;
    }

    /**
     * {@inheritDoc}
     */
    public function create()
    {
        return new $this->modelClass();
    }

    /**
     * {@inheritDoc}
     */
    public function support($model)
    {
        return $model instanceof $this->modelClass;
    }

    /**
     * {@inheritDoc}
     */
    public function update($model)
    {
        $this->assertModelSupported($model);

        $this->doUpdateModel($model);
    }

    /**
     * {@inheritDoc}
     */
    public function find($id)
    {
        if ($id instanceof IdentityInterface) {
            if (ltrim($id->getClass(), '\\') === ltrim($this->modelClass, '\\')) {
                return $this->doFind($id->getId());
            }

            return;
        }

        return $this->doFind($id);
    }

    /**
     * {@inheritDoc}
     */
    public function delete($model)
    {
        $this->assertModelSupported($model);

        $this->doDeleteModel($model);
    }

    /**
     * {@inheritDoc}
     */
    public function identify($model)
    {
        $this->assertModelSupported($model);

        return $this->doGetIdentity($model);
    }

    /**
     * @param object $model
     *
     * @return void
     */
    abstract protected function doUpdateModel($model);

    /**
     * @param object $model
     *
     * @return void
     */
    abstract protected function doDeleteModel($model);

    /**
     * @param object $model
     *
     * @return IdentityInterface
     */
    abstract protected function doGetIdentity($model);

    /**
     * @param mixed $id
     *
     * @return object|null
     */
    abstract protected function doFind($id);

    /**
     * @param object $model
     *
     * @throws \Payum\Core\Exception\InvalidArgumentException
     */
    protected function assertModelSupported($model)
    {
        if (false == $this->support($model)) {
            throw new InvalidArgumentException(sprintf(
                'Invalid model given. Should be instance of %s but it is %s',
                $this->modelClass,
                is_object($model) ? get_class($model) : gettype($model)
            ));
        }
    }
}


<?php
namespace Payum\Core\Registry;

use Payum\Core\Extension\StorageExtension;
use Payum\Core\Gateway;
use Payum\Core\GatewayInterface;

class SimpleRegistry extends AbstractRegistry
{
    /**
     * @var boolean[]
     */
    protected $initializedStorageExtensions;

    /**
     * @deprecated since 1.3.3 and ill be removed in 2.x. It is here for BC
     *
     * @var bool
     */
    protected $addStorageExtensions = true;

    /**
     * @deprecated since 1.3.3 and will be removed in 2.x. It is here for BC
     *
     * @param boolean $bool
     */
    public function setAddStorageExtensions($bool)
    {
        $this->addStorageExtensions = $bool;
    }

    /**
     * {@inheritDoc}
     */
    public function getGateway($name)
    {
        $gateway = parent::getGateway($name);

        if ($this->addStorageExtensions) {
            $this->addStorageToGateway($name, $gateway);
        }

        return $gateway;
    }

    /**
     * {@inheritDoc}
     */
    protected function getService($id)
    {
        return $id;
    }

    /**
     * @deprecated since 1.3.3 and will be removed in 2.x.
     *
     * @param string           $name
     * @param GatewayInterface $gateway
     */
    protected function addStorageToGateway($name, GatewayInterface $gateway)
    {
        /** @var Gateway $gateway */
        if (false == $gateway instanceof Gateway) {
            return;
        }
        if (isset($this->initializedStorageExtensions[$name])) {
            return;
        }

        foreach ($this->getStorages() as $storage) {
            $gateway->addExtension(new StorageExtension($storage));
        }

        $this->initializedStorageExtensions[$name] = true;
    }
}


<?php

namespace Payum\Paypal\ProHosted\Nvp;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayFactory;
use Payum\Paypal\ProHosted\Nvp\Action\Api\GetTransactionDetailsAction;
use Payum\Paypal\ProHosted\Nvp\Action\Api\CreateButtonPaymentAction;
use Payum\Paypal\ProHosted\Nvp\Action\ConvertPaymentAction;
use Payum\Paypal\ProHosted\Nvp\Action\CaptureAction;
use Payum\Paypal\ProHosted\Nvp\Action\NotifyAction;
use Payum\Paypal\ProHosted\Nvp\Action\StatusAction;
use Payum\Paypal\ProHosted\Nvp\Action\SyncAction;

class PaypalProHostedGatewayFactory extends GatewayFactory
{
    /**
     * {@inheritDoc}
     */
    protected function populateConfig(ArrayObject $config)
    {
        $config->defaults([
            'payum.factory_name'                       => 'paypal_pro_hosted',
            'payum.factory_title'                      => 'Paypal Pro Hosted',
            'payum.action.capture'                     => new CaptureAction(),
            'payum.action.notify'                      => new NotifyAction(),
            'payum.action.status'                      => new StatusAction(),
            'payum.action.sync'                        => new SyncAction(),
            'payum.action.convert_payment'             => new ConvertPaymentAction(),
            'payum.action.api.get_transaction_details' => new GetTransactionDetailsAction(),
            'payum.action.api.create_button_payment'   => new CreateButtonPaymentAction(),
        ]);

        if (false == $config['payum.api']) {
            $config['payum.default_options'] = [
                'username'  => '',
                'password'  => '',
                'signature' => '',
                'business'  => '',
                'sandbox'   => true,
            ];

            $config->defaults($config['payum.default_options']);
            $config['payum.required_options'] = [
                'username',
                'password',
                'signature',
            ];

            $config['payum.api'] = function (ArrayObject $config) {
                $config->validateNotEmpty($config['payum.required_options']);

                $paypalConfig = array(
                    'username'  => $config['username'],
                    'password'  => $config['password'],
                    'signature' => $config['signature'],
                    'business'  => $config['business'],
                    'sandbox'   => $config['sandbox'],
                );

                return new Api($paypalConfig, $config['payum.http_client'], $config['httplug.message_factory']);
            };
        }
    }
}


<?php
namespace Payum\Klarna\Invoice\Action\Api;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayInterface;
use Payum\Klarna\Invoice\Request\Api\PopulateKlarnaFromDetails;
use Payum\Klarna\Invoice\Request\Api\Update;

class UpdateAction extends BaseApiAwareAction implements GatewayAwareInterface
{
    /**
     * @var GatewayInterface
     */
    protected $gateway;

    /**
     * {@inheritDoc}
     */
    public function setGateway(GatewayInterface $gateway)
    {
        $this->gateway = $gateway;
    }

    /**
     * {@inheritDoc}
     *
     * @param Update $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        $klarna = $this->getKlarna();

        try {
            $this->gateway->execute(new PopulateKlarnaFromDetails($details, $klarna));

            $details['updated'] = $klarna->update($details['rno']);
        } catch (\KlarnaException $e) {
            $this->populateDetailsWithError($details, $e, $request);
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Update &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Core\Debug;

use Payum\Core\Model\ModelAggregateInterface;
use Payum\Core\Reply\HttpRedirect;

abstract class Humanify
{
    /**
     * @param  mixed  $request
     * @return string
     */
    public static function request($request)
    {
        $return = self::value($request);

        $details = array();

        if ($request instanceof ModelAggregateInterface) {
            $details[] = sprintf('model: %s', self::value($request->getModel()));
        }
        if ($request instanceof HttpRedirect) {
            $details[] = sprintf('url: %s', $request->getUrl());
        }

        if (false == empty($details)) {
            $return .= sprintf('{%s}', implode(', ', $details));
        }

        return $return;
    }

    /**
     * @param mixed $value
     * @param bool  $shortClass
     *
     * @return string
     */
    public static function value($value, $shortClass = true)
    {
        if (is_object($value)) {
            if ($shortClass) {
                $ro = new \ReflectionObject($value);

                return $ro->getShortName();
            }

            return get_class($value);
        }

        return gettype($value);
    }

    final private function __construct()
    {
    }
}


<?php

namespace Payum\Sofort\Action;

use Payum\Sofort\Api;
use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\GetStatusInterface;

class StatusAction implements ActionInterface
{
    /**
     * {@inheritdoc}
     *
     * @param $request GetStatusInterface
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        if (!isset($details['status'])
           && isset($details['transaction_id'])
           && isset($details['expires'])
           && $details['expires'] < time()) {
            $request->markExpired();

            return;
        }

        if (!isset($details['transaction_id']) || !strlen($details['transaction_id'])) {
            $request->markNew();

            return;
        }

        if (!isset($details['status'])) {
            $request->markNew();

            return;
        }

        $subcode = isset($details['statusReason']) ? $details['statusReason'] : null;
        switch ($details['status']) {
            case Api::STATUS_LOSS:
                $request->markFailed();
                break;
            case Api::STATUS_PENDING:
                $request->markPending();
                break;
            case Api::STATUS_RECEIVED:
                switch ($subcode) {
                    case Api::SUB_PARTIALLY:
                        $request->markUnknown();
                        break;
                    case Api::SUB_CREDITED:
                    case Api::SUB_OVERPAYMENT:
                        $request->markCaptured();
                        break;
                }
                break;
            case Api::STATUS_REFUNDED:
                switch ($subcode) {
                    default:
                    case Api::SUB_COMPENSATION:
                        $request->markUnknown();
                        break;
                    case Api::SUB_REFUNDED:
                        $request->markRefunded();
                        break;
                }
                break;
            case Api::STATUS_UNTRACEABLE:
                $request->markCaptured();
                break;
            default:
                $request->markUnknown();
                break;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetStatusInterface &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Stripe;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\GatewayFactory;
use Payum\Stripe\Action\Api\CreateChargeAction;
use Payum\Stripe\Action\Api\CreateCustomerAction;
use Payum\Stripe\Action\Api\CreatePlanAction;
use Payum\Stripe\Action\Api\CreateSubscriptionAction;
use Payum\Stripe\Action\Api\CreateTokenAction;
use Payum\Stripe\Action\Api\ObtainTokenAction;
use Payum\Stripe\Action\CaptureAction;
use Payum\Stripe\Action\ConvertPaymentAction;
use Payum\Stripe\Action\GetCreditCardTokenAction;
use Payum\Stripe\Extension\CreateCustomerExtension;
use Payum\Stripe\Action\StatusAction;
use Stripe\Stripe;

class StripeCheckoutGatewayFactory extends GatewayFactory
{
    /**
     * {@inheritDoc}
     */
    protected function populateConfig(ArrayObject $config)
    {
        if (false == class_exists(Stripe::class)) {
            throw new LogicException('You must install "stripe/stripe-php:~2.0|~3.0" library.');
        }

        $config->defaults([
            'payum.factory_name' => 'stripe_checkout',
            'payum.factory_title' => 'Stripe Checkout',

            'payum.template.obtain_token' => '@PayumStripe/Action/obtain_checkout_token.html.twig',

            'payum.action.capture' => new CaptureAction(),
            'payum.action.convert_payment' => new ConvertPaymentAction(),
            'payum.action.status' => new StatusAction(),
            'payum.action.get_credit_card_token' => new GetCreditCardTokenAction(),
            'payum.action.obtain_token' => function (ArrayObject $config) {
                return new ObtainTokenAction($config['payum.template.obtain_token']);
            },
            'payum.action.create_charge' => new CreateChargeAction(),
            'payum.action.create_customer' => new CreateCustomerAction(),
            'payum.action.create_plan' => new CreatePlanAction(),
            'payum.action.create_token' => new CreateTokenAction(),
            'payum.action.create_subscription' => new CreateSubscriptionAction(),

            'payum.extension.create_customer' => new CreateCustomerExtension(),
        ]);

        if (false == $config['payum.api']) {
            $config['payum.default_options'] = [
                'publishable_key' => '',
                'secret_key' => ''
            ];
            $config->defaults($config['payum.default_options']);
            $config['payum.required_options'] = ['publishable_key', 'secret_key'];

            $config['payum.api'] = function (ArrayObject $config) {
                $config->validateNotEmpty($config['payum.required_options']);

                return new Keys($config['publishable_key'], $config['secret_key']);
            };
        }

        $config['payum.paths'] = array_replace([
            'PayumStripe' => __DIR__.'/Resources/views',
        ], $config['payum.paths'] ?: []);
    }
}


<?php
namespace Payum\Core\Bridge\PlainPhp\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\GetHttpRequest;

class GetHttpRequestAction implements ActionInterface
{
    /**
     * {@inheritDoc}
     *
     * @param GetHttpRequest $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $request->method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
        $request->query = $_GET;
        $request->request = $_REQUEST;
        $request->clientIp = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
        $request->uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
        $request->userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        $request->content = file_get_contents('php://input');
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return $request instanceof GetHttpRequest;
    }
}


<?php

namespace Payum\Core\Bridge\Guzzle;

use GuzzleHttp\Client;
use Http\Discovery\HttpClientDiscovery;
use Payum\Core\HttpClientInterface;

/**
 * @deprecated This will be removed in 2.0. Consider using Http\Discovery\HttpClientDiscovery.
 */
class HttpClientFactory
{
    /**
     * Create a Guzzle client.
     *
     * @return \GuzzleHttp\Client
     */
    public static function createGuzzle()
    {
        $client = null;
        if (!class_exists(Client::class)) {
            @trigger_error('The function "HttpClientFactory::createGuzzle" is depcrecated and will be removed in 2.0.', E_USER_DEPRECATED);
            throw new \LogicException('Can not use "HttpClientFactory::createGuzzle" since Guzzle is not installed. This function is deprecated and will be removed in 2.0.');
        }

        $version = \GuzzleHttp\ClientInterface::VERSION;
        if (substr($version, 0, 1) !== '6') {
            throw new \LogicException('This version of Guzzle is not supported.');
        }

        $curl = curl_version();

        $curlOptions = [
             CURLOPT_USERAGENT => sprintf('Payum/1.x curl/%s PHP/%s', $curl['version'], phpversion()),
         ];

        return new \GuzzleHttp\Client([
             'curl' => $curlOptions,
         ]);
    }

    /**
     * @return HttpClientInterface
     */
    public static function create()
    {
        return new HttpClient(static::createGuzzle());
    }
}


<?php
namespace Payum\Core\Action;

use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\GetCurrency;
use Payum\ISO4217\ISO4217;

class GetCurrencyAction implements ActionInterface
{
    /**
     * @var ISO4217
     */
    protected $iso4217;

    /**
     * @param ISO4217 $iso4217
     */
    public function __construct(ISO4217 $iso4217 = null)
    {
        $this->iso4217 = $iso4217 ?: new ISO4217();
    }

    /**
     * {@inheritDoc}
     *
     * @param GetCurrency $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $currency = is_numeric($request->code) ?
            $this->iso4217->findByNumeric($request->code) :
            $this->iso4217->findByAlpha3($request->code)
        ;

        $request->alpha3 = $currency->getAlpha3();
        $request->country = $currency->getCountry();
        $request->exp = $currency->getExp();
        $request->name = $currency->getName();
        $request->numeric = $currency->getNumeric();
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetCurrency &&
            $request->code
        ;
    }
}


<?php
namespace Payum\Core\Bridge\Symfony\Builder;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Bridge\Symfony\Action\ObtainCreditCardAction;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class ObtainCreditCardActionBuilder
{
    /**
     * @var FormFactoryInterface
     */
    private $formFactory;

    /**
     * @var RequestStack
     */
    private $requestStack;

    /**
     * @param FormFactoryInterface $formFactory
     * @param RequestStack $requestStack
     */
    public function __construct(FormFactoryInterface $formFactory, RequestStack $requestStack)
    {
        $this->formFactory = $formFactory;
        $this->requestStack = $requestStack;
    }

    /**
     * @param ArrayObject $config
     *
     * @return ObtainCreditCardAction
     */
    public function build(ArrayObject $config)
    {
        $action = new ObtainCreditCardAction($this->formFactory, $config['payum.template.obtain_credit_card']);
        $action->setRequestStack($this->requestStack);

        return $action;
    }

    public function __invoke()
    {
        return call_user_func_array([$this, 'build'], func_get_args());
    }
}


<?php
namespace Payum\Klarna\Invoice;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\GatewayFactory;
use Payum\Klarna\Invoice\Action\Api\ActivateAction;
use Payum\Klarna\Invoice\Action\Api\ActivateReservationAction;
use Payum\Klarna\Invoice\Action\Api\CancelReservationAction;
use Payum\Klarna\Invoice\Action\Api\CheckOrderStatusAction;
use Payum\Klarna\Invoice\Action\Api\CreditInvoiceAction;
use Payum\Klarna\Invoice\Action\Api\CreditPartAction;
use Payum\Klarna\Invoice\Action\Api\EmailInvoiceAction;
use Payum\Klarna\Invoice\Action\Api\GetAddressesAction;
use Payum\Klarna\Invoice\Action\Api\PopulateKlarnaFromDetailsAction;
use Payum\Klarna\Invoice\Action\Api\ReserveAmountAction;
use Payum\Klarna\Invoice\Action\Api\ReturnAmountAction;
use Payum\Klarna\Invoice\Action\Api\SendInvoiceAction;
use Payum\Klarna\Invoice\Action\Api\UpdateAction;
use Payum\Klarna\Invoice\Action\AuthorizeAction;
use Payum\Klarna\Invoice\Action\CaptureAction;
use Payum\Klarna\Invoice\Action\RefundAction;
use Payum\Klarna\Invoice\Action\StatusAction;
use Payum\Klarna\Invoice\Action\SyncAction;

class KlarnaInvoiceGatewayFactory extends GatewayFactory
{
    /**
     * {@inheritDoc}
     */
    protected function populateConfig(ArrayObject $config)
    {
        if (!class_exists('KlarnaCurrency')) {
            throw new \LogicException('You must install "fp/klarna-invoice" library.');
        }

        $config->defaults(array(
            'payum.factory_name' => 'klarna_invoice',
            'payum.factory_title' => 'Klarna Invoice',
            'sandbox' => true,
            'pClassStorage' => 'json',
            'pClassStoragePath' => './pclasses.json',
            'xmlRpcVerifyHost' => 2,
            'xmlRpcVerifyPeer' => true,

            'payum.action.capture' => new CaptureAction(),
            'payum.action.authorize' => new AuthorizeAction(),
            'payum.action.status' => new StatusAction(),
            'payum.action.sync' => new SyncAction(),
            'payum.action.refund' => new RefundAction(),

            'payum.action.api.activate' => new ActivateAction(),
            'payum.action.api.activate_reservation' => new ActivateReservationAction(),
            'payum.action.api.cancel_reservation' => new CancelReservationAction(),
            'payum.action.api.check_order_status' => new CheckOrderStatusAction(),
            'payum.action.api.get_addresses' => new GetAddressesAction(),
            'payum.action.api.populate_klarna_from_details' => new PopulateKlarnaFromDetailsAction(),
            'payum.action.api.credit_invoice' => new CreditInvoiceAction(),
            'payum.action.api.credit_part' => new CreditPartAction(),
            'payum.action.api.reserve_amount' => new ReserveAmountAction(),
            'payum.action.api.return_amount' => new ReturnAmountAction(),
            'payum.action.api.email_invoice' => new EmailInvoiceAction(),
            'payum.action.api.send_invoice' => new SendInvoiceAction(),
            'payum.action.api.update' => new UpdateAction(),
        ));

        if (false == $config['payum.api']) {
            $config['payum.default_options'] = array(
                'eid' => '',
                'secret' => '',
                'country' => '',
                'language' => '',
                'currency' => '',
                'sandbox' => true,
            );
            $config->defaults($config['payum.default_options']);
            $config['payum.required_options'] = array('eid', 'secret', 'country', 'language', 'currency');
            $config->defaults(array(
                'sandbox' => true,
            ));

            $config['payum.api'] = function (ArrayObject $config) {
                $config->validateNotEmpty($config['payum.required_options']);

                $config['mode'] = $config['sandbox'] ? \Klarna::BETA : \Klarna::LIVE;

                if (null === $country = \KlarnaCountry::fromCode($config['country'])) {
                    throw new LogicException(sprintf('Given %s country code is not valid. Klarna cannot recognize it.', $config['country']));
                }
                if (null === $language = \KlarnaLanguage::fromCode($config['language'])) {
                    throw new LogicException(sprintf('Given %s language code is not valid. Klarna cannot recognize it.', $config['language']));
                }
                if (null === $currency = \KlarnaCurrency::fromCode($config['currency'])) {
                    throw new LogicException(sprintf('Given %s currency code is not valid. Klarna cannot recognize it.', $config['currency']));
                }

                $klarnaConfig = new Config();
                $klarnaConfig->eid = $config['eid'];
                $klarnaConfig->secret = $config['secret'];
                $klarnaConfig->mode = $config['mode'];
                $klarnaConfig->country = $country;
                $klarnaConfig->language = $language;
                $klarnaConfig->currency = $currency;
                $klarnaConfig->pClassStorage = $config['pClassStorage'];
                $klarnaConfig->pClassStoragePath = $config['pClassStoragePath'];
                $klarnaConfig->xmlRpcVerifyHost = $config['xmlRpcVerifyHost'];
                $klarnaConfig->xmlRpcVerifyHost = $config['xmlRpcVerifyHost'];

                return $klarnaConfig;
            };
        }
    }
}


<?php
namespace Payum\Payex\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Capture;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Payex\Request\Api\AutoPayAgreement;

class AutoPayPaymentDetailsCaptureAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request \Payum\Core\Request\Capture */
        RequestNotSupportedException::assertSupports($this, $request);

        $this->gateway->execute(new AutoPayAgreement($request->getModel()));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        if (false == (
                $request instanceof Capture &&
                $request->getModel() instanceof \ArrayAccess
            )) {
            return false;
        }

        $model = ArrayObject::ensureArrayObject($request->getModel());

        //Make sure it is not recurring payment. There is an other capture action for recurring payments;
        if (true == $model['recurring']) {
            return false;
        }

        if ($model['autoPay']) {
            return true;
        }

        return false;
    }
}


<?php
namespace Payum\Klarna\Checkout\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Authorize;
use Payum\Klarna\Checkout\Config;
use Payum\Klarna\Checkout\Constants;
use Payum\Klarna\Checkout\Request\Api\CreateOrder;

/**
 * @param Config $api
 * @param Config $config
 */
class AuthorizeRecurringAction implements ActionInterface, ApiAwareInterface, GatewayAwareInterface
{
    use ApiAwareTrait {
        setApi as _setApi;
    }
    use GatewayAwareTrait;

    /**
     * @deprecated BC. will be removed in 2.x. Use $this->api
     *
     * @var Config
     */
    protected $config;

    public function __construct()
    {
        $this->apiClass = Config::class;
    }

    /**
     * {@inheritDoc}
     */
    public function setApi($api)
    {
        $this->_setApi($api);

        // BC. will be removed in 2.x. Use $this->api
        $this->config = $this->api;
    }

    /**
     * {@inheritDoc}
     *
     * @param Authorize $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if ($model['reservation']) {
            return;
        }

        $model['activate'] = false;

        $backupConfig = clone $this->api;

        $token = $model['recurring_token'];

        try {
            unset($model['recurring_token']);

            $baseUri = Constants::BASE_URI_LIVE == $backupConfig->baseUri ?
                Constants::BASE_URI_RECURRING_LIVE :
                Constants::BASE_URI_RECURRING_SANDBOX
            ;

            $this->api->contentType = Constants::CONTENT_TYPE_RECURRING_ORDER_V1;
            $this->api->acceptHeader = Constants::ACCEPT_HEADER_RECURRING_ORDER_ACCEPTED_V1;
            $this->api->baseUri = str_replace('{recurring_token}', $token, $baseUri);

            $this->gateway->execute($createOrderRequest = new CreateOrder($model));

            $model->replace($createOrderRequest->getOrder()->marshal());
        } catch (\Exception $e) {
            $this->api->contentType = $backupConfig->contentType;
            $this->api->acceptHeader = $backupConfig->acceptHeader;
            $this->api->baseUri = $backupConfig->baseUri;

            $model['recurring_token'] = $token;

            throw $e;
        }

        $model['recurring_token'] = $token;

        $this->api->contentType = $backupConfig->contentType;
        $this->api->acceptHeader = $backupConfig->acceptHeader;
        $this->api->baseUri = $backupConfig->baseUri;
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        if (false == ($request instanceof Authorize && $request->getModel() instanceof \ArrayAccess)) {
            return false;
        }

        $model = ArrayObject::ensureArrayObject($request->getModel());

        return false == $model['recurring'] && $model['recurring_token'];
    }
}


<?php
namespace Payum\Offline\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Model\PayoutInterface;
use Payum\Core\Request\Convert;
use Payum\Offline\Constants;

class ConvertPayoutAction implements ActionInterface
{
    /**
     * {@inheritDoc}
     *
     * @param Convert $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        /** @var PayoutInterface $payout */
        $payout = $request->getSource();

        $details = ArrayObject::ensureArrayObject($payout->getDetails());
        $details['amount'] = $payout->getTotalAmount();
        $details['currency'] = $payout->getCurrencyCode();
        $details['description'] = $payout->getDescription();
        $details['recipient_email'] = $payout->getRecipientEmail();
        $details['recipient_id'] = $payout->getRecipientId();

        $details->defaults(array(
            Constants::FIELD_PAYOUT => true,
        ));

        $request->setResult((array) $details);
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Convert &&
            $request->getSource() instanceof PayoutInterface &&
            $request->getTo() == 'array'
        ;
    }
}


<?php
namespace Payum\Core\Action;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Model\DetailsAggregateInterface;
use Payum\Core\Model\DetailsAwareInterface;
use Payum\Core\Model\ModelAggregateInterface;
use Payum\Core\Model\ModelAwareInterface;

class ExecuteSameRequestWithModelDetailsAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     *
     * @param ModelAggregateInterface|ModelAwareInterface $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        /** @var DetailsAggregateInterface $model */
        $model = $request->getModel();
        $details = $model->getDetails();

        if (is_array($details)) {
            $details = ArrayObject::ensureArrayObject($details);
        }

        $request->setModel($details);
        try {
            $this->gateway->execute($request);
        } finally {
            if ($model instanceof DetailsAwareInterface) {
                $model->setDetails($details);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof ModelAggregateInterface &&
            $request instanceof ModelAwareInterface &&
            $request->getModel() instanceof DetailsAggregateInterface
        ;
    }
}


<?php
namespace Payum\AuthorizeNet\Aim;

use Payum\AuthorizeNet\Aim\Action\ConvertPaymentAction;
use Payum\AuthorizeNet\Aim\Action\CaptureAction;
use Payum\AuthorizeNet\Aim\Action\StatusAction;
use Payum\AuthorizeNet\Aim\Bridge\AuthorizeNet\AuthorizeNetAIM;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayFactory;

class AuthorizeNetAimGatewayFactory extends GatewayFactory
{
    /**
     * {@inheritDoc}
     */
    protected function populateConfig(ArrayObject $config)
    {
        if (!class_exists(\AuthorizeNetAIM::class)) {
            throw new \LogicException('You must install "authorizenet/authorizenet" library.');
        }

        $config->defaults(array(
            'payum.factory_name' => 'authorize_net_aim',
            'payum.factory_title' => 'Authorize.NET AIM',
            'payum.action.capture' => new CaptureAction(),
            'payum.action.status' => new StatusAction(),
            'payum.action.convert_payment' => new ConvertPaymentAction(),
        ));

        if (false == $config['payum.api']) {
            $config['payum.default_options'] = array(
                'login_id' => '',
                'transaction_key' => '',
                'sandbox' => true,
            );
            $config->defaults($config['payum.default_options']);
            $config['payum.required_options'] = array('login_id', 'transaction_key');

            $config['payum.api'] = function (ArrayObject $config) {
                $config->validateNotEmpty($config['payum.required_options']);

                $api = new AuthorizeNetAIM($config['login_id'], $config['transaction_key']);
                $api->setSandbox($config['sandbox']);

                return $api;
            };
        }
    }
}


<?php
namespace Payum\Stripe\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareTrait;
use Payum\Stripe\Keys;
use Payum\Stripe\Request\Api\CreateCharge;
use Stripe\Charge;
use Stripe\Error;
use Stripe\Stripe;

class CreateChargeAction implements ActionInterface, ApiAwareInterface
{
    use ApiAwareTrait {
        setApi as _setApi;
    }
    use GatewayAwareTrait;

    /**
     * @deprecated BC will be removed in 2.x. Use $this->api
     *
     * @var Keys
     */
    protected $keys;

    public function __construct()
    {
        $this->apiClass = Keys::class;
    }

    /**
     * {@inheritDoc}
     */
    public function setApi($api)
    {
        $this->_setApi($api);

        // BC. will be removed in 2.x
        $this->keys = $this->api;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request CreateCharge */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if (false == ($model['card'] || $model['customer'])) {
            throw new LogicException('The either card token or customer id has to be set.');
        }

        if (is_array($model['card'])) {
            throw new LogicException('The token has already been used.');
        }

        try {
            Stripe::setApiKey($this->keys->getSecretKey());

            $charge = Charge::create($model->toUnsafeArrayWithoutLocal());

            $model->replace($charge->__toArray(true));
        } catch (Error\Base $e) {
            $model->replace($e->getJsonBody());
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof CreateCharge &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Klarna\Checkout\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\GetStatusInterface;
use Payum\Klarna\Checkout\Constants;

class StatusAction implements ActionInterface
{
    /**
     * {@inheritDoc}
     *
     * @param GetStatusInterface $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if ($model['error_code']) {
            $request->markFailed();

            return;
        }

        if ($model['invoice_number']) {
            $request->markCaptured();

            return;
        }

        if ($model['reservation']) {
            $request->markAuthorized();

            return;
        }

        if (false == $model['status'] || Constants::STATUS_CHECKOUT_INCOMPLETE == $model['status']) {
            $request->markNew();

            return;
        }

        if (Constants::STATUS_CHECKOUT_COMPLETE == $model['status']) {
            $request->markPending();

            return;
        }

        $request->markUnknown();
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetStatusInterface &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Payex\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Sync;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Payex\Request\Api\CheckAgreement;

class AgreementDetailsSyncAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Sync */
        RequestNotSupportedException::assertSupports($this, $request);

        $this->gateway->execute(new CheckAgreement($request->getModel()));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Sync &&
            $request->getModel() instanceof \ArrayAccess &&
            //Make sure it is payment. Apparently an order(payment) does not have this field.
            $request->getModel()->offsetExists('agreementRef') &&
            false == $request->getModel()->offsetExists('orderId')
        ;
    }
}


<?php
namespace Payum\Payex\Api;

class OrderApi extends BaseApi
{
    const VIEW_CREDITCARD = 'CREDITCARD';

    const VIEW_MICROACCOUNT = 'MICROACCOUNT';

    const VIEW_DIRECTDEBIT = 'DIRECTDEBIT';

    /**
     * Norwegian and Swedish overcharged SMS
     */
    const VIEW_CPA = 'CPA';

    /**
     * Overcharged call
     */
    const VIEW_IVR = 'IVR';

    /**
     * Value code
     */
    const VIEW_EVC = 'EVC';

    const VIEW_INVOICE = 'INVOICE';

    const VIEW_LOAN = 'LOAN';

    /**
     * Gift card / generic card
     */
    const VIEW_GC = 'GC';

    /**
     * Credit account
     */
    const VIEW_CA = 'GC';

    /**
     * PayPal transactions
     */
    const VIEW_PAYPAL = 'PAYPAL';

    const VIEW_FINANCING = 'FINANCING';

    const TRANSACTIONSTATUS_SALE = 0;

    const TRANSACTIONSTATUS_INITIALIZE = 1;

    const TRANSACTIONSTATUS_CREDIT = 2;

    const TRANSACTIONSTATUS_AUTHORIZE = 3;

    const TRANSACTIONSTATUS_CANCEL = 4;

    const TRANSACTIONSTATUS_FAILURE = 5;

    const TRANSACTIONSTATUS_CAPTURE = 6;

    /**
     * Returns the Status of the order0 = The order is completed (a purchase has been done, but check the transactionStatus to see the result).
     */
    const ORDERSTATUS_COMPLETED = 0;

    /**
     * 1 = The order is processing. The customer has not started the purchase. PxOrder.Complete can return orderStatus 1 for 2 weeks after PxOrder.Initialize is called. Afterwards the orderStatus will be set to 2
     */
    const ORDERSTATUS_PROCESSING = 1;

    /**
     * 2 = No order or transaction is found
     */
    const ORDERSTATUS_NOT_FOUND = 2;

    /**
     * @link http://www.payexpim.com/technical-reference/pxorder/initialize8/
     *
     * @var array $parameters
     *
     * @return array
     */
    public function initialize(array $parameters)
    {
        $parameters['accountNumber'] = $this->options['account_number'];

        //DEPRICATED. Send in as empty string.
        $parameters['externalID'] = '';

        if (isset($parameters['orderId'])) {
            //On request it requires orderID fields when in response it is orderId.
            $parameters['orderID'] = $parameters['orderId'];
            unset($parameters['orderId']);
        }

        $parameters['hash'] = $this->calculateHash($parameters, array(
            'accountNumber',
            'purchaseOperation',
            'price',
            'priceArgList',
            'currency',
            'vat',
            'orderID',
            'productNumber',
            'description',
            'clientIPAddress',
            'clientIdentifier',
            'additionalValues',
            'externalID',
            'returnUrl',
            'view',
            'agreementRef',
            'cancelUrl',
            'clientLanguage',
        ));

        return $this->call('Initialize8', $parameters, $this->getPxOrderWsdl());
    }

    /**
     * @link http://www.payexpim.com/technical-reference/pxorder/complete-2/
     *
     * @param array $parameters
     *
     * @return array
     */
    public function complete(array $parameters)
    {
        $parameters['accountNumber'] = $this->options['account_number'];

        $parameters['hash'] = $this->calculateHash($parameters, array(
            'accountNumber',
            'orderRef',
        ));

        return $this->call('Complete', $parameters, $this->getPxOrderWsdl());
    }

    /**
     * @link http://www.payexpim.com/technical-reference/pxorder/check2/
     *
     * @param array $parameters
     *
     * @return array
     */
    public function check(array $parameters)
    {
        $parameters['accountNumber'] = $this->options['account_number'];

        $parameters['hash'] = $this->calculateHash($parameters, array(
            'accountNumber',
            'transactionNumber',
        ));

        return $this->call('Check2', $parameters, $this->getPxOrderWsdl());
    }

    /**
     * {@inheritDoc}
     */
    protected function getPxOrderWsdl()
    {
        return $this->options['sandbox'] ?
            'https://test-external.payex.com/pxorder/pxorder.asmx?wsdl' :
            'https://external.payex.com/pxorder/pxorder.asmx?wsdl'
        ;
    }
}


<?php
namespace Payum\Payex\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Exception\UnsupportedApiException;
use Payum\Core\Reply\HttpRedirect;
use Payum\Payex\Api\OrderApi;
use Payum\Payex\Request\Api\InitializeOrder;

class InitializeOrderAction implements ActionInterface, ApiAwareInterface
{
    use ApiAwareTrait;

    public function __construct()
    {
        $this->apiClass = OrderApi::class;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request InitializeOrder */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if ($model['orderRef']) {
            throw new LogicException('The order has already been initialized.');
        }

        $model->validatedKeysSet(array(
            'price',
            'priceArgList',
            'vat',
            'currency',
            'orderId',
            'productNumber',
            'purchaseOperation',
            'view',
            'description',
            'additionalValues',
            'returnUrl',
            'cancelUrl',
            'clientIPAddress',
            'clientIdentifier',
            'agreementRef',
            'clientLanguage',
        ));

        $result = $this->api->initialize((array) $model);

        $model->replace($result);

        if ($model['redirectUrl']) {
            throw new HttpRedirect($model['redirectUrl']);
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof InitializeOrder &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Core\Bridge\Symfony\Extension;

use Payum\Core\Bridge\Symfony\Event\ExecuteEvent;
use Payum\Core\Extension\Context;
use Payum\Core\Extension\ExtensionInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Payum\Core\Bridge\Symfony\PayumEvents;

class EventDispatcherExtension implements ExtensionInterface
{
    /**
     * @var EventDispatcherInterface
     */
    private $dispatcher;

    /**
     * @param EventDispatcherInterface $dispatcher
     */
    public function __construct(EventDispatcherInterface $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    /**
     * {@inheritDoc}
     */
    public function onPreExecute(Context $context)
    {
        $event = new ExecuteEvent($context);
        $this->dispatcher->dispatch(PayumEvents::GATEWAY_PRE_EXECUTE, $event);
    }

    /**
     * {@inheritDoc}
     */
    public function onExecute(Context $context)
    {
        $event = new ExecuteEvent($context);
        $this->dispatcher->dispatch(PayumEvents::GATEWAY_EXECUTE, $event);
    }

    /**
     * {@inheritDoc}
     */
    public function onPostExecute(Context $context)
    {
        $event = new ExecuteEvent($context);
        $this->dispatcher->dispatch(PayumEvents::GATEWAY_POST_EXECUTE, $event);
    }
}


<?php
namespace Payum\Paypal\ExpressCheckout\Nvp\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Paypal\ExpressCheckout\Nvp\Request\Api\GetRecurringPaymentsProfileDetails;
use Payum\Core\Request\Sync;
use Payum\Core\Exception\RequestNotSupportedException;

class RecurringPaymentDetailsSyncAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Sync */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if (false == $model['PROFILEID']) {
            return;
        }

        $this->gateway->execute(new GetRecurringPaymentsProfileDetails($model));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        if (false == $request instanceof Sync) {
            return false;
        }

        $model = $request->getModel();
        if (false == $model instanceof \ArrayAccess) {
            return false;
        }

        return isset($model['BILLINGPERIOD']) && null !== $model['BILLINGPERIOD'];
    }
}


<?php

namespace Payum\Sofort\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Security\GenericTokenFactoryAwareTrait;
use Payum\Sofort\Request\Api\CreateTransaction;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\Capture;
use Payum\Core\Request\Sync;
use Payum\Core\Security\GenericTokenFactoryAwareInterface;

class CaptureAction implements ActionInterface, GatewayAwareInterface, GenericTokenFactoryAwareInterface
{
    use GatewayAwareTrait;
    use GenericTokenFactoryAwareTrait;

    /**
     * {@inheritdoc}
     *
     * @param Capture $request
     */
    public function execute($request)
    {
        /* @var $request Capture */
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        if (false == $details['transaction_id']) {
            if (false == $details['success_url'] && $request->getToken()) {
                $details['success_url'] = $request->getToken()->getTargetUrl();
            }
            if (false == $details['abort_url'] && $request->getToken()) {
                $details['abort_url'] = $request->getToken()->getTargetUrl();
            }

            if (false == $details['notification_url'] && $request->getToken() && $this->tokenFactory) {
                $notifyToken = $this->tokenFactory->createNotifyToken(
                    $request->getToken()->getGatewayName(),
                    $request->getToken()->getDetails()
                );

                $details['notification_url'] = $notifyToken->getTargetUrl();
            }

            $this->gateway->execute(new CreateTransaction($details));
        }

        $this->gateway->execute(new Sync($details));
    }

    /**
     * {@inheritdoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Capture &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Paypal\ProCheckout\Nvp;

use Http\Message\MessageFactory;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\Http\HttpException;
use Payum\Core\Exception\LogicException;
use Payum\Core\HttpClientInterface;

/**
 * @author Ton Sharp <Forma-PRO@66ton99.org.ua>
 * @see https://www.x.com/sites/default/files/payflowgateway_guide.pdf
 */
class Api
{
    /**
     * Use an AMOUNT of $1000 or less
     * For all processors except Global Payments Central (MAPP) and FDI
     * Credit (C) and force (F) transactions will always be approved regardless of dollar amount or card number
     * @var int
     */
    const RESULT_SUCCESS = 0;

    /**
     * Use an invalid PWD
     * @var int
     */
    const RESULT_USER_AUTH_FAIL = 1;

    /**
     * Use an invalid TENDER, such as G
     * @var int
     */
    const RESULT_INVALID_TENDER = 2;

    /**
     * Use an invalid TRXTYPE, such as G
     * Use the AMOUNT 10402
     * @var int
     */
    const RESULT_INVALID_TRANSACTION_TYPE = 3;

    /**
     * Use an invalid AMOUNT, such as –1
     * Use any of these as AMOUNT: 10400, 10401, 10403, 10404
     * @var int
     */
    const RESULT_INVALID_AMOUNT = 4;

    /**
     * Use the AMOUNT1005 - Applies only to the following processors:
     * Global Payments East
     * Global Payments Central
     * American Express
     * Use any of these as AMOUNT: 10548, 10549
     * @var int
     */
    const RESULT_INVALID_MERCHANT_INFORMATION = 5;

    /**
     * Submit a delayed capture transaction with no ORIGID
     * Use any of these as AMOUNT: 10405, 10406, 10407, 10408, 10409, 10410, 10412, 10413, 10416, 10419, 10420, 10421,
     * 10509, 10512, 10513, 10514, 10515, 10516, 10517, 10518, 10540, 10542
     * @var int
     */
    const RESULT_FIELD_FORMAT_ERROR = 7;

    /**
     * Use the AMOUNT1012 or an AMOUNT of 2001 or more
     * Use any of these as AMOUNT: 10417, 15002, 15005, 15006, 15028, 15039, 10544, 10545, 10546
     * @var int
     */
    const RESULT_DECLINED = 12;

    /**
     * Use the AMOUNT1013
     * Use the AMOUNT 10422
     * @var int
     */
    const RESULT_REFERRAL = 13;

    /**
     * Use any of these as AMOUNT: 10519, 10521, 10522, 10527, 10535, 10541, 10543
     * @var int
     */
    const RESULT_INVALID_ACCOUNT_NUMBER = 23;

    /**
     * Use any of these as AMOUNT: 10502, 10508
     * @var int
     */
    const RESULT_INVALID_EXPIRATION_DATE = 24;

    /**
     * Use the AMOUNT 10536
     * @var int
     */
    const RESULT_DUPLICATE_TRANSACTION = 30;

    /**
     * Attempt to credit an authorization
     * @var int
     */
    const RESULT_CREDIT_ERROR = 105;

    /**
     * Use the AMOUNT 10505
     * @var int
     */
    const RESULT_FAILED_AVS_CHECK = 112;

    /**
     * Use the AMOUNT 10504
     * @var int
     */
    const RESULT_CVV2_MISMATCH = 114;

    // Here more error codes

    /**
     * Fraud Protection Services Filter — Declined by filters
     * @var int
     */
    const RESULT_DECLINED_BY_FILTERS = 125;

    // Here more error codes

    /**
     * Use an AMOUNT other than those listed in this column
     * @var int
     */
    const RESULT_GENERIC_HOST_OR_PROCESSOR_ERROR = 1000;

    const TRXTYPE_SALE = 'S';

    const TRXTYPE_CREDIT = 'C';

    const TRXTYPE_AUTHORIZATION = 'A';

    const TRXTYPE_DELAYED_CAPUTER = 'D';

    const TRXTYPE_VOID = 'V';

    const TRXTYPE_VOICE_AUTHORIZATION = 'F';

    const TRXTYPE_INQUIRY = 'I';

    const TRXTYPE_DUPLICATE_TRANSACTION = 'N';

    const TENDER_AUTOMATED_CLEARINGHOUSE = 'A';

    const TENDER_CREDIT_CARD = 'C';

    const TENDER_PINLESS_DEBIT = 'D';

    const TENDER_TELECHECK = 'K';

    const TENDER_PAYPAL = 'P';

    /**
     * @var HttpClientInterface
     */
    protected $client;

    /**
     * @var MessageFactory
     */
    protected $messageFactory;

    /**
     * @var array
     */
    protected $options = array(
        'username' => '',
        'password' => '',
        'partner' => '',
        'vendor' => '',
        'tender' => self::TENDER_CREDIT_CARD,
        'sandbox' => true,
    );

    /**
     * @param array               $options
     * @param HttpClientInterface $client
     * @param MessageFactory      $messageFactory
     *
     * @throw InvalidArgumentException
     */
    public function __construct(array $options, HttpClientInterface $client, MessageFactory $messageFactory)
    {
        $options = ArrayObject::ensureArrayObject($options);
        $options->defaults($this->options);
        $options->validateNotEmpty(array(
            'username',
            'password',
            'partner',
            'vendor',
            'tender',
        ));

        if (false == is_bool($options['sandbox'])) {
            throw new LogicException('The boolean sandbox option must be set.');
        }

        $this->options = $options;
        $this->client = $client;
        $this->messageFactory = $messageFactory;
    }

    /**
     * @param array $fields
     *
     * @return array
     */
    public function doSale(array $fields)
    {
        $fields['TRXTYPE'] = self::TRXTYPE_SALE;
        $this->addAuthorizeFields($fields);

        $result = $this->doRequest($fields);
        $result['TRXTYPE'] = self::TRXTYPE_SALE;

        return $result;
    }

    /**
     * @param array $fields
     *
     * @return array
     */
    public function doCredit(array $fields)
    {
        $fields['TRXTYPE'] = self::TRXTYPE_CREDIT;
        $this->addAuthorizeFields($fields);

        $result = $this->doRequest($fields);
        $result['TRXTYPE'] = self::TRXTYPE_CREDIT;

        return $result;
    }

    /**
     * @param array $fields
     *
     * @return array
     */
    protected function doRequest(array $fields)
    {
        $headers = array(
            'Content-Type' => 'application/x-www-form-urlencoded',
        );

        $request = $this->messageFactory->createRequest('POST', $this->getApiEndpoint(), $headers, http_build_query($fields));

        $response = $this->client->send($request);

        if (false == ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) {
            throw HttpException::factory($request, $response);
        }

        $result = array();
        parse_str($response->getBody()->getContents(), $result);
        foreach ($result as &$value) {
            $value = urldecode($value);
        }

        return $result;
    }

    /**
     * @return string
     */
    protected function getApiEndpoint()
    {
        return $this->options['sandbox'] ?
            'https://pilot-payflowpro.paypal.com/' :
            'https://payflowpro.paypal.com/'
        ;
    }

    /**
     * @param array $fields
     */
    protected function addAuthorizeFields(array &$fields)
    {
        $fields['USER'] = $this->options['username'];
        $fields['PWD'] = $this->options['password'];
        $fields['PARTNER'] = $this->options['partner'];
        $fields['VENDOR'] = $this->options['vendor'];
        $fields['TENDER'] = $this->options['tender'];
    }
}


<?php
namespace Payum\Core\Bridge\Doctrine\Storage;

use Doctrine\Common\Persistence\ObjectManager;
use Payum\Core\Model\Identity;
use Payum\Core\Storage\AbstractStorage;

class DoctrineStorage extends AbstractStorage
{
    /**
     * @var \Doctrine\Common\Persistence\ObjectManager
     */
    protected $objectManager;

    /**
     * @param \Doctrine\Common\Persistence\ObjectManager $objectManager
     * @param string                                     $modelClass
     */
    public function __construct(ObjectManager $objectManager, $modelClass)
    {
        parent::__construct($modelClass);

        $this->objectManager = $objectManager;
    }

    /**
     * {@inheritDoc}
     */
    public function findBy(array $criteria)
    {
        return $this->objectManager->getRepository($this->modelClass)->findBy($criteria);
    }

    /**
     * {@inheritDoc}
     */
    protected function doFind($id)
    {
        return $this->objectManager->find($this->modelClass, $id);
    }

    /**
     * {@inheritDoc}
     */
    protected function doUpdateModel($model)
    {
        $this->objectManager->persist($model);
        $this->objectManager->flush();
    }

    /**
     * {@inheritDoc}
     */
    protected function doDeleteModel($model)
    {
        $this->objectManager->remove($model);
        $this->objectManager->flush();
    }

    /**
     * {@inheritDoc}
     */
    protected function doGetIdentity($model)
    {
        $modelMetadata = $this->objectManager->getClassMetadata(get_class($model));
        $id = $modelMetadata->getIdentifierValues($model);
        if (count($id) > 1) {
            throw new \LogicException('Storage not support composite primary ids');
        }

        return new Identity(array_shift($id), $model);
    }
}


<?php

namespace Payum\Sofort\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Sofort\Api;
use Payum\Sofort\Request\Api\RefundTransaction;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Exception\LogicException;

class RefundTransactionAction implements ActionInterface, ApiAwareInterface
{
    use ApiAwareTrait;

    public function __construct()
    {
        $this->apiClass = Api::class;
    }

    /**
     * {@inheritdoc}
     *
     * @param $request RefundTransaction
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        if (!isset($details['transaction_id'])) {
            throw new LogicException('The parameter "transaction_id" must be set. Have you run CreateTransactionAction?');
        }

        if (!isset($details['refund_amount'])) {
            if (!isset($details['amount'])) {
                throw new LogicException('One of the parameters "refund_amount" or "amount" must be set.');
            }

            $details['refund_amount'] = $details['amount'];
        }

        $details->replace(
            $this->api->refundTransaction((array) $details)
        );
    }

    /**
     * {@inheritdoc}
     */
    public function supports($request)
    {
        return
            $request instanceof RefundTransaction &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Klarna\Checkout\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Reply\HttpResponse;
use Payum\Core\Request\Authorize;
use Payum\Core\Request\RenderTemplate;
use Payum\Core\Request\Sync;
use Payum\Core\Security\GenericTokenFactoryAwareInterface;
use Payum\Core\Security\GenericTokenFactoryAwareTrait;
use Payum\Klarna\Checkout\Config;
use Payum\Klarna\Checkout\Constants;
use Payum\Klarna\Checkout\Request\Api\CreateOrder;

/**
 * @property Config $api
 */
class AuthorizeAction implements ActionInterface, GatewayAwareInterface, GenericTokenFactoryAwareInterface, ApiAwareInterface
{
    use ApiAwareTrait;
    use GatewayAwareTrait;
    use GenericTokenFactoryAwareTrait;

    /**
     * @var string
     */
    protected $templateName;

    /**
     * @param string|null $templateName
     */
    public function __construct($templateName)
    {
        $this->templateName = $templateName;
        $this->apiClass = Config::class;
    }

    /**
     * {@inheritDoc}
     *
     * @param Authorize $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        $merchant = ArrayObject::ensureArrayObject($model['merchant'] ?: []);

        if (false == $merchant['checkout_uri'] && $this->api->checkoutUri) {
            $merchant['checkout_uri'] = $this->api->checkoutUri;
        }

        if (false == $merchant['terms_uri'] && $this->api->termsUri) {
            $merchant['terms_uri'] = $this->api->termsUri;
        }

        if (false == $merchant['confirmation_uri'] && $request->getToken()) {
            $merchant['confirmation_uri'] = $request->getToken()->getTargetUrl();
        }

        if (empty($merchant['push_uri']) && $request->getToken() && $this->tokenFactory) {
            $notifyToken = $this->tokenFactory->createNotifyToken(
                $request->getToken()->getGatewayName(),
                $request->getToken()->getDetails()
            );

            $merchant['push_uri'] = $notifyToken->getTargetUrl();
        }

        $merchant->validateNotEmpty(['checkout_uri', 'terms_uri', 'confirmation_uri', 'push_uri']);
        $model['merchant'] = (array) $merchant;

        if (false == $model['location']) {
            $createOrderRequest = new CreateOrder($model);
            $this->gateway->execute($createOrderRequest);

            $model->replace($createOrderRequest->getOrder()->marshal());
            $model['location'] = $createOrderRequest->getOrder()->getLocation();
        }

        $this->gateway->execute(new Sync($model));

        if (Constants::STATUS_CHECKOUT_INCOMPLETE == $model['status']) {
            $renderTemplate = new RenderTemplate($this->templateName, array(
                'snippet' => $model['gui']['snippet'],
            ));
            $this->gateway->execute($renderTemplate);

            throw new HttpResponse($renderTemplate->getResult());
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Authorize &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Core\Bridge\Symfony;

use Payum\Core\Bridge\Symfony\Reply\HttpResponse as SymfonyHttpResponse;
use Payum\Core\Exception\LogicException;
use Payum\Core\Reply\ReplyInterface;
use Payum\Core\Reply\HttpResponse;
use Symfony\Component\HttpFoundation\Response;

class ReplyToSymfonyResponseConverter
{
    /**
     * @param ReplyInterface $reply
     *
     * @return Response
     */
    public function convert(ReplyInterface $reply)
    {
        if ($reply instanceof SymfonyHttpResponse) {
            return $reply->getResponse();
        } elseif ($reply instanceof HttpResponse) {
            $headers = $reply->getHeaders();
            $headers['X-Status-Code'] = $reply->getStatusCode();

            return new Response($reply->getContent(), $reply->getStatusCode(), $headers);
        }

        $ro = new \ReflectionObject($reply);

        throw new LogicException(
            sprintf('Cannot convert reply %s to http response.', $ro->getShortName()),
            null,
            $reply
        );
    }
}


<?php
namespace Payum\Klarna\Checkout\Action\Api;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Klarna\Checkout\Request\Api\FetchOrder;

class FetchOrderAction extends BaseApiAwareAction
{
    /**
     * {@inheritDoc}
     *
     * @param FetchOrder $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if (false == $model['location']) {
            throw new LogicException('Location has to be provided to fetch an order');
        }

        $this->callWithRetry(function () use ($model, $request) {
            $order = new \Klarna_Checkout_Order($this->getConnector(), $model['location']);
            $order->fetch();

            $request->setOrder($order);
        });
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return $request instanceof FetchOrder;
    }
}


<?php
namespace Payum\Core\Action;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Model\PayoutInterface;
use Payum\Core\Request\Convert;
use Payum\Core\Request\GetHumanStatus;
use Payum\Core\Request\Payout;

class PayoutPayoutAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     *
     * @param Payout $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        /** @var $payout PayoutInterface */
        $payout = $request->getModel();

        $this->gateway->execute($status = new GetHumanStatus($payout));
        if ($status->isNew()) {
            $this->gateway->execute($convert = new Convert($payout, 'array', $request->getToken()));

            $payout->setDetails($convert->getResult());
        }

        $details = ArrayObject::ensureArrayObject($payout->getDetails());

        $request->setModel($details);
        try {
            $this->gateway->execute($request);
        } finally {
            $payout->setDetails($details);
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Payout &&
            $request->getModel() instanceof PayoutInterface
        ;
    }
}


<?php
namespace Payum\Paypal\ProCheckout\Nvp\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Exception\LogicException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\ObtainCreditCard;
use Payum\Core\Security\SensitiveValue;
use Payum\Paypal\ProCheckout\Nvp\Api;
use Payum\Core\Request\Capture;

/**
 * @author Ton Sharp <Forma-PRO@66ton99.org.ua>
 *
 * @param Api $api
 */
class CaptureAction implements ActionInterface, ApiAwareInterface, GatewayAwareInterface
{
    use ApiAwareTrait;
    use GatewayAwareTrait;

    public function __construct()
    {
        $this->apiClass = Api::class;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Capture */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = new ArrayObject($request->getModel());

        if (is_numeric($model['RESULT'])) {
            return;
        }

        $cardFields = array('ACCT', 'CVV2', 'EXPDATE');
        if (false == $model->validateNotEmpty($cardFields, false)) {
            try {
                $obtainCreditCard = new ObtainCreditCard($request->getToken());
                $obtainCreditCard->setModel($request->getFirstModel());
                $obtainCreditCard->setModel($request->getModel());
                $this->gateway->execute($obtainCreditCard);
                $card = $obtainCreditCard->obtain();

                $model['EXPDATE'] = SensitiveValue::ensureSensitive($card->getExpireAt()->format('my'));
                $model['ACCT'] = SensitiveValue::ensureSensitive($card->getNumber());
                $model['CVV2'] = SensitiveValue::ensureSensitive($card->getSecurityCode());
            } catch (RequestNotSupportedException $e) {
                throw new LogicException('Credit card details has to be set explicitly or there has to be an action that supports ObtainCreditCard request.');
            }
        }

        $model->replace($this->api->doSale($model->toUnsafeArray()));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Capture &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Paypal\ExpressCheckout\Nvp\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Sync;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Paypal\ExpressCheckout\Nvp\Api;
use Payum\Paypal\ExpressCheckout\Nvp\Request\Api\GetExpressCheckoutDetails;
use Payum\Paypal\ExpressCheckout\Nvp\Request\Api\GetTransactionDetails;

class PaymentDetailsSyncAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Sync */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if (false == $model['TOKEN']) {
            return;
        }

        $copiedModel = new ArrayObject(array(
            'TOKEN' => $model['TOKEN'],
        ));

        $this->gateway->execute(new GetExpressCheckoutDetails($copiedModel));
        if (Api::L_ERRORCODE_SESSION_HAS_EXPIRED != $copiedModel['L_ERRORCODE0']) {
            $model->replace($copiedModel);
        }

        foreach (range(0, 9) as $index) {
            if ($model['PAYMENTREQUEST_'.$index.'_TRANSACTIONID']) {
                $this->gateway->execute(new GetTransactionDetails($model, $index));
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        if (false == $request instanceof Sync) {
            return false;
        }

        $model = $request->getModel();
        if (false == $model instanceof \ArrayAccess) {
            return false;
        }

        return false == isset($model['BILLINGPERIOD']);
    }
}


<?php
namespace Payum\Payex\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Capture;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\GetHttpRequest;
use Payum\Payex\Request\Api\StartRecurringPayment;
use Payum\Payex\Request\Api\InitializeOrder;
use Payum\Payex\Request\Api\CompleteOrder;

class PaymentDetailsCaptureAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     *
     * @param Capture $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        if (false == $details['returnUrl'] && $request->getToken()) {
            $details['returnUrl'] = $request->getToken()->getTargetUrl();
        }

        if (false == $details['cancelUrl'] && $request->getToken()) {
            $details['cancelUrl'] = $request->getToken()->getTargetUrl();
        }

        if (false == $details['clientIPAddress']) {
            $this->gateway->execute($httpRequest = new GetHttpRequest());

            $details['clientIPAddress'] = $httpRequest->clientIp;
        }

        if (false == $details['orderRef']) {
            $this->gateway->execute(new InitializeOrder($details));
        }

        if ($details['orderRef']) {
            $this->gateway->execute(new CompleteOrder($details));

            if ($details['recurring']) {
                $this->gateway->execute(new StartRecurringPayment($details));
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        if (false == (
            $request instanceof Capture &&
            $request->getModel() instanceof \ArrayAccess
        )) {
            return false;
        }

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if ($model['recurring']) {
            return true;
        }

        //Make sure it is not auto pay payment. There is an other capture action for auto pay payments;
        if (false == $model['autoPay']) {
            return true;
        }

        return false;
    }
}


<?php
namespace Payum\Paypal\ProHosted\Nvp\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Paypal\ProHosted\Nvp\Api;
use Payum\Paypal\ProHosted\Nvp\Request\Api\GetTransactionDetails;

class GetTransactionDetailsAction implements ActionInterface, ApiAwareInterface
{
    use ApiAwareTrait;

    public function __construct()
    {
        $this->apiClass = Api::class;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request GetTransactionDetails */
        RequestNotSupportedException::assertSupports($this, $request);
        $model = ArrayObject::ensureArrayObject($request->getModel());

        if (null == $model['txn_id']) {
            throw new LogicException('TRANSACTIONID must be set.');
        }

        $fields = new ArrayObject([]);

        $fields['TRANSACTIONID'] = $model['txn_id'];

        $result = $this->api->getTransactionDetails((array) $fields);

        $model->replace($result);
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetTransactionDetails &&
            $request->getModel() instanceof \ArrayAccess;
    }
}


<?php
namespace Payum\Klarna\Invoice\Action\Api;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Klarna\Invoice\Request\Api\ReturnAmount;

class ReturnAmountAction extends BaseApiAwareAction
{
    /**
     * {@inheritDoc}
     *
     * @param ReturnAmount $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        $klarna = $this->getKlarna();

        try {
            $klarna->returnAmount(
                $details['invoice_number'],
                $details['amount'],
                $details['vat'],
                $details['flags'] ?: \KlarnaFlags::NO_FLAG,
                $details['description']
            );
        } catch (\KlarnaException $e) {
            $this->populateDetailsWithError($details, $e, $request);
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof ReturnAmount &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Klarna\Invoice\Action\Api;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayInterface;
use Payum\Klarna\Invoice\Request\Api\PopulateKlarnaFromDetails;
use Payum\Klarna\Invoice\Request\Api\ReserveAmount;

class ReserveAmountAction extends BaseApiAwareAction implements GatewayAwareInterface
{
    /**
     * @var GatewayInterface
     */
    protected $gateway;

    /**
     * {@inheritDoc}
     */
    public function setGateway(GatewayInterface $gateway)
    {
        $this->gateway = $gateway;
    }

    /**
     * {@inheritDoc}
     *
     * @param ReserveAmount $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        $klarna = $this->getKlarna();

        try {
            $this->gateway->execute(new PopulateKlarnaFromDetails($details, $klarna));

            $result = $klarna->reserveAmount(
                $details['pno'],
                $details['gender'],
                $details['amount'] ?: -1,
                $details['reservation_flags'] ?: \KlarnaFlags::NO_FLAG
            );

            $details['rno'] = $result[0];
            $details['status'] = $result[1];
        } catch (\KlarnaException $e) {
            $this->populateDetailsWithError($details, $e, $request);
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof ReserveAmount &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Core\Registry;

use Doctrine\Common\Persistence\Proxy;
use Payum\Core\Exception\InvalidArgumentException;

abstract class AbstractRegistry implements RegistryInterface
{
    /**
     * @var array
     */
    protected $gateways;

    /**
     * @var array
     */
    protected $storages;

    /**
     * @var array
     */
    protected $gatewayFactories;

    /**
     * @param array $gateways
     * @param array $storages
     * @param array $gatewayFactories
     */
    public function __construct(array $gateways = array(), array $storages = array(), array $gatewayFactories = array())
    {
        $this->gateways = $gateways;
        $this->storages = $storages;
        $this->gatewayFactories = $gatewayFactories;
    }

    /**
     * Fetches/creates the given services
     *
     * A service in this context is a storage or a gateway or gateway factory instance
     *
     * @param string $id name of the service
     *
     * @return object instance of the given service
     */
    abstract protected function getService($id);

    /**
     * {@inheritDoc}
     */
    public function getStorage($class)
    {
        $class = is_object($class) ? get_class($class) : $class;

        // TODO: this is a quick fix. I have to find a better\clean solution.
        if (class_exists($class) && interface_exists(Proxy::class)) {
            $rc = new \ReflectionClass($class);
            if ($rc->implementsInterface(Proxy::class)) {
                $class = $rc->getParentClass()->getName();
            }
        }

        if (!isset($this->storages[$class])) {
            throw new InvalidArgumentException(sprintf(
                'A storage for model %s was not registered. There are storages for next models: %s.',
                $class,
                implode(', ', array_keys($this->storages))
            ));
        }

        return $this->getService($this->storages[$class]);
    }

    /**
     * {@inheritDoc}
     */
    public function getStorages()
    {
        $storages = array();
        foreach ($this->storages as $modelClass => $storageId) {
            $storages[$modelClass] = $this->getService($storageId);
        }

        return $storages;
    }

    /**
     * {@inheritDoc}
     */
    public function getGateway($name)
    {
        if (!isset($this->gateways[$name])) {
            throw new InvalidArgumentException(sprintf('Gateway "%s" does not exist.', $name));
        }

        return $this->getService($this->gateways[$name]);
    }

    /**
     * {@inheritDoc}
     */
    public function getGateways()
    {
        $gateways = array();
        foreach ($this->gateways as $name => $id) {
            $gateways[$name] = $this->getGateway($name);
        }

        return $gateways;
    }

    /**
     * {@inheritDoc}
     */
    public function getGatewayFactory($name)
    {
        if (!isset($this->gatewayFactories[$name])) {
            throw new InvalidArgumentException(sprintf('Gateway factory "%s" does not exist.', $name));
        }

        return $this->getService($this->gatewayFactories[$name]);
    }

    /**
     * {@inheritDoc}
     */
    public function getGatewayFactories()
    {
        $gatewayFactories = array();
        foreach ($this->gatewayFactories as $name => $id) {
            $gatewayFactories[$name] = $this->getGatewayFactory($name);
        }

        return $gatewayFactories;
    }
}


<?php
namespace Payum\Stripe\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\ApiAwareTrait;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Stripe\Keys;
use Payum\Stripe\Request\Api\CreateSubscription;
use Stripe\Error;
use Stripe\Stripe;
use Stripe\Subscription;

/**
 * @param Keys $keys
 * @param Keys $api
 */
class CreateSubscriptionAction implements ActionInterface, ApiAwareInterface
{
    use ApiAwareTrait {
        setApi as _setApi;
    }

    /**
     * @deprecated BC will be removed in 2.x. Use $this->api
     *
     * @var Keys
     */
    protected $keys;

    public function __construct()
    {
        $this->apiClass = Keys::class;
    }

    /**
     * {@inheritDoc}
     */
    public function setApi($api)
    {
        $this->_setApi($api);

        // BC. will be removed in 2.x
        $this->keys = $this->api;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request CreateSubscription */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        try {
            Stripe::setApiKey($this->api->getSecretKey());

            $subscription = Subscription::create($model->toUnsafeArrayWithoutLocal());

            $model->replace($subscription->__toArray(true));
        } catch (Error\Base $e) {
            $model->replace($e->getJsonBody());
        }
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof CreateSubscription &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
namespace Payum\Klarna\Invoice\Action\Api;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Klarna\Invoice\Request\Api\PopulateKlarnaFromDetails;

class PopulateKlarnaFromDetailsAction implements ActionInterface
{
    /**
     * {@inheritDoc}
     *
     * @param PopulateKlarnaFromDetails $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());
        $klarna = $request->getKlarna();

        if ($details['articles']) {
            foreach ($details['articles'] as $article) {
                $article = ArrayObject::ensureArrayObject($article);

                $klarna->addArticle(
                    utf8_decode($article['qty']),
                    utf8_decode($article['artNo']),
                    utf8_decode($article['title']),
                    utf8_decode($article['price']),
                    utf8_decode($article['vat']),
                    utf8_decode($article['discount']),
                    $article['flags'] ?: \KlarnaFlags::NO_FLAG
                );
            }
        }

        if ($details['partial_articles']) {
            foreach ($details['partial_articles'] as $article) {
                $klarna->addArtNo(
                    utf8_decode($article['qty']),
                    utf8_decode($article['artNo'])
                );
            }
        }

        if ($details['shipping_address']) {
            $address = ArrayObject::ensureArrayObject($details['shipping_address']);

            $klarna->setAddress(\KlarnaFlags::IS_SHIPPING, new \KlarnaAddr(
                utf8_decode($address['email']),
                utf8_decode($address['telno']),
                utf8_decode($address['cellno']),
                utf8_decode($address['fname']),
                utf8_decode($address['lname']),
                utf8_decode($address['careof']),
                utf8_decode($address['street']),
                utf8_decode($address['zip']),
                utf8_decode($address['city']),
                utf8_decode($address['country']),
                utf8_decode($address['house_number']),
                utf8_decode($address['house_extension'])
            ));
        }

        if ($details['billing_address']) {
            $address = ArrayObject::ensureArrayObject($details['billing_address']);

            $klarna->setAddress(\KlarnaFlags::IS_BILLING, new \KlarnaAddr(
                utf8_decode($address['email']),
                utf8_decode($address['telno']),
                utf8_decode($address['cellno']),
                utf8_decode($address['fname']),
                utf8_decode($address['lname']),
                utf8_decode($address['careof']),
                utf8_decode($address['street']),
                utf8_decode($address['zip']),
                utf8_decode($address['city']),
                utf8_decode($address['country']),
                utf8_decode($address['house_number']),
                utf8_decode($address['house_extension'])
            ));
        }

        if ($details['estore_info']) {
            $estoreInfo = ArrayObject::ensureArrayObject($details['estore_info']);

            $klarna->setEstoreInfo(
                utf8_decode($estoreInfo['order_id1']),
                utf8_decode($estoreInfo['order_id2']),
                utf8_decode($estoreInfo['username'])
            );
        }

        $klarna->setComment(utf8_decode($details['comment']));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return $request instanceof PopulateKlarnaFromDetails;
    }
}


<?php
namespace Payum\Be2Bill\Action;

use League\Uri\Http as HttpUri;
use League\Uri\Components\Query;
use Payum\Core\Action\ActionInterface;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Reply\HttpRedirect;
use Payum\Core\Reply\HttpResponse;
use Payum\Core\Request\Capture;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Request\GetToken;

class CaptureOffsiteNullAction implements ActionInterface, GatewayAwareInterface
{
    use GatewayAwareTrait;

    /**
     * {@inheritDoc}
     *
     * @param Capture $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $this->gateway->execute($httpRequest = new GetHttpRequest());

        //we are back from be2bill site so we have to just update model.
        if (empty($httpRequest->query['EXTRADATA'])) {
            throw new HttpResponse('The capture is invalid. Code Be2Bell1', 400);
        }

        $extraDataJson = $httpRequest->query['EXTRADATA'];
        if (false == $extraData = json_decode($extraDataJson, true)) {
            throw new HttpResponse('The capture is invalid. Code Be2Bell2', 400);
        }

        if (empty($extraData['capture_token'])) {
            throw new HttpResponse('The capture is invalid. Code Be2Bell3', 400);
        }

        $this->gateway->execute($getToken = new GetToken($extraData['capture_token']));

        $uri = HttpUri::createFromString($getToken->getToken()->getTargetUrl());
        $uri = $uri->withQuery((string)Query::createFromPairs($httpRequest->query));

        throw new HttpRedirect((string) $uri);
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Capture &&
            null === $request->getModel()
        ;
    }
}


<?php
namespace Payum\Paypal\ExpressCheckout\Nvp\Action;

use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Request\Authorize;
use Payum\Core\Request\Capture;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Paypal\ExpressCheckout\Nvp\Api;

class AuthorizeAction extends PurchaseAction
{
    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Capture */
        RequestNotSupportedException::assertSupports($this, $request);

        $details = ArrayObject::ensureArrayObject($request->getModel());

        $details['PAYMENTREQUEST_0_PAYMENTACTION'] = Api::PAYMENTACTION_AUTHORIZATION;

        parent::execute($request);
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Authorize &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}