# Content

# Configuration

You have to register this extension at first.

extensions:
	contributte.thepay: Contributte\ThePay\DI\ThePayExtension
1
2

List of all options:

contributte.thepay:
	demo: true/false # if is true, extension rewrite merchant values with debug ones
	merchant:
		gateUrl: 'https://www.thepay.cz/gate/'
		merchantId: (int)
		accountId: (int)
		password: ''
		dataApiPassword: ''
		webServicesWsdl: 'https://www.thepay.cz/gate/api/api-demo.wsdl'
		dataWebServicesWsdl: 'https://www.thepay.cz/gate/api/data-demo.wsdl'
1
2
3
4
5
6
7
8
9
10

Minimal production configuration:

contributte.thepay:
	demo: false
	merchant:
		merchantId: (int)
		accountId: (int)
		password: ''
		dataApiPassword: ''
1
2
3
4
5
6
7

# Factories available in DI container

  • Contributte\ThePay\IPayment
  • Contributte\ThePay\IPermanentPayment
  • Contributte\ThePay\IReturnedPayment
  • Contributte\ThePay\Helper\IRadioMerchant

# Services available in DI container

  • Contributte\ThePay\MerchantConfig
  • Contributte\ThePay\Helper\DataApi

# Usage

Simple DTO for simple and type secure passing payment method information in the template

PaymentMethodDTO.php:

final class PaymentMethodDTO {
	private string $paymentMethodName;
	private string $paymentIcon;
	private bool $isPaymentByCard;

	public function __construct(
		string $paymentMethodName,
		string $paymentIcon,
		bool $isPaymentByCard
	) {
		$this->paymentMethodName = $paymentMethodName;
		$this->paymentIcon = $paymentIcon;
		$this->isPaymentByCard = $isPaymentByCard;
	}

	public function getPaymentMethodName(): string {
		return $this->paymentMethodName;
	}

	public function getPaymentIcon(): string {
		return $this->paymentIcon;
	}

	public function isPaymentByCard(): bool {
		return $this->isPaymentByCard;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

Prepare list of available payment methods

OrderPresenter.php:

use Contributte\ThePay\Helper\DataApi;
use Contributte\ThePay\Helper\IPaymentMethod;
use Nette\Application\UI\Presenter;

class OrderPresenter extend Presenter {
	/**
	 * @inject
	 */
	public DataApi $thePayDataApi;

	public function renderListMethods(): void {
		$template = $this->getTemplate();
		$paymentMethods = [];

		foreach ($this->thePayDataApi->getPaymentMethods()->getMethods() as $_paymentMethod) {
			$paymentIcon = $this->thePayDataApi->getPaymentMethodIcon($_paymentMethod, '209x127');
			$isPaymentByCard = $_paymentMethod->getId() === IPaymentMethod::CREDIT_CARD_PAYMENT_ID;
			$paymentName = $_paymentMethod->getId();

			$paymentMethods[$_paymentMethod->getId()] = new PaymentMethodDTO(
				$_paymentMethod->getName(),
				$paymentIcon,
				$isPaymentByCard
			);
		}

		$template->paymentMethods = $paymentMethods;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Order/listMethods.latte:

<ul>
    <li n:foreach="$paymentMethods as $paymentMethodId => $paymentMethod">
        <a n:href="pay paymentMethodId => $paymentMethodId">
            <img n:if="$paymentMethod->getPaymentIcon() !== null" src="{$paymentMethod->getPaymentIcon()}" alt="{$paymentMethod->getPaymentMethodName()}" title="{$paymentMethod->getPaymentMethodName()}">
            <span n:if="$paymentMethod->getPaymentIcon() === null">{$paymentMethod->getPaymentMethodName()}</span>
        </a>
    </li>
</ul>
1
2
3
4
5
6
7
8

Payment is configured and invoked using following code

use Contributte\ThePay\IPayment;
use Nette\Application\UI\Presenter;
use Tp\Payment;

class OrderPresenter extend Presenter {
	//...

	/**
	 * @inject
	 */
	public IPayment $tpPayment;

	public function actionPay(int $paymentMethodId): void {
		$payment = $this->tpPayment->create();
		assert($payment instanceof Payment);

		$payment->setMethodId($paymentMethodId);
		$payment->setValue(1000.0);
		$payment->setCurrency('CZK');
		$payment->setMerchantData('local-payment-unique-id');
		$payment->setMerchantSpecificSymbol('local-user-id');
		$payment->setReturnUrl($this->link('//onlineConfirmation', ['cartId' => 'local-payment-unique-id']));
		$payment->setBackToEshopUrl(
			'offlineConfirmation',
			['cartId' => 'local-payment-unique-id']
		);

		$payment->redirectOnlinePayment($this);
	}

	...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

Now is user redirected to ThePay site, when payment is completed we receive:

  • HEAD request to action offlineConfirmation with specified cartId
  • GET request to action onlineConfirmation with specified cartId

In each offline or online action is necessary to active validate received data e.g. like this

use Contributte\ThePay\Helper\DataApi;
use Contributte\ThePay\IReturnedPayment;
use Tp\InvalidSignatureException;
use Tp\ReturnedPayment;

class OrderPresenter extend Presenter {
	/**
	 * @inject
	 */
	public IReturnedPayment $tpReturnedPayment;

	/**
	 * @inject
	 */
	public DataApi $thePayDataApi;

	//...

	public function actionOnlineConfirmation(int $cartId): void {
		$returnedPayment = $this->tpReturnedPayment->create();

		try {
			if ($returnedPayment->verifySignature()) {
				if (in_array($returnedPayment->getStatus(), [
					ReturnedPayment::STATUS_OK,
					ReturnedPayment::STATUS_WAITING,
				], TRUE)) {
					//Demo gate doesn't allow active check...
					if ($this->thePayDataApi->getMerchantConfig()->isDemo()) {
						//Do not load thePayDataApi->getPayment

						if (bccomp(number_format($returnedPayment->getValue(), 2, '.', ''), '1000.00', 2) === 0) {
							// everything is ok
						}
					}
					else {
						$paymentId = $returnedPayment->getPaymentId();
						$payment = $this->thePayDataApi->getPayment($paymentId);

						if (bccomp(number_format($payment->getPayment()->getValue(), 2, '.', ''), '1000.00', 2) === 0) {
							// everything is ok
						}
					}
				}
			}
		}
		catch (InvalidSignatureException $e) {
			// TODO handle invalid request signature
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# Official documentation

You can find an official documentation with examples here https://www.thepay.cz/ke-stazeni/ (opens new window)