1
0
Fork 0
mirror of synced 2025-04-19 17:01:00 +00:00

Compare commits

..

32 commits

Author SHA1 Message Date
Ichern
0adfb9edda
Merge pull request #18 from retailcrm/resolve-logger-version-conflict
Resolve conflict with psr/log
2024-07-17 12:44:28 +03:00
Nikolay Parshakov
aecbdeafcc Resolve conflict with psr/log 2024-07-17 12:12:51 +03:00
Ilyas Salikhov
a857ba561a
Merge pull request #17 from retailcrm/sf6
compability with symfony 6
2024-06-17 18:29:03 +03:00
Ilyas Salikhov
f570c20839 compability with symfony 6 2024-06-17 18:28:35 +03:00
Ilyas Salikhov
726b51151c Check deprecations in tests 2024-01-27 19:40:29 +03:00
Ilyas Salikhov
1b75a04cf9 Compability with guzzlehttp/guzzle:^7.0 2024-01-27 19:37:04 +03:00
Ilyas Salikhov
68df0e1f49 Environment to run test locally 2024-01-27 19:36:37 +03:00
Alexey
5158cf22b3
bump "symfony/validator" version in composer.json (#16)
* bump "symfony/validator" version in composer.json
2022-09-05 13:45:33 +03:00
Alexey
c68448954b
fix jms/serializer versions (#15)
* fix jms/serializer versions
* add php 7.4 to travis
* fix travis badge
2021-10-29 12:39:14 +03:00
raulleo
c9f5fa92af
change quantity type from int to float (#14) 2021-05-27 12:06:51 +03:00
Alexey
b09a4259dd
Update README.md 2019-12-26 11:36:49 +03:00
Vragov Roman
5e6ad7544c Update jms serializer (#12) 2019-12-26 11:36:15 +03:00
Alexey
c209002c5a
Update composer.json
fix "symfony/validator" version
2019-11-25 18:18:41 +03:00
Vragov Roman
ae80596b33 Fix vats request (#11) 2019-08-26 12:04:00 +03:00
Vragov Roman
ffd5b85fe0 Remove V3 (#8) 2019-08-22 17:04:26 +03:00
CrazyProgg
6e0adffb46 add fns_site payload property support (#10) 2019-08-22 16:49:05 +03:00
Alexey
ed84369c2c
fix types (#9) 2019-08-08 11:01:53 +03:00
Alexey
5791ca5107
Update README.md 2019-07-24 17:48:07 +03:00
Alexey Chelnakov
1c0d39725d add version badge 2019-07-24 17:46:59 +03:00
Alexey Chelnakov
cdc570e0cd phpunit ~7.0 2019-07-24 17:39:11 +03:00
Alexey Chelnakov
7cfd902db2 add build status 2019-07-24 17:29:56 +03:00
Vragov Roman
342d15ba5b Update guzzle to guzzlehttp/guzzle": "~6.3" 2019-07-24 17:13:55 +03:00
Alexey Chelnakov
9c300796b0 Добавлены параметры:
- Код товара receipt -> items -> nomenclature_code (тег 1162);
  - Покупатель (клиент), (receipt → client → name), (тег 1227);
  - ИНН покупателя (клиента), (receipt → client → inn), (тег 1228).
2019-06-21 12:16:41 +03:00
Alexey
f21bf18401
Merge pull request #2 from raulleo/fix-debug-typo
fix typo
2019-04-11 14:58:36 +03:00
raulleo
21c0f804a5 fix typo 2019-04-11 14:47:05 +03:00
Alexey Chelnakov
73dc060297 fix возвращаем response с ошибкой 2019-04-10 19:22:43 +03:00
Alexey
aa735cff8d
fix Request serialization sno field 2018-12-04 17:47:41 +03:00
Ilyas Salikhov
df1543abd3
Merge pull request #1 from linniksa/sf
add symfony versions other that 2.8
2018-11-26 19:41:01 +03:00
Sergey Linnik
ef14e9a109 add symfony versions other that 2.8 2018-11-26 14:57:28 +03:00
Alexey Chelnakov
6feaaf3fa6 fix type string VatReceiptRequest.sum 2018-08-06 17:33:40 +03:00
Ilyas Salikhov
becb2f5d11 Updated README 2018-06-28 10:44:21 +03:00
Alexey Chelnakov
397fa42b72 удалил composer.lock 2018-06-28 10:33:34 +03:00
47 changed files with 1723 additions and 3400 deletions

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
/.idea
/vendor
composer.lock
.phpunit.result.cache
.env

16
.travis.yml Normal file
View file

@ -0,0 +1,16 @@
language: php
php:
- 7.2
- 7.3
- 7.4
env:
- JMS=0.12
- JMS=1.0
- JMS=2.0
- JMS=3.0
before_install:
- composer selfupdate
- composer require jms/serializer=^$JMS --no-interaction --prefer-dist

6
Dockerfile Normal file
View file

@ -0,0 +1,6 @@
ARG PHP_IMAGE_TAG
FROM php:${PHP_IMAGE_TAG}-cli-alpine
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /opt/test

16
Makefile Normal file
View file

@ -0,0 +1,16 @@
ifneq (,$(shell (type docker-compose 2>&1 >/dev/null && echo 1) || true))
PHP=docker-compose run --rm --no-deps php
else
PHP=php
endif
PHP_CONSOLE_DEPS=vendor
vendor: composer.json
@$(PHP) composer install -o -n --no-ansi
@touch vendor || true
phpunit: $(PHP_CONSOLE_DEPS)
@$(PHP) vendor/bin/phpunit --color=always
check: phpunit

View file

@ -1,11 +1,20 @@
# API клиент для сервиса фискализации платежей АТОЛ Онлайн
[![Build Status](https://app.travis-ci.com/retailcrm/atol-online-client.svg?branch=master)](https://app.travis-ci.com/retailcrm/atol-online-client)
[![Latest stable](https://img.shields.io/packagist/v/retailcrm/atol-online-client.svg?style=flat-square)](https://packagist.org/packages/retailcrm/atol-online-client)
Пример использования:
# API-клиент для АТОЛ.Онлайн
API-клиент на PHP для сервиса онлайн-фискализации платежей АТОЛ.Онлайн
## Требования
* PHP 7.2 и выше
* PHP extension cURL
## Пример использования
```php
$atol = new \AtolOnlineClient\AtolOnline();
$client = new \Guzzle\Http\Client();
$connection = new \AtolOnlineClient\Configuration\Connection();
$connection->version = \AtolOnlineClient\AtolOnlineApi::API_VERSION_V4;
$connection->login = 'login';
@ -15,13 +24,15 @@ $connection->group = 'group';
$config = new \AtolOnlineClient\Configuration();
$config->connections = [$connection];
$api = $this->atol->createApi($client, $connection);
//$api->setLogger();
//$api->setCache();
$client = new \Guzzle\Http\Client();
$api = $atol->createApi($client, $connection);
// $api->setLogger(...);
// $api->setCache(...);
// собираем объект запроса
$request = new \AtolOnlineClient\Request\V4\PaymentReceiptRequest();
/// ...
/// собираем объект запроса
///
$paymentReceiptRequest = $atol->serializeOperationRequest($request);
$response = $atol->getApi()->sell($paymentReceiptRequest);

View file

@ -1,13 +0,0 @@
<?php
use Composer\Autoload\ClassLoader;
use Doctrine\Common\Annotations\AnnotationRegistry;
/**
* @var ClassLoader $loader
*/
$loader = require __DIR__.'/vendor/autoload.php';
AnnotationRegistry::registerLoader('class_exists');
return $loader;

View file

@ -2,7 +2,7 @@
"name": "retailcrm/atol-online-client",
"type": "library",
"license": "proprietary",
"description": "Api client for Atol Online",
"description": "PHP API client for ATOL Online",
"authors": [
{
"name": "retailCRM",
@ -10,21 +10,29 @@
}
],
"require": {
"php": ">=7.1",
"php": ">=7.2",
"ext-curl": "*",
"guzzle/guzzle": "~3.7",
"jms/serializer": "~0.12 || ~1.4.2",
"symfony/validator": "2.8.*",
"ext-json": "*",
"guzzlehttp/guzzle": "~6.3|^7.0",
"jms/serializer": "^0.12|^1.0|^2.0|^3.0",
"symfony/validator": "~2.8|~3.0|~4.0|^5.0|^6.0",
"doctrine/cache": "~1.6",
"psr/log": "~1.0"
"psr/log": "~1.0|^2.0|^3.0"
},
"require-dev": {
"phpunit/phpunit": "7.1."
"phpunit/phpunit": "~8.0"
},
"support": {
"email": "support@retailcrm.ru"
},
"autoload": {
"psr-0": { "AtolOnlineClient\\": "src/" }
"psr-0": {
"AtolOnlineClient\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"AtolOnlineClient\\": "tests/"
}
}
}

2389
composer.lock generated

File diff suppressed because it is too large Load diff

11
docker-compose.yml Normal file
View file

@ -0,0 +1,11 @@
version: '3.4'
services:
php:
build:
context: .
args:
PHP_IMAGE_TAG: ${PHP_IMAGE_TAG:-7.4}
volumes:
- "./:/opt/test"

View file

@ -1,24 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "true"
convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "true"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "bootstrap.php" >
<phpunit bootstrap="tests/bootstrap.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
convertDeprecationsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="php">
<directory>./tests/*/Tests</directory>
<directory>./tests/AtolOnlineClient</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
</phpunit>

View file

@ -3,18 +3,25 @@
namespace AtolOnlineClient;
use AtolOnlineClient\Configuration\Connection;
use AtolOnlineClient\Exception\InvalidResponseException;
use AtolOnlineClient\Response\OperationResponse;
use Guzzle\Http\Client;
use GuzzleHttp\Client;
use JMS\Serializer\DeserializationContext;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\SerializerInterface;
class AtolOnline
{
/**
* @var SerializerInterface
*/
private $serializer;
/** @var AtolOnlineApi */
/**
* @var AtolOnlineApi
*/
private $api;
public function __construct()
@ -22,37 +29,48 @@ class AtolOnline
$this->serializer = SerializerBuilder::create()->build();
}
public function createConfiguration()
/**
* @return Configuration
*/
public function createConfiguration(): ConfigurationInterface
{
return new Configuration();
}
/**
* @param $response
* @param string $response
* @return OperationResponse
*/
public function deserializeOperationResponse($response)
public function deserializeOperationResponse(string $response): OperationResponse
{
return $this->serializer->deserialize(
$response,
OperationResponse::class,
'json',
DeserializationContext::create()->setGroups(['post'])
);
try {
return $this->serializer->deserialize(
$response,
OperationResponse::class,
'json',
DeserializationContext::create()->setGroups(['post'])
);
} catch (RuntimeException $exception) {
throw $this->createInvalidResponseException($response, $exception);
}
}
/**
* @param $response
* @return OperationResponse
*/
public function deserializeCheckStatusResponse($response)
public function deserializeCheckStatusResponse($response): OperationResponse
{
return $this->serializer->deserialize(
$response,
OperationResponse::class,
'json',
DeserializationContext::create()->setGroups(['get'])
);
try {
return $this->serializer->deserialize(
$response,
OperationResponse::class,
'json',
DeserializationContext::create()->setGroups(['get'])
);
} catch (RuntimeException $exception) {
throw $this->createInvalidResponseException($response, $exception);
}
}
/**
@ -69,11 +87,11 @@ class AtolOnline
}
/**
* @param $client
* @param Client $client
* @param Connection $connection
* @return AtolOnlineApi
*/
public function createApi(Client $client, Connection $connection)
public function createApi(Client $client, Connection $connection): AtolOnlineApi
{
if (!$this->api) {
$this->api = new AtolOnlineApi($client, $connection);
@ -85,8 +103,30 @@ class AtolOnline
/**
* @return AtolOnlineApi
*/
public function getApi()
public function getApi(): AtolOnlineApi
{
return $this->api;
}
}
/**
* @param string $response
* @param RuntimeException $previous
* @return InvalidResponseException
*/
private function createInvalidResponseException(string $response, RuntimeException $previous): InvalidResponseException
{
$exception = new InvalidResponseException($previous->getMessage());
preg_match('/<head><title>(\d+) ([\w ]+)<\/title><\/head>/m', $response, $matches);
if (count($matches) === 3) {
[, $code, $message] = $matches;
$exception
->setCodeError($code)
->setMessageError($message);
}
return $exception;
}
}

View file

@ -4,36 +4,28 @@ namespace AtolOnlineClient;
use AtolOnlineClient\Configuration\Connection;
use Doctrine\Common\Cache\Cache;
use Guzzle\Http\Client;
use Guzzle\Http\Exception\BadResponseException;
use Guzzle\Http\Message\Response;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
class AtolOnlineApi
{
public const API_VERSION_V4 = 'v4';
const API_VERSION_V4 = 'v4';
const API_VERSION_V3 = 'v3';
const TOKEN_CACHE_KEY = 'crm_fiscal_atol_online_token';
const TOKEN_CACHE_TIME = 60 * 60 * 24;
public const TOKEN_CACHE_KEY = 'crm_fiscal_atol_online_token';
public const TOKEN_CACHE_TIME = 86400;
private $baseApiUrl = 'https://online.atol.ru/possystem';
private $login;
private $pass;
private $groupCode;
private $debug;
private $testApiUrl = 'https://testonline.atol.ru/possystem';
/**
* @var LoggerInterface
* @var LoggerInterface|null
*/
private $logger;
/**
* @var Cache
* @var Cache|null
*/
private $cache;
@ -42,6 +34,11 @@ class AtolOnlineApi
*/
private $client;
/**
* @var Connection
*/
private $connection;
/**
* @var int
*/
@ -52,9 +49,6 @@ class AtolOnlineApi
*/
private $attemptsCheckStatus;
/** @var string */
private $version;
/**
* @param Client $client
* @param Connection $connectionConfig
@ -62,18 +56,44 @@ class AtolOnlineApi
public function __construct(Client $client, Connection $connectionConfig)
{
$this->client = $client;
$this->login = $connectionConfig->login;
$this->pass = $connectionConfig->pass;
$this->groupCode = $connectionConfig->group;
if (!$connectionConfig->version) {
$connectionConfig->version = self::API_VERSION_V3;
}
$this->version = $connectionConfig->version;
$this->debug = $connectionConfig->isDebug();
$this->connection = $connectionConfig;
$this->attempts = 0;
if ($connectionConfig->isTestMode()) {
$this->baseApiUrl = 'https://testonline.atol.ru/possystem';
}
}
/**
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/**
* @param Cache $cache
*/
public function setCache(Cache $cache): void
{
$this->cache = $cache;
}
/**
* @param string $version
* @return AtolOnlineApi
*/
public function setVersion(string $version): AtolOnlineApi
{
$this->connection->version = $version;
return $this;
}
/**
* @return string
*/
public function getVersion(): string
{
return $this->connection->version ?: self::API_VERSION_V4;
}
/**
@ -84,9 +104,7 @@ class AtolOnlineApi
*/
public function sell($paymentReceiptRequest)
{
if ($response = $this->sendOperationRequest('sell', $paymentReceiptRequest)) {
return $response->getBody()->__toString();
};
return $this->sendOperationRequest('sell', $paymentReceiptRequest);
}
/**
@ -97,73 +115,48 @@ class AtolOnlineApi
*/
public function sellRefund($paymentReceiptRequest)
{
if ($response = $this->sendOperationRequest('sell_refund', $paymentReceiptRequest)) {
return $response->getBody()->__toString();
};
return $this->sendOperationRequest('sell_refund', $paymentReceiptRequest);
}
/**
* Запрос для проверки статуса
*
* @param $uuid
* @param string $uuid
* @return mixed
*/
public function checkStatus($uuid)
{
$token = $this->getToken();
$url = $this->buildUrl('report/'.$uuid, $token);
$request = $this->client->get($url);
$response = false;
$url = $this->buildUrl('report/'.$uuid, $token);
try {
$this->attemptsCheckStatus++;
$response = $request->send();
} catch (BadResponseException $e) {
$this->cache->delete($this->getTokenCacheKey());
$body = json_decode($e->getResponse()->getBody());
if ($this->isTokenExpired($body) && $this->attemptsCheckStatus <= 1) {
$response = $this->client->get($url);
} catch (BadResponseException $exception) {
if ($this->cache) {
$this->cache->delete($this->getTokenCacheKey());
}
$response = $exception->getResponse();
$body = json_decode($response->getBody(), false);
if ($this->attemptsCheckStatus <= 1 && $this->isTokenExpired($body)) {
return $this->checkStatus($uuid);
}
$this->logDebug($url, $uuid, $e->getResponse());
}
if ($response) {
return $response->getBody()->__toString();
}
$this->logDebug($url, $uuid, $response);
return false;
}
/**
* @param $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* @param Cache $cache
*/
public function setCache(Cache $cache)
{
$this->cache = $cache;
}
/**
* @param mixed $version
*/
public function setVersion($version): void
{
$this->version = $version;
return $response->getBody()->__toString();
}
/**
* @return string
*/
public function getVersion(): string
protected function getUri(): string
{
return $this->version;
return $this->connection->isTestMode() ? $this->testApiUrl : $this->baseApiUrl;
}
/**
@ -173,134 +166,137 @@ class AtolOnlineApi
protected function getToken()
{
$data = [
'login' => $this->login,
'pass' => $this->pass,
'login' => $this->connection->login,
'pass' => $this->connection->pass,
];
if ($token = $this->cache->fetch($this->getTokenCacheKey())) {
if ($this->cache && ($token = $this->cache->fetch($this->getTokenCacheKey()))) {
return $token;
}
$dataJson = json_encode((object)$data, JSON_UNESCAPED_UNICODE);
$url = $this->baseApiUrl
.'/'.$this->version
.'/getToken';
$request = $this->client->createRequest('POST', $url, null, $dataJson);
$url = $this->getUri().'/'.$this->connection->version.'/getToken';
$response = false;
try {
$response = $this->client->send($request);
} catch (BadResponseException $e) {
if ($this->logger) {
$this->logger->error($e->getResponse()->getBody());
$response = $this->client->post($url, ['body' => $dataJson]);
} catch (BadResponseException $exception) {
if ($this->logger && $exception->getResponse()) {
$this->logger->error((string) $exception->getResponse()->getBody());
}
}
if ($response) {
$response = json_decode($response->getBody());
$response = json_decode($response->getBody(), true);
if ($this->version === self::API_VERSION_V4) {
if (!isset ($response->error)) {
$this->cache->save($this->getTokenCacheKey(), $response->token, self::TOKEN_CACHE_TIME);
return $response->token;
} else {
$this->logger->error($response->error->code . ' '. $response->error->text);
}
} else {
if (isset($response->code) && ($response->code == 1 || $response->code == 0)) {
$this->cache->save($this->getTokenCacheKey(), $response->token, self::TOKEN_CACHE_TIME);
return $response->token;
}
if ($this->cache && !isset($response['error'])) {
$this->cache->save($this->getTokenCacheKey(), $response['token'], self::TOKEN_CACHE_TIME);
}
}
if ($this->logger && isset($response['error'])) {
$this->logger->error($response['error']['code'] . ' '. $response['error']['text']);
}
if (!isset($response['error'])) {
return $response['token'];
}
}
return false;
}
/**
* @return string
*/
protected function getTokenCacheKey()
{
return self::TOKEN_CACHE_KEY.'_'.md5($this->login.$this->pass).'_'.$this->version;
}
/**
* @param string $operation
* @param null $token
* @param string|null $token
* @return string
*/
protected function buildUrl($operation, $token = null)
protected function buildUrl(string $operation, string $token = null): string
{
$url = $this->baseApiUrl
.'/'.$this->version
.'/'.$this->groupCode
$url = $this->getUri()
.'/'.$this->connection->version
.'/'.$this->connection->group
.'/'.$operation;
if ($token) {
if ($this->version === self::API_VERSION_V4) {
$url .= '?token='.$token;
} elseif ($this->version === self::API_VERSION_V3) {
$url .= '?tokenid='.$token;
}
if (!$token) {
return $url;
}
return $url;
return $url.'?token='.$token;
}
/**
* @param string $operation
* @param string $data
* @return Response|bool
* @param mixed $data
* @return string
*/
protected function sendOperationRequest($operation, $data)
protected function sendOperationRequest(string $operation, $data): string
{
$token = $this->getToken();
$url = $this->buildUrl($operation, $token);
$request = $this->client->createRequest('POST', $url, null, $data);
$response = false;
try {
$this->attempts++;
$response = $this->client->send($request);
$response = $this->client->post($url, ['body' => $data]);
} catch (BadResponseException $e) {
$this->cache->delete($this->getTokenCacheKey());
$body = json_decode($e->getResponse()->getBody());
if ($this->cache) {
$this->cache->delete($this->getTokenCacheKey());
}
$response = $e->getResponse();
$body = json_decode($response->getBody()->__toString(), false);
if ($this->isTokenExpired($body) && $this->attempts <= 1) {
return $this->sendOperationRequest($operation, $data);
}
$this->logDebug($url, $data, $e->getResponse());
}
if ($response) {
$this->logDebug($url, $data, $response);
}
return $response;
return $response->getBody()->__toString();
}
protected function logDebug($url, $data, Response $response)
/**
* @param string $url
* @param string $data
* @param ResponseInterface $response
*/
protected function logDebug(string $url, string $data, ResponseInterface $response): void
{
if ($this->debug && $this->logger) {
$v = "* URL: ".$url;
$v .= "\n * POSTFILEDS: ".$data;
$v .= "\n * RESPONSE HEADERS: ".$response->getRawHeaders();
if ($this->logger && $this->connection->isDebug()) {
$headers = [];
foreach ($response->getHeaders() as $key => $value) {
$headers[] = implode(': ', [$key, $value[0]]);
}
$v = '* URL: '.$url;
$v .= "\n * POSTFIELDS: ".$data;
$v .= "\n * RESPONSE HEADERS: ".implode(', ', $headers);
$v .= "\n * RESPONSE BODY: ".$response->getBody();
$v .= "\n * ATTEMPTS: ".$this->attempts;
$this->logger->debug($v);
}
}
protected function isTokenExpiredCode($code)
/**
* @return string
*/
protected function getTokenCacheKey(): string
{
return in_array($code, [4, 5, 6, 12, 13, 14]);
return self::TOKEN_CACHE_KEY.'_'.md5($this->connection->login.$this->connection->pass).'_'.$this->connection->version;
}
private function isTokenExpired($body)
/**
* @param object $body
* @return bool
*/
private function isTokenExpired($body): bool
{
return isset($body->error) && $this->isTokenExpiredCode($body->error->code);
return isset($body->error) && in_array($body->error->code, [4, 5, 6, 12, 13, 14], true);
}
}

View file

@ -8,14 +8,20 @@ use Symfony\Component\Validator\Mapping\ClassMetadata;
class Configuration implements ConfigurationInterface
{
/** @var Connection[] */
/**
* @var Connection[]
*/
public $connections;
/** @var boolean */
public $enabled;
/**
* @var boolean
*/
public $enabled = true;
/** @var bool */
public $debug;
/**
* @var bool
*/
public $debug = false;
/**
* @param ClassMetadata $metadata

View file

@ -25,7 +25,6 @@ class Connection
];
const versions = [
AtolOnlineApi::API_VERSION_V3,
AtolOnlineApi::API_VERSION_V4,
];
@ -45,7 +44,7 @@ class Connection
public $sno;
/** @var string */
public $version;
public $version = AtolOnlineApi::API_VERSION_V4;
/** @var bool */
public $testMode = false;
@ -53,7 +52,7 @@ class Connection
/**
* @return bool
*/
public function isTestMode()
public function isTestMode(): bool
{
return $this->testMode;
}
@ -61,7 +60,7 @@ class Connection
/**
* @param bool $testMode
*/
public function setTestMode(bool $testMode)
public function setTestMode(bool $testMode): void
{
$this->testMode = $testMode;
}
@ -85,7 +84,7 @@ class Connection
/**
* @param ClassMetadata $metadata
*/
public static function loadValidatorMetadata(ClassMetadata $metadata)
public static function loadValidatorMetadata(ClassMetadata $metadata): void
{
$metadata->addPropertyConstraint('login', new Assert\NotBlank());
$metadata->addPropertyConstraint('pass', new Assert\NotBlank());
@ -111,14 +110,6 @@ class Connection
return $this->version;
}
/**
* @return bool
*/
public function isVersion3()
{
return $this->getVersion() === AtolOnlineApi::API_VERSION_V3;
}
/**
* @return bool
*/

View file

@ -2,7 +2,8 @@
namespace AtolOnlineClient\Exception;
class AtolException extends \Exception
{
use Exception;
class AtolException extends Exception
{
}

View file

@ -0,0 +1,59 @@
<?php
namespace AtolOnlineClient\Exception;
/**
* Class InvalidResponseException
*
* @package AtolOnlineClient\Exception
*/
class InvalidResponseException extends AtolException
{
/**
* @var int|null
*/
protected $codeError;
/**
* @var string|null
*/
protected $messageError;
/**
* @return int|null
*/
public function getCodeError(): ?int
{
return $this->codeError;
}
/**
* @param int|null $codeError
* @return InvalidResponseException
*/
public function setCodeError(?int $codeError): InvalidResponseException
{
$this->codeError = $codeError;
return $this;
}
/**
* @return string|null
*/
public function getMessageError(): ?string
{
return $this->messageError;
}
/**
* @param string|null $messageError
* @return InvalidResponseException
*/
public function setMessageError(?string $messageError): InvalidResponseException
{
$this->messageError = $messageError;
return $this;
}
}

View file

@ -1,129 +0,0 @@
<?php
namespace AtolOnlineClient\Request\V3;
use JMS\Serializer\Annotation as Serializer;
class PaymentReceiptRequest
{
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("timestamp")
* @Serializer\Type("string")
*/
private $timestamp;
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("external_id")
* @Serializer\Type("string")
*/
private $externalId;
/**
* @var ServiceRequest
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("service")
* @Serializer\Type("AtolOnlineClient\Request\V3\ServiceRequest")
*/
private $service;
/**
* @var ReceiptRequest
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("receipt")
* @Serializer\Type("AtolOnlineClient\Request\V3\ReceiptRequest")
*/
private $receipt;
public function __construct()
{
$this->timestamp = (new \DateTime())->format('d.m.Y H:i:s');
}
/**
* @return string
*/
public function getTimestamp()
{
return $this->timestamp;
}
/**
* @param string $timestamp
*
* @return $this
*/
public function setTimestamp($timestamp)
{
$this->timestamp = $timestamp;
return $this;
}
/**
* @return string
*/
public function getExternalId()
{
return $this->externalId;
}
/**
* @param string $externalId
*
* @return $this
*/
public function setExternalId($externalId)
{
$this->externalId = $externalId;
return $this;
}
/**
* @return \AtolOnlineClient\Request\V3\ServiceRequest
*/
public function getService()
{
return $this->service;
}
/**
* @param \AtolOnlineClient\Request\V3\ServiceRequest $service
*
* @return $this
*/
public function setService($service)
{
$this->service = $service;
return $this;
}
/**
* @return ReceiptRequest
*/
public function getReceipt()
{
return $this->receipt;
}
/**
* @param ReceiptRequest $receipt
*
* @return $this
*/
public function setReceipt($receipt)
{
$this->receipt = $receipt;
return $this;
}
}

View file

@ -1,98 +0,0 @@
<?php
namespace AtolOnlineClient\Request\V3;
use JMS\Serializer\Annotation as Serializer;
class ReceiptAttributesRequest
{
/**
* @var string
*
* "enum": [
* "osn",
* "usn_income",
* "usn_income_outcome",
* "envd",
* "esn",
* "patent"
* ]
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("sno")
* @Serializer\Type("string")
*/
private $sno;
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("email")
* @Serializer\Type("string")
*/
private $email;
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("phone")
* @Serializer\Type("string")
*/
private $phone;
/**
* ReceiptAttributesRequest constructor.
* @param string $email
* @param string $phone
*/
public function __construct($email, $phone)
{
$this->email = $email;
if ($email == null) {
$this->email = '';
}
$this->phone = $phone;
if ($phone == null) {
$this->phone = '';
}
}
/**
* @return string
*/
public function getSno()
{
return $this->sno;
}
/**
* @param string $sno
*
* @return $this
*/
public function setSno($sno)
{
$this->sno = $sno;
return $this;
}
/**
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* @return string
*/
public function getPhone()
{
return $this->phone;
}
}

View file

@ -1,163 +0,0 @@
<?php
namespace AtolOnlineClient\Request\V3;
use JMS\Serializer\Annotation as Serializer;
class ReceiptItemRequest
{
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("name")
* @Serializer\Type("string")
*/
private $name;
/**
* @var float
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("price")
* @Serializer\Type("float")
*/
private $price;
/**
* @var integer
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("quantity")
* @Serializer\Type("integer")
*/
private $quantity;
/**
* @var float
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("sum")
* @Serializer\Type("float")
*/
private $sum;
/**
* @var string
*
* "enum": [
* "none",
* "vat0",
* "vat10",
* "vat18",
* "vat110",
* "vat118"
* ]
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("tax")
* @Serializer\Type("string")
*/
private $tax;
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*
* @return $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return float
*/
public function getPrice()
{
return $this->price;
}
/**
* @param float $price
*
* @return $this
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* @return integer
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* @param int $quantity
*
* @return $this
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* @return float
*/
public function getSum()
{
return $this->sum;
}
/**
* @param float $sum
*
* @return $this
*/
public function setSum($sum)
{
$this->sum = $sum;
return $this;
}
/**
* @return string
*/
public function getTax()
{
return $this->tax;
}
/**
* @param string $tax
*
* @return $this
*/
public function setTax($tax)
{
$this->tax = $tax;
return $this;
}
}

View file

@ -1,59 +0,0 @@
<?php
namespace AtolOnlineClient\Request\V3;
use JMS\Serializer\Annotation as Serializer;
class ReceiptPaymentRequest
{
const TYPE_ELECTRON = 1;
const TYPE_PREPAY = 2;
const TYPE_CREDIT = 3;
const TYPE_OTHER = 4;
/**
* @var int
* "enum": 0..9
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("type")
* @Serializer\Type("integer")
*/
private $type;
/**
* @var float
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("sum")
* @Serializer\Type("float")
*/
private $sum;
/**
* @param int $type
* @param float $sum
*/
public function __construct($type, $sum)
{
$this->type = $type;
$this->sum = $sum;
}
/**
* @return int
*/
public function getType()
{
return $this->type;
}
/**
* @return float
*/
public function getSum()
{
return $this->sum;
}
}

View file

@ -1,127 +0,0 @@
<?php
namespace AtolOnlineClient\Request\V3;
use JMS\Serializer\Annotation as Serializer;
class ReceiptRequest
{
/**
* @var ReceiptAttributesRequest
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("attributes")
* @Serializer\Type("AtolOnlineClient\Request\V3\ReceiptAttributesRequest")
*/
private $attributes;
/**
* @var ReceiptItemRequest[]
* "minItems": 1, "maxItems": 100,
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("items")
* @Serializer\Type("array<AtolOnlineClient\Request\V3\ReceiptItemRequest>")
*/
private $items;
/**
* @var float
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("total")
* @Serializer\Type("float")
*/
private $total;
/**
* @var \AtolOnlineClient\Request\V3\ReceiptPaymentRequest[]
* "minItems": 1, "maxItems": 10,
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("payments")
* @Serializer\Type("array<AtolOnlineClient\Request\V3\ReceiptPaymentRequest>")
*/
private $payments;
/**
* @return ReceiptAttributesRequest
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* @param ReceiptAttributesRequest $attributes
*
* @return $this
*/
public function setAttributes($attributes)
{
$this->attributes = $attributes;
return $this;
}
/**
* @return ReceiptItemRequest[]
*/
public function getItems()
{
return $this->items;
}
/**
* @param ReceiptItemRequest[] $items
*
* @return $this
*/
public function setItems($items)
{
$this->items = $items;
return $this;
}
/**
* @return float
*/
public function getTotal()
{
return $this->total;
}
/**
* @param float $total
*
* @return $this
*/
public function setTotal($total)
{
$this->total = $total;
return $this;
}
/**
* @return \AtolOnlineClient\Request\V3\ReceiptPaymentRequest[]
*/
public function getPayments()
{
return $this->payments;
}
/**
* @param \AtolOnlineClient\Request\V3\ReceiptPaymentRequest[] $payments
*
* @return $this
*/
public function setPayments($payments)
{
$this->payments = $payments;
return $this;
}
}

View file

@ -1,106 +0,0 @@
<?php
namespace AtolOnlineClient\Request\V3;
use JMS\Serializer\Annotation as Serializer;
class ServiceRequest
{
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("inn")
* @Serializer\Type("string")
*/
private $inn;
/**
* @var string
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("callback_url")
* @Serializer\Type("string")
*/
private $callbackUrl;
/**
* @var string
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("payment_address")
* @Serializer\Type("string")
*/
private $paymentAddress;
/**
* Service constructor.
* @param string $inn
* @param string $paymentAddress
*/
public function __construct($inn, $paymentAddress)
{
$this->inn = $inn;
$this->paymentAddress = $paymentAddress;
}
/**
* @return string
*/
public function getCallbackUrl()
{
return $this->callbackUrl;
}
/**
* @param string $callbackUrl
*
* @return $this
*/
public function setCallbackUrl($callbackUrl)
{
$this->callbackUrl = $callbackUrl;
return $this;
}
/**
* @return string
*/
public function getInn()
{
return $this->inn;
}
/**
* @param string $inn
*
* @return $this
*/
public function setInn($inn)
{
$this->inn = $inn;
return $this;
}
/**
* @return string
*/
public function getPaymentAddress()
{
return $this->paymentAddress;
}
/**
* @param string $paymentAddress
*
* @return $this
*/
public function setPaymentAddress($paymentAddress)
{
$this->paymentAddress = $paymentAddress;
return $this;
}
}

View file

@ -7,12 +7,12 @@ use JMS\Serializer\Annotation as Serializer;
/**
* В запросе обязательно должно быть заполнено хотя бы одно из полей: email или phone.
* Если заполнены оба поля, ОФД отправит электронный чек только на email.
* @Serializer\AccessType("public_method")
*/
class ClientReceiptRequest
{
/**
* @var string
* required
* @var string|null
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("email")
* @Serializer\Type("string")
@ -20,8 +20,7 @@ class ClientReceiptRequest
private $email;
/**
* @var string
* required
* @var string|null
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("phone")
* @Serializer\Type("string")
@ -29,25 +28,91 @@ class ClientReceiptRequest
private $phone;
public function __construct($email, $phone)
/**
* @var string|null
*
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("name")
* @Serializer\Type("string")
*/
private $name;
/**
* @var string|null
*
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("inn")
* @Serializer\Type("string")
*/
private $inn;
public function __construct(string $email = null, string $phone = null)
{
$this->email = $email;
$this->phone = $phone;
}
/**
* @return string
* @return string|null
*/
public function getEmail(): string
public function getEmail(): ?string
{
return $this->email;
}
/**
* @return string
* @param string|null $email
*/
public function getPhone(): string
public function setEmail(?string $email): void
{
$this->email = $email;
}
/**
* @return string|null
*/
public function getPhone(): ?string
{
return $this->phone;
}
/**
* @param string|null $phone
*/
public function setPhone(?string $phone): void
{
$this->phone = $phone;
}
/**
* @return string|null
*/
public function getName(): ?string
{
return $this->name;
}
/**
* @param string|null $name
*/
public function setName(?string $name): void
{
$this->name = $name;
}
/**
* @return string|null
*/
public function getInn(): ?string
{
return $this->inn;
}
/**
* @param string|null $inn
*/
public function setInn(?string $inn): void
{
$this->inn = $inn;
}
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class CompanyReceiptRequest
{
/**
@ -16,10 +19,10 @@ class CompanyReceiptRequest
private $email;
/**
* @var string
* @var string|null
* Поле необязательно, если у организации один тип налогообложения
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("phone")
* @Serializer\SerializedName("sno")
* @Serializer\Type("string")
*/
private $sno;
@ -59,17 +62,17 @@ class CompanyReceiptRequest
}
/**
* @return string
* @return string|null
*/
public function getSno(): string
public function getSno(): ?string
{
return $this->sno;
}
/**
* @param string $sno
* @param string|null $sno
*/
public function setSno(string $sno): void
public function setSno(?string $sno): void
{
$this->sno = $sno;
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class PaymentReceiptRequest
{
/**
@ -44,7 +47,6 @@ class PaymentReceiptRequest
private $service;
public function __construct()
{
$this->timestamp = (new \DateTime())->format('d.m.Y H:i:s');
@ -90,6 +92,14 @@ class PaymentReceiptRequest
return $this->timestamp;
}
/**
* @param string $timestamp
*/
public function setTimestamp(string $timestamp): void
{
$this->timestamp = $timestamp;
}
/**
* @return ServiceRequest
*/

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class ReceiptItemRequest
{
@ -50,11 +53,11 @@ class ReceiptItemRequest
private $price;
/**
* @var integer
* @var float
* required
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("quantity")
* @Serializer\Type("integer")
* @Serializer\Type("float")
*/
private $quantity;
@ -68,7 +71,7 @@ class ReceiptItemRequest
private $sum;
/**
* @var string
* @var string|null
*
* required
* @Serializer\Groups({"set", "get"})
@ -88,7 +91,7 @@ class ReceiptItemRequest
* «partial_payment» частичный расчет и кредит. Частичная оплата предмета расчета в момент его передачи с последующей оплатой в кредит.
* «credit» передача в кредит. Передача предмета расчета без его оплаты в момент его передачи с последующей оплатой в кредит.
* «credit_payment» оплата кредита. Оплата предмета расчета после его передачи с оплатой в кредит (оплата кредита).
* @var string
* @var string|null
*
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("payment_method")
@ -113,7 +116,7 @@ class ReceiptItemRequest
* «composite» составной предмет расчета. О предмете расчета, состоящем из предметов, каждому из которых может быть присвоено значение выше перечисленных признаков.
* «another» иной предмет расчета. О предмете расчета, не относящемуся к выше перечисленным предметам расчета
*
* @var string
* @var string|null
*
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("payment_object")
@ -131,6 +134,14 @@ class ReceiptItemRequest
*/
private $vat;
/**
* @var string|null
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("nomenclature_code")
* @Serializer\Type("string")
*/
private $nomenclatureCode;
/**
* @return string
*/
@ -164,17 +175,17 @@ class ReceiptItemRequest
}
/**
* @return int
* @return float
*/
public function getQuantity(): int
public function getQuantity(): float
{
return $this->quantity;
}
/**
* @param int $quantity
* @param float $quantity
*/
public function setQuantity(int $quantity): void
public function setQuantity(float $quantity): void
{
$this->quantity = $quantity;
}
@ -196,49 +207,49 @@ class ReceiptItemRequest
}
/**
* @return string
* @return string|null
*/
public function getMeasurementUnit(): string
public function getMeasurementUnit(): ?string
{
return $this->measurementUnit;
}
/**
* @param string $measurementUnit
* @param string|null $measurementUnit
*/
public function setMeasurementUnit(string $measurementUnit): void
public function setMeasurementUnit(?string $measurementUnit): void
{
$this->measurementUnit = $measurementUnit;
}
/**
* @return string
* @return string|null
*/
public function getPaymentMethod(): string
public function getPaymentMethod(): ?string
{
return $this->paymentMethod;
}
/**
* @param string $paymentMethod
* @param string|null $paymentMethod
*/
public function setPaymentMethod(string $paymentMethod): void
public function setPaymentMethod(?string $paymentMethod): void
{
$this->paymentMethod = $paymentMethod;
}
/**
* @return string
* @return string|null
*/
public function getPaymentObject(): string
public function getPaymentObject(): ?string
{
return $this->paymentObject;
}
/**
* @param string $paymentObject
* @param string|null $paymentObject
*/
public function setPaymentObject(string $paymentObject): void
public function setPaymentObject(?string $paymentObject): void
{
$this->paymentObject = $paymentObject;
}
@ -258,4 +269,20 @@ class ReceiptItemRequest
{
$this->vat = $vat;
}
/**
* @return string|null
*/
public function getNomenclatureCode(): ?string
{
return $this->nomenclatureCode;
}
/**
* @param string|null $nomenclatureCode
*/
public function setNomenclatureCode(?string $nomenclatureCode): void
{
$this->nomenclatureCode = $nomenclatureCode;
}
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class ReceiptPaymentRequest
{
const TYPE_ELECTRON = 1;
@ -49,6 +52,14 @@ class ReceiptPaymentRequest
return $this->type;
}
/**
* @param int $type
*/
public function setType(int $type): void
{
$this->type = $type;
}
/**
* @return float
*/
@ -56,4 +67,12 @@ class ReceiptPaymentRequest
{
return $this->sum;
}
/**
* @param float $sum
*/
public function setSum(float $sum): void
{
$this->sum = $sum;
}
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class ReceiptRequest
{
@ -47,9 +50,9 @@ class ReceiptRequest
private $payments;
/**
* @var \AtolOnlineClient\Request\V4\VatReceiptRequest[]
* @var \AtolOnlineClient\Request\V4\VatReceiptRequest[]|null
* "minItems": 1, "maxItems": 6,
* required
*
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("vats")
* @Serializer\Type("array<AtolOnlineClient\Request\V4\VatReceiptRequest>")
@ -130,17 +133,17 @@ class ReceiptRequest
}
/**
* @return VatReceiptRequest[]
* @return VatReceiptRequest[]|null
*/
public function getVats(): array
public function getVats(): ?array
{
return $this->vats;
}
/**
* @param VatReceiptRequest[] $vats
* @param VatReceiptRequest[]|null $vats
*/
public function setVats(array $vats): void
public function setVats(?array $vats): void
{
$this->vats = $vats;
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class ServiceRequest
{

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Request\V4;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class VatReceiptRequest
{
/**
@ -12,9 +15,9 @@ class VatReceiptRequest
* "none",
* "vat0",
* "vat10",
* "vat18",
* "vat20",
* "vat110",
* "vat118"
* "vat120"
* ]
*
* @var string
@ -26,8 +29,8 @@ class VatReceiptRequest
private $type;
/**
* @var float
* required
* @var float|null
*
* @Serializer\Groups({"set", "get"})
* @Serializer\SerializedName("sum")
* @Serializer\Type("float")
@ -39,10 +42,10 @@ class VatReceiptRequest
* @param string $type
* @param float $sum
*/
public function __construct(string $type, string $sum)
public function __construct(string $type, $sum)
{
$this->type = $type;
$this->sum = $sum;
$this->sum = (float) $sum;
}
/**
@ -53,11 +56,27 @@ class VatReceiptRequest
return $this->type;
}
/**
* @param string $type
*/
public function setType(string $type): void
{
$this->type = $type;
}
/**
* @return float
*/
public function getSum(): string
public function getSum()
{
return $this->sum;
}
}
/**
* @param float $sum
*/
public function setSum(float $sum): void
{
$this->sum = $sum;
}
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Response;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class Error
{

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Response;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class OperationResponse
{
@ -223,7 +226,7 @@ class OperationResponse
/**
* @param string $groupCode
*/
public function setGroupCode(string $groupCode)
public function setGroupCode(?string $groupCode)
{
$this->groupCode = $groupCode;
}
@ -239,7 +242,7 @@ class OperationResponse
/**
* @param string $daemonCode
*/
public function setDaemonCode(string $daemonCode)
public function setDaemonCode(?string $daemonCode)
{
$this->daemonCode = $daemonCode;
}
@ -255,7 +258,7 @@ class OperationResponse
/**
* @param string $deviceCode
*/
public function setDeviceCode(string $deviceCode)
public function setDeviceCode(?string $deviceCode)
{
$this->deviceCode = $deviceCode;
}

View file

@ -4,6 +4,9 @@ namespace AtolOnlineClient\Response;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\AccessType("public_method")
*/
class Payload
{
/**
@ -86,6 +89,16 @@ class Payload
*/
private $fiscalDocumentAttribute;
/**
* Адрес сайта ФНС
*
* @var string
* @Serializer\Groups({"get"})
* @Serializer\SerializedName("fns_site")
* @Serializer\Type("string")
*/
private $fnsSite;
/**
* @return mixed
*/
@ -245,4 +258,24 @@ class Payload
return $this;
}
/**
* @return string
*/
public function getFnsSite()
{
return $this->fnsSite;
}
/**
* @param $string $fnsSite
*
* @return $this
*/
public function setFnsSite($fnsSite)
{
$this->fnsSite = $fnsSite;
return $this;
}
}

View file

@ -0,0 +1,415 @@
<?php
namespace AtolOnlineClient\AtolOnlineClient;
use AtolOnlineClient\AtolOnline;
use AtolOnlineClient\AtolOnlineApi;
use AtolOnlineClient\AtolOnlineClient\Traits\PaymentReceiptRequestTrait;
use AtolOnlineClient\Configuration\Connection;
use Doctrine\Common\Cache\ArrayCache;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
use Psr\Log\Test\TestLogger;
/**
* Class AtolOnlineApiTest
*
* @package AtolOnlineClient\AtolOnlineClient
*/
class AtolOnlineApiTest extends TestCase
{
use PaymentReceiptRequestTrait;
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::__construct
* @covers \AtolOnlineClient\AtolOnlineApi::setLogger
* @covers \AtolOnlineClient\AtolOnlineApi::setCache
* @covers \AtolOnlineClient\AtolOnlineApi::setVersion
* @covers \AtolOnlineClient\AtolOnlineApi::getVersion
*/
public function testCreateApi(): void
{
$api = new AtolOnlineApi(new Client(), new Connection());
$this->assertInstanceOf(AtolOnlineApi::class, $api);
$api->setVersion(AtolOnlineApi::API_VERSION_V4);
$this->assertSame(AtolOnlineApi::API_VERSION_V4, $api->getVersion());
$api->setLogger(new NullLogger());
$this->assertInstanceOf(NullLogger::class, $this->getProperty($api, 'logger'));
$api->setCache(new ArrayCache());
$this->assertInstanceOf(ArrayCache::class, $this->getProperty($api, 'cache'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::sell
*/
public function testSell(): void
{
$responses = [
new Response(200, [], $this->getTokenSuccessResponseV4()),
new Response(200, [], $this->getReportSuccessReportV4()),
];
$request = (new AtolOnline())->serializeOperationRequest($this->getPaymentReceiptRequest());
$response = $this->getApi($responses)->sell($request);
$this->assertSame('2ea26f1708844f08b120306fc096a58f', json_decode($response, true)['uuid']);
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::sellRefund
*/
public function testSellRefund(): void
{
$responses = [
new Response(200, [], $this->getTokenSuccessResponseV4()),
new Response(200, [], $this->getReportSuccessReportV4()),
];
$request = (new AtolOnline())->serializeOperationRequest($this->getPaymentReceiptRequest());
$response = $this->getApi($responses)->sellRefund($request);
$this->assertSame('2ea26f1708844f08b120306fc096a58f', json_decode($response, true)['uuid']);
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::checkStatus
*/
public function testCheckStatusSuccessResponse(): void
{
$responses = [
new Response(200, [], $this->getTokenSuccessResponseV4()),
new Response(200, [], $this->getReportSuccessReportV4()),
];
$response = $this->callMethod($this->getApi($responses), 'checkStatus', [
'uuid' => '2ea26f1708844f08b120306fc096a58f',
]);
$this->assertSame('2ea26f1708844f08b120306fc096a58f', json_decode($response, true)['uuid']);
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::checkStatus
*/
public function testCheckStatusBadResponse(): void
{
$responses = [
new Response(200, [], $this->getTokenSuccessResponseV4()),
new BadResponseException('', new Request('GET', 'test'), new Response(200, [], $this->getErrorResponseV4())),
new Response(200, [], $this->getTokenSuccessResponseV4()),
new Response(200, [], $this->getReportSuccessReportV4()),
];
$api = $this->getApi($responses);
$api->setCache(new ArrayCache());
$response = $this->callMethod($api, 'checkStatus', [
'uuid' => '2ea26f1708844f08b120306fc096a58f',
]);
$this->assertSame('2ea26f1708844f08b120306fc096a58f', json_decode($response, true)['uuid']);
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getUri
*/
public function testGetUri(): void
{
$this->assertSame('https://online.atol.ru/possystem', $this->callMethod($this->getApi(), 'getUri'));
$this->assertSame('https://testonline.atol.ru/possystem', $this->callMethod($this->getApi([], true, true), 'getUri'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getToken
*/
public function testGetTokenBadResponse(): void
{
$api = $this->getApi([new BadResponseException('', new Request('GET', 'test'), new Response())]);
$this->assertFalse($this->callMethod($api, 'getToken'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getToken
*/
public function testGetTokenSuccessResponse(): void
{
$api = $this->getApi([new Response(200, [], $this->getTokenSuccessResponseV4())]);
$this->assertSame('fj45u923j59ju42395iu9423i59243u0', $this->callMethod($api, 'getToken'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getToken
*/
public function testGetTokenErrorResponseWithLogger(): void
{
$logger = new TestLogger();
$api = $this->getApi([new Response(200, [], $this->getErrorResponseV4())]);
$api->setLogger($logger);
$this->assertFalse($this->callMethod($api, 'getToken'));
$this->assertTrue($logger->hasError('12 Неверный логин или пароль'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getToken
*/
public function testGetTokenBadResponseWithLogger(): void
{
$logger = new TestLogger();
$api = $this->getApi([new BadResponseException('', new Request('GET', 'test'), new Response(200, [], $this->getErrorResponseV4()))]);
$api->setLogger($logger);
$this->assertFalse($this->callMethod($api, 'getToken'));
$this->assertTrue($logger->hasError('{"error":{"error_id":"4475d6d8d-844d-4d05-aa8b-e3dbdf3defd5","code":12,"text":"\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c","type":"system"},"timestamp":"30.11.2017 17:58:53"}'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getToken
*/
public function testGetTokenSuccessResponseWithCache(): void
{
$cache = new ArrayCache();
$api = $this->getApi([new Response(200, [], $this->getTokenSuccessResponseV4())]);
$api->setCache($cache);
$this->assertSame('fj45u923j59ju42395iu9423i59243u0', $this->callMethod($api, 'getToken'));
$this->assertTrue($cache->contains($this->callMethod($api, 'getTokenCacheKey')));
$this->assertSame('fj45u923j59ju42395iu9423i59243u0', $this->callMethod($api, 'getToken'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::buildUrl
*/
public function testBuildUrlWithoutToken(): void
{
$args = ['operation' => 'test'];
$this->assertSame('https://online.atol.ru/possystem/v4/group/test', $this->callMethod($this->getApi(), 'buildUrl', $args));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::buildUrl
*/
public function testBuildUrlWithToken(): void
{
$args = ['operation' => 'test', 'token' => 'test'];
$this->assertSame('https://online.atol.ru/possystem/v4/group/test?token=test', $this->callMethod($this->getApi(), 'buildUrl', $args));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::sendOperationRequest
*/
public function testSendOperationRequestSuccessResponse(): void
{
$responses = [
new Response(200, [], $this->getTokenSuccessResponseV4()),
new Response(200, [], $this->getTokenSuccessResponseV4())
];
$request = (new AtolOnline())->serializeOperationRequest($this->getPaymentReceiptRequest());
$response = $this->callMethod($this->getApi($responses), 'sendOperationRequest', [
'operation' => 'sell',
'data' => $request,
]);
$this->assertSame('fj45u923j59ju42395iu9423i59243u0', json_decode($response, true)['token']);
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::sendOperationRequest
*/
public function testSendOperationRequestBadResponse(): void
{
$responses = [
new Response(200, [], $this->getTokenSuccessResponseV4()),
new BadResponseException('', new Request('GET', 'test'), new Response(200, [], $this->getErrorResponseV4())),
new Response(200, [], $this->getTokenSuccessResponseV4()),
new Response(200, [], $this->getTokenSuccessResponseV4()),
];
$request = (new AtolOnline())->serializeOperationRequest($this->getPaymentReceiptRequest());
$api = $this->getApi($responses);
$api->setCache(new ArrayCache());
$response = $this->callMethod($api, 'sendOperationRequest', [
'operation' => 'sell',
'data' => $request,
]);
$this->assertSame('fj45u923j59ju42395iu9423i59243u0', json_decode($response, true)['token']);
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::logDebug
*/
public function testLogDebug(): void
{
$logger = new TestLogger();
$api = $this->getApi();
$api->setLogger($logger);
$this->callMethod($api, 'logDebug', [
'url' => '/test',
'data' => 'test',
'response' => new Response(200, ['X-Foo' => 'Bar', 'X-Foo2' => 'Bar2'], 'test'),
]);
$this->assertTrue($logger->hasDebug('* URL: /test
* POSTFIELDS: test
* RESPONSE HEADERS: X-Foo: Bar, X-Foo2: Bar2
* RESPONSE BODY: test
* ATTEMPTS: 0'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::getTokenCacheKey
*/
public function testGetTokenCacheKey(): void
{
$this->assertSame('crm_fiscal_atol_online_token_68526766e6751745b52ae70b7bd3c6fe_v4', $this->callMethod($this->getApi(), 'getTokenCacheKey'));
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnlineApi::isTokenExpired
*/
public function testIsTokenExpired(): void
{
$body = new \stdClass();
$body->error = new \stdClass();
$body->error->code = 4;
$this->assertTrue($this->callMethod($this->getApi(), 'isTokenExpired', ['body' => $body]));
$body = new \stdClass();
$this->assertFalse($this->callMethod($this->getApi(), 'isTokenExpired', ['body' => $body]));
}
/**
* @param array $responses
* @param bool $debug
* @param bool $test
* @return AtolOnlineApi
*/
private function getApi(array $responses = [], bool $debug = true, bool $test = false): AtolOnlineApi
{
$connection = new Connection();
$connection->login = 'login';
$connection->pass = 'pass';
$connection->group = 'group';
$connection->sno = Connection::SNO_GENERAL;
$connection->version = AtolOnlineApi::API_VERSION_V4;
$connection->setDebug($debug);
$connection->setTestMode($test);
$mock = new MockHandler($responses);
$handler = HandlerStack::create($mock);
return new AtolOnlineApi(new Client(['handler' => $handler]), $connection);
}
/**
* @param mixed $object
* @param string $name
* @param array $args
* @return mixed
*/
private function callMethod($object, string $name, array $args = [])
{
$reflection = new \ReflectionClass($object);
$method = $reflection->getMethod($name);
$method->setAccessible(true);
return $method->invokeArgs($object, $args);
}
/**
* @param mixed $object
* @param string $name
* @return mixed
*/
private function getProperty($object, string $name)
{
$reflection = new \ReflectionClass($object);
$property = $reflection->getProperty($name);
$property->setAccessible(true);
return $property->getValue($object);
}
/**
* @return false|string
*/
private function getTokenSuccessResponseV4()
{
return json_encode([
'error' => null,
'token' => 'fj45u923j59ju42395iu9423i59243u0',
'timestamp' => '30.11.2017 17:58:53',
]);
}
/**
* @return false|string
*/
private function getErrorResponseV4()
{
return json_encode([
'error' => [
'error_id' => '4475d6d8d-844d-4d05-aa8b-e3dbdf3defd5',
'code' => 12,
'text' => 'Неверный логин или пароль',
'type' => 'system',
],
'timestamp' => '30.11.2017 17:58:53',
]);
}
/**
* @return string
*/
private function getReportSuccessReportV4(): string
{
return file_get_contents(__DIR__.'/../fixtures/success_response_v4_3.json');
}
}

View file

@ -0,0 +1,259 @@
<?php
namespace AtolOnlineClient\Tests;
use AtolOnlineClient\AtolOnline;
use AtolOnlineClient\AtolOnlineClient\Traits\PaymentReceiptRequestTrait;
use AtolOnlineClient\Configuration\Connection;
use AtolOnlineClient\ConfigurationInterface;
use AtolOnlineClient\Exception\InvalidResponseException;
use GuzzleHttp\Client;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\SerializerInterface;
use PHPUnit\Framework\TestCase;
class AtolOnlineTest extends TestCase
{
use PaymentReceiptRequestTrait;
/**
* @var AtolOnline
*/
protected $atol;
/**
* @return void
*/
public function setUp(): void
{
$this->atol = new AtolOnline();
}
/**
* @return void
* @covers \AtolOnlineClient\AtolOnline::__construct
*/
public function testConstructor(): void
{
$reflection = new \ReflectionClass(get_class($this->atol));
$property = $reflection->getProperty('serializer');
$property->setAccessible(true);
$this->assertInstanceOf(SerializerInterface::class, $property->getValue($this->atol));
}
/**
* @covers \AtolOnlineClient\AtolOnline::createConfiguration
* @return void
*/
public function testCreateConfiguration(): void
{
$this->assertInstanceOf(ConfigurationInterface::class, $this->atol->createConfiguration());
}
/**
* @param string $file
* @covers \AtolOnlineClient\AtolOnline::deserializeOperationResponse
* @dataProvider dataSuccessResponse
*/
public function testSuccessDeserializeOperationResponse(string $file): void
{
$response = file_get_contents(__DIR__.'/../fixtures/'. $file);
$operationResponse = $this->atol->deserializeOperationResponse($response);
$this->assertEquals('12.04.2017 06:15:06', $operationResponse->getTimestamp());
}
/**
* @param string $file
* @covers \AtolOnlineClient\AtolOnline::deserializeOperationResponse
* @dataProvider dataErrorResponse
*/
public function testErrorDeserializeOperationResponse(string $file): void
{
$response = file_get_contents(__DIR__.'/../fixtures/'. $file);
$operationResponse = $this->atol->deserializeOperationResponse($response);
$this->assertEquals('12.04.2017 06:15:06', $operationResponse->getTimestamp());
$this->assertEquals('fail', $operationResponse->getStatus());
$this->assertEquals(30, $operationResponse->getError()->getCode());
$this->assertEquals('system', $operationResponse->getError()->getType());
$this->assertEquals(
' Передан некорректный UUID : "{0}". Необходимо повторить запрос с корректными данными ',
$operationResponse->getError()->getText()
);
}
/**
* @covers \AtolOnlineClient\AtolOnline::deserializeOperationResponse
*/
public function testFailDeserializeOperationResponse(): void
{
$this->expectException(InvalidResponseException::class);
$this->atol->deserializeOperationResponse('<html></html>');
}
/**
* @param string $file
* @covers \AtolOnlineClient\AtolOnline::deserializeCheckStatusResponse
* @dataProvider dataSuccessResponse
*/
public function testSuccessDeserializeCheckStatusResponse(string $file): void
{
$response = file_get_contents(__DIR__.'/../fixtures/'. $file);
$operationResponse = $this->atol->deserializeCheckStatusResponse($response);
$this->assertEquals('12.04.2017 06:15:06', $operationResponse->getTimestamp());
}
/**
* @covers \AtolOnlineClient\AtolOnline::deserializeCheckStatusResponse
*/
public function testFailDeserializeCheckStatusResponse(): void
{
$this->expectException(InvalidResponseException::class);
$this->atol->deserializeCheckStatusResponse('<html></html>');
}
/**
* @param int|null $code
* @param string|null $message
* @param string $html
* @covers \AtolOnlineClient\AtolOnline::createInvalidResponseException
* @covers \AtolOnlineClient\Exception\InvalidResponseException
* @dataProvider dataInvalidResponse
*/
public function testCreateInvalidResponseException(?int $code, ?string $message, string $html): void
{
/** @var InvalidResponseException $exception */
$exception = $this->callMethod($this->atol, 'createInvalidResponseException', [
'response' => $html,
'previous' => new RuntimeException()
]);
$this->assertInstanceOf(InvalidResponseException::class, $exception);
$this->assertEquals($code, $exception->getCodeError());
$this->assertEquals($message, $exception->getMessageError());
}
/**
* @covers \AtolOnlineClient\AtolOnline::serializeOperationRequest
* @covers \AtolOnlineClient\Request\V4\ClientReceiptRequest
* @covers \AtolOnlineClient\Request\V4\CompanyReceiptRequest
* @covers \AtolOnlineClient\Request\V4\PaymentReceiptRequest
* @covers \AtolOnlineClient\Request\V4\ReceiptItemRequest
* @covers \AtolOnlineClient\Request\V4\ReceiptPaymentRequest
* @covers \AtolOnlineClient\Request\V4\ReceiptRequest
* @covers \AtolOnlineClient\Request\V4\ServiceRequest
* @covers \AtolOnlineClient\Request\V4\VatReceiptRequest
*/
public function testSerializeOperationRequest(): void
{
$request = $this->getPaymentReceiptRequest();
$request->setTimestamp('17.07.2019 10:14:22');
$this->assertEquals(
'{"external_id":"test","receipt":{"client":{"email":"test@test.local"},"company":{"email":"test@test.local","inn":"11111111","payment_address":"address"},"items":[{"name":"test item","price":100.1,"quantity":1.1,"sum":100.1,"measurement_unit":"kg","payment_method":"advance","payment_object":"agent_commission","vat":{"type":"vat20","sum":20.2},"nomenclature_code":"00"}],"payments":[{"type":0,"sum":100.1}],"vats":[{"type":"vat20","sum":20.2}],"total":100.1},"timestamp":"17.07.2019 10:14:22","service":{"callback_url":"test.local"}}',
$this->atol->serializeOperationRequest($request)
);
}
/**
* @return void
*
* @covers \AtolOnlineClient\AtolOnline::createApi
*/
public function testCreateApi(): void
{
$api1 = $this->atol->createApi(new Client(), new Connection());
$api2 = $this->atol->createApi(new Client(), new Connection());
$this->assertSame($api1, $api2);
}
/**
* @return void
*
* @covers \AtolOnlineClient\AtolOnline::getApi
*/
public function testGetApi(): void
{
$api1 = $this->atol->createApi(new Client(), new Connection());
$api2 = $this->atol->getApi();
$this->assertSame($api1, $api2);
}
/**
* @return array
*/
public function dataSuccessResponse(): array
{
return [
['success_response_v4_1.json'],
['success_response_v4_2.json'],
['success_response_v4_3.json'],
];
}
/**
* @return array
*/
public function dataErrorResponse(): array
{
return [
['error_response_v4.json']
];
}
/**
* @return array
*/
public function dataInvalidResponse(): array
{
return [
[
'code' => 404,
'message' => 'Not Found',
'html' => '<html><head><title>404 Not Found</title></head><body><center><h1>404 Not Found</h1></center><hr><center>openresty/1.15.8.1rc1</center></body></html>',
],
[
'code' => 502,
'message' => 'Bad Gateway',
'html' => '<html><head><title>502 Bad Gateway</title></head><body><center><h1>502 Bad Gateway</h1></center><hr><center>nginx/1.15.8</center></body></html>',
],
[
'code' => null,
'message' => null,
'html' => '<html></html>',
],
[
'code' => null,
'message' => null,
'html' => '',
],
];
}
/**
* @param mixed $object
* @param string $name
* @param array $args
* @return mixed
*/
private function callMethod($object, string $name, array $args = [])
{
$reflection = new \ReflectionClass($object);
$method = $reflection->getMethod($name);
$method->setAccessible(true);
return $method->invokeArgs($object, $args);
}
}

View file

@ -0,0 +1,85 @@
<?php
namespace AtolOnlineClient\AtolOnlineClient\Connection;
use AtolOnlineClient\AtolOnlineApi;
use AtolOnlineClient\Configuration\Connection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Validation;
class ConnectionTest extends TestCase
{
/**
* @var Connection
*/
private $connection;
/**
* @return void
*/
public function setUp(): void
{
$this->connection = new Connection();
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration\Connection::setDebug
* @covers \AtolOnlineClient\Configuration\Connection::isDebug
*/
public function testDebug(): void
{
$this->assertFalse($this->connection->isDebug());
$this->connection->setDebug(true);
$this->assertTrue($this->connection->isDebug());
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration\Connection::isTestMode
* @covers \AtolOnlineClient\Configuration\Connection::setTestMode
*/
public function testTestMode(): void
{
$this->assertFalse($this->connection->isTestMode());
$this->connection->setTestMode(true);
$this->assertTrue($this->connection->isTestMode());
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration\Connection::getVersion
* @covers \AtolOnlineClient\Configuration\Connection::isVersion4
*/
public function testVersion(): void
{
$this->connection->version = AtolOnlineApi::API_VERSION_V4;
$this->assertTrue($this->connection->isVersion4());
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration\Connection::loadValidatorMetadata
*/
public function testValidator(): void
{
$validator = Validation::createValidatorBuilder()
->addMethodMapping('loadValidatorMetadata')
->getValidator();
$list = $validator->validate($this->connection);
$this->assertEquals(3, $list->count());
$this->connection->login = 'login';
$this->connection->pass = 'login';
$this->connection->group = 'group';
$list = $validator->validate($this->connection);
$this->assertEquals(0, $list->count());
}
}

View file

@ -0,0 +1,78 @@
<?php
namespace AtolOnlineClient\AtolOnlineClient;
use AtolOnlineClient\Configuration;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Validation;
/**
* Class ConfigurationTest
*
* @package AtolOnlineClient\AtolOnlineClient
*/
class ConfigurationTest extends TestCase
{
/**
* @var Configuration
*/
private $configuration;
public function setUp(): void
{
$this->configuration = new Configuration();
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration::isDebug
* @covers \AtolOnlineClient\Configuration::setDebug
*/
public function testDebug(): void
{
$this->assertFalse($this->configuration->isDebug());
$this->configuration->setDebug(true);
$this->assertTrue($this->configuration->isDebug());
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration::isEnabled
* @covers \AtolOnlineClient\Configuration::setEnabled
*/
public function testEnabled(): void
{
$this->assertTrue($this->configuration->isEnabled());
$this->configuration->setEnabled(false);
$this->assertFalse($this->configuration->isEnabled());
}
/**
* @return void
* @covers \AtolOnlineClient\Configuration::loadValidatorMetadata
*/
public function testValidator(): void
{
$validator = Validation::createValidatorBuilder()
->addMethodMapping('loadValidatorMetadata')
->getValidator();
$list = $validator->validate($this->configuration);
$this->assertEquals(1, $list->count());
$connection = new Configuration\Connection();
$connection->login = 'login';
$connection->pass = 'login';
$connection->group = 'group';
$this->configuration->connections[] = $connection;
$list = $validator->validate($this->configuration);
$this->assertEquals(0, $list->count());
}
}

View file

@ -0,0 +1,102 @@
<?php
namespace AtolOnlineClient\AtolOnlineClient\Response;
use AtolOnlineClient\Request\V4\PaymentReceiptRequest;
use JMS\Serializer\SerializerBuilder;
use PHPUnit\Framework\TestCase;
/**
*/
class RequestTest extends TestCase
{
/**
* @return void
* @covers \AtolOnlineClient\Request\V4\ClientReceiptRequest
* @covers \AtolOnlineClient\Request\V4\CompanyReceiptRequest
* @covers \AtolOnlineClient\Request\V4\PaymentReceiptRequest
* @covers \AtolOnlineClient\Request\V4\ReceiptItemRequest
* @covers \AtolOnlineClient\Request\V4\ReceiptPaymentRequest
* @covers \AtolOnlineClient\Request\V4\ReceiptRequest
* @covers \AtolOnlineClient\Request\V4\ServiceRequest
* @covers \AtolOnlineClient\Request\V4\VatReceiptRequest
*/
public function testRequest(): void
{
$serializer = SerializerBuilder::create()->build();
$request = '{
"external_id": "17052917561851307",
"receipt": {
"client": {
"name": "name",
"email": "kkt@kkt.ru",
"phone": "88002000600",
"inn": "111111111"
},
"company": {
"email": "chek@romashka.ru",
"sno": "osn",
"inn": "1234567891",
"payment_address": "http://magazin.ru/"
},
"items": [
{
"name": "колбаса Клинский Брауншвейгская с/к в/с ",
"price": 1000,
"quantity": 0.3,
"sum": 300,
"measurement_unit": "кг",
"payment_method": "full_payment",
"payment_object": "commodity",
"vat": {
"type": "vat18"
}
},
{
"name": "яйцоОкскоекуриноеС0 белое",
"price": 100,
"quantity": 1,
"sum": 100,
"measurement_unit": "Упаковка10 шт.",
"payment_method": "full_payment",
"payment_object": "commodity",
"vat": {
"type": "vat10"
}
}
],
"payments": [
{
"type": 1,
"sum": 400
}
],
"vats": [
{
"type": "vat18",
"sum": 45.76
},
{
"type": "vat10",
"sum": 9.09
}
],
"total": 400
},
"service": {
"callback_url": "http://testtest"
},
"timestamp": "01.02.1713:45:00"
}';
/** @var PaymentReceiptRequest $request */
$request = $serializer->deserialize(
$request,
PaymentReceiptRequest::class,
'json'
);
$this->assertSame('17052917561851307', $request->getExternalId());
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace AtolOnlineClient\AtolOnlineClient\Response;
use AtolOnlineClient\Response\OperationResponse;
use JMS\Serializer\SerializerBuilder;
use PHPUnit\Framework\TestCase;
/**
*/
class ResponseTest extends TestCase
{
/**
* @return void
* @covers \AtolOnlineClient\Response\OperationResponse
* @covers \AtolOnlineClient\Response\Error
* @covers \AtolOnlineClient\Response\Payload
*/
public function testResponse(): void
{
$serializer = SerializerBuilder::create()->build();
$response = '{
"uuid": "4355",
"timestamp": "12.04.2017 06:15:06",
"status": "fail",
"error": {
"error_id": "475d6d8d-844d-4d05-aa8b-e3dbdf4defd6",
"code": 30,
"text": " Передан некорректный UUID : \"{0}\". Необходимо повторить запрос с корректными данными ",
"type": "system"
},
"payload": {
"total": 1598,
"fns_site": "www.nalog.ru",
"fn_number": "1110000100238211",
"shift_number": 23,
"receipt_datetime": "12.04.2017 20:16:00",
"fiscal_receipt_number": 6,
"fiscal_document_number": 133,
"ecr_registration_number": "0000111118041361",
"fiscal_document_attribute": 3449555941
},
"group_code": " MyCompany_MyShop",
"daemon_code": "prodagent1",
"device_code": "KSR13.00111",
"external_id": "TRF10601_1",
"callback_url": ""
}';
/** @var OperationResponse $response */
$response = $serializer->deserialize(
$response,
OperationResponse::class,
'json'
);
$serializer->serialize(
$response,
'json'
);
$this->assertSame('4355', $response->getUuid());
}
}

View file

@ -1,46 +0,0 @@
<?php
namespace AtolOnlineClient\Tests;
use AtolOnlineClient\AtolOnline;
use AtolOnlineClient\Configuration;
use AtolOnlineClient\Response\OperationResponse;
use PHPUnit\Framework\TestCase;
class AtolOnlineTest extends TestCase
{
public function testCreateConfiguration()
{
$atol = new AtolOnline();
$this->assertInstanceOf(Configuration::class, $atol->createConfiguration());
}
/**
* @dataProvider dataSellErrorResponse
*/
public function testDeserializeOperationResponse($file)
{
$response = file_get_contents(__DIR__ . '/data/'. $file);
$atol = new AtolOnline();
$operationResponse = $atol->deserializeOperationResponse($response);
$this->assertInstanceOf(OperationResponse::class, $operationResponse);
$this->assertEquals('12.04.2017 06:15:06', $operationResponse->getTimestamp());
$this->assertEquals('fail', $operationResponse->getStatus());
$this->assertEquals(30, $operationResponse->getError()->getCode());
$this->assertEquals('system', $operationResponse->getError()->getType());
$this->assertEquals(
' Передан некорректный UUID : "{0}". Необходимо повторить запрос с корректными данными ',
$operationResponse->getError()->getText()
);
}
public function dataSellErrorResponse()
{
return [
['sell_error_response_v3.json'],
['sell_error_response_v3.json']
];
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace AtolOnlineClient\AtolOnlineClient\Traits;
use AtolOnlineClient\Request\V4\ClientReceiptRequest;
use AtolOnlineClient\Request\V4\CompanyReceiptRequest;
use AtolOnlineClient\Request\V4\PaymentReceiptRequest;
use AtolOnlineClient\Request\V4\ReceiptItemRequest;
use AtolOnlineClient\Request\V4\ReceiptPaymentRequest;
use AtolOnlineClient\Request\V4\ReceiptRequest;
use AtolOnlineClient\Request\V4\ServiceRequest;
use AtolOnlineClient\Request\V4\VatReceiptRequest;
trait PaymentReceiptRequestTrait
{
/**
* @return PaymentReceiptRequest
*/
protected function getPaymentReceiptRequest(): PaymentReceiptRequest
{
$service = new ServiceRequest();
$service->setCallbackUrl('test.local');
$client = new ClientReceiptRequest('test@test.local');
$company = new CompanyReceiptRequest();
$company->setEmail('test@test.local');
$company->setInn('11111111');
$company->setPaymentAddress('address');
$item = new ReceiptItemRequest();
$item->setName('test item');
$item->setPrice(100.1);
$item->setQuantity(1.1);
$item->setSum(100.1);
$item->setMeasurementUnit('kg');
$item->setPaymentMethod(ReceiptItemRequest::PAYMENT_METHOD_ADVANCE);
$item->setPaymentObject(ReceiptItemRequest::PAYMENT_OBJECT_AGENT_COMMISSION);
$item->setVat(new VatReceiptRequest('vat20', 20.2));
$item->setNomenclatureCode('00');
$receipt = new ReceiptRequest();
$receipt->setTotal(100.1);
$receipt->setClient($client);
$receipt->setCompany($company);
$receipt->setItems([$item]);
$receipt->setPayments([new ReceiptPaymentRequest(0, 100.1)]);
$receipt->setVats([new VatReceiptRequest('vat20', 20.2)]);
/** @var PaymentReceiptRequest $request */
$request = new PaymentReceiptRequest();
$request->setExternalId('test');
$request->setService($service);
$request->setReceipt($receipt);
return $request;
}
}

3
tests/bootstrap.php Normal file
View file

@ -0,0 +1,3 @@
<?php
return require __DIR__.'/../vendor/autoload.php';

View file

@ -0,0 +1,5 @@
{
"error": null,
"token": "fj45u923j59ju42395iu9423i59243u0",
"timestamp": "12.04.2017 06:15:06"
}

View file

@ -0,0 +1,6 @@
{
"uuid": "2ea26f1708844f08b120306fc096a58f",
"timestamp": "12.04.2017 06:15:06",
"error": null,
"status": "wait"
}

View file

@ -0,0 +1,22 @@
{
"uuid": "2ea26f1708844f08b120306fc096a58f",
"error": null,
"status": "done",
"payload": {
"total": 1598,
"fns_site": "www.nalog.ru",
"fn_number": "1110000100238211",
"shift_number": 23,
"receipt_datetime": "12.04.2017 20:16:00",
"fiscal_receipt_number": 6,
"fiscal_document_number": 133,
"ecr_registration_number": "0000111118041361",
"fiscal_document_attribute": 3449555941
},
"timestamp": "12.04.2017 06:15:06",
"group_code": "MyCompany_MyShop",
"daemon_code": "prodagent1",
"device_code": "KSR13.00111",
"external_id": "TRF10601_1",
"callback_url": ""
}