diff --git a/.gitignore b/.gitignore index a1b2007..425ba19 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ # Folders /vendor -/.idea -/.composer # Files composer.lock \ No newline at end of file diff --git a/README.md b/README.md index 2252ee7..ed57939 100644 --- a/README.md +++ b/README.md @@ -4,268 +4,530 @@ PHP client for Tinkoff REST API. ## 1 Requirements -- PHP 7.0 or above +- PHP 7.1 or latter -## 2 Installation +## 2 Install ```sh composer require 'sergey-zatulivetrov/tinkoff-acquiring-client' ``` -## 3 Uses +## 3 Client + +**Methods** + +Return|Name|Description +---|---|--- +array|init([Init](#init) $data)|Creation of order +array|finishAuthorize([FinishAuthorize](#finishauthorize) $data)|Confirms the payment of the transfer of details and write-off / blocking funds +array|confirm([Confirm](#confirm) $data)|Confirmation of payment +array|cancel([Cancel](#cancel) $data)|Cancellation +array|getState([GetState](#getstate) $data)|Get the status of payment +array|resend([Resend](#resend) $data)|Sending lackless notifications +array|submit3DSAuthorization([Submit3DSAuthorization](#submit3dsauthorization) $data)|Carries out test results 3-D Secure +array|sendClosingReceipt([SendClosingReceipt](#sendclosingreceipt) $data)|Sends a closing check to the cashier +array|charge([Charge](#charge) $data)|Performs auto plates +array|addCustomer([AddCustomer](#addcustomer) $data)|Registers the buyer and its data in the seller's system +array|getCustomer([GetCustomer](#getcustomer) $data)|Returns the buyer's data +array|removeCustomer([RemoveCustomer](#removecustomer) $data)|Removes the registered buyer data +array|getCardList([GetCardList](#getcardlist) $data)|Returns a list of saved registered buyer maps +array|removeCard([RemoveCard](#removecard) $data)|Removes a tied buyer card + +## 4 Data + +### Init + +**Properties** + +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal identifier. Issued to the seller by the bank when opening the terminal +int|$Amount|The amount in kopecks +string|$OrderId|Order ID in the seller's system +string|$IP|Buyer's IP address +string|$Description|Description of the order +string|$Language|Payment form language +string|$Recurrent|Parent payment ID +string|$CustomerKey|Buyer's identifier in the seller's system. Passed along with the CardId parameter +string|$RedirectDueDate|Link lifetime (no more than 90 days) +string|$NotificationURL|Address for receiving http notifications +string|$SuccessURL|Success page +string|$FailURL|Error page +string|$PayType|Payment type +[Receipt](#receipt)|$Receipt|Receipt data array +array|$DATA|Additional payment parameters in the "key" format: "value" (no more than 20 pairs) +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### FinishAuthorize + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$CardData|Encrypted card data +string|$EncryptedPaymentData|Card data +int|$Amount|Amount in kopecks +array|$DATA|Advanced payment options in "Key" format: "Value" (no more than 20 pairs) +string|$InfoEmail|Email to send payment information +string|$IP|IP address client +int|$PaymentId|A unique transaction identifier in the bank system obtained in response to the initiating method +string|$Phone|Phone Client +bool|$SendEmail|True - Send the client information on payment of payment, false - Do not send +string|$Route|Method of payment +string|$Source|Source of payment +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation +void|encodeCardData($publicKey, [CardData](#carddata) $cardData)|Encryption data cards + +### Cancel + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +int|$PaymentId|Payment Identifier in the Bank System +int|$Amount|Return rate in kopecks +string|$IP|Buyer's IP address +[Receipt](#receipt)|$Receipt|An array of check data +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### Confirm + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +int|$PaymentId|Payment Identifier in the Bank System +int|$Amount|Amount in kopecks +string|$IP|Buyer's IP address +[Receipt](#receipt)|$Receipt|An array of check data +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### GetState + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +int|$PaymentId|Payment Identifier in the Bank System +string|$IP|Buyer's IP address +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### Resend + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### Submit3DSAuthorization + +**Properties** +Type|Name|Description +---|---|--- +string|$MD|Unique transaction identifier in the bank system +string|$PaRes|Encrypted string containing results 3-D Secure authentication +int|$PaymentId|Unique transaction identifier in the bank system +string|$TerminalKey|Terminal ID, issued to the seller by the bank +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### SendClosingReceipt + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +int|$PaymentId|Payment Identifier in the Bank System +[Receipt](#receipt)|$Receipt|An array of check data +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### Charge + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +int|$PaymentId|Payment Identifier in the Bank System +int|$RebillId|Identifier auto-payment +bool|$SendEmail|Obtaining a buyer of email notifications +string|$InfoEmail|Email buyer +string|$IP|Buyer's IP address +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### AddCustomer + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$CustomerKey|Buyer identifier in the seller +string|$Email|Email buyer +string|$Phone|Phone buyer in format +71234567890 +string|$IP|Buyer's IP address +string|$Token|Token -### 3.1 Сonnection definition +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### GetCustomer + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$CustomerKey|Buyer identifier in the seller +string|$IP|Buyer's IP address +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### RemoveCustomer + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$CustomerKey|Buyer identifier in the seller +string|$IP|Buyer's IP address +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### GetCardList + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$CustomerKey|Buyer identifier in the seller +string|$IP|Buyer's IP address +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### RemoveCard + +**Properties** +Type|Name|Description +---|---|--- +string|$TerminalKey|Terminal ID. It is issued to the Seller by the Bank at the Terminal Institution +string|$CustomerKey|Buyer identifier in the seller +string|$CardId|Card ID in the Bank System +string|$IP|Buyer's IP address +string|$Token|Token + +**Methods** + +Return|Name|Description +---|---|--- +void|generateToken(string $password)|Token generation + +### Receipt + +**Properties** + +Type|Name|Description +---|---|--- +string|$Email|Buyer email +string|$Phone|Buyer's phone number +string|$EmailCompany|Seller Email +string|$Taxation|Tax system +[Item[]](#item)|$Items|Array of check items with information about goods +[Payments](#payments)|$Payments|Object with information about the types of payment amount + +**Methods** + +Return|Name|Description +---|---|--- +void|initItems(int $count)|Generation of an empty array of check positions +Item|getItem()|Conclusion of check position + +### Item + +**Properties** + +Type|Name|Description +---|---|--- +string|$Name|Name of product +float|$Quantity|Number or weight of the goods +int|$Amount|Cost of goods in kopecks +int|$Price|Price per unit of goods in kopecks +string|$PaymentMethod|Sign of payment method +string|$PaymentObject|Sign of the subject of the calculation +string|$Tax|VAT rate +string|$Ean13|Barcode in the required format +[AgentData](#agentdata)|$AgentData|Agent data +[SupplierInfo](#supplierinfo)|$SupplierInfo|Payment Agent Supplier Data + +### AgentData + +**Properties** + +Type|Name|Description +---|---|--- +string|$AgentSign|Sign of agent +string|$OperationName|The name of the operation +string[]|$Phones|Phones of the payment agent +string[]|$ReceiverPhones|Phone operator for receiving payments +string[]|$TransferPhones|Phones Translation Operator +string|$OperatorName|Name of transformation operator +string|$OperatorAddress|Alternator address translation +string|$OperatorInn|Inn Translation Operator + +### SupplierInfo + +**Properties** + +Type|Name|Description +---|---|--- +string[]|$Phones|Phone supplier +string|$Name|Supplier name +string|$Inn|TIN supplier + +### Payments + +**Properties** + +Type|Name|Description +---|---|--- +int|$Cash|Payment type "Cash". Amount to be paid in kopecks, no more than 14 digits +int|$Electronic|Payment type "Non-cash" +int|$AdvancePayment|Payment type "Advance payment (Advance payment)" +int|$Credit|Payment type "Postpaid (Credit)" +int|$Provision|Payment type "Other form of payment" + +### CardData + +Type|Name|Description +---|---|--- +int|$PAN|Card number +string|$ExpDate|Month and year of the duration of the card. In MMYY format +string|$CardHolder|Name and surname card holder as on map +string|$CVV|Protection code +string|$ECI|Electronic Commerce Indicator. The indicator showing the degree of protection used in providing the buyer of its TSP data. Used and is required for Apple Pay or Google Pay +string|$CAVV|Cardholder Authentication Verification Value or Accountholder Authentication Value Used and is required for Apple Pay or Google Pay + +## 5 Constants + +### AgentSign + +Name|Description +---|--- +BANK_PAYING_AGENT|Bank payment agent +BANK_PAYING_SUBAGENT|Bank payment subagent +PAYING_AGENT|Payment Agent +PAYING_SUBAGENT|Payment Subagent +ATTORNEY|Attorney +COMMISSION_AGENT|Commissioner +ANOTHER|Another type of agent + +### Language + +Name|Description +---|--- +RU|Russian +EN|English + +### PaymentMethod + +Name|Description +---|--- +FULL_PREPAYMENT|Prepay 100% +PREPAYMENT|Prepayment +ADVANCE|Avanc +FULL_PAYMENT|Full calculation +PARTIAL_PAYMENT|Partial calculation and credit +CREDIT|Transfer to Credit +CREDIT_PAYMENT|Payment of credit + +### PaymentObject + +Name|Description +---|--- +COMMODITY|Product +EXCISE|Crossing commodity +JOB|Work +SERVICE|Service +GAMBLING_BET|Betting a gambling +GAMBLING_PRIZE|Gambling win +LOTTERY|Lottery ticket +LOTTERY_PRIZE|Winning lottery +INTELLECTUAL_ACTIVITY|Providing Intellectual Activities +PAYMENT|Payment +AGENT_COMMISSION|Agent's commission +COMPOSITE|Composite subject of calculation +ANOTHER|Other subject of calculation + +### PayType + +Name|Description +---|--- +O|Singadail payment +T|Double-step payment + +### Route + +Name|Description +---|--- +ACQ|ACQ + +### Source + +Name|Description +---|--- +CARDS|Cards +APPLE_PAY|ApplePay +GOOGLE_PAY|GooglePay + +### Taxation + +Name|Description +---|--- +OSN|General +USN_INCOME|Simplified (income) +USN_INCOME_OUTCOME|Simplified (income minus costs) +PATENT|Patent +ENVD|A single tax on imputed income +ESN|Single agricultural tax + +### Vat + +Name|Description +---|--- +NONE|None +VAT0|0% +VAT10|10% +VAT20|20% +VAT110|10/110 +VAT120|20/120 + +## 6 Example ```php use SergeyZatulivetrov\TinkoffAcquiring\Client; - -$client = new Client(); -``` - -#### 3.1.1 Init connection - -```php -$client->init($data); -``` - -#### 3.1.2 Confirm connection - -```php -$client->confirm($data); -``` - -#### 3.1.3 Cancel connection - -```php -$client->cancel($data); -``` - -#### 3.1.4 GetState connection - -```php -$client->getState($data); -``` - -#### 3.1.5 Resend connection - -```php -$client->resend($data); -``` - -### 3.2 Data - -#### 3.2.1 Init data - -##### 3.2.1.1 Property - -```php -/** - * Class InitData - * - * @property string $TerminalKey - * @property integer $Amount - * @property string $OrderId - * @property string $IP - * @property string $Description - * @property string $Language - * @property string $CustomerKey - * @property string $Recurrent - * @property string $RedirectDueDate - * @property array $DATA - * @property string $NotificationURL - * @property string $SuccessURL - * @property string $FailURL - * @property string $PayType - * @property array $Receipt - */ - -/** - * Class ReceiptData - * - * @property array $Items - * @property string $Email - * @property string $Phone - * @property string $EmailCompany - * @property string $Taxation - */ - -/** - * Class ItemData - * - * @property string $Name - * @property integer $Price - * @property float $Quantity - * @property integer $Amount - * @property string $PaymentMethod - * @property string $PaymentObject - * @property string $Tax - * @property string $Ean13 - * @property string $ShopCode - */ -``` - -##### 3.2.1.2 Example - -```php use SergeyZatulivetrov\TinkoffAcquiring\Constants\PaymentMethod; use SergeyZatulivetrov\TinkoffAcquiring\Constants\PaymentObject; use SergeyZatulivetrov\TinkoffAcquiring\Constants\Taxation; use SergeyZatulivetrov\TinkoffAcquiring\Constants\Vat; -use SergeyZatulivetrov\TinkoffAcquiring\Data\InitData; -use SergeyZatulivetrov\TinkoffAcquiring\Data\ItemData; -use SergeyZatulivetrov\TinkoffAcquiring\Data\ReceiptData; - -$data = new InitData(); -$data->TerminalKey = "TestB"; -$data->Amount = 140000; -$data->OrderId = "21050"; -$data->Description = "Подарочная карта на 1400.00 рублей"; -$data->DATA = [ - "Phone" => "+71234567890", - "Email" => "a@test.com", -]; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Init; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Receipt; -$item1 = new ItemData(); -$item1->Name = "Наименование товара 1"; -$item1->Price = 10000; -$item1->Quantity = 1.00; -$item1->Amount = 10000; -$item1->PaymentMethod = PaymentMethod::FULL_PREPAYMENT; -$item1->PaymentObject = PaymentObject::COMMODITY; -$item1->Tax = Vat::VAT10; -$item1->Ean13 = "0123456789"; - -$item2 = new ItemData(); -$item2->Name = "Наименование товара 2"; -$item2->Price = 20000; -$item2->Quantity = 2.00; -$item2->Amount = 40000; -$item2->PaymentMethod = PaymentMethod::PREPAYMENT; -$item2->PaymentObject = PaymentObject::SERVICE; -$item2->Tax = Vat::VAT20; - -$item3 = new ItemData(); -$item3->Name = "Наименование товара 3"; -$item3->Price = 30000; -$item3->Quantity = 3.00; -$item3->Amount = 90000; -$item3->Tax = Vat::VAT10; - -$receipt = new ReceiptData(); -$receipt->Email = "a@test.ru"; -$receipt->Phone = "+79031234567"; -$receipt->EmailCompany = "b@test.ru"; -$receipt->Taxation = Taxation::OSN; -$receipt->Items = [$item1, $item2, $item3]; -$data->Receipt = $receipt; -``` - -#### 3.2.2 Confirm data - -##### 3.2.2.1 Property - -```php -/** - * Class ConfirmData - * - * @property string $Token - * @property string $TerminalKey - * @property integer $PaymentId - * @property string $IP - * @property integer $Amount - * @property array $Receipt - */ -``` - -##### 3.2.2.2 Example - -```php -use SergeyZatulivetrov\TinkoffAcquiring\Data\ConfirmData; - -$data = new ConfirmData(); -$data->TerminalKey = "TinkoffBankTest"; -$data->PaymentId = "2164657"; -$data->generateToken("password"); -``` - -#### 3.2.3 Cancel data - -##### 3.2.3.1 Property - -```php -/** - * Class CancelData - * - * @property string $Token - * @property string $TerminalKey - * @property integer $PaymentId - * @property string $IP - * @property integer $Amount - * @property array $Receipt - */ -``` - -##### 3.2.3.2 Example - -```php -use SergeyZatulivetrov\TinkoffAcquiring\Data\CancelData; - -$data = new CancelData(); -$data->TerminalKey = "TinkoffBankTest"; -$data->PaymentId = "2164657"; -$data->generateToken("password"); -``` - -#### 3.2.4 GetState data - -##### 3.2.4.1 Property - -```php -/** - * Class GetStateData - * - * @property string $Token - * @property string $TerminalKey - * @property integer $PaymentId - * @property integer $Amount - * @property string $IP - */ -``` - -##### 3.2.4.2 Example - -```php -use SergeyZatulivetrov\TinkoffAcquiring\Data\GetStateData; - -$data = new GetStateData(); +$data = new Init(); $data->TerminalKey = "TinkoffBankTest"; -$data->PaymentId = "2164657"; -$data->generateToken("password"); -``` - -#### 3.2.5 Resend data - -##### 3.2.5.1 Property - -```php -/** - * Class ResendData - * - * @property string $Token - * @property string $TerminalKey - */ -``` +$data->Amount = "140000"; +$data->OrderId = "21050"; +$data->Description = "Gift card for 1400.00 rubles"; +$data->DATA = [ + "Phone" => "+71234567890", + "Email" => "a@test.com" +]; +$data->Receipt = new Receipt(); +$data->Receipt->Email = "a@test.ru"; +$data->Receipt->Phone = "+79031234567"; +$data->Receipt->EmailCompany = "b@test.ru"; +$data->Receipt->Taxation = Taxation::OSN; + +$data->Receipt->initItems(3); + +$data->Receipt->getItem(0)->Name = "Product name 1."; +$data->Receipt->getItem(0)->Price = 10000; +$data->Receipt->getItem(0)->Quantity = 1.00; +$data->Receipt->getItem(0)->Amount = 10000; +$data->Receipt->getItem(0)->PaymentMethod = PaymentMethod::FULL_PREPAYMENT; +$data->Receipt->getItem(0)->PaymentObject = PaymentObject::COMMODITY; +$data->Receipt->getItem(0)->Tax = Vat::VAT10; +$data->Receipt->getItem(0)->Ean13 = "0123456789"; + +$data->Receipt->getItem(1)->Name = "Product Name 2."; +$data->Receipt->getItem(1)->Price = 20000; +$data->Receipt->getItem(1)->Quantity = 2.00; +$data->Receipt->getItem(1)->Amount = 40000; +$data->Receipt->getItem(1)->PaymentMethod = PaymentMethod::PREPAYMENT; +$data->Receipt->getItem(1)->PaymentObject = PaymentObject::SERVICE; +$data->Receipt->getItem(1)->Tax = Vat::VAT20; + +$data->Receipt->getItem(2)->Name = "Product Name 3."; +$data->Receipt->getItem(2)->Price = 30000; +$data->Receipt->getItem(2)->Quantity = 3.00; +$data->Receipt->getItem(2)->Amount = 90000; +$data->Receipt->getItem(2)->Tax = Vat::VAT10; -##### 3.2.5.2 Example -```php -use SergeyZatulivetrov\TinkoffAcquiring\Data\ResendData; +$client = new Client(); +$res = $client->init($data); -$data = new ResendData(); -$data->TerminalKey = "TinkoffBankTest"; -$data->generateToken("password"); +var_dump($res); ``` -## 4 License +## 7 License Copyright (c) Zatulivetrov Sergey. Distributed under the MIT. diff --git a/composer.json b/composer.json index 2b4e259..cf80ed5 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "sergey-zatulivetrov/tinkoff-acquiring-client", "type": "library", - "version": "2.0.1", + "version": "3.0.0", "description": "Client for working with Tinkoff's acquiring REST API", "keywords": [ "tinkoff", @@ -9,6 +9,9 @@ "credit card", "client" ], + "scripts": { + "tests": "./vendor/bin/phpunit" + }, "homepage": "https://github.com/sergey-zatulivetrov/tinkoff-acquiring-client", "license": "MIT", "authors": [ @@ -18,9 +21,10 @@ } ], "require": { - "php": ">=7.0", + "php": ">=7.1", "ext-json": "*", - "guzzlehttp/guzzle": ">=6.5.5" + "ext-openssl": "*", + "guzzlehttp/guzzle": ">=6.3" }, "autoload": { "psr-4": { @@ -36,4 +40,4 @@ "require-dev": { "phpunit/phpunit": ">=6.5.14" } -} +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 48bfd68..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: "3" - -services: - app: - container_name: tinkoff-acquiring-client - build: - context: ./docker - dockerfile: php.Dockerfile - volumes: - - ./:/var/www - networks: - - default \ No newline at end of file diff --git a/docker/php.Dockerfile b/docker/php.Dockerfile deleted file mode 100644 index f2bfe0d..0000000 --- a/docker/php.Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM php:7.0-cli - -RUN apt-get update && apt-get upgrade -y \ - libzip-dev \ - libxml2-dev \ - bash \ - git \ - unzip \ - zip - -RUN docker-php-ext-install bcmath mbstring zip xml - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin/ --filename=composer - -WORKDIR /var/www \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..0272b14 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,10 @@ + + + + ./tests/Unit + + + ./tests/Feature + + + \ No newline at end of file diff --git a/src/Client.php b/src/Client.php index 792a20a..91824be 100644 --- a/src/Client.php +++ b/src/Client.php @@ -5,44 +5,99 @@ namespace SergeyZatulivetrov\TinkoffAcquiring; use GuzzleHttp\Client as HttpClient; +use GuzzleHttp\RequestOptions; use SergeyZatulivetrov\TinkoffAcquiring\Contracts\ClientContract; use SergeyZatulivetrov\TinkoffAcquiring\Contracts\DataContract; -use SergeyZatulivetrov\TinkoffAcquiring\Data\CancelData; -use SergeyZatulivetrov\TinkoffAcquiring\Data\ConfirmData; -use SergeyZatulivetrov\TinkoffAcquiring\Data\GetStateData; -use SergeyZatulivetrov\TinkoffAcquiring\Data\InitData; -use SergeyZatulivetrov\TinkoffAcquiring\Data\ResendData; +use SergeyZatulivetrov\TinkoffAcquiring\Data\AddCustomer; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Cancel; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Charge; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Confirm; +use SergeyZatulivetrov\TinkoffAcquiring\Data\FinishAuthorize; +use SergeyZatulivetrov\TinkoffAcquiring\Data\GetCardList; +use SergeyZatulivetrov\TinkoffAcquiring\Data\GetCustomer; +use SergeyZatulivetrov\TinkoffAcquiring\Data\GetState; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Init; +use SergeyZatulivetrov\TinkoffAcquiring\Data\RemoveCard; +use SergeyZatulivetrov\TinkoffAcquiring\Data\RemoveCustomer; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Resend; +use SergeyZatulivetrov\TinkoffAcquiring\Data\SendClosingReceipt; +use SergeyZatulivetrov\TinkoffAcquiring\Data\Submit3DSAuthorization; class Client implements ClientContract { - const API_URL = 'https://securepay.tinkoff.ru/v2/'; + public const API_URL = 'https://securepay.tinkoff.ru/v2/'; - public function init(InitData $data): array + public function init(Init $data): array { return $this->execute('Init', $data); } - public function confirm(ConfirmData $data): array + public function finishAuthorize(FinishAuthorize $data): array + { + return $this->execute('FinishAuthorize', $data); + } + + public function confirm(Confirm $data): array { return $this->execute('Confirm', $data); } - public function cancel(CancelData $data): array + public function cancel(Cancel $data): array { return $this->execute('Cancel', $data); } - public function getState(GetStateData $data): array + public function getState(GetState $data): array { return $this->execute('GetState', $data); } - public function resend(ResendData $data): array + public function resend(Resend $data): array { return $this->execute('Resend', $data); } - public function execute(string $action, DataContract $data): array + public function submit3DSAuthorization(Submit3DSAuthorization $data): array + { + return $this->execute('Submit3DSAuthorization', $data, 'application/x-www-form-urlencoded'); + } + + public function sendClosingReceipt(SendClosingReceipt $data): array + { + return $this->execute('SendClosingReceipt', $data); + } + + public function charge(Charge $data): array + { + return $this->execute('Charge', $data); + } + + public function addCustomer(AddCustomer $data): array + { + return $this->execute('AddCustomer', $data); + } + + public function getCustomer(GetCustomer $data): array + { + return $this->execute('GetCustomer', $data); + } + + public function removeCustomer(RemoveCustomer $data): array + { + return $this->execute('RemoveCustomer', $data); + } + + public function getCardList(GetCardList $data): array + { + return $this->execute('GetCardList', $data); + } + + public function removeCard(RemoveCard $data): array + { + return $this->execute('RemoveCard', $data); + } + + private function execute(string $action, DataContract $data, string $contentType = 'application/json'): array { $client = new HttpClient(); @@ -50,16 +105,13 @@ public function execute(string $action, DataContract $data): array 'POST', self::API_URL . $action, [ - 'headers' => [ - 'Content-Type' => 'application/json', + RequestOptions::HEADERS => [ + 'Content-Type' => $contentType, ], - 'body' => json_encode($data->toArray()), + RequestOptions::BODY => json_encode($data->toArray()), ] ); - return [ - 'status' => $response->getStatusCode(), - 'response' => json_decode($response->getBody()->getContents(), true), - ]; + return json_decode($response->getBody()->getContents(), true); } } diff --git a/src/Constants/AgentSign.php b/src/Constants/AgentSign.php new file mode 100644 index 0000000..a913702 --- /dev/null +++ b/src/Constants/AgentSign.php @@ -0,0 +1,32 @@ +data; + return $this->converter($this->data); } public function __set($name, $value) @@ -31,4 +31,19 @@ public function __unset($name) unset($this->data[$name]); } } + + private function converter(array $data): array + { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = $this->converter($value); + continue; + } + if ($value instanceof DataContract) { + $data[$key] = $value->toArray(); + } + } + + return $data; + } } diff --git a/src/Data/AbstractDataWithToken.php b/src/Data/AbstractDataWithToken.php new file mode 100644 index 0000000..764c9e2 --- /dev/null +++ b/src/Data/AbstractDataWithToken.php @@ -0,0 +1,33 @@ +toArray(); + + $data['Password'] = $password; + + unset($data['Shops'], $data['Receipt'], $data['DATA']); + + ksort($data); + + $this->Token = hash('sha256', join('', $data)); + } +} diff --git a/src/Data/AddCustomer.php b/src/Data/AddCustomer.php new file mode 100644 index 0000000..6739696 --- /dev/null +++ b/src/Data/AddCustomer.php @@ -0,0 +1,20 @@ +toArray(); - - $data['Password'] = $password; - - unset($data['Receipt'], $data['DATA']); - - ksort($data); - - $token = join('', array_values($data)); - - $this->Token = hash('sha256', $token); - } -} diff --git a/src/Data/Cancel.php b/src/Data/Cancel.php new file mode 100644 index 0000000..699dbe1 --- /dev/null +++ b/src/Data/Cancel.php @@ -0,0 +1,20 @@ +toArray(); - } - - parent::__set($name, $value); - } -} diff --git a/src/Data/CardData.php b/src/Data/CardData.php new file mode 100644 index 0000000..cf0a92d --- /dev/null +++ b/src/Data/CardData.php @@ -0,0 +1,21 @@ +toArray(); - } - - parent::__set($name, $value); - } -} diff --git a/src/Data/FinishAuthorize.php b/src/Data/FinishAuthorize.php new file mode 100644 index 0000000..17340e6 --- /dev/null +++ b/src/Data/FinishAuthorize.php @@ -0,0 +1,51 @@ +toArray() as $key => $value) { + $data[] = "{$key}={$value}"; + } + + openssl_public_encrypt(join(';', $data), $encrypted, openssl_get_publickey($publicKey)); + + $this->CardData = base64_encode($encrypted); + } +} diff --git a/src/Data/GetCardList.php b/src/Data/GetCardList.php new file mode 100644 index 0000000..538e8c3 --- /dev/null +++ b/src/Data/GetCardList.php @@ -0,0 +1,18 @@ +toArray(); - } - - parent::__set($name, $value); - } -} diff --git a/src/Data/Item.php b/src/Data/Item.php new file mode 100644 index 0000000..1338bdc --- /dev/null +++ b/src/Data/Item.php @@ -0,0 +1,25 @@ +Items); + + $items = []; + + for ($i = 0; $i < $count; $i++) { + $items[] = new Item(); + } + + $this->Items = $items; + + unset($items); + } + + /** + * Conclusion of positions from the array + * + * @param int $index Position + */ + public function getItem(int $index): Item + { + return $this->Items[$index]; + } +} diff --git a/src/Data/ReceiptData.php b/src/Data/ReceiptData.php deleted file mode 100644 index 48bb09e..0000000 --- a/src/Data/ReceiptData.php +++ /dev/null @@ -1,31 +0,0 @@ -toArray(); - }, $value); - } - - parent::__set($name, $value); - } -} diff --git a/src/Data/RemoveCard.php b/src/Data/RemoveCard.php new file mode 100644 index 0000000..5686c24 --- /dev/null +++ b/src/Data/RemoveCard.php @@ -0,0 +1,19 @@ +client = $this->getMockBuilder(Client::class)->getMock(); + } + + public function testInit(): void + { + $this->client->method('init')->willReturn(['status' => 200]); + + $res = $this->client->init(new Init()); + + $this->assertEquals(['status' => 200], $res); + } + + + public function testFinishAuthorize(): void + { + $this->client->method('finishAuthorize')->willReturn(['status' => 200]); + + $res = $this->client->finishAuthorize(new FinishAuthorize()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testConfirm(): void + { + $this->client->method('confirm')->willReturn(['status' => 200]); + + $res = $this->client->confirm(new Confirm()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testCancel(): void + { + $this->client->method('cancel')->willReturn(['status' => 200]); + + $res = $this->client->cancel(new Cancel()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testGetState(): void + { + $this->client->method('getState')->willReturn(['status' => 200]); + + $res = $this->client->getState(new GetState()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testResend(): void + { + $this->client->method('resend')->willReturn(['status' => 200]); + + $res = $this->client->resend(new Resend()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testSubmit3DSAuthorization(): void + { + $this->client->method('submit3DSAuthorization')->willReturn(['status' => 200]); + + $res = $this->client->submit3DSAuthorization(new Submit3DSAuthorization()); + + $this->assertEquals(['status' => 200], $res); + } + + + public function testSendClosingReceipt(): void + { + $this->client->method('sendClosingReceipt')->willReturn(['status' => 200]); + + $res = $this->client->sendClosingReceipt(new SendClosingReceipt()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testCharge(): void + { + $this->client->method('charge')->willReturn(['status' => 200]); + + $res = $this->client->charge(new Charge()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testAddCustomer(): void + { + $this->client->method('addCustomer')->willReturn(['status' => 200]); + + $res = $this->client->addCustomer(new AddCustomer()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testGetCustomer(): void + { + $this->client->method('getCustomer')->willReturn(['status' => 200]); + + $res = $this->client->getCustomer(new GetCustomer()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testRemoveCustomer(): void + { + $this->client->method('removeCustomer')->willReturn(['status' => 200]); + + $res = $this->client->removeCustomer(new RemoveCustomer()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testGetCardList(): void + { + $this->client->method('getCardList')->willReturn(['status' => 200]); + + $res = $this->client->getCardList(new GetCardList()); + + $this->assertEquals(['status' => 200], $res); + } + + public function testRemoveCard(): void + { + $this->client->method('removeCard')->willReturn(['status' => 200]); + + $res = $this->client->removeCard(new RemoveCard()); + + $this->assertEquals(['status' => 200], $res); + } +} diff --git a/tests/Feature/TestClient.php b/tests/Feature/TestClient.php deleted file mode 100644 index d76f03f..0000000 --- a/tests/Feature/TestClient.php +++ /dev/null @@ -1,67 +0,0 @@ -client = $this->getMockBuilder(Client::class) - ->setMethods(['execute']) - ->getMock(); - - $this->client->method('execute') - ->willReturn(['status' => 200]); - } - - public function testInit() - { - $res = $this->client->init(new InitData()); - - $this->assertEquals(200, $res['status']); - } - - public function testConfirm() - { - $res = $this->client->confirm(new ConfirmData()); - - $this->assertEquals(200, $res['status']); - } - - public function testCancel() - { - $res = $this->client->cancel(new CancelData()); - - $this->assertEquals(200, $res['status']); - } - - public function testGetState() - { - $res = $this->client->getState(new GetStateData()); - - $this->assertEquals(200, $res['status']); - } - - public function testResend() - { - $res = $this->client->resend(new ResendData()); - - $this->assertEquals(200, $res['status']); - } -} diff --git a/tests/Unit/DataTest.php b/tests/Unit/DataTest.php new file mode 100644 index 0000000..1fd954f --- /dev/null +++ b/tests/Unit/DataTest.php @@ -0,0 +1,125 @@ +TerminalKey = "TinkoffBankTest"; + $data->Amount = "140000"; + $data->OrderId = "21050"; + $data->Description = "Gift card for 1400.00 rubles"; + $data->DATA = [ + "Phone" => "+71234567890", + "Email" => "a@test.com" + ]; + $data->Receipt = new Receipt(); + $data->Receipt->Email = "a@test.ru"; + $data->Receipt->Phone = "+79031234567"; + $data->Receipt->EmailCompany = "b@test.ru"; + $data->Receipt->Taxation = Taxation::OSN; + + $data->Receipt->initItems(3); + + $data->Receipt->getItem(0)->Name = "Product name 1."; + $data->Receipt->getItem(0)->Price = 10000; + $data->Receipt->getItem(0)->Quantity = 1.00; + $data->Receipt->getItem(0)->Amount = 10000; + $data->Receipt->getItem(0)->PaymentMethod = PaymentMethod::FULL_PREPAYMENT; + $data->Receipt->getItem(0)->PaymentObject = PaymentObject::COMMODITY; + $data->Receipt->getItem(0)->Tax = Vat::VAT10; + $data->Receipt->getItem(0)->Ean13 = "0123456789"; + + $data->Receipt->getItem(1)->Name = "Product Name 2."; + $data->Receipt->getItem(1)->Price = 20000; + $data->Receipt->getItem(1)->Quantity = 2.00; + $data->Receipt->getItem(1)->Amount = 40000; + $data->Receipt->getItem(1)->PaymentMethod = PaymentMethod::PREPAYMENT; + $data->Receipt->getItem(1)->PaymentObject = PaymentObject::SERVICE; + $data->Receipt->getItem(1)->Tax = Vat::VAT20; + + $data->Receipt->getItem(2)->Name = "Product Name 3."; + $data->Receipt->getItem(2)->Price = 30000; + $data->Receipt->getItem(2)->Quantity = 3.00; + $data->Receipt->getItem(2)->Amount = 90000; + $data->Receipt->getItem(2)->Tax = Vat::VAT10; + + $this->assertEquals([ + "TerminalKey" => "TinkoffBankTest", + "Amount" => "140000", + "OrderId" => "21050", + "Description" => "Gift card for 1400.00 rubles", + "DATA" => [ + "Phone" => "+71234567890", + "Email" => "a@test.com" + ], + "Receipt" => [ + "Email" => "a@test.ru", + "Phone" => "+79031234567", + "EmailCompany" => "b@test.ru", + "Taxation" => "osn", + "Items" => [ + [ + "Name" => "Product name 1.", + "Price" => 10000, + "Quantity" => 1.00, + "Amount" => 10000, + "PaymentMethod" => "full_prepayment", + "PaymentObject" => "commodity", + "Tax" => "vat10", + "Ean13" => "0123456789" + ], + [ + "Name" => "Product Name 2.", + "Price" => 20000, + "Quantity" => 2.00, + "Amount" => 40000, + "PaymentMethod" => "prepayment", + "PaymentObject" => "service", + "Tax" => "vat20" + ], + [ + "Name" => "Product Name 3.", + "Price" => 30000, + "Quantity" => 3.00, + "Amount" => 90000, + "Tax" => "vat10" + ] + ] + ] + ], $data->toArray()); + } + + public function testEncryptCardData(): void + { + $privateKey = openssl_pkey_new(); + $publicKey = openssl_pkey_get_details($privateKey)['key']; + + $cardData = new CardData(); + $cardData->PAN = 4300000000000777; + $cardData->ExpDate = "0519"; + $cardData->CardHolder = "IVAN PETROV"; + $cardData->CVV = "111"; + + $data = new FinishAuthorize(); + $data->encodeCardData($publicKey, $cardData); + + openssl_private_decrypt(base64_decode($data->CardData), $decrypted, openssl_get_privatekey($privateKey)); + + $this->assertEquals("PAN=4300000000000777;ExpDate=0519;CardHolder=IVAN PETROV;CVV=111", $decrypted); + } +} diff --git a/tests/Unit/TestData.php b/tests/Unit/TestData.php deleted file mode 100644 index 290b4be..0000000 --- a/tests/Unit/TestData.php +++ /dev/null @@ -1,183 +0,0 @@ -TerminalKey = "TestB"; - $data->Amount = 140000; - $data->OrderId = "21050"; - $data->Description = "Подарочная карта на 1400.00 рублей"; - $data->DATA = [ - "Phone" => "+71234567890", - "Email" => "a@test.com", - ]; - - $item1 = new ItemData(); - $item1->Name = "Наименование товара 1"; - $item1->Price = 10000; - $item1->Quantity = 1.00; - $item1->Amount = 10000; - $item1->PaymentMethod = PaymentMethod::FULL_PREPAYMENT; - $item1->PaymentObject = PaymentObject::COMMODITY; - $item1->Tax = Vat::VAT10; - $item1->Ean13 = "0123456789"; - - $item2 = new ItemData(); - $item2->Name = "Наименование товара 2"; - $item2->Price = 20000; - $item2->Quantity = 2.00; - $item2->Amount = 40000; - $item2->PaymentMethod = PaymentMethod::PREPAYMENT; - $item2->PaymentObject = PaymentObject::SERVICE; - $item2->Tax = Vat::VAT20; - - $item3 = new ItemData(); - $item3->Name = "Наименование товара 3"; - $item3->Price = 30000; - $item3->Quantity = 3.00; - $item3->Amount = 90000; - $item3->Tax = Vat::VAT10; - - $receipt = new ReceiptData(); - $receipt->Email = "a@test.ru"; - $receipt->Phone = "+79031234567"; - $receipt->EmailCompany = "b@test.ru"; - $receipt->Taxation = Taxation::OSN; - $receipt->Items = [$item1, $item2, $item3]; - $data->Receipt = $receipt; - - $array = [ - "TerminalKey" => "TestB", - "Amount" => 140000, - "OrderId" => "21050", - "Description" => "Подарочная карта на 1400.00 рублей", - "DATA" => [ - - "Phone" => "+71234567890", - "Email" => "a@test.com", - ], - - "Receipt" => [ - "Email" => "a@test.ru", - "Phone" => "+79031234567", - "EmailCompany" => "b@test.ru", - "Taxation" => "osn", - "Items" => [ - [ - "Name" => "Наименование товара 1", - "Price" => 10000, - "Quantity" => 1.00, - "Amount" => 10000, - "PaymentMethod" => "full_prepayment", - "PaymentObject" => "commodity", - "Tax" => "vat10", - "Ean13" => "0123456789", - ], - [ - "Name" => "Наименование товара 2", - "Price" => 20000, - "Quantity" => 2.00, - "Amount" => 40000, - "PaymentMethod" => "prepayment", - "PaymentObject" => "service", - "Tax" => "vat20", - ], - [ - "Name" => "Наименование товара 3", - "Price" => 30000, - "Quantity" => 3.00, - "Amount" => 90000, - "Tax" => "vat10", - ], - ], - ], - ]; - - $this->assertEquals($data->toArray(), $array); - } - - public function testConfirmData() - { - $data = new ConfirmData(); - - $data->TerminalKey = "TinkoffBankTest"; - $data->PaymentId = "2164657"; - $data->generateToken("password"); - - $array = [ - "TerminalKey" => "TinkoffBankTest", - "PaymentId" => "2164657", - "Token" => "3cb13992b28bc106867e32c9a1a9185f9715860c09d21f91b3ab5dcc5dfe211b", - ]; - - $this->assertEquals($data->toArray(), $array); - } - - public function testCancelData() - { - $data = new CancelData(); - - $data->TerminalKey = "TinkoffBankTest"; - $data->PaymentId = "2164657"; - $data->generateToken("password"); - - $array = [ - "TerminalKey" => "TinkoffBankTest", - "PaymentId" => "2164657", - "Token" => "3cb13992b28bc106867e32c9a1a9185f9715860c09d21f91b3ab5dcc5dfe211b", - ]; - - $this->assertEquals($data->toArray(), $array); - } - - public function testGetStateData() - { - $data = new GetStateData(); - - $data->TerminalKey = "TinkoffBankTest"; - $data->PaymentId = "2164657"; - $data->generateToken("password"); - - $array = [ - "TerminalKey" => "TinkoffBankTest", - "PaymentId" => "2164657", - "Token" => "3cb13992b28bc106867e32c9a1a9185f9715860c09d21f91b3ab5dcc5dfe211b", - ]; - - $this->assertEquals($data->toArray(), $array); - } - - public function testResendData() - { - $data = new ResendData(); - - $data->TerminalKey = "TinkoffBankTest"; - $data->generateToken("password"); - - $array = [ - "TerminalKey" => "TinkoffBankTest", - "Token" => "79e28c81bdd95b8a8a2d4778aa40978e54161a9ed261ac76de8f5d03f2fd78c0", - ]; - - $this->assertEquals($data->toArray(), $array); - } -}