karser/payum-saferpay 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

karser/payum-saferpay

Composer 安装命令:

composer require karser/payum-saferpay

包简介

Saferpay Payum plugin providing Ecommerce and Business features

README 文档

README

Build Status Scrutinizer Code Quality Code Coverage Total Downloads

Introduction

This plugin implements Saferpay specification v1.10, including all features from e-commerce and business licenses. Saferpay e-commerce license provides access to Payment Page interface only. Saferpay Business license provides Transaction Interface, recurring payments, storing cards aliases and etc. For more detailed comparison please refer to Licensing options and Supported payment methods per interface.

Transaction Interface provides two options: an iframe (similar to Payment Page) and submitting the card data directly. The last option is available only if you are PCI compliant.

Here is how Payment Page interface looks like:

Here is how Transaction interface looks like:

Requirements

Features

This plugin supports

All features are covered with tests. You can find useful examples in functional tests.

Installation

$ composer require karser/payum-saferpay

Configuration

With PayumBundle (Symfony)

First register the gateway factory in your services definition:

# config/services.yaml or app/config/services.yml
services:
    app.saferpay.gateway_factory:
        class: Payum\Core\Bridge\Symfony\Builder\GatewayFactoryBuilder
        arguments: [Karser\PayumSaferpay\SaferpayGatewayFactory]
        tags:
            - { name: payum.gateway_factory_builder, factory: saferpay }

Then configure the gateway:

You can use General test account credentials or create personal test account here

# config/packages/payum.yaml or app/config/config.yml

payum:
    gateways:
        saferpay:
            factory: saferpay
            # this is test credentials
            username: 'API_401860_80003225'
            password: 'C-y*bv8346Ze5-T8'
            customerId: '401860'
            terminalId: '17795278'
            interface: 'TRANSACTION' #optionally, can be defined via details too
            optionalParameters: #optionally, add some additional interface options, read more below in section "Additional Configuration"
                styling_css_url: 'https://acme.com/hosted-page-styles.css'
            sandbox: true

With Payum

//config.php

use Payum\Core\GatewayFactoryInterface;
use Payum\Core\PayumBuilder;
use Payum\Core\Payum;
use Karser\PayumSaferpay\SaferpayGatewayFactory;

/** @var Payum $payum */
$payum = (new PayumBuilder())
    ->addDefaultStorages()
    ->addGatewayFactory('saferpay', static function(array $config, GatewayFactoryInterface $coreGatewayFactory) {
        return new SaferpayGatewayFactory($config, $coreGatewayFactory);
    })
    ->addGateway('saferpay', [
        'factory' => 'saferpay',
        # this is test credentials
        'username' => 'API_401860_80003225',
        'password' => 'C-y*bv8346Ze5-T8',
        'customerId' => '401860',
        'terminalId' => '17795278',
        'interface' => 'TRANSACTION', #optionally, can be defined via details too
        'sandbox' => true,
    ])
    ->getPayum()
;

Configure the routes

You can include the default Payum Bundle's routes, although only these routes are actually required by this plugin:

#config/routes.yaml
payum_capture_do:
    path: /payment/capture/{payum_token}
    controller: PayumBundle:Capture:do

#notification route is required only if you use payment page interface
#payum_notify_do:
#    path: /payment/notify/{payum_token}
#    controller: PayumBundle:Notify:do

Usage

Capture example

Make sure you defined Payment and Token entities like it is described here

//capture.php

use App\Entity\Payment;
use Payum\Core\Payum;
use Payum\Core\Request\Capture;
use Karser\PayumSaferpay\Constants;

/** @var Payum $payum */
$storage = $payum->getStorage(Payment::class);
$payment = $storage->create();
$payment->setNumber(uniqid());
$payment->setCurrencyCode('USD');
$payment->setTotalAmount(123); //$1.23 USD
$payment->setDescription('test payment');

// capture using TRANSACTION interface (default)
$payment->setDetails(['Interface' => Constants::INTERFACE_TRANSACTION]);
// or capture using PAYMENT_PAGE interface
$payment->setDetails(['Interface' => Constants::INTERFACE_PAYMENT_PAGE]);

$storage->update($payment);

$token = $payum->getTokenFactory()->createCaptureToken('saferpay', $payment, 'done.php');

$captureRequest = new Capture($token);
$captureRequest->setModel($payment);
$reply = $this->gateway->execute($captureRequest, true);

//then redirect user to $reply->getUrl();
//done.php

use App\Entity\Payment;
use Payum\Core\Payum;
use Payum\Core\Request\GetHumanStatus;

/** @var Payum $payum */
$token = $payum->getHttpRequestVerifier()->verify($_GET);
$this->payum->getHttpRequestVerifier()->invalidate($token);

$payment = $payum->getStorage(Payment::class)->find($token);

$this->assertStatus(GetHumanStatus::STATUS_CAPTURED, $payment);

$this->gateway->execute($status = new GetHumanStatus($payment));

//status of the payment is in $status->getValue()

Recurring Payments with the referenced transactions Method

  1. Capture payment with Recurring or Installment option:
use Karser\PayumSaferpay\Constants;

$payment = $storage->create();

$payment->setDetails(['Payment' => ['Recurring' => ['Initial' => true]]]);
//or
$payment->setDetails(['Payment' => ['Installment' => ['Initial' => true]]]);

//then capture the payment
$captureRequest = new Capture($token);
$captureRequest->setModel($payment);
$reply = $this->gateway->execute($captureRequest, true);
//then redirect user to $reply->getUrl();
  1. Capture a new transaction by providing a reference to the previous one:
$refTransactionId = $payment->getDetails()['Transaction']['Id'];

$payment = $storage->create();

$payment->setDetails([
    'TransactionReference' => [
        'TransactionId' =>  $refTransactionId,
    ]
]);

//then capture the payment
$captureRequest = new Capture($token);
$captureRequest->setModel($payment);
$this->gateway->execute($captureRequest);

Recurring Payments using an alias

  1. Obtaining the Alias: The user will have to enter their card details in an iframe.
use Karser\PayumSaferpay\Constants;
use Karser\PayumSaferpay\Model\CardAlias;


$cardAliasStorage = $this->payum->getStorage(CardAlias::class);
$alias = $cardAliasStorage->create();
$alias->setDetails([
    'Alias' => [
        'IdGenerator' => Constants::ALIAS_ID_GENERATOR_MANUAL,
        'Id' => $generatedId = uniqid('id', true),
        'Lifetime' => 1600, //days
    ]
]);
$this->cardAliasStorage->update($alias);
$token = $this->payum->getTokenFactory()->createCaptureToken(self::GATEWAY_NAME, $cardAlias, 'done.php');

$insertCardAliasRequest = new InsertCardAlias($token);
$insertCardAliasRequest->setModel($cardAlias);
$reply = $this->gateway->execute($insertCardAliasRequest, true);
//then redirect user to $reply->getUrl();
  1. Capture a new transaction by providing an alias id:
$aliasId = $cardAlias->getDetails()['Alias']['Id'];

$payment = $storage->create();

$payment->setDetails([
    'PaymentMeans' => [
        'Alias' => [
            'Id' => $aliasId,
        ],
    ],
]);

//then capture the payment
$captureRequest = new Capture($token);
$captureRequest->setModel($payment);
$this->gateway->execute($captureRequest);

Change Payload Locale

  1. Create a custom extension (If you're using the symfony bundle):
AppBundle\Extension\ConvertPaymentExtension:
    autowire: true
    public: true
    tags:
        - { name: payum.extension, alias: saferpay_locale_extension, factory: saferpay, gateway: saferpay, prepend: false }
  1. Create service:
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Extension\Context;
use Payum\Core\Extension\ExtensionInterface;
use Payum\Core\Request\Convert;

class ConvertPaymentExtension implements ExtensionInterface
{
    public function onPostExecute(Context $context)
    {
        $action = $context->getAction();
        $previousActionClassName = get_class($action);

        if (false === stripos($previousActionClassName, 'ConvertPaymentAction')) {
            return;
        }

        /** @var Convert $request */
        $request = $context->getRequest();
        if (false === $request instanceof Convert) {
            return;
        }
        
        // do your locale logic here
        $customLocale = 'de';

        $result = ArrayObject::ensureArrayObject($request->getResult());

        $payerData = [];
        if (isset($result['Payer']) && is_array($result['Payer'])) {
            $payerData = $result['Payer'];
        }

        $payerData['LanguageCode'] = $customLocale;

        $result['Payer'] = $payerData;

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

Additional Configuration

Depending on given interface, there are several optional options available.

Example:

payum:
    gateways:
        saferpay:
            optionalParameters:
                styling_css_url: 'https://acme.com/hosted-page-styles.css'

Payment Page interface

Key Description
config_set This parameter let you define your payment page config (PPConfig) by name. If this parameters is not set, your default PPConfig will be applied if available. When the PPConfig can't be found (e.g. wrong name), the Saferpay basic style will be applied to the payment page.
payment_methods Used to restrict the means of payment which are available to the payer for this transaction. If only one payment method id is set, the payment selection step will be skipped.
wallets Used to control if wallets should be enabled on the payment selection page and to go directly to the given wallet (if exactly one wallet is filled and PaymentMethods is not set).
notification_merchant_email Email addresses to which a confirmation email will be sent to the merchants after successful authorizations.
notification_payer_email Email address to which a confirmation email will be sent to the payer after successful authorizations.
styling_css_url Deprecated
styling_content_security_enabled When enabled, then ContentSecurity/SAQ-A is requested, which leads to the CSS being loaded from the saferpay server.
styling_theme This parameter let you customize the appearance of the displayed payment pages. Per default a lightweight responsive styling will be applied.If you don't want any styling use 'NONE'.
payer_note Text which will be printed on payer's debit note. Supported by SIX Acquiring. No guarantee that it will show up on the payer's debit note, because his bank has to support it too. Please note that maximum allowed characters are rarely supported. It's usually around 10-12.

Transaction interface

Key Description
config_set This parameter let you define your payment page config (PPConfig) by name. If this parameters is not set, your default PPConfig will be applied if available. When the PPConfig can't be found (e.g. wrong name), the Saferpay basic style will be applied to the payment page.
payment_methods Used to restrict the means of payment which are available to the payer for this transaction. If only one payment method id is set, the payment selection step will be skipped.
styling_css_url Deprecated
styling_content_security_enabled When enabled, then ContentSecurity/SAQ-A is requested, which leads to the CSS being loaded from the saferpay server.
styling_theme This parameter let you customize the appearance of the displayed payment pages. Per default a lightweight responsive styling will be applied. If you don't want any styling use 'NONE'.
payer_note Text which will be printed on payer's debit note. Supported by SIX Acquiring. No guarantee that it will show up on the payer's debit note, because his bank has to support it too. Please note that maximum allowed characters are rarely supported. It's usually around 10-12.

Testing

composer update
vendor/bin/phpunit

ToDo

  • Implement separate actions: Authorize, Cancel transaction
  • Improve and add more unit tests
  • config parameters: LIABILITY_SHIFT condition

Credits

License

This plugin is under the MIT license. For the whole copyright, see the LICENSE file distributed with this source code.

karser/payum-saferpay 适用场景与选型建议

karser/payum-saferpay 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 35.12k 次下载、GitHub Stars 达 5, 最近一次更新时间为 2019 年 05 月 22 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「ecommerce」 「payment」 「saferpay」 「ipn」 「recurring payment」 「instant payment notification」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 karser/payum-saferpay 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 karser/payum-saferpay 我们能提供哪些服务?
定制开发 / 二次开发

基于 karser/payum-saferpay 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 35.12k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 5
  • 点击次数: 8
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 5
  • Watchers: 2
  • Forks: 3
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2019-05-22