[PoC] Payum integration with paypal and stripe examples

This commit is contained in:
Maksim Kotlyar 2013-10-15 16:42:31 +03:00
parent 1a0ff1eab6
commit 5540995af1
45 changed files with 1956 additions and 57 deletions

View file

@ -70,6 +70,7 @@ script:
- cd ../SettingsBundle; ../../../../bin/phpspec run -fpretty --verbose
- cd ../PromotionsBundle; ../../../../bin/phpspec run -fpretty --verbose
- cd ../PaymentsBundle; ../../../../bin/phpspec run -fpretty --verbose
- cd ../PayumBundle; ../../../../bin/phpspec run -fpretty --verbose
notifications:
email: "travis-ci@sylius.org"

View file

@ -39,6 +39,7 @@ class AppKernel extends Kernel
new Sylius\Bundle\TaxationBundle\SyliusTaxationBundle(),
new Sylius\Bundle\ShippingBundle\SyliusShippingBundle(),
new Sylius\Bundle\PaymentsBundle\SyliusPaymentsBundle(),
new Sylius\Bundle\PayumBundle\SyliusPayumBundle(),
new Sylius\Bundle\PromotionsBundle\SyliusPromotionsBundle(),
new Sylius\Bundle\AddressingBundle\SyliusAddressingBundle(),
new Sylius\Bundle\InventoryBundle\SyliusInventoryBundle(),
@ -71,6 +72,7 @@ class AppKernel extends Kernel
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new JMS\TranslationBundle\JMSTranslationBundle(),
new Knp\Bundle\SnappyBundle\KnpSnappyBundle(),
new Payum\Bundle\PayumBundle\PayumBundle(),
);
if (in_array($this->getEnvironment(), array('dev'))) {

View file

@ -2,6 +2,7 @@ imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: sylius.yml }
- { resource: payum.yml }
framework:
translator: { fallback: %sylius.locale% }
@ -129,4 +130,4 @@ knp_snappy:
image:
enabled: true
binary: /usr/bin/wkhtmltoimage
options: []
options: []

View file

@ -17,3 +17,11 @@ parameters:
sylius.currency: EUR
sylius.cache: file_system
paypal.express_checkout.username: EDITME
paypal.express_checkout.password: EDITME
paypal.express_checkout.signature: EDITME
paypal.express_checkout.sandbox: true
stripe.secret_key: EDITME
stripe.test_mode: true

60
app/config/payum.yml Normal file
View file

@ -0,0 +1,60 @@
payum:
security:
token_storage:
Sylius\Bundle\PayumBundle\Model\PaymentSecurityToken:
doctrine:
driver: orm
contexts:
paypal_express_checkout:
paypal_express_checkout_nvp:
api:
options:
username: %paypal.express_checkout.username%
password: %paypal.express_checkout.password%
signature: %paypal.express_checkout.signature%
sandbox: %paypal.express_checkout.sandbox%
actions:
- sylius.payum.action.capture_order_with_paypal
- sylius.payum.action.order_status
storages:
Sylius\Bundle\CoreBundle\Model\Order:
doctrine:
driver: orm
Sylius\Bundle\PaymentsBundle\Model\Payment:
doctrine:
driver: orm
stripe:
omnipay:
type: Stripe
options:
apiKey: %stripe.secret_key%
testMode: %stripe.test_mode%
actions:
- sylius.payum.action.capture_order_with_stripe
- sylius.payum.action.obtain_credit_card
- sylius.payum.action.order_status
storages:
Sylius\Bundle\CoreBundle\Model\Order:
doctrine:
driver: orm
Sylius\Bundle\PaymentsBundle\Model\Payment:
doctrine:
driver: orm
dummy:
custom:
actions:
- sylius.payum.action.capture_order_with_dummy
- sylius.payum.action.dummy_order_status
storages:
Sylius\Bundle\CoreBundle\Model\Order:
doctrine:
driver: orm
Sylius\Bundle\PaymentsBundle\Model\Payment:
doctrine:
driver: orm

View file

@ -4,6 +4,9 @@ sylius_installer:
sylius_web:
resource: @SyliusWebBundle/Resources/config/routing/main.yml
payum_capture:
resource: "@PayumBundle/Resources/config/routing/capture.xml"
fos_user_security:
resource: "@FOSUserBundle/Resources/config/routing/security.xml"

View file

@ -72,6 +72,9 @@ sylius_payments:
dummy: Test
stripe: Stripe
sylius_payum:
driver: doctrine/orm
sylius_addressing:
classes:
address:

View file

@ -1,3 +1,4 @@
{
"name": "sylius/sylius",
"type": "project",
@ -38,7 +39,6 @@
"liip/doctrine-cache-bundle": "*",
"liip/imagine-bundle": "~0.9",
"mathiasverraes/money": "*@dev",
"omnipay/omnipay": "*@dev",
"sensio/distribution-bundle": "2.3.*",
"stof/doctrine-extensions-bundle": "1.1.*",
"symfony/assetic-bundle": "2.3.*",
@ -47,7 +47,12 @@
"symfony/swiftmailer-bundle": "2.3.*",
"symfony/symfony": "~2.3",
"twig/extensions": "1.0.*",
"white-october/pagerfanta-bundle": "1.0.*@dev"
"white-october/pagerfanta-bundle": "1.0.*@dev",
"omnipay/omnipay": "1.0.*",
"payum/payum": "0.6.*@dev",
"payum/payum-bundle": "0.6.*@dev",
"payum/paypal-express-checkout-nvp": "0.6.*@dev",
"payum/omnipay-bridge": "0.6.*@dev"
},
"require-dev": {
"behat/behat": "2.4.*@stable",

375
composer.lock generated
View file

@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "44206bb63f0af4d9594c308f6dcbb0cc",
"hash": "275dc038a243748ecf2b11bfb9340c59",
"packages": [
{
"name": "athari/yalinqo",
@ -53,12 +53,12 @@
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "40db0c96985aab2822edbc4848b3bd2429e02670"
"reference": "v1.1.2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/40db0c96985aab2822edbc4848b3bd2429e02670",
"reference": "40db0c96985aab2822edbc4848b3bd2429e02670",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/v1.1.2",
"reference": "v1.1.2",
"shasum": ""
},
"require": {
@ -773,17 +773,17 @@
"source": {
"type": "git",
"url": "https://github.com/FriendsOfSymfony/FOSRest.git",
"reference": "9a84df8220553e2ae3163b8325a3c4c2e9792426"
"reference": "0.8.0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSRest/zipball/9a84df8220553e2ae3163b8325a3c4c2e9792426",
"reference": "9a84df8220553e2ae3163b8325a3c4c2e9792426",
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSRest/zipball/0.8.0",
"reference": "0.8.0",
"shasum": ""
},
"require": {
"php": ">=5.3.2",
"symfony/http-foundation": "~2.0"
"symfony/http-foundation": ">=2.0,<3.0"
},
"type": "library",
"extra": {
@ -1644,7 +1644,7 @@
],
"authors": [
{
"name": "Johannes M. Schmitt",
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "http://jmsyst.com",
"role": "Developer of wrapped JMSSerializerBundle"
@ -2159,6 +2159,54 @@
],
"time": "2013-07-19 00:03:27"
},
{
"name": "kriswallsmith/buzz",
"version": "v0.10",
"source": {
"type": "git",
"url": "https://github.com/kriswallsmith/Buzz.git",
"reference": "759432d66387e3433d3b06cb6f773b97225b9b17"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kriswallsmith/Buzz/zipball/759432d66387e3433d3b06cb6f773b97225b9b17",
"reference": "759432d66387e3433d3b06cb6f773b97225b9b17",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"suggest": {
"ext-curl": "*"
},
"type": "library",
"autoload": {
"psr-0": {
"Buzz": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kris Wallsmith",
"email": "kris.wallsmith@gmail.com",
"homepage": "http://kriswallsmith.net/"
}
],
"description": "Lightweight HTTP client",
"homepage": "https://github.com/kriswallsmith/Buzz",
"keywords": [
"curl",
"http client"
],
"time": "2013-05-19 03:41:15"
},
{
"name": "liip/doctrine-cache-bundle",
"version": "1.0.3",
@ -2231,7 +2279,7 @@
"symfony/options-resolver": ">=2.0.16,~2.0"
},
"require-dev": {
"symfony/yaml": ">=2.0.16,~2.0",
"symfony/yaml": ">=2.0.16.0,>=2.0,<3.0",
"twig/twig": ">=1.0,<2.0-dev"
},
"suggest": {
@ -2383,13 +2431,13 @@
"version": "v0.9.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "b1cc9ce676b4350b23d0fafc8244d08eee2fe287"
"url": "https://github.com/nikic/PHP-Parser",
"reference": "v0.9.1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/b1cc9ce676b4350b23d0fafc8244d08eee2fe287",
"reference": "b1cc9ce676b4350b23d0fafc8244d08eee2fe287",
"url": "https://github.com/nikic/PHP-Parser/archive/v0.9.1.zip",
"reference": "v0.9.1",
"shasum": ""
},
"require": {
@ -2415,20 +2463,20 @@
"parser",
"php"
],
"time": "2012-04-23 22:52:11"
"time": "2012-04-23 15:52:11"
},
{
"name": "omnipay/omnipay",
"version": "dev-master",
"version": "v1.0.4",
"source": {
"type": "git",
"url": "https://github.com/adrianmacneil/omnipay.git",
"reference": "4de6c429661af33ce6323d9a58f60b4e82fcf35d"
"reference": "4f5e82232161939c0b14f5921c092ed77980d450"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/adrianmacneil/omnipay/zipball/4de6c429661af33ce6323d9a58f60b4e82fcf35d",
"reference": "4de6c429661af33ce6323d9a58f60b4e82fcf35d",
"url": "https://api.github.com/repos/adrianmacneil/omnipay/zipball/4f5e82232161939c0b14f5921c092ed77980d450",
"reference": "4f5e82232161939c0b14f5921c092ed77980d450",
"shasum": ""
},
"require": {
@ -2445,11 +2493,6 @@
"twig/twig": "~1.12"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Omnipay": "src/"
@ -2486,7 +2529,6 @@
"merchant",
"migs",
"mollie",
"multisafepay",
"netaxept",
"netbanx",
"pay",
@ -2503,11 +2545,10 @@
"stripe",
"tala",
"tala-payments",
"targetpay",
"twocheckout",
"worldpay"
],
"time": "2013-10-10 23:03:59"
"time": "2013-09-20 23:40:41"
},
{
"name": "pagerfanta/pagerfanta",
@ -2571,6 +2612,267 @@
],
"time": "2013-09-23 08:06:55"
},
{
"name": "payum/omnipay-bridge",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/Payum/OmnipayBridge.git",
"reference": "da2a1c061efe27ecc8006bc8c7e7e7ba7a17e763"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Payum/OmnipayBridge/zipball/da2a1c061efe27ecc8006bc8c7e7e7ba7a17e763",
"reference": "da2a1c061efe27ecc8006bc8c7e7e7ba7a17e763",
"shasum": ""
},
"require": {
"omnipay/omnipay": "1.0.*",
"payum/payum": "0.6.x-dev",
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.6-dev"
}
},
"autoload": {
"psr-0": {
"Payum\\Bridge\\Omnipay": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kotlyar Maksim",
"email": "kotlyar.maksim@gmail.com"
}
],
"description": "This bridge allows you to use omnipay gateways but in payum like way.",
"homepage": "https://github.com/Payum/OmnipayBridge",
"keywords": [
"omnipay",
"payment"
],
"time": "2013-07-31 10:48:07"
},
{
"name": "payum/paypal-express-checkout-nvp",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/Payum/PaypalExpressCheckoutNvp.git",
"reference": "7aaaf140b5348a9676feb87881df5893b84b06f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Payum/PaypalExpressCheckoutNvp/zipball/7aaaf140b5348a9676feb87881df5893b84b06f9",
"reference": "7aaaf140b5348a9676feb87881df5893b84b06f9",
"shasum": ""
},
"require": {
"kriswallsmith/buzz": "*",
"payum/payum": "0.6.x-dev",
"php": ">=5.3.2"
},
"require-dev": {
"doctrine/mongodb-odm": "~1.0@dev",
"doctrine/orm": ">=2.3,<2.4-dev",
"ext-curl": "*",
"ext-pdo_sqlite": "*",
"fp/testo": "dev-master",
"phpunit/phpunit": "3.7.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.6-dev"
}
},
"autoload": {
"psr-0": {
"Payum\\Paypal\\ExpressCheckout\\Nvp": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kotlyar Maksim",
"email": "kotlyar.maksim@gmail.com"
}
],
"description": "Paypal express checkout",
"keywords": [
"digital goods",
"express checkout",
"payment",
"paypal",
"recurring payment"
],
"time": "2013-10-10 20:10:49"
},
{
"name": "payum/payum",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/Payum/Payum.git",
"reference": "57b553f6dac1e4a2499f3f79797447476f9d9542"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Payum/Payum/zipball/57b553f6dac1e4a2499f3f79797447476f9d9542",
"reference": "57b553f6dac1e4a2499f3f79797447476f9d9542",
"shasum": ""
},
"require": {
"kriswallsmith/buzz": "*",
"php": ">=5.3.2"
},
"require-dev": {
"doctrine/mongodb": "1.0.*@dev",
"doctrine/mongodb-odm": "1.0.*@dev",
"doctrine/orm": "2.*",
"ext-curl": "*",
"ext-pdo_sqlite": "*",
"fp/testo": "dev-master",
"phpunit/phpunit": "3.7.*",
"psr/log": "~1.0"
},
"suggest": {
"doctrine/mongodb-odm": "If you want to store models to mongo doctrin2 ODM",
"doctrine/orm": "If you want to store models to database using doctrin2 ORM",
"monolog/monolog": "In case you want to use logger",
"payum/authorize-net-aim": "If you want to use Authorize.Net AIM payment gateway",
"payum/be2bill": "If you want to use be2bill payment gateway",
"payum/omnipay-bridge": "If you want to use omnipay's gateways",
"payum/paypal-express-checkout-nvp": "If you want to use paypal express checkout, digital goods or recurring payments",
"payum/paypal-ipn": "If you want to use paypal instant payment notifications(Paypal IPN)",
"payum/paypal-pro-checkout-nvp": "If you want to use paypal pro checkout"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.6-dev"
}
},
"autoload": {
"psr-0": {
"Payum": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kotlyar Maksim",
"email": "kotlyar.maksim@gmail.com"
}
],
"description": "Payment lib",
"keywords": [
"authorize.net",
"be2bill",
"omnipay gateways",
"payment",
"paypal",
"paypal digital goods",
"paypal ipn",
"paypal recurring payments"
],
"time": "2013-10-14 18:47:40"
},
{
"name": "payum/payum-bundle",
"version": "dev-master",
"target-dir": "Payum/Bundle/PayumBundle",
"source": {
"type": "git",
"url": "https://github.com/Payum/PayumBundle.git",
"reference": "7f4708009c256b2dcc5dea378e8c003e61c3c09c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Payum/PayumBundle/zipball/7f4708009c256b2dcc5dea378e8c003e61c3c09c",
"reference": "7f4708009c256b2dcc5dea378e8c003e61c3c09c",
"shasum": ""
},
"require": {
"payum/payum": "0.6.x-dev",
"php": ">=5.3.2",
"symfony/framework-bundle": "2.*"
},
"require-dev": {
"doctrine/orm": "*",
"fp/testo": "@dev",
"payum/authorize-net-aim": "0.6.x-dev",
"payum/be2bill": "0.6.x-dev",
"payum/omnipay-bridge": "0.6.x-dev",
"payum/payex": "0.6.x-dev",
"payum/paypal-express-checkout-nvp": "0.6.x-dev",
"payum/paypal-pro-checkout-nvp": "0.6.x-dev",
"phpunit/phpunit": "*"
},
"suggest": {
"payum/authorize-net-aim": "If you want to use authorize.net gateway",
"payum/be2bill": "If you want to use be2bill gateway",
"payum/omnipay-bridge": "If you want to use omnipay provided gateways",
"payum/payex": "If you want to use payex gateway",
"payum/paypal-express-checkout-nvp": "If you want to use paypal express checkout nvp gateway",
"payum/paypal-pro-checkout-nvp": "If you want to use paypal pro checkout nvp gateway"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "0.6-dev"
}
},
"autoload": {
"psr-0": {
"Payum\\Bundle\\PayumBundle": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kotlyar Maksim",
"email": "kotlyar.maksim@gmail.com"
},
{
"name": "Community",
"homepage": "https://github.com/Payum/PayumBundle/graphs/contributors"
}
],
"description": "The payment bundle integrates payum libs into symfony2 framework",
"homepage": "https://github.com/Payum/PayumBundle",
"keywords": [
"authorize.net",
"be2bill",
"omnipay",
"payex",
"payment",
"paypal",
"paypal express checkout",
"paypal pro checkout",
"paypal recurring payment"
],
"time": "2013-09-30 20:51:39"
},
{
"name": "phpcollection/phpcollection",
"version": "0.2.0",
@ -2675,13 +2977,13 @@
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
"url": "https://github.com/php-fig/log",
"reference": "1.0.0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"url": "https://github.com/php-fig/log/archive/1.0.0.zip",
"reference": "1.0.0",
"shasum": ""
},
"type": "library",
@ -3864,12 +4166,12 @@
"source": {
"type": "git",
"url": "https://github.com/phpspec/php-diff.git",
"reference": "8d82ac415225fac373a4073ba14b1fe286aa2312"
"reference": "v1.0.1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/php-diff/zipball/8d82ac415225fac373a4073ba14b1fe286aa2312",
"reference": "8d82ac415225fac373a4073ba14b1fe286aa2312",
"url": "https://api.github.com/repos/phpspec/php-diff/zipball/v1.0.1",
"reference": "v1.0.1",
"shasum": ""
},
"type": "library",
@ -4028,8 +4330,11 @@
"knplabs/knp-gaufrette-bundle": 20,
"knplabs/knp-snappy-bundle": 20,
"mathiasverraes/money": 20,
"omnipay/omnipay": 20,
"white-october/pagerfanta-bundle": 20,
"payum/payum": 20,
"payum/payum-bundle": 20,
"payum/paypal-express-checkout-nvp": 20,
"payum/omnipay-bridge": 20,
"behat/behat": 0,
"phpspec/phpspec": 20
},

View file

@ -20,8 +20,8 @@ Feature: Checkout finalization
| zone | name |
| UK | DHL Express |
And the following payment methods exist:
| name | gateway | enabled |
| Credit Card | stripe | yes |
| name | gateway | enabled |
| Dummy | dummy | yes |
Scenario: Placing the order
Given I am logged in user
@ -31,7 +31,7 @@ Feature: Checkout finalization
And I press "Continue"
And I select the "DHL Express" radio button
And I press "Continue"
And I select the "Credit Card" radio button
And I select the "Dummy" radio button
And I press "Continue"
When I click "Place order"
Then I should be on the store homepage

View file

@ -24,8 +24,8 @@ Feature: Checkout security
| zone | name |
| UK | DHL Express |
And the following payment methods exist:
| name | gateway | enabled |
| Credit Card | stripe | yes |
| name | gateway | enabled |
| Dummy | dummy | yes |
And I added product "PHP Top" to cart
And I go to the checkout start page
@ -62,7 +62,7 @@ Feature: Checkout security
And I press "Continue"
And I select the "DHL Express" radio button
And I press "Continue"
And I select the "Credit Card" radio button
And I select the "Dummy" radio button
And I press "Continue"
And I click "Place order"
Then I should be on the store homepage

View file

@ -26,8 +26,8 @@ Feature: Checkout taxation
| zone | name |
| UK | DHL Express |
And the following payment methods exist:
| name | gateway | enabled |
| Credit Card | stripe | yes |
| name | gateway | enabled |
| Dummy | dummy | yes |
And I am logged in user
And I added product "PHP Top" to cart
And I go to the checkout start page
@ -37,7 +37,7 @@ Feature: Checkout taxation
And I press "Continue"
And I select the "DHL Express" radio button
And I press "Continue"
And I select the "Credit Card" radio button
And I select the "Dummy" radio button
When I press "Continue"
Then I should be on the checkout finalize step
And "Tax total: 37.50" should appear on the page

View file

@ -52,6 +52,7 @@ class CheckoutProcessScenario implements ProcessScenarioInterface
->add('shipping', 'sylius_checkout_shipping')
->add('payment', 'sylius_checkout_payment')
->add('finalize', 'sylius_checkout_finalize')
->add('purchase', 'sylius_checkout_purchase')
;
$builder

View file

@ -13,6 +13,7 @@ namespace Sylius\Bundle\CoreBundle\Checkout\Step;
use Sylius\Bundle\CoreBundle\Checkout\SyliusCheckoutEvents;
use Sylius\Bundle\CoreBundle\Model\OrderInterface;
use Sylius\Bundle\CoreBundle\Model\Order;
use Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface;
use Sylius\Bundle\SalesBundle\SyliusOrderEvents;
@ -45,10 +46,6 @@ class FinalizeStep extends CheckoutStep
$order->setUser($this->getUser());
$this->completeOrder($order);
$this->getCartProvider()->abandonCart();
$translator = $this->get('translator');
$this->get('session')->getFlashBag()->add('success', $translator->trans('sylius.checkout.success', array(), 'flashes'));
return $this->complete();
}

View file

@ -25,9 +25,9 @@ class LoadPaymentMethodsData extends DataFixture
*/
public function load(ObjectManager $manager)
{
$manager->persist($this->createPaymentMethod('Test Credit Card', 'dummy'));
$manager->persist($this->createPaymentMethod('Stripe', 'dummy'));
$manager->persist($this->createPaymentMethod('Disabled Payment method', 'dummy'), false);
$manager->persist($this->createPaymentMethod('Dummy', 'dummy'));
$manager->persist($this->createPaymentMethod('Paypal Express Checkout', 'paypal_express_checkout'));
$manager->persist($this->createPaymentMethod('Stripe', 'stripe'));
$manager->flush();
}

View file

@ -50,6 +50,7 @@ class CheckoutProcessScenarioSpec extends ObjectBehavior
$builder->add('shipping', 'sylius_checkout_shipping')->willReturn($builder)->shouldBeCalled();
$builder->add('payment', 'sylius_checkout_payment')->willReturn($builder)->shouldBeCalled();
$builder->add('finalize', 'sylius_checkout_finalize')->willReturn($builder)->shouldBeCalled();
$builder->add("purchase", "sylius_checkout_purchase")->willReturn($builder)->shouldBeCalled();
$builder->setDisplayRoute('sylius_checkout_display')->willReturn($builder)->shouldBeCalled();
$builder->setForwardRoute('sylius_checkout_forward')->willReturn($builder)->shouldBeCalled();

View file

@ -83,15 +83,21 @@ class Payment implements PaymentInterface
*/
protected $updatedAt;
/**
* @var array
*/
protected $details;
/**
* Constructor.
*/
public function __construct()
{
$this->amount = 0;
$this->state = PaymentInterface::STATE_PENDING;
$this->state = PaymentInterface::STATE_NEW;
$this->logs = new ArrayCollection();
$this->createdAt = new \DateTime('now');
$this->details = array();
}
/**
@ -275,4 +281,20 @@ class Payment implements PaymentInterface
return $this;
}
/**
* @param array $details
*/
public function setDetails(array $details)
{
$this->details = $details;
}
/**
* @return array
*/
public function getDetails()
{
return $this->details;
}
}

View file

@ -27,6 +27,8 @@ interface PaymentInterface extends TimestampableInterface
const STATE_FAILED = 'failed';
const STATE_VOID = 'void';
const STATE_COMPLETED = 'completed';
const STATE_NEW = 'new';
const STATE_UNKNOWN = 'unknown';
/**
* Get payment method associated with this payment.
@ -127,4 +129,14 @@ interface PaymentInterface extends TimestampableInterface
* @param PaymentLogInterface $log
*/
public function removeLog(PaymentLogInterface $log);
/**
* @param array $details
*/
public function setDetails(array $details);
/**
* @return array
*/
public function getDetails();
}

View file

@ -26,6 +26,7 @@
<field name="currency" column="currency" type="string" />
<field name="amount" column="amount" type="integer" />
<field name="state" column="state" type="string" />
<field name="details" column="details" type="json_array" />
<many-to-one field="creditCard" target-entity="Sylius\Bundle\PaymentsBundle\Model\CreditCardInterface">
<join-column name="credit_card_id" referenced-column-name="id" nullable="true" on-delete="SET NULL" />

View file

@ -94,9 +94,9 @@ class PaymentSpec extends ObjectBehavior
$this->getAmount()->shouldReturn(4999);
}
function it_has_pending_state_by_default()
function it_has_new_state_by_default()
{
$this->getState()->shouldReturn(PaymentInterface::STATE_PENDING);
$this->getState()->shouldReturn(PaymentInterface::STATE_NEW);
}
function its_state_is_mutable()

View file

@ -0,0 +1,5 @@
vendor/
bin/
composer.phar
composer.lock

View file

@ -0,0 +1,120 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Checkout\Step;
use Payum\Bundle\PayumBundle\Security\TokenFactory;
use Payum\Registry\RegistryInterface;
use Payum\Security\HttpRequestVerifierInterface;
use Sylius\Bundle\CoreBundle\Checkout\Step\CheckoutStep;
use Sylius\Bundle\CoreBundle\Model\OrderInterface;
use Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface;
use Sylius\Bundle\PayumBundle\Payum\Request\StatusRequest;
use Symfony\Component\HttpFoundation\RedirectResponse;
class PurchaseStep extends CheckoutStep
{
/**
* {@inheritdoc}
*/
public function displayAction(ProcessContextInterface $context)
{
$order = $this->getCurrentCart();
$captureToken = $this->getTokenFactory()->createCaptureToken(
$order->getPayment()->getMethod()->getGateway(),
$order,
'sylius_checkout_forward',
array('stepName' => $this->getName())
);
return new RedirectResponse($captureToken->getTargetUrl());
}
/**
* {@inheritdoc}
*/
public function forwardAction(ProcessContextInterface $context)
{
$token = $this->getHttpRequestVerifier()->verify($this->getRequest());
$this->getHttpRequestVerifier()->invalidate($token);
$this->getCartProvider()->abandonCart();
$payment = $this->getPayum()->getPayment($token->getPaymentName());
$status = new StatusRequest($token);
$payment->execute($status);
/** @var OrderInterface $order */
$order = $status->getModel();
if (!$order instanceof OrderInterface) {
throw new \RuntimeException(sprintf('Expected order to be set as model but it is %s', get_class($order)));
}
$order->getPayment()->setState($status->getStatus());
if ($status->isSuccess()) {
$type = 'success';
$msg = 'sylius.checkout.success';
} elseif ($status->isPending()) {
$type = 'notice';
$msg = 'sylius.checkout.pending';
} elseif ($status->isCanceled()) {
$type = 'notice';
$msg = 'sylius.checkout.canceled';
} elseif ($status->isExpired()) {
$type = 'notice';
$msg = 'sylius.checkout.expired';
} elseif ($status->isSuspended()) {
$type = 'notice';
$msg = 'sylius.checkout.suspended';
} elseif ($status->isFailed()) {
$type = 'error';
$msg = 'sylius.checkout.failed';
} else {
$type = 'error';
$msg = 'sylius.checkout.unknown';
}
//TODO: an event here
$this->getDoctrine()->getManager()->flush();
$this->get('session')->getFlashBag()->add($type, $this->get('translator')->trans($msg, array(), 'flashes'));
return $this->complete();
}
/**
* @return RegistryInterface
*/
protected function getPayum()
{
return $this->get('payum');
}
/**
* @return TokenFactory
*/
protected function getTokenFactory()
{
return $this->get('payum.security.token_factory');
}
/**
* @return HttpRequestVerifierInterface
*/
protected function getHttpRequestVerifier()
{
return $this->get('payum.security.http_request_verifier');
}
}

View file

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('sylius_payum');
$rootNode
->addDefaultsIfNotSet()
->children()
->scalarNode('driver')->cannotBeOverwritten()->isRequired()->cannotBeEmpty()->end()
->end()
;
$this->addClassesSection($rootNode);
return $treeBuilder;
}
/**
* Adds `classes` section.
*
* @param ArrayNodeDefinition $node
*/
private function addClassesSection(ArrayNodeDefinition $node)
{
$node
->children()
->arrayNode('classes')
->addDefaultsIfNotSet()
->children()
->arrayNode('payment_security_token')
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->defaultValue('Sylius\\Bundle\\PayumBundle\\Model\\PaymentSecurityToken')->end()
->end()
->end()
->end()
->end()
->end()
;
}
}

View file

@ -0,0 +1,73 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\DependencyInjection;
use Sylius\Bundle\PayumBundle\SyliusPayumBundle;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
class SyliusPayumExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $config, ContainerBuilder $container)
{
$processor = new Processor();
$configuration = new Configuration();
$config = $processor->processConfiguration($configuration, $config);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$driver = $config['driver'];
if (!in_array($driver, SyliusPayumBundle::getSupportedDrivers())) {
throw new \InvalidArgumentException(sprintf('Driver "%s" is unsupported for SyliusPayumBundle', $driver));
}
$loader->load(sprintf('driver/%s.xml', $driver));
$container->setParameter('sylius_payum.driver', $driver);
$container->setParameter('sylius_payum.driver.'.$driver, true);
$loader->load('services.xml');
$classes = $config['classes'];
$this->mapClassParameters($classes, $container);
if ($container->hasParameter('sylius.config.classes')) {
$classes = array_merge($classes, $container->getParameter('sylius.config.classes'));
}
$container->setParameter('sylius.config.classes', $classes);
}
/**
* Remap class parameters.
*
* @param array $classes
* @param ContainerBuilder $container
*/
protected function mapClassParameters(array $classes, ContainerBuilder $container)
{
foreach ($classes as $model => $serviceClasses) {
foreach ($serviceClasses as $service => $class) {
$service = $service === 'form' ? 'form.type' : $service;
$container->setParameter(sprintf('sylius.%s.%s.class', $service, $model), $class);
}
}
}
}

View file

@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Model;
use Payum\Model\Token;
class PaymentSecurityToken extends Token
{
}

View file

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Action;
use Payum\Action\PaymentAwareAction;
use Payum\Exception\RequestNotSupportedException;
use Payum\Request\CaptureRequest;
use Sylius\Bundle\CoreBundle\Model\OrderInterface;
class CaptureOrderWithDummyAction extends PaymentAwareAction
{
/**
* {@inheritDoc}
*/
public function execute($request)
{
/** @var $request CaptureRequest */
if (!$this->supports($request)) {
throw RequestNotSupportedException::createActionNotSupported($this, $request);
}
/** @var OrderInterface $order */
$order = $request->getModel();
$paymentDetails = $order->getPayment()->getDetails();
if (empty($paymentDetails)) {
$order->getPayment()->setDetails(array(
'captured' => true,
));
}
}
/**
* {@inheritDoc}
*/
public function supports($request)
{
return
$request instanceof CaptureRequest &&
$request->getModel() instanceof OrderInterface
;
}
}

View file

@ -0,0 +1,81 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Action;
use Payum\Action\PaymentAwareAction;
use Payum\Bridge\Spl\ArrayObject;
use Payum\Exception\RequestNotSupportedException;
use Payum\Request\CaptureRequest;
use Payum\Request\SecuredCaptureRequest;
use Sylius\Bundle\CoreBundle\Model\OrderInterface;
class CaptureOrderWithPaypalAction extends PaymentAwareAction
{
/**
* {@inheritDoc}
*/
public function execute($request)
{
/** @var $request SecuredCaptureRequest */
if (!$this->supports($request)) {
throw RequestNotSupportedException::createActionNotSupported($this, $request);
}
/** @var OrderInterface $order */
$order = $request->getModel();
$paymentDetails = $order->getPayment()->getDetails();
if (empty($paymentDetails)) {
$paymentDetails['RETURNURL'] = $request->getToken()->getTargetUrl();
$paymentDetails['CANCELURL'] = $request->getToken()->getTargetUrl();
$paymentDetails['INVNUM'] = $order->getNumber();
$paymentDetails['PAYMENTREQUEST_0_CURRENCYCODE'] = $order->getCurrency();
$paymentDetails['PAYMENTREQUEST_0_AMT'] = number_format(($order->getTotal() + $order->getShippingTotal()) / 100, 2);
$paymentDetails['PAYMENTREQUEST_0_ITEMAMT'] = number_format($order->getItemsTotal() / 100, 2);
$paymentDetails['PAYMENTREQUEST_0_TAXAMT'] = number_format($order->getTaxTotal() / 100, 2);
$paymentDetails['PAYMENTREQUEST_0_SHIPPINGAMT'] = number_format($order->getShippingTotal() / 100, 2);
$m = 0;
foreach ($order->getItems() as $item) {
$paymentDetails['L_PAYMENTREQUEST_0_AMT'.$m] = number_format($item->getTotal() / 100, 2);
$paymentDetails['L_PAYMENTREQUEST_0_QTY'.$m] = $item->getQuantity();
$m++;
}
}
// TODO: find a way to simply the next logic
$paymentDetails = ArrayObject::ensureArrayObject($paymentDetails);
try {
$this->payment->execute(new CaptureRequest($paymentDetails));
$order->getPayment()->setDetails((array) $paymentDetails);
} catch (\Exception $e) {
$order->getPayment()->setDetails((array) $paymentDetails);
throw $e;
}
}
/**
* {@inheritDoc}
*/
public function supports($request)
{
return
$request instanceof SecuredCaptureRequest &&
$request->getModel() instanceof OrderInterface
;
}
}

View file

@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Action;
use Payum\Action\PaymentAwareAction;
use Payum\Bridge\Spl\ArrayObject;
use Payum\Exception\RequestNotSupportedException;
use Payum\Request\CaptureRequest;
use Payum\Request\SecuredCaptureRequest;
use Sylius\Bundle\CoreBundle\Model\OrderInterface;
use Sylius\Bundle\PayumBundle\Payum\Request\ObtainCreditCardRequest;
class CaptureOrderWithStripeAction extends PaymentAwareAction
{
/**
* {@inheritdoc}
*/
public function execute($request)
{
/** @var $request SecuredCaptureRequest */
if (!$this->supports($request)) {
throw RequestNotSupportedException::createActionNotSupported($this, $request);
}
/** @var OrderInterface $order */
$order = $request->getModel();
$paymentDetails = $order->getPayment()->getDetails();
if (empty($paymentDetails)) {
$this->payment->execute($obtainCreditCardRequest = new ObtainCreditCardRequest($order));
$paymentDetails = array(
'card' => array(
'number' => $obtainCreditCardRequest->getCreditCard()->getNumber(),
'expiryMonth' => $obtainCreditCardRequest->getCreditCard()->getExpiryMonth(),
'expiryYear' => $obtainCreditCardRequest->getCreditCard()->getExpiryYear(),
'cvv' => $obtainCreditCardRequest->getCreditCard()->getSecurityCode()
),
'amount' => number_format($order->getTotal() / 100, 2),
'currency' => $order->getCurrency(),
);
}
// TODO: find a way to simply the next logic
$paymentDetails = ArrayObject::ensureArrayObject($paymentDetails);
try {
$this->payment->execute(new CaptureRequest($paymentDetails));
unset($paymentDetails['card']);
$order->getPayment()->setDetails((array) $paymentDetails);
} catch (\Exception $e) {
unset($paymentDetails['card']);
$order->getPayment()->setDetails((array) $paymentDetails);
throw $e;
}
}
/**
* {@inheritdoc}
*/
public function supports($request)
{
return
$request instanceof SecuredCaptureRequest &&
$request->getModel() instanceof OrderInterface
;
}
}

View file

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Action;
use Payum\Action\PaymentAwareAction;
use Payum\Exception\RequestNotSupportedException;
use Payum\Request\StatusRequestInterface;
use Sylius\Bundle\CoreBundle\Model\Order;
class DummyOrderStatusAction extends PaymentAwareAction
{
/**
* {@inheritDoc}
*/
public function execute($request)
{
/** @var $request StatusRequestInterface */
if (!$this->supports($request)) {
throw RequestNotSupportedException::createActionNotSupported($this, $request);
}
/** @var Order $order */
$order = $request->getModel();
$paymentDetails = $order->getPayment()->getDetails();
if (empty($paymentDetails)) {
$request->markNew();
return;
}
if (isset($paymentDetails['captured'])) {
$request->markSuccess();
return;
}
$request->markUnknown();
}
/**
* {@inheritDoc}
*/
public function supports($request)
{
return
$request instanceof StatusRequestInterface &&
$request->getModel() instanceof Order
;
}
}

View file

@ -0,0 +1,102 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Action;
use Payum\Action\ActionInterface;
use Payum\Bundle\PayumBundle\Request\ResponseInteractiveRequest;
use Payum\Exception\LogicException;
use Payum\Exception\RequestNotSupportedException;
use Sylius\Bundle\PayumBundle\Payum\Request\ObtainCreditCardRequest;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Templating\EngineInterface;
class ObtainCreditCardAction implements ActionInterface
{
/**
* @var FormFactoryInterface
*/
protected $formFactory;
/**
* @var EngineInterface
*/
protected $templating;
/**
* @var Request
*/
protected $httpRequest;
/**
* @param FormFactoryInterface $formFactory
* @param EngineInterface $templating
*/
public function __construct(FormFactoryInterface $formFactory, EngineInterface $templating)
{
$this->formFactory = $formFactory;
$this->templating = $templating;
}
/**
* @param Request $request
*/
public function setRequest(Request $request = null)
{
$this->httpRequest = $request;
}
/**
* {@inheritDoc}
*/
public function execute($request)
{
/** @var $request ObtainCreditCardRequest */
if (!$this->supports($request)) {
throw RequestNotSupportedException::createActionNotSupported($this, $request);
}
if (!$this->httpRequest) {
throw new LogicException('The action can be run only when http request is set.');
}
$form = $this->createCreditCardForm();
$form->handleRequest($this->httpRequest);
if ($form->isValid()) {
$request->setCreditCard($form->getData());
return;
}
throw new ResponseInteractiveRequest(new Response(
$this->templating->render('SyliusPayumBundle::Payum\Action\obtainCreditCard.html.twig', array(
'form' => $form->createView()
))
));
}
/**
* {@inheritDoc}
*/
public function supports($request)
{
return $request instanceof ObtainCreditCardRequest;
}
/**
* @return \Symfony\Component\Form\Form
*/
protected function createCreditCardForm()
{
return $this->formFactory->create('sylius_credit_card');
}
}

View file

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Action;
use Payum\Action\PaymentAwareAction;
use Payum\Exception\RequestNotSupportedException;
use Payum\Request\StatusRequestInterface;
use Sylius\Bundle\CoreBundle\Model\OrderInterface;
class OrderStatusAction extends PaymentAwareAction
{
/**
* {@inheritDoc}
*/
public function execute($request)
{
/** @var $request StatusRequestInterface */
if (!$this->supports($request)) {
throw RequestNotSupportedException::createActionNotSupported($this, $request);
}
/** @var OrderInterface $order */
$order = $request->getModel();
if ($order->getPayment()->getDetails()) {
$request->setModel($order->getPayment()->getDetails());
$this->payment->execute($request);
$request->setModel($order);
} else {
$request->markNew();
}
}
/**
* {@inheritDoc}
*/
public function supports($request)
{
return
$request instanceof StatusRequestInterface &&
$request->getModel() instanceof OrderInterface
;
}
}

View file

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Request;
use Sylius\Bundle\PaymentsBundle\Model\CreditCardInterface;
use Sylius\Bundle\SalesBundle\Model\OrderInterface;
class ObtainCreditCardRequest
{
/**
* @var OrderInterface
*/
private $order;
/**
* @var CreditCardInterface
*/
protected $creditCard;
/**
* @param OrderInterface $order
*/
public function __construct(OrderInterface $order)
{
$this->order = $order;
}
/**
* @return OrderInterface
*/
public function getOrder()
{
return $this->order;
}
/**
* @param CreditCardInterface $creditCard
*/
public function setCreditCard(CreditCardInterface $creditCard)
{
$this->creditCard = $creditCard;
}
/**
* @return CreditCardInterface
*/
public function getCreditCard()
{
return $this->creditCard;
}
}

View file

@ -0,0 +1,146 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle\Payum\Request;
use Payum\Request\BaseStatusRequest;
use Sylius\Bundle\PaymentsBundle\Model\PaymentInterface;
class StatusRequest extends BaseStatusRequest
{
/**
* {@inheritdoc}
*/
public function markNew()
{
$this->status = PaymentInterface::STATE_NEW;
}
/**
* {@inheritdoc}
*/
public function isNew()
{
return $this->status === PaymentInterface::STATE_NEW;
}
/**
* {@inheritdoc}
*/
public function markSuccess()
{
$this->status = PaymentInterface::STATE_COMPLETED;
}
/**
* {@inheritdoc}
*/
public function isSuccess()
{
return $this->status === PaymentInterface::STATE_COMPLETED;
}
/**
* {@inheritdoc}
*/
public function markSuspended()
{
$this->status = PaymentInterface::STATE_VOID;
}
/**
* {@inheritdoc}
*/
public function isSuspended()
{
return $this->status === PaymentInterface::STATE_VOID;
}
/**
* {@inheritdoc}
*/
public function markExpired()
{
$this->status = PaymentInterface::STATE_FAILED;
}
/**
* {@inheritdoc}
*/
public function isExpired()
{
return $this->status === PaymentInterface::STATE_FAILED;
}
/**
* {@inheritdoc}
*/
public function markCanceled()
{
$this->status = PaymentInterface::STATE_VOID;
}
/**
* {@inheritdoc}
*/
public function isCanceled()
{
return $this->status === PaymentInterface::STATE_VOID;
}
/**
* {@inheritdoc}
*/
public function markPending()
{
$this->status = PaymentInterface::STATE_PENDING;
}
/**
* {@inheritdoc}
*/
public function isPending()
{
return $this->status === PaymentInterface::STATE_PENDING;
}
/**
* {@inheritdoc}
*/
public function markFailed()
{
$this->status = PaymentInterface::STATE_FAILED;
}
/**
* {@inheritdoc}
*/
public function isFailed()
{
return $this->status === PaymentInterface::STATE_FAILED;
}
/**
* {@inheritdoc}
*/
public function markUnknown()
{
$this->status = PaymentInterface::STATE_UNKNOWN;
}
/**
* {@inheritdoc}
*/
public function isUnknown()
{
return $this->status === PaymentInterface::STATE_UNKNOWN;
}
}

View file

@ -0,0 +1,4 @@
SyliusPayumBundle
=================
Provide payum integration for sylius.

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"
>
<mapped-superclass name="Sylius\Bundle\PayumBundle\Model\PaymentSecurityToken" table="sylius_payment_security_token">
<id name="hash" column="hash" type="string" />
<field name="details" column="details" type="object" nullable="true" />
<field name="afterUrl" column="after_url" type="text" nullable="true" />
<field name="targetUrl" column="target_url" type="text" nullable="false" />
<field name="paymentName" column="payment_name" type="string" length="255" nullable="false" />
</mapped-superclass>
</doctrine-mapping>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
This file is part of the Sylius package.
(c) Paweł Jędrzejewski
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
-->
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="sylius.repository.payment_security_token.class">Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository</parameter>
</parameters>
<services>
<service id="sylius.manager.payment_security_token" alias="doctrine.orm.entity_manager" />
<service id="sylius.repository.payment_security_token" class="%sylius.repository.payment_security_token.class%">
<argument type="service" id="sylius.manager.payment_security_token" />
<argument type="service">
<service
factory-service="sylius.manager.payment_security_token"
factory-method="getClassMetadata"
class="Doctrine\ORM\Mapping\ClassMetadata"
>
<argument>%sylius.model.payment_security_token.class%</argument>
</service>
</argument>
</service>
</services>
</container>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is part of the Sylius package.
(c) Paweł Jędrzejewski
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
-->
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="sylius.payum.checkout_step.purchase.class">Sylius\Bundle\PayumBundle\Checkout\Step\PurchaseStep</parameter>
<parameter key="sylius.payum.action.capture_order_with_paypal.class">Sylius\Bundle\PayumBundle\Payum\Action\CaptureOrderWithPaypalAction</parameter>
<parameter key="sylius.payum.action.capture_order_with_dummy.class">Sylius\Bundle\PayumBundle\Payum\Action\CaptureOrderWithDummyAction</parameter>
<parameter key="sylius.payum.action.capture_order_with_stripe.class">Sylius\Bundle\PayumBundle\Payum\Action\CaptureOrderWithStripeAction</parameter>
<parameter key="sylius.payum.action.order_status.class">Sylius\Bundle\PayumBundle\Payum\Action\OrderStatusAction</parameter>
<parameter key="sylius.payum.action.dummy_order_status.class">Sylius\Bundle\PayumBundle\Payum\Action\DummyOrderStatusAction</parameter>
<parameter key="sylius.payum.action.obtain_credit_card.class">Sylius\Bundle\PayumBundle\Payum\Action\ObtainCreditCardAction</parameter>
</parameters>
<services>
<service id="sylius.payum.checkout_step.purchase" class="%sylius.payum.checkout_step.purchase.class%">
<call method="setContainer">
<argument type="service" id="service_container" />
</call>
<tag name="sylius.process.step" alias="sylius_checkout_purchase" />
</service>
<service id="sylius.payum.action.capture_order_with_paypal" class="%sylius.payum.action.capture_order_with_paypal.class%" />
<service id="sylius.payum.action.capture_order_with_stripe" class="%sylius.payum.action.capture_order_with_stripe.class%" />
<service id="sylius.payum.action.order_status" class="%sylius.payum.action.order_status.class%" />
<service id="sylius.payum.action.obtain_credit_card" class="%sylius.payum.action.obtain_credit_card.class%" >
<argument type="service" id="form.factory" />
<argument type="service" id="templating" />
<call method="setRequest">
<argument type="service" id="request" on-invalid="null" strict="false" />
</call>
</service>
<!-- dummy -->
<service id="sylius.payum.action.capture_order_with_dummy" class="%sylius.payum.action.capture_order_with_dummy.class%" />
<service id="sylius.payum.action.dummy_order_status" class="%sylius.payum.action.dummy_order_status.class%" />
</services>
</container>

View file

@ -0,0 +1,19 @@
Copyright (c) 2011-2013 Paweł Jędrzejewski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,24 @@
{% extends 'SyliusWebBundle:Frontend:layout.html.twig' %}
{% block content %}
<div class="page-header">
<h1>{{ 'sylius.checkout.credit_card.header'|trans|raw }}</h1>
</div>
<form method="post" class="form-horizontal" novalidate>
{{ form_errors(form) }}
<fieldset>
{{ form_widget(form) }}
</fieldset>
{{ form_widget(form._token) }}
<div class="form-actions">
<a href="{{ path('sylius_cart_summary') }}" class="btn btn-lg"><i class="icon-chevron-left"></i> {{ 'sylius.checkout.back'|trans }}</a> &nbsp;
<button type="submit" class="btn btn-primary btn-lg">{{ 'sylius.checkout.forward'|trans }} <i class="icon-chevron-right"></i></button>
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\PayumBundle;
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Compiler\ResolveDoctrineTargetEntitiesPass;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class SyliusPayumBundle extends Bundle
{
/**
* Return array with currently supported drivers.
*
* @return array
*/
public static function getSupportedDrivers()
{
return array(
SyliusResourceBundle::DRIVER_DOCTRINE_ORM
);
}
/**
* {@inheritdoc}
*/
public function build(ContainerBuilder $container)
{
$interfaces = array(
'Payum\Security\TokenInterface' => 'sylius.model.payment_security_token.class',
);
$container->addCompilerPass(new ResolveDoctrineTargetEntitiesPass('sylius_payum', $interfaces));
$mappings = array(
realpath(__DIR__ . '/Resources/config/doctrine/model') => 'Sylius\Bundle\PayumBundle\Model',
);
$container->addCompilerPass(DoctrineOrmMappingsPass::createXmlMappingDriver($mappings, array('doctrine.orm.entity_manager'), 'sylius_payum.driver.doctrine/orm'));
}
}

View file

@ -0,0 +1,40 @@
{
"name": "sylius/payum-bundle",
"type": "symfony-bundle",
"description": "Payum integration for Symfony2 e-commerce applications.",
"keywords": ["payments", "payment", "payum"],
"homepage": "http://sylius.com",
"license": "MIT",
"authors": [
{
"name": "Kotlyar Maksim",
"email": "kotlyar.maksim@gmail.com",
},
{
"name": "Community contributions",
"homepage": "https://github.com/Sylius/SyliusPaymentsBundle/contributors"
}
],
"require": {
"php": ">=5.3.3",
"sylius/sales-bundle": "1.0.*@dev",
"sylius/core-bundle": "1.0.*@dev",
"sylius/payments-bundle": "1.0.*@dev",
"sylius/resource-bundle": "1.0.*@dev",
"payum/payum-bundle": "0.6.*@dev",
"payum/payum": "0.6.*@dev"
},
"config": {
"bin-dir": "bin"
},
"autoload": {
"psr-0": { "Sylius\\Bundle\\PayumBundle": "" }
},
"target-dir": "Sylius/Bundle/PayumBundle",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace spec\Sylius\Bundle\PayumBundle\Model;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class PaymentSecurityTokenSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Bundle\PayumBundle\Model\PaymentSecurityToken');
}
function it_extends_payum_token()
{
$this->shouldHaveType('Payum\Model\Token');
}
}

View file

@ -0,0 +1,103 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\PayumBundle\Payum\Action;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class OrderStatusActionSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Bundle\PayumBundle\Payum\Action\OrderStatusAction');
}
function it_extends_payum_payment_aware_action()
{
$this->shouldHaveType('Payum\Action\PaymentAwareAction');
}
/**
* @param Sylius\Bundle\CoreBundle\Model\OrderInterface $order
* @param Payum\Request\StatusRequestInterface $statusRequest
*/
function it_should_support_status_request_with_order_model($order, $statusRequest)
{
$statusRequest->getModel()->willReturn($order);
$this->supports($statusRequest)->shouldReturn(true);
}
/**
* @param Payum\Request\StatusRequestInterface $statusRequest
*/
function it_should_not_support_status_request_with_no_order_model($statusRequest)
{
$statusRequest->getModel()->willReturn('foo');
$this->supports($statusRequest)->shouldReturn(false);
}
function it_should_not_support_any_no_status_requests()
{
$this->supports('foo')->shouldReturn(false);
}
function it_throws_exception_if_executing_not_supported_request()
{
$notSupportedRequest = 'foo';
$this
->shouldThrow('Payum\Exception\RequestNotSupportedException')
->duringExecute($notSupportedRequest)
;
}
/**
* @param Sylius\Bundle\CoreBundle\Model\OrderInterface $order
* @param Sylius\Bundle\PaymentsBundle\Model\PaymentInterface $payment
* @param Payum\Request\StatusRequestInterface $statusRequest
*/
function it_should_mark_new_if_order_have_empty_payment_details($order, $payment, $statusRequest)
{
$statusRequest->getModel()->willReturn($order);
$statusRequest->markNew()->shouldBeCalled();
$order->getPayment()->willReturn($payment);
$payment->getDetails()->willReturn(array());
$this->execute($statusRequest);
}
/**
* @param Sylius\Bundle\CoreBundle\Model\OrderInterface $order
* @param Sylius\Bundle\PaymentsBundle\Model\PaymentInterface $payment
* @param Payum\Request\StatusRequestInterface $statusRequest
* @param Payum\PaymentInterface $payment
*/
function it_should_do_status_subrequest_with_payment_details_as_model($order, $payment, $statusRequest, $payment)
{
$details = array('foo' => 'foo', 'bar' => 'baz');
$statusRequest->getModel()->willReturn($order);
$statusRequest->setModel($details)->shouldBeCalled();
$statusRequest->setModel($order)->shouldBeCalled();
$payment->execute($statusRequest)->shouldBeCalled();
$order->getPayment()->willReturn($payment);
$payment->getDetails()->willReturn($details);
$this->setPayment($payment);
$this->execute($statusRequest);
}
}

View file

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\PayumBundle\Payum\Request;
use PhpSpec\ObjectBehavior;
class ObtainCreditCardRequestSpec extends ObjectBehavior
{
/**
* @param Sylius\Bundle\CoreBundle\Model\OrderInterface $order
*/
function let($order)
{
$this->beConstructedWith($order);
}
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Bundle\PayumBundle\Payum\Request\ObtainCreditCardRequest');
}
/**
* @param Sylius\Bundle\CoreBundle\Model\OrderInterface $order
*/
function it_should_allow_get_order_set_in_constructor($order)
{
$this->getOrder()->shouldReturn($order);
}
/**
* @param Sylius\Bundle\PaymentsBundle\Model\CreditCardInterface $creditCard
*/
function it_should_allow_get_credit_card_set_before($creditCard)
{
$this->setCreditCard($creditCard);
$this->getCreditCard()->shouldReturn($creditCard);
}
}

View file

@ -0,0 +1,146 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace spec\Sylius\Bundle\PayumBundle\Payum\Request;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\PaymentsBundle\Model\PaymentInterface;
class StatusRequestSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(new \stdClass);
}
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Bundle\PayumBundle\Payum\Request\StatusRequest');
}
function it_extends_base_status_class()
{
$this->shouldHaveType('Payum\Request\BaseStatusRequest');
}
function it_is_new_when_marked_as_new()
{
$this->markNew();
$this->isNew()->shouldReturn(true);
}
function it_is_return_new_status_when_marked_as_new()
{
$this->markNew();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_NEW);
}
function it_is_success_when_marked_as_success()
{
$this->markSuccess();
$this->isSuccess()->shouldReturn(true);
}
function it_is_return_completed_status_when_marked_as_success()
{
$this->markSuccess();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_COMPLETED);
}
function it_is_pending_when_marked_as_pending()
{
$this->markPending();
$this->isPending()->shouldReturn(true);
}
function it_is_return_pending_status_when_marked_as_pending()
{
$this->markPending();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_PENDING);
}
function it_is_failed_when_marked_as_failed()
{
$this->markFailed();
$this->isFailed()->shouldReturn(true);
}
function it_is_return_failed_status_when_marked_as_failed()
{
$this->markFailed();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_FAILED);
}
function it_is_canceled_when_marked_as_canceled()
{
$this->markCanceled();
$this->isCanceled()->shouldReturn(true);
}
function it_is_return_void_status_when_marked_as_canceled()
{
$this->markCanceled();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_VOID);
}
function it_is_suspended_when_marked_as_suspended()
{
$this->markSuspended();
$this->isSuspended()->shouldReturn(true);
}
function it_is_return_void_status_when_marked_as_suspended()
{
$this->markSuspended();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_VOID);
}
function it_is_expired_when_marked_as_expired()
{
$this->markExpired();
$this->isExpired()->shouldReturn(true);
}
function it_is_return_failed_status_when_marked_as_expired()
{
$this->markExpired();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_FAILED);
}
function it_is_unknown_when_marked_as_unknown()
{
$this->markUnknown();
$this->isUnknown()->shouldReturn(true);
}
function it_is_return_unknown_status_when_marked_as_unknown()
{
$this->markUnknown();
$this->getStatus()->shouldReturn(PaymentInterface::STATE_UNKNOWN);
}
}