phcorp/payment-sips-bundle

提供访问 ATOS SIPS 解决方案的支付包

安装: 1,706

依赖项: 0

建议者: 0

安全: 0

星标: 0

关注者: 1

分支: 0

开放问题: 0

类型:symfony-bundle

v1.0.2 2015-01-29 16:49 UTC

This package is auto-updated.

Last update: 2024-09-29 04:48:49 UTC


README

Build Status SensioLabs Insight

KptivePaymentSipsBundle 通过 JMSPaymentCoreBundle 提供对 Atos Worldline SIPS 支付解决方案的访问。

以下支付服务由 Atos SIPS 提供

  • Merc@net (BNP Parisbas)
  • Cyberplus (Banque Populaire)
  • Elys Net (HSBC)
  • Scellius (La Banque Postale)
  • SogenActif (Société Générale)
  • Webaffaires (Crédit du Nord)
  • Sherlocks (LCL)
  • Citelis (Crédit Mutuel)
  • ...

这意味着这个包应该可以与它们中的任何一个无缝工作。

安装

步骤 1

运行

$ php composer.phar require kptive/payment-sips-bundle

或者在你更新供应商之前将以下内容添加到你的 composer.json

{
    "require": {
        "kptive/payment-sips-bundle": "*@dev"
    }
}

步骤 2

AppKernel 类中注册这个包。你还需要注册 JMSPaymentCoreBundle 并进行配置。

<?php
// app/AppKernel.php

    public function registerBundles()
    {
        $bundles = array(
            // ...
            new JMS\Payment\CoreBundle\JMSPaymentCoreBundle(),
            new Kptive\PaymentSipsBundle\KptivePaymentSipsBundle(),
        );

        // ...
    }

    // ...

步骤 3

将你的 SIPS 文件夹内容复制到 app/sips/。如果你想放在其他地方,只需编辑 pathfile 和二进制位置配置值(见下文)。

你还需要根据你在 pathfile 中指定的内容将你自己的标志图像复制到正确的位置。

配置

kptive_payment_sips:
    config:
        merchant_id: "082584341411111"
        merchant_country: fr
        normal_return_url: %base_url%/checkout/complete
        cancel_return_url: %base_url%/checkout/cancel
        automatic_response_url: %base_url%/checkout/notification
        pathfile: %kernel.root_dir%/config/sips/param/pathfile
        currency_code: 978
    bin:
        request_bin: %kernel.root_dir%/config/sips/bin/static/request
        response_bin: %kernel.root_dir%/config/sips/bin/static/response

用法

假设你有一个 AcmePaymentBundle,并且你用 Acme\PaymentBundle\Entity\Order 类处理你的订单

<?php

namespace Acme\PaymentBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Payment\CoreBundle\Entity\PaymentInstruction;

/**
 * @ORM\Table(name="acme_order")
 */
class Order
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="JMS\Payment\CoreBundle\Entity\PaymentInstruction")
     */
    private $paymentInstruction;

    /**
     * @ORM\Column(type="decimal", precision=10, scale=2)
     */
    private $amount;

    /**
     * @ORM\Column(type="datetime", name="payed_at", nullable=true)
     */
    private $payedAt;

    // ...

    public function getId()
    {
        return $this->id;
    }

    public function getAmount()
    {
        return $this->amount;
    }

    public function getPaymentInstruction()
    {
        return $this->paymentInstruction;
    }

    public function setPaymentInstruction(PaymentInstruction $instruction)
    {
        $this->paymentInstruction = $instruction;

        return $this;
    }

    public function getPayedAt()
    {
        return $this->payedAt;
    }

    public function setPayedAt($payedAt)
    {
        $this->payedAt = $payedAt;

        return $this;
    }

创建一个控制器,带有 details 动作。这是客户可以查看并确认订单的地方。

<?php

namespace Acme\PaymentBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use JMS\Payment\CoreBundle\Entity\PaymentInstruction;
use Acme\PaymentBundle\Entity\Order;

/**
 * @Route("/checkout")
 */
class CheckoutController extends Controller
{
    // ...

    /**
     * @Route("/details/{id}", name = "payment_details")
     * @Template()
     */
    public function detailsAction(Order $order)
    {
        $request = $this->get('request');
        $em = $this->get('doctrine')->getEntityManager();
        $router = $this->get('router');
        $ppc = $this->get('payment.plugin_controller');

        $confirm = new \StdClass();

        $form = $this->createFormBuilder($confirm)
            ->add('save', 'submit', array('label' => 'confirmer'))
            ->getForm();

        if ('POST' === $request->getMethod()) {
            $form->handleRequest($request);

            if ($form->isValid()) {
                $instruction = new PaymentInstruction($order->getAmount(), 978, 'sips');

                $ppc->createPaymentInstruction($instruction);

                $order->setPaymentInstruction($instruction);
                $em->persist($order);
                $em->flush($order);

                return new RedirectResponse($router->generate('payment_gateway', array(
                    'id' => $order->getId(),
                )));
            }
        }

        return array(
            'order' => $order,
            'form' => $form->createView()
        );
    }
}

如前一个动作所示,当用户确认订单时,我们创建一个新的 PaymentInstruction(有关其工作方式的更多信息,请参阅 JMSPaymentCoreBundle 文档)。然后,用户将被重定向到 payment_gateway 路由。这里是我们将调用 SIPS API 以显示 SIPS 信用卡选择表单的地方。

让我们实现相应的动作

    /**
     * @Route("/gateway/{id}", name="payment_gateway")
     * @Template()
     */
    public function sipsGatewayAction(Order $order)
    {
        $client = $this->get('kptive_payment_sips.client');

        $config = array(
            'amount' => $order->getAmount() * 100,
            'order_id' => $order->getId(),
        );

        $sips = $client->request($config);

        return array('sips' => $sips);
    }

在相应的视图中向用户显示表单

{# src/Acme/PaymentBundle/Resources/views/Checkout/sipsGateway.html.twig #}

{{ sips|raw }}

当用户在 SIPS 平台上完成支付工作流程后,他们将被重定向到你之前在包配置部分配置的 normal_return_url

让我们实现这个动作

    /**
     * @Route("/complete", name="payment_complete")
     * @Template()
     */
    public function completeAction(Request $request)
    {
        $data = $request->request->get('DATA');
        $em = $this->get('doctrine')->getEntityManager();
        $client = $this->get('kptive_payment_sips.client');

        $response = $client->handleResponseData($data);
        $order = $em->getRepository('KsPaymentBundle:Order')->find($response['order_id']);
        $instruction = $order->getPaymentInstruction();

        $result = $this->get('kptive_payment_sips.return_handler')->handle($instruction, $response);

        return array('order' => $order);
    }

目前,我们没有对订单做任何事情,我们只是处理了银行响应并将支付标记为有效。

JMSPaymentCoreBundle 将触发一个 payment.state_change 事件。所以我们将监听这个事件,并在 PaymentListener 中执行我们想要的任何有用的操作。

<?php

namespace Acme\PaymentBundle\EventListener;

use Doctrine\ORM\EntityManager;
use JMS\Payment\CoreBundle\PluginController\Event\PaymentStateChangeEvent;
use JMS\Payment\CoreBundle\Model\PaymentInterface;

class PaymentListener
{

    protected $entityManager;

    public function __construct(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function onPaymentStateChange(PaymentStateChangeEvent $event)
    {
        if (PaymentInterface::STATE_DEPOSITED === $event->getNewState()) {
            $order = $this
                ->entityManager
                ->getRepository('AcmePaymentBundle:Order')
                ->findOneBy(array('paymentInstruction' => $event->getPaymentInstruction()));

            $order->setPayedAt(new \DateTime());

            // Do various things with the Order here
            // ...

            $this->entityManager->persist($order);
            $this->entityManager->flush();
        }
    }
}

将其注册为一个服务

        <service id="acme_payment.payment_listener" class="Acme\PaymentBundle\EventListener\PaymentListener">
            <tag name="kernel.event_listener" event="payment.state_change" method="onPaymentStateChange" />
            <argument type="service" id="doctrine.orm.entity_manager">
        </service>

就这样!

如果你的客户没有点击银行平台的“返回”按钮,将自动向配置的 automatic_response_url 发出请求。

你可以使用与 normal_return_url 相同的 URL,或者实现自己的。

注意:这些示例没有考虑安全问题。不要忘记检查订单的所有权!

鸣谢

非常感谢 Johannes M Schmitt 的出色的 JMSPayementCoreBundle。感谢 https://github.com/Kitano/KitanoPaymentSipsBundle 提供的灵感。

许可

“KptivePaymentSipsBundle”是在MIT许可证下发布的。有关详细信息,请参阅捆绑的LICENSE文件。