otobul/epaybg-bundle

Symfony 扩展包,用于商户使用 ePay.bg 通信包。

安装: 64

依赖者: 0

建议者: 0

安全: 0

星标: 1

关注者: 3

分支: 0

公开问题: 0

类型:symfony-bundle

v1.0.6 2022-12-08 12:46 UTC

This package is auto-updated.

Last update: 2024-09-08 16:39:49 UTC


README

OtobulEpaybgBundle 是一个 symfony 扩展包,用于帮助商户处理 ePay.bg 通信包。

1. 安装

使用以下命令安装包

composer require otobul/epaybg-bundle

如果你没有使用 Symfony Flex,你还需要在 config/bundles.php 文件中启用 Otobul\EpaybgBundle\OtobulEpaybgBundle 并配置该扩展包。

2. 配置

2.1 配置扩展包

packages/otobul_epaybg.yaml 中配置扩展包

otobul_epaybg:
    # Identification number of the merchant
    min: '%env(OTOBUL_EPAYBG_MIN)%'

    # The secret word of the merchant
    secret: '%env(OTOBUL_EPAYBG_SECRET)%'

    # If true all requests will be sent to ePay.bg’s Demo System
    isDemo: '%env(bool:OTOBUL_EPAYBG_IS_DEMO)%'

使用以下命令列出默认值

php bin/console config:dump otobul_epaybg

为了正常工作,你还需要配置开发环境文件。如果你无法访问 ePay.bg 演示系统,你可以访问 https://demo.epay.bg/ 并注册以获取演示商户编号和密钥。

2.2 配置 webhook 通知

要使用 webhook 通知,你需要将 webhook 通知路由添加到你的配置中。在 config/routes/otobul_epaybg.yaml 中配置该路由

otobul_epaybg:
    resource: '@OtobulEpaybgBundle/Resources/config/routes.xml'
    prefix: /webhook/epaybg
    methods: ['POST']

新的通知 URL 将类似于:https://your-domain.com/webhook/epaybg/,在 ePay.bg 账户中添加通知 URL。

3. 使用

此扩展包提供以下功能

  • 用于处理 ePay.bg webhook 通知的控制器;
  • 可以在控制台命令或自定义控制器中使用的服务;
  • 模板函数,可以直接在模板中生成“支付”按钮和 Easypay 支付代码。

3.1 模板

3.1.1 为 WEB_LOGIN 表单生成“支付”按钮

要在模板中生成简单的 web_login “支付”按钮,你可以使用 epayWebLoginForm twig 函数。示例

{% include '@OtobulEpaybg/Form/web_login.html.twig' with {
    form: epayWebLoginForm({invoice: 1, amount: 100})
} only %}

必需参数

  • invoice:您的唯一发票号码;
  • amount:总金额(保加利亚列弗)。这是默认货币。

高级配置 web_login “支付”按钮允许您配置其他可选参数

{% include '@OtobulEpaybg/Form/web_login.html.twig' with {
    form: epayWebLoginForm({
        invoice: 1,
        amount: 100,
        returnUrl: url('your_payment_success_route'),
        cancelUrl: url('your_payment_cancel_route'),
        expDate: 'now'|date_modify('+7 day'),
        currency: 'EUR',
        description: 'Extra description max to 100 symbols',
        encoding: 'utf-8',
    }), button: 'Pay'
} only %}

可选参数

  • returnUrl:您的成功路由。ePay.bg 在成功支付后会将用户重定向到此;
  • cancelUrl:您的取消路由。ePay.bg 在取消支付后会将用户重定向到此;
  • expDate:过期日期。变量需要是 \DateTime 类型。默认为 +7 天;
  • currency:ISO 三字母货币代码。接受值为 BGN|EUR|USD;
  • description:额外描述,最多 100 个符号;
  • encoding:接受值为 utf-8 或 CP1251;
  • button:支付按钮的标签。

3.1.2 为 CREDIT_CARD 表单生成“支付”按钮

要在模板中生成简单的 credit_card “支付”按钮,你可以使用 epayCreditCardForm twig 函数。示例

{% include '@OtobulEpaybg/Form/web_login.html.twig' with {
    form: epayCreditCardForm({invoice: 1, amount: 100})
} only %}

对于高级配置,你可以使用上面相同的可选参数。

3.1.3 在模板中生成“Easypay 代码”

要在模板中生成 Easypay 代码,你可以使用 epayEasypayCode twig 函数。示例

{{ epayEasypayCode({invoice: 1, amount: 100}) }}

请注意,这将在 Easypay 服务器上执行 HTTP 请求以检索代码。请谨慎使用!推荐的方式是在控制器中生成代码并存储以供以后使用。

3.2 控制器

3.2.1 在控制器中生成“Easypay 代码”

以下是在控制器中使用 EpayManager 服务的示例用法,以检索 Easypay 支付代码。

// src/Controller/PaymentController.php

namespace App\Controller;

use Otobul\EpaybgBundle\Model\EpayPayloadData;
use Otobul\EpaybgBundle\Service\EpayManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class PaymentController extends AbstractController
{
    public function generateEasypayCode(EpayManagerInterface $epayManager)
    {
        $invoice = 1; // Generate your unique invoice number
        $amount = 100; // Total sum for payment

        $easypayCode = $epayManager->getEasypayCode(
            new EpayPayloadData($invoice, $amount)
        );

        return $this->render("payment/easypay_code.html.twig", [
            'invoice' => $invoice,
            'easypayCode' => $easypayCode,
        ]);
    }
}

3.2.2 在控制器中为 WEB_LOGIN 表单生成“支付”按钮

以下是在控制器中使用 EpayManager 服务的示例用法,以生成“支付”按钮表单。

// src/Controller/PaymentController.php

namespace App\Controller;

use Otobul\EpaybgBundle\Model\EpayPayloadData;
use Otobul\EpaybgBundle\Service\EpayManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\RouterInterface;

class PaymentController extends AbstractController
{
    public function generateEasypayCode(EpayManagerInterface $epayManager, RouterInterface $router)
    {
        $payload = EpayPayloadData::createFromArray([
            'invoice' => 1,
            'amount' => 100,
        ]);
        $returnUrl = $this->router->generate('your_payment_success_route');
        $cancelUrl = $this->router->generate('your_payment_cancel_route');

        $form = $epayManager->createWebLoginForm($payload, $returnUrl, $cancelUrl);

        return $this->render("payment/easypay_code.html.twig", [
            'form' => $form->createView(),            
        ]);
    }
}

要生成 CREDIT_CARD 表单,请使用 createCreditCardForm 函数。

3.3 事件

  • NOTIFICATION_RECEIVED:在接收到webhook通知后直接调用。监听器有机会获取原始内容。
  • NOTIFICATION_ERROR:如果webhook通知没有有效的校验和或数据,将调用此函数。监听器有机会获取错误信息。
  • NOTIFICATION_RESPONSE:在发送webhook通知响应之前直接调用。监听器有机会获取原始响应内容。
  • INVOICE_NOTIFICATION_RECEIVED:在接收到发票通知后直接调用。监听器有机会处理发票数据。
  • EASYPAY_CODE_CREATED:在接收到Easypay代码后直接调用。监听器有机会获取代码和支付数据。

针对INVOICE_NOTIFICATION_RECEIVED此事件的示例事件订阅器:该事件在接收到发票通知后直接调用。监听器有机会处理发票数据。

// src/EventSubscriber/EpayInvoiceNotificationSubscriber.php

namespace App\EventSubscriber;

use Doctrine\ORM\EntityManagerInterface;
use Otobul\EpaybgBundle\Event\OtobulEpaybgEvents;
use Otobul\EpaybgBundle\Event\InvoiceNotificationReceivedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class EpayInvoiceNotificationSubscriber implements EventSubscriberInterface
{
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public static function getSubscribedEvents()
    {
        return [
            OtobulEpaybgEvents::INVOICE_NOTIFICATION_RECEIVED => 'epayInvoiceNotification',
        ];
    }

    public function epayInvoiceNotification(InvoiceNotificationReceivedEvent $event)
    {
        // Example logic to find some entity related to this invoice.
        $order = $this->entityManager->getRepository(Order::class)->find($event->getInvoice());
        if (!$order) {
            // If invoice cannot be found. Sending back NO, so ePay.bg system stops sending notification about the invoice.
            $event->setResponseStatusNo();
            return;
        }

        // process order state below
        if($event->isPaid()) {
            // process PAID order here
        }else {
            // process DENIED or EXPIRED order here
        }

        // Sending back OK, so ePay.bg system stops sending notification about the invoice.
        $event->setResponseStatusOk();
    }
}

高级事件订阅器的示例。

// src/EventSubscriber/EpayInvoiceNotificationSubscriber.php

namespace App\EventSubscriber;

use Otobul\EpaybgBundle\Event\EasypayCodeCreatedEvent;
use Otobul\EpaybgBundle\Event\NotificationErrorEvent;
use Otobul\EpaybgBundle\Event\NotificationReceivedEvent;
use Otobul\EpaybgBundle\Event\NotificationResponseEvent;
use Otobul\EpaybgBundle\Event\OtobulEpaybgEvents;
use Otobul\EpaybgBundle\Event\InvoiceNotificationReceivedEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class EpayInvoiceNotificationSubscriber implements EventSubscriberInterface
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public static function getSubscribedEvents()
    {
        return [
            OtobulEpaybgEvents::NOTIFICATION_RECEIVED => 'epayNotificationReceived',
            OtobulEpaybgEvents::NOTIFICATION_ERROR => 'epayNotificationError',
            OtobulEpaybgEvents::NOTIFICATION_RESPONSE => 'epayNotificationResponse',
            OtobulEpaybgEvents::INVOICE_NOTIFICATION_RECEIVED => 'epayInvoiceNotification',
            OtobulEpaybgEvents::EASYPAY_CODE_CREATED => 'epayEasypayCodeCreated',
        ];
    }

    public function epayNotificationReceived(NotificationReceivedEvent $event)
    {
        $this->logger->info('epayNotificationReceived: '. $event->getContent());
    }

    public function epayNotificationError(NotificationErrorEvent $event)
    {
        $this->logger->info('epayNotificationError: '. $event->getMessage());
    }

    public function epayNotificationResponse(NotificationResponseEvent $event)
    {
        $this->logger->info('epayNotificationResponse: '. $event->getContent());
    }

    public function epayEasypayCodeCreated(EasypayCodeCreatedEvent $event)
    {
        $this->logger->info('epayEasypayCodeCreated: code'. $event->getCode());
        $this->logger->info('epayEasypayCodeCreated: paymentData:'. print_r($event->getPaymentData()->toArray(), 1));
    }

    public function epayInvoiceNotification(InvoiceNotificationReceivedEvent $event)
    {
        $this->logger->info('epayInvoiceNotification: '. $event->getInvoice() .' isPaid: '. $event->isPaid());

        // Event object has access to invoice notification details

        /**
         * Invoice number
         * @var int $invoice
         */
        $invoice = $event->getInvoice();

        /**
         * Invoice status, can be PAID|DENIED|EXPIRED
         * @var string $status
         */
        $status = $event->getStatus();

        /**
         * Payment date
         * @var \DateTime $payDate
         */
        $payDate = $event->getPayDate();

        /**
         * Transaction number
         * @var int $stan
         */
        $stan = $event->getStan();

        /**
         * Authorization code
         * @var string $bcode
         */
        $bcode = $event->getBcode();

        /*
        // Your logic to find some entity related to this invoice. Example:

        $order = $this->orderRepository->find($invoice);
        if (!$order) {
            // If invoice cannot be found. Sending back NO, so ePay.bg system stops sending notification about the invoice.
            $event->setResponseStatusNo();
            return;
        }

        process order state below
        */

        if($event->isPaid()) {
            // process PAID order here
        }else {
            // process DENIED or EXPIRED order here
        }

        // Sending back OK, so ePay.bg system stops sending notification about the invoice.
        $event->setResponseStatusOk();
    }
}