toodiz/payment-sips-bundle

安装数: 2,645

依赖关系: 0

建议者: 0

安全: 0

星标: 0

关注者: 2

分支: 0

开放问题: 0

类型:symfony-bundle

v1.0.3 2017-07-12 08:49 UTC

This package is not auto-updated.

Last update: 2024-09-18 03:32:50 UTC


README

Build Status

ToodizPaymentSipsBundle 通过 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 Toodiz/payment-sips-bundle

或者在你的 composer.json 中添加以下内容,然后更新你的供应商

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

步骤 2

在你的 AppKernel 类中注册该软件包。你还需要注册 JMSPaymentCoreBundle配置它

<?php
// app/AppKernel.php

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

        // ...
    }

    // ...

步骤 3

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

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

配置

c6ril_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('c6ril_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('c6ril_payment_sips.client');

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

        $result = $this->get('c6ril_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的灵感。

许可证

c6rilPaymentSipsBundle遵循MIT许可证发布。请参阅捆绑的LICENSE文件以获取详细信息。