martiman/gopay

Gopay支付系统对Nette Framework的集成。

v2.1.0 2015-04-27 10:55 UTC

README

  • 适用于Nette Framework 2.1
  • 支持Gopay API 2.4

安装

最简单的方法是通过Composer安装Gopay

$ composer require Markette/Gopay

如果您不使用Composer,请将 /Gopay 目录复制到您的库中 - 如果您使用RobotLoader,则无需做任何其他操作。

可以直接在 config.neon 文件中注册库作为扩展

extensions:
	gopay: Markette\Gopay\Extension

然后我们可以在配置文件中设置参数

gopay:
	gopayId        : ***
	gopaySecretKey : ***
	testMode       : false

然后,通过autowiring和@inject注解,在presenter中的访问将如下所示

use Markette\Gopay;

/** @var Gopay\Service @inject */
public $gopay;

使用

支付前

在支付前,需要创建一个包含相应支付按钮的表单。每个支付渠道都由一个按钮表示。您可以通过bindPaymentButtons()方法向表单中添加按钮

$gopay->bindPaymentButtons($form, array($this->submittedForm));

传递的callback将在表单通过其中一个支付按钮成功提交后调用(即调用按钮上的->onClick[])。可以从按钮中获取所选的渠道

public function submittedForm(Markette\Gopay\PaymentButton $button)
{
	$channel = $button->getChannel();
}

如果您想手动渲染表单(例如使用表单模板),最好将使用的渠道列表传递到模板中并遍历它

$this->template->channels = $gopay->getChannels();
{foreach $channels as $channel}
	{input $channel->control}
{/foreach}

调用getChannels()时,建议捕获GopayFatalException异常,因为第一次调用时会向Gopay服务器查询以获取默认列表。

自定义支付渠道

您可以注册自定义支付渠道以实现统一工作

$gopay->addChannel('name', 'My channel', array(
	'image' => '/my-channel.png', // absolutní cesta k obrázku
));

您还可以禁用或启用任何预定义的(或您自己的)支付渠道

$gopay->denyChannel($gopay::METHOD_TRANSFER);
$gopay->allowChannel($gopay::METHOD_GOPAY);

我们也可以在配置文件中执行这些设置

gopay:
	channels:
		transfer: no # deny
		gopay: yes # allow (in default, all Gopay channels are disallowed)
		name: # add new one
			title: My channel
			image: /my-channel.png

执行支付

支付可以通过以下步骤执行。首先,需要创建一个新的支付实例

$payment = $gopay->createPayment(array(
	'sum'         => $sum,      // placená částka
	'variable'    => $variable, // variabilní symbol
	'specific'    => $specific, // specifický symbol
	'productName' => $product,  // název produktu (popis účelu platby)
	'customer' => array(
		'firstName'   => $name,
		'lastName'    => NULL,    // všechna parametry jsou volitelné
		'street'      => NULL,    // pokud některý neuvedete,
		'city'        => NULL,    // použije se prázdný řetězec
		'postalCode'  => $postal,
		'countryCode' => 'CZE',
		'email'       => $email,
		'phoneNumber' => NULL,
	),
));

其次,设置Gopay支付网关在支付成功或失败时重定向到的地址。

$gopay->successUrl = $this->link('//success');
$gopay->failureUrl = $this->link('//failure');

记录支付ID很有用(例如,如果支付与某个订单相关)。这可以通过将回调作为pay()方法的第三个参数传递来实现。

$storeIdCallback = function ($paymentId) use ($order) {
	$order->setPaymentId($paymentId);
};

最后,使用支付进行支付 :) (第二个参数是执行支付的支付渠道)

$response = $gopay->pay($payment, $gopay::METHOD_TRANSFER, $storeIdCallback);

pay()操作将返回一个Response对象,该对象将应用程序重定向到Gopay支付网关。

$this->sendResponse($response);

调用pay()时可能出错的两件事

  1. 提供了错误的参数
  2. 官方的Gopay支付网关损坏

第一个错误永远不会发生。这意味着您的代码中存在某种错误。第二个错误可能会随时发生,因此会生成不同的异常,需要捕获并根据异常通知客户,错误不是在您这边。

try {
	$gopay->pay($payment, $gopay::TRANSFER);
} catch (GopayException $e) {
	echo 'Platební služba Gopay bohužel momentálně nefunguje. Zkuste to
	prosím za chvíli.';
}

支付后

您的客户将在Gopay支付网关上执行必要的操作,一旦过程完成,就会被重定向回您的应用程序,无论是到successUrl还是failureUrl地址。Gopay将提供以下参数集给这两个地址

  • paymentSessionId
  • targetGoId
  • orderNumber // 变量号
  • encryptedSignature

第一个参数与我们之前章节中保存到我们的内部订单模型表示中的参数相同。我们可以使用它来重新加载订单。

然后,我们将使用所有这些数据和加载的订单数据来重新构建支付对象

$order = $database->getOrderByPaymentId($paymentSessionId);

$payment = $gopay->restorePayment(array(
	'sum'          => $order->price,
	'variable'    => $order->varSymbol,
	'specific'    => $order->specSymbol,
	'productName' => $order->product,
), array(
	'paymentSessionId'   => $paymentSessionId,
	'targetGoId'         => $targetGoId,
	'orderNumber'        => $orderNumber,
	'encryptedSignature' => $encryptedSignature,
));

支付对象可以调用两种检查方法:isFraud()isPaid()。第一个告诉我们支付是否真实,或者说是否是欺诈(内部会检查从支付网关传递的四个参数。

第二个 isPaid() 将返回 TRUE,如果支付确实已经完成。如果是这样,流程就结束了,我们可以标记订单已支付,并发送电子邮件给客户。

在支付失败的情况下,仍然会传递所有四个参数,因此可以再次读取有关相关订单的信息。但是没有必要进行检查,因为失败信息已经非常清楚地从请求的性质中显示出来。

您可以在 示例presenter 中查看 gopay 服务的使用示例。

这个工具不能做什么以及如何处理

这个迷你库,更像是代码片段,并没有涵盖 Gopay API 的很大一部分。如果您在这里缺少什么您需要的东西,请友好地补充所需的代码部分,甚至可以作为一个 pull-request 发送。同样,您可以在 issues 中通知关于官方 API 的更新(该 API 最近刚刚扩展)。