diff --git a/.github/workflows/integration-v3.yml b/.github/workflows/integration-v3.yml
new file mode 100644
index 0000000..fba01ab
--- /dev/null
+++ b/.github/workflows/integration-v3.yml
@@ -0,0 +1,63 @@
+name: "Integration tests"
+
+on:
+ pull_request:
+ branches:
+ - v3
+ push:
+ branches:
+ - v3
+
+env:
+ COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist"
+ LOYALTY_API_ENDPOINT_URL: ${{ vars.LOYALTY_API_ENDPOINT_URL }}
+ LOYALTY_API_CLIENT_ID: ${{ secrets.LOYALTY_API_CLIENT_ID }}
+ LOYALTY_API_ADMIN_KEY: ${{ secrets.LOYALTY_API_ADMIN_KEY }}
+
+jobs:
+ tests:
+ name: "Integration tests"
+ runs-on: ${{ matrix.operating-system }}
+ environment: integration-tests
+ strategy:
+ fail-fast: false
+ matrix:
+ php-version:
+ - "7.4"
+ dependencies: [ highest ]
+ operating-system: [ ubuntu-latest, windows-latest ]
+
+ steps:
+
+ - name: "Checkout"
+ uses: "actions/checkout@v2"
+
+ - name: "Install PHP"
+ uses: shivammathur/setup-php@2.30.4
+ with:
+ coverage: xdebug
+ extensions: mbstring, intl, json, bcmath, curl
+ php-version: "${{ matrix.php-version }}"
+ ini-values: variables_order=EGPCS
+
+ - name: "Install dependencies"
+ run: |
+ composer update ${{ env.COMPOSER_FLAGS }}
+
+ - name: "Debug ENV variables"
+ run: |
+ printenv
+
+ - name: "Run integration tests"
+ run: |
+ php vendor/bin/phpunit --colors=always --testsuite integration-tests
+
+ - name: "integration tests succeeded"
+ if: ${{ success() }}
+ run: |
+ echo '✅ integration tests pass, congratulations!'
+
+ - name: "integration tests failed"
+ if: ${{ failure() }}
+ run: |
+ echo '::error:: ❗integration tests failed (╯°益°)╯彡┻━┻ '
\ No newline at end of file
diff --git a/.github/workflows/integration-v4.yml b/.github/workflows/integration-v4.yml
new file mode 100644
index 0000000..216b12d
--- /dev/null
+++ b/.github/workflows/integration-v4.yml
@@ -0,0 +1,62 @@
+name: "Integration tests"
+
+on:
+ push:
+ branches:
+ - v4
+ - master
+
+env:
+ COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist"
+ LOYALTY_API_ENDPOINT_URL: ${{ vars.LOYALTY_API_ENDPOINT_URL }}
+ LOYALTY_API_CLIENT_ID: ${{ secrets.LOYALTY_API_CLIENT_ID }}
+ LOYALTY_API_ADMIN_KEY: ${{ secrets.LOYALTY_API_ADMIN_KEY }}
+
+jobs:
+ tests:
+ name: "Integration tests"
+ runs-on: ${{ matrix.operating-system }}
+ environment: integration-tests
+ strategy:
+ fail-fast: false
+ matrix:
+ php-version:
+ - "8.2"
+ - "8.3"
+ dependencies: [ highest ]
+ operating-system: [ ubuntu-latest, windows-latest ]
+
+ steps:
+
+ - name: "Checkout"
+ uses: "actions/checkout@v2"
+
+ - name: "Install PHP"
+ uses: shivammathur/setup-php@2.30.4
+ with:
+ coverage: xdebug
+ extensions: mbstring, intl, json, bcmath, curl
+ php-version: "${{ matrix.php-version }}"
+ ini-values: variables_order=EGPCS
+
+ - name: "Install dependencies"
+ run: |
+ composer update ${{ env.COMPOSER_FLAGS }}
+
+ - name: "Debug ENV variables"
+ run: |
+ printenv
+
+ - name: "Run integration tests"
+ run: |
+ php vendor/bin/phpunit --colors=always --testsuite integration-tests
+
+ - name: "integration tests succeeded"
+ if: ${{ success() }}
+ run: |
+ echo '✅ integration tests pass, congratulations!'
+
+ - name: "integration tests failed"
+ if: ${{ failure() }}
+ run: |
+ echo '::error:: ❗integration tests failed (╯°益°)╯彡┻━┻ '
\ No newline at end of file
diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml
index 471afeb..0e8ad1a 100644
--- a/.github/workflows/phpstan.yml
+++ b/.github/workflows/phpstan.yml
@@ -13,7 +13,7 @@ jobs:
fail-fast: false
matrix:
php-version:
- - "8.3"
+ - "7.4"
dependencies: [ highest ]
steps:
@@ -37,7 +37,7 @@ jobs:
run: "composer update --no-interaction --no-progress --no-suggest"
- name: "PHPStan"
- run: "make phpstan"
+ run: "make lint-phpstan"
- name: "is PHPStan check succeeded"
if: ${{ success() }}
diff --git a/Makefile b/Makefile
index dcfbe70..c9c86b0 100644
--- a/Makefile
+++ b/Makefile
@@ -2,10 +2,29 @@ default:
@echo "make needs target:"
@egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /'
-phpstan:
- vendor/bin/phpstan analyse
-phpinsights:
- vendor/bin/phpinsights analyse ./src
-test-integration:
- php vendor/bin/phpunit --colors=always --testsuite integration-tests
\ No newline at end of file
+init:
+ docker-compose down --remove-orphans
+ docker-compose build
+ docker-compose run --rm php-cli composer install
+ docker-compose run --rm php-cli chown -R www-data:www-data /var/www/html/var/
+ docker-compose up -d
+
+cli-bash:
+ docker-compose run --rm php-cli sh $(filter-out $@,$(MAKECMDGOALS))
+integration-tests:
+ docker-compose run --rm php-cli vendor/bin/phpunit --colors=always --testsuite=integration-tests
+lint-phpstan:
+ docker-compose run --rm php-cli vendor/bin/phpstan analyse --memory-limit 1G
+lint-rector:
+ docker-compose run --rm php-cli vendor/bin/rector process --dry-run
+lint-rector-fix:
+ docker-compose run --rm php-cli vendor/bin/rector process
+
+composer-install:
+ @echo "install dependencies"
+ docker-compose run --rm php-cli composer install
+composer-update:
+ @echo "update dependencies"
+ docker-compose run --rm php-cli composer update
+
diff --git a/composer.json b/composer.json
index c677ad0..9b70b1b 100644
--- a/composer.json
+++ b/composer.json
@@ -20,31 +20,32 @@
}
],
"require": {
- "php": "8.2.* || 8.3.*",
+ "php": "7.4.* || 8.2.* || 8.3.*",
"ext-json": "*",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-intl": "*",
"psr/log": "^1.1.4 || ^2.0 || ^3.0",
"fig/http-message-util": "1.1.*",
- "symfony/console": "7.*",
- "symfony/dotenv": "7.*",
- "symfony/http-client": "7.*",
- "symfony/http-client-contracts": "^3.1",
- "symfony/http-foundation": "7.*",
- "symfony/uid": "7.*",
- "symfony/filesystem": "7.*",
- "moneyphp/money": "4.*",
+ "symfony/console": "^5.4 || 7.*",
+ "symfony/dotenv": "^5.4 || 7.*",
+ "symfony/http-client": "^5.4 || 7.*",
+ "symfony/http-client-contracts": "^2.4 ||^3.1",
+ "symfony/http-foundation": "^5.4 || 7.*",
+ "symfony/uid": "^5.4 || 7.*",
+ "symfony/filesystem": "^5.4 || 7.*",
+ "moneyphp/money": "^3.3 || 4.*",
"giggsey/libphonenumber-for-php": "8.1.*",
"league/csv": "^9.0",
- "mesilov/moneyphp-percentage": "0.2.0"
+ "mesilov/moneyphp-percentage": "0.1.0 || 0.2.0"
},
"require-dev": {
- "monolog/monolog": "2.1.*",
- "symfony/debug-bundle": "7.*",
+ "rector/rector": "*",
+ "monolog/monolog": "^2.5 || ^3.0",
+ "symfony/debug-bundle": "^5.4 || 7.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "*",
- "symfony/stopwatch": "7.*",
+ "symfony/stopwatch": "^5.4 || 7.*",
"roave/security-advisories": "dev-master",
"nunomaduro/phpinsights": "2.*",
"fakerphp/faker": "1.23.*"
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..5978f88
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,9 @@
+version: '3'
+
+services:
+ php-cli:
+ build:
+ context: ./docker/php-cli
+ volumes:
+ - .:/var/www/html
+ working_dir: /var/www/html
\ No newline at end of file
diff --git a/docker/php-cli/Dockerfile b/docker/php-cli/Dockerfile
new file mode 100644
index 0000000..5841820
--- /dev/null
+++ b/docker/php-cli/Dockerfile
@@ -0,0 +1,10 @@
+FROM php:7.4-cli-alpine
+
+RUN apk add unzip libpq-dev git icu-dev \
+ && docker-php-ext-install bcmath intl \
+ && docker-php-ext-enable bcmath intl
+
+RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/bin --filename=composer --quiet
+
+ENV COMPOSER_ALLOW_SUPERUSER 1
+WORKDIR /var/www/html
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 409988a..0c293fd 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -5,9 +5,9 @@
tests/Integration/
-
+
+
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000..671cd0a
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,26 @@
+withPaths([
+ __DIR__ . '/src',
+ __DIR__ . '/tests',
+ ])
+ ->withSets(
+ [DowngradeLevelSetList::DOWN_TO_PHP_74]
+ )
+ ->withPhpSets(
+ false, // 8.3
+ false, // 8.2
+ false, // 8.1
+ false, // 8.0
+ true // 7.4
+ )
+ ->withRules([
+ AddVoidReturnTypeWhereNoReturnRector::class,
+ ]);
\ No newline at end of file
diff --git a/src/Commands/Cards/ExportCards.php b/src/Commands/Cards/ExportCards.php
index 66c8be2..3ca0b32 100644
--- a/src/Commands/Cards/ExportCards.php
+++ b/src/Commands/Cards/ExportCards.php
@@ -24,21 +24,28 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
-#[AsCommand(
- name: 'cards:export',
- description: 'Export loyalty cards to csv file')]
+
class ExportCards extends Command
{
+ protected CardItemFormatter $cardItemFormatter;
+ protected CardLevelItemFormatter $cardLevelItemFormatter;
+ protected ContactItemFormatter $contactItemFormatter;
+ protected LoggerInterface $logger;
+ protected static $defaultName = 'cards:export';
+ protected static $defaultDescription = 'Export loyalty cards to csv file';
public function __construct(
- protected CardItemFormatter $cardItemFormatter,
- protected CardLevelItemFormatter $cardLevelItemFormatter,
- protected ContactItemFormatter $contactItemFormatter,
- protected LoggerInterface $logger
+ CardItemFormatter $cardItemFormatter,
+ CardLevelItemFormatter $cardLevelItemFormatter,
+ ContactItemFormatter $contactItemFormatter,
+ LoggerInterface $logger
)
{
+ $this->cardItemFormatter = $cardItemFormatter;
+ $this->cardLevelItemFormatter = $cardLevelItemFormatter;
+ $this->contactItemFormatter = $contactItemFormatter;
+ $this->logger = $logger;
parent::__construct();
}
-
protected function configure(): void
{
$this->addOption(
@@ -63,7 +70,6 @@ protected function configure(): void
InputOption::VALUE_REQUIRED,
'file to store cards');
}
-
/**
* @throws UnavailableStream
* @throws CannotInsertRecord
@@ -133,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
)
);
- foreach ($admSb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc)) as $card) {
+ foreach ($admSb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc())) as $card) {
$contact = array_fill(0, count($this->contactItemFormatter->fields()), null);
if ($card->contact !== null) {
//todo add external_id_key to cli arguments
diff --git a/src/Commands/Transactions/BulkTransactions.php b/src/Commands/Transactions/BulkTransactions.php
index a1816cf..97bc4fa 100644
--- a/src/Commands/Transactions/BulkTransactions.php
+++ b/src/Commands/Transactions/BulkTransactions.php
@@ -8,6 +8,8 @@
use B24io\Loyalty\SDK\Common\Requests\ItemsOrder;
use B24io\Loyalty\SDK\Common\Requests\OrderDirection;
use B24io\Loyalty\SDK\Common\TransactionType;
+use B24io\Loyalty\SDK\Core\Exceptions\BaseException;
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
use B24io\Loyalty\SDK\Services\ServiceBuilderFactory;
use Money\Currencies\ISOCurrencies;
use Money\Currency;
@@ -23,16 +25,16 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
-#[AsCommand(
- name: 'transactions:bulk-transaction',
- description: 'Bulk accrual or payment transaction to all active cards')]
class BulkTransactions extends Command
{
- public function __construct(private LoggerInterface $logger)
+ private LoggerInterface $logger;
+ protected static $defaultName='transactions:bulk-transaction';
+ protected static $defaultDescription='Bulk accrual or payment transaction to all active cards';
+ public function __construct(LoggerInterface $logger)
{
+ $this->logger = $logger;
parent::__construct();
}
-
protected function configure(): void
{
$this->addOption(
@@ -88,6 +90,10 @@ protected function configure(): void
);
}
+ /**
+ * @throws InvalidArgumentException
+ * @throws BaseException
+ */
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln([
@@ -120,13 +126,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::INVALID;
}
-
- $transactionType = TransactionType::tryFrom((string)$input->getOption('transaction-type'));
- if ($transactionType === null) {
+ /**
+ * @var ?string $rawTransactionType
+ */
+ $rawTransactionType = $input->getOption('transaction-type');
+ if ($rawTransactionType === null) {
$io->error('you must set «transaction-type» option: «accrual» or «payment»');
return Command::INVALID;
}
+ $transactionType = new TransactionType($rawTransactionType);
$currency = $input->getOption('currency');
if ($currency === null) {
@@ -178,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
]);
$progressBar = new ProgressBar($output, $cardsTotal);
- foreach ($admSb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc)) as $card) {
+ foreach ($admSb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc())) as $card) {
try {
if ($isDryrun) {
$io->note(['', 'dry run mode is active', '']);
@@ -186,9 +195,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$trxHistoryByCard = $admSb->transactionsScope()->transactions()->getByCardNumber($card->number);
- $reasonCodeHistory = array_map(static function (Reason $reason) {
- return $reason->code;
- }, array_column($trxHistoryByCard->getTransactions(), 'reason'));
+ $reasonCodeHistory = array_map(static fn(Reason $reason) => $reason->code, array_column($trxHistoryByCard->getTransactions(), 'reason'));
if (in_array($reasonCode, $reasonCodeHistory, true)) {
$this->logger->info(sprintf('transaction already processed for card %s', $card->number));
continue;
diff --git a/src/Commands/Transactions/BurnBonuses.php b/src/Commands/Transactions/BurnBonuses.php
index 6d27355..1a1a640 100644
--- a/src/Commands/Transactions/BurnBonuses.php
+++ b/src/Commands/Transactions/BurnBonuses.php
@@ -27,15 +27,19 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
-#[AsCommand(
- name: 'transactions:burn-bonuses',
- description: 'Burning of bonuses accrued before the specified date')]
class BurnBonuses extends Command
{
- private const string REASON_ID = 'b24io.loyalty.sdk.cli.util';
-
- public function __construct(private LoggerInterface $logger)
+ private LoggerInterface $logger;
+ /**
+ * @var string
+ */
+ private const REASON_ID = 'b24io.loyalty.sdk.cli.util';
+ protected static $defaultName = 'transactions:burn-bonuses';
+ protected static $defaultDescription = 'Burning of bonuses accrued before the specified date';
+
+ public function __construct(LoggerInterface $logger)
{
+ $this->logger = $logger;
parent::__construct();
}
@@ -135,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::INVALID;
}
$burnoutDate = DateTime::createFromFormat('d.m.Y', $rawBurnoutDate);
- if(!$burnoutDate){
+ if (!$burnoutDate) {
$io->error('you must set valid «date» option in format dd.mm.YYYY');
return Command::INVALID;
@@ -156,7 +160,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$progressBar = new ProgressBar($output, $cardsTotal);
- foreach ($admSb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc)) as $cnt => $card) {
+ foreach ($admSb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc())) as $cnt => $card) {
$progressBar->advance();
try {
// filter cards with balance > 0
@@ -167,9 +171,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
// get last 50 transactions for current card
$trxHistoryByCard = $admSb->transactionsScope()->transactions()->getByCardNumber($card->number);
- $reasonCodeHistory = array_map(static function (Reason $reason) {
- return $reason->code;
- }, array_column($trxHistoryByCard->getTransactions(), 'reason'));
+ $reasonCodeHistory = array_map(static fn(Reason $reason) => $reason->code, array_column($trxHistoryByCard->getTransactions(), 'reason'));
// if trx with reason-code exists, pass card
if (in_array($reasonCode, $reasonCodeHistory, true)) {
@@ -226,7 +228,7 @@ private function sumAccrualTransactionsAfterDate(
{
$totalSum = new Money(0, $defaultCurrency);
foreach ($adminServiceBuilder->transactionsScope()->fetcher()->listByCardNumber($cardNumber) as $trxItem) {
- if ($burnDate < $trxItem->created && $trxItem->type === TransactionType::accrual) {
+ if ($burnDate < $trxItem->created && $trxItem->type === TransactionType::accrual()) {
$totalSum = $totalSum->add($trxItem->value);
}
}
diff --git a/src/Commands/Transactions/ExportTransactions.php b/src/Commands/Transactions/ExportTransactions.php
index 6d3ec0e..e04bad9 100644
--- a/src/Commands/Transactions/ExportTransactions.php
+++ b/src/Commands/Transactions/ExportTransactions.php
@@ -23,18 +23,20 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
-#[AsCommand(
- name: 'transactions:export',
- description: 'Export transactions to csv file')]
class ExportTransactions extends Command
{
+ protected TransactionItemFormatter $transactionItemFormatter;
+ protected LoggerInterface $logger;
+ protected static $defaultName = 'transactions:export';
+ protected static $defaultDescription = 'Export transactions to csv file';
public function __construct(
- protected TransactionItemFormatter $transactionItemFormatter,
- protected LoggerInterface $logger)
+ TransactionItemFormatter $transactionItemFormatter,
+ LoggerInterface $logger)
{
+ $this->transactionItemFormatter = $transactionItemFormatter;
+ $this->logger = $logger;
parent::__construct();
}
-
protected function configure(): void
{
$this->addOption(
@@ -59,7 +61,6 @@ protected function configure(): void
InputOption::VALUE_REQUIRED,
'file to store transactions');
}
-
/**
* @throws UnavailableStream
* @throws CannotInsertRecord
diff --git a/src/Commands/Transactions/LoadTransactionsFromFile.php b/src/Commands/Transactions/LoadTransactionsFromFile.php
index fa7f157..c55c0cc 100644
--- a/src/Commands/Transactions/LoadTransactionsFromFile.php
+++ b/src/Commands/Transactions/LoadTransactionsFromFile.php
@@ -30,25 +30,23 @@
use Symfony\Component\Console\Helper\ProgressBar;
use Throwable;
-#[AsCommand(
- name: 'transactions:load-from-file',
- description: 'Process transactions from csv file' . PHP_EOL .
- 'file columns:' . PHP_EOL .
- ' card_number - card number, example: 12345' . PHP_EOL .
- ' transaction_amount - bonus amount, example: 245.65' . PHP_EOL .
- ' transaction_type - accrual or payment transaction, example: accrual' . PHP_EOL .
- ' reason_id - unique reason id per client transaction list, example: gift2024.04.25' . PHP_EOL .
- ' reason_code - reason code, example: marketingGiftProgram ' . PHP_EOL .
- ' reason_comment - reason comment for user, example: Spring gift! We double your bonuses!'
-)]
class LoadTransactionsFromFile extends Command
{
+ private TransactionsReader $transactionsReader;
+ private DecimalMoneyFormatter $decimalMoneyFormatter;
+ private LoggerInterface $logger;
+ protected static $defaultName = 'transactions:process';
+ protected static $defaultDescription = 'Process transactions from csv file';
+
public function __construct(
- private TransactionsReader $transactionsReader,
- private DecimalMoneyFormatter $decimalMoneyFormatter,
- private LoggerInterface $logger
+ TransactionsReader $transactionsReader,
+ DecimalMoneyFormatter $decimalMoneyFormatter,
+ LoggerInterface $logger
)
{
+ $this->transactionsReader = $transactionsReader;
+ $this->decimalMoneyFormatter = $decimalMoneyFormatter;
+ $this->logger = $logger;
parent::__construct();
}
@@ -216,7 +214,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
'cardNumber' => $newTrx->cardNumber
]);
$status = sprintf('transaction type %s with amount %s for card %s number already processed',
- $newTrx->type->value,
+ (string)$newTrx->type,
$this->decimalMoneyFormatter->format($newTrx->amount),
$newTrx->cardNumber,
);
@@ -226,7 +224,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$revokedTrxLog->insertOne([
$newTrx->cardId->toRfc4122(),
$newTrx->cardNumber,
- $newTrx->type->value,
+ (string)$newTrx->type,
$this->decimalMoneyFormatter->format($newTrx->amount),
$newTrx->amount->getCurrency()->getCode(),
'транзакция уже проведена',
@@ -238,9 +236,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
}
}
-
+ $resTrx = null;
switch ($newTrx->type) {
- case TransactionType::accrual:
+ case TransactionType::accrual():
$resTrx = $admSb->transactionsScope()->transactions()->processAccrualTransactionByCardNumber(
$newTrx->cardNumber,
$newTrx->amount,
@@ -250,7 +248,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$status = sprintf('accrual transaction %s processed - %s', $resTrx->getTransaction()->id, $resTrx->getTransaction()->value->getAmount());
break;
- case TransactionType::payment:
+ case TransactionType::payment():
$resTrx = $admSb->transactionsScope()->transactions()->processPaymentTransactionByCardNumber(
$newTrx->cardNumber,
$newTrx->amount,
@@ -260,16 +258,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$status = sprintf('payment transaction %s processed - %s', $resTrx->getTransaction()->id, $resTrx->getTransaction()->value->getAmount());
break;
}
- // write to processed file
- $processedTrxLog->insertOne([
- $newTrx->cardId->toRfc4122(),
- $newTrx->cardNumber,
- $newTrx->type->value,
- $this->decimalMoneyFormatter->format($newTrx->amount),
- $newTrx->amount->getCurrency()->getCode(),
- $resTrx->getTransaction()->id->toRfc4122(),
- ]
- );
+ if ($resTrx !== null) {
+ // write to processed file
+ $processedTrxLog->insertOne([
+ $newTrx->cardId->toRfc4122(),
+ $newTrx->cardNumber,
+ (string)$newTrx->type,
+ $this->decimalMoneyFormatter->format($newTrx->amount),
+ $newTrx->amount->getCurrency()->getCode(),
+ $resTrx->getTransaction()->id->toRfc4122(),
+ ]
+ );
+ }
} catch (Throwable $exception) {
$this->logger->error('LoadTransactionsFromFile.processItem.error', [
'message' => $exception->getMessage()
@@ -277,7 +277,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$failureTrxLog->insertOne([
$newTrx->cardId->toRfc4122(),
$newTrx->cardNumber,
- $newTrx->type->value,
+ (string)$newTrx->type,
$this->decimalMoneyFormatter->format($newTrx->amount),
$newTrx->amount->getCurrency()->getCode(),
$exception->getMessage()
diff --git a/src/Common/Formatters/Cards/CardItemFormatter.php b/src/Common/Formatters/Cards/CardItemFormatter.php
index 9fd7196..472688d 100644
--- a/src/Common/Formatters/Cards/CardItemFormatter.php
+++ b/src/Common/Formatters/Cards/CardItemFormatter.php
@@ -8,7 +8,10 @@
use Money\Currencies\ISOCurrencies;
use Money\Formatter\DecimalMoneyFormatter;
-readonly class CardItemFormatter
+/**
+ * @readonly
+ */
+class CardItemFormatter
{
/**
* @return string[]
@@ -39,7 +42,7 @@ public function toFlatArray(CardItemResult $card): array
[
'card_id' => $card->id->toRfc4122(),
'card_number' => $card->number,
- 'card_status' => $card->status->name,
+ 'card_status' => (string)$card->status,
'card_barcode' => $card->barcode,
'card_balance' => $decimalMoneyFormatter->format($card->balance),
'card_iso_currency_code' => $card->balance->getCurrency()->getCode(),
diff --git a/src/Common/Formatters/Cards/CardLevelItemFormatter.php b/src/Common/Formatters/Cards/CardLevelItemFormatter.php
index ec1f16d..845491a 100644
--- a/src/Common/Formatters/Cards/CardLevelItemFormatter.php
+++ b/src/Common/Formatters/Cards/CardLevelItemFormatter.php
@@ -6,7 +6,10 @@
use B24io\Loyalty\SDK\Common\Result\Cards\CardLevelItemResult;
-readonly class CardLevelItemFormatter
+/**
+ * @readonly
+ */
+class CardLevelItemFormatter
{
/**
* @return string[]
@@ -25,21 +28,36 @@ public function fields(): array
'card_level_modified'
];
}
+
/**
* @return array
*/
public function toFlatArray(?CardLevelItemResult $level): array
{
+ if ($level === null) {
+ return [
+ 'card_level_id' => null,
+ 'card_level_next_level_id' => null,
+ 'card_level_name' => null,
+ 'card_level_code' => null,
+ 'card_level_default_percentage' => null,
+ 'card_level_description' => null,
+ 'card_level_external_id' => null,
+ 'card_level_created' => null,
+ 'card_level_modified' => null,
+ ];
+ }
+
return [
- 'card_level_id' => $level?->id->toRfc4122(),
- 'card_level_next_level_id' => $level?->nextLevelId?->toRfc4122(),
- 'card_level_name' => $level?->name,
- 'card_level_code' => $level?->code,
- 'card_level_default_percentage' => $level?->defaultPercentage->format(),
- 'card_level_description' => $level?->description,
- 'card_level_external_id' => $level?->externalId,
- 'card_level_created' => $level?->created->format(DATE_ATOM),
- 'card_level_modified' => $level?->modified->format(DATE_ATOM),
+ 'card_level_id' => $level->id->toRfc4122(),
+ 'card_level_next_level_id' => $level->nextLevelId!==null? $level->nextLevelId->toRfc4122() : null,
+ 'card_level_name' => $level->name,
+ 'card_level_code' => $level->code,
+ 'card_level_default_percentage' =>$level->defaultPercentage->format(),
+ 'card_level_description' => $level->description,
+ 'card_level_external_id' => $level->externalId,
+ 'card_level_created' => $level->created->format(DATE_ATOM),
+ 'card_level_modified' => $level->modified->format(DATE_ATOM),
];
}
}
\ No newline at end of file
diff --git a/src/Common/Formatters/Contacts/ContactItemFormatter.php b/src/Common/Formatters/Contacts/ContactItemFormatter.php
index a9c87d3..ac3834c 100644
--- a/src/Common/Formatters/Contacts/ContactItemFormatter.php
+++ b/src/Common/Formatters/Contacts/ContactItemFormatter.php
@@ -6,7 +6,10 @@
use B24io\Loyalty\SDK\Common\Result\Contacts\ContactItemResult;
-readonly class ContactItemFormatter
+/**
+ * @readonly
+ */
+class ContactItemFormatter
{
/**
* @return string[]
@@ -37,8 +40,8 @@ public function toFlatArray(ContactItemResult $contact, string $externalIdKey):
'contact_surname' => $contact->fullName->surname,
'contact_patronymic' => $contact->fullName->patronymic,
'contact_timezone_name' => $contact->timezone->getName(),
- 'contact_birthday' => $contact->birthday?->format('Y.m.d'),
- 'contact_gender' => $contact->gender->name,
+ 'contact_birthday' => ($nullsafeVariable1 = $contact->birthday) ? $nullsafeVariable1->format('Y.m.d') : null,
+ 'contact_gender' => (string)$contact->gender,
'contact_external_id' => $contact->externalIds[$externalIdKey],
'contact_created' => $contact->created->format(DATE_ATOM),
'contact_modified' => $contact->modified->format(DATE_ATOM),
diff --git a/src/Common/Formatters/Transactions/TransactionItemFormatter.php b/src/Common/Formatters/Transactions/TransactionItemFormatter.php
index 00347d3..00d143d 100644
--- a/src/Common/Formatters/Transactions/TransactionItemFormatter.php
+++ b/src/Common/Formatters/Transactions/TransactionItemFormatter.php
@@ -8,7 +8,10 @@
use Money\Currencies\ISOCurrencies;
use Money\Formatter\DecimalMoneyFormatter;
-readonly class TransactionItemFormatter
+/**
+ * @readonly
+ */
+class TransactionItemFormatter
{
/**
* @return string[]
@@ -40,7 +43,7 @@ public function toFlatArray(TransactionItemResult $trx): array
'transaction_id' => $trx->id->toRfc4122(),
'transaction_amount' => $decimalMoneyFormatter->format($trx->value),
'transaction_iso_currency_code' => $trx->value->getCurrency()->getCode(),
- 'transaction_type' => $trx->type->value,
+ 'transaction_type' => $trx->type,
'transaction_created' => $trx->created->format(DATE_ATOM),
'transaction_reason_id' => $trx->reason->id,
'transaction_reason_code' => $trx->reason->code,
diff --git a/src/Common/FullName.php b/src/Common/FullName.php
index 0e943b0..72ca352 100644
--- a/src/Common/FullName.php
+++ b/src/Common/FullName.php
@@ -4,14 +4,25 @@
namespace B24io\Loyalty\SDK\Common;
-readonly class FullName
+class FullName
{
- public function __construct(
- public string $name,
- public ?string $surname = null,
- public ?string $patronymic = null
- )
+ /**
+ * @readonly
+ */
+ public string $name;
+ /**
+ * @readonly
+ */
+ public ?string $surname = null;
+ /**
+ * @readonly
+ */
+ public ?string $patronymic = null;
+ public function __construct(string $name, ?string $surname = null, ?string $patronymic = null)
{
+ $this->name = $name;
+ $this->surname = $surname;
+ $this->patronymic = $patronymic;
}
/**
diff --git a/src/Common/Gender.php b/src/Common/Gender.php
index 2ab9ba2..b0329fe 100644
--- a/src/Common/Gender.php
+++ b/src/Common/Gender.php
@@ -4,9 +4,63 @@
namespace B24io\Loyalty\SDK\Common;
-enum Gender: string
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
+
+class Gender
{
- case male = 'male';
- case female = 'female';
- case unknown = 'unknown';
+ private const male = 'male';
+ private const female = 'female';
+ private const unknown = 'unknown';
+ private string $value;
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ public function __construct(string $genderCode)
+ {
+ if (!in_array($genderCode, [self::male, self::female, self::unknown])) {
+ throw new InvalidArgumentException(sprintf('Gender code "%s" is not valid', $genderCode));
+ }
+ $this->value = $genderCode;
+ }
+
+ public function __toString()
+ {
+ return $this->value;
+ }
+
+ public static function male(): self
+ {
+ return new self(self::male);
+ }
+
+ public static function female(): self
+ {
+ return new self(self::female);
+ }
+
+ public static function unknown(): self
+ {
+ return new self(self::unknown);
+ }
+
+ public function equals(self $gender): bool
+ {
+ return $this->value === (string)$gender;
+ }
+
+ public function isMale(): bool
+ {
+ return $this->value === self::male;
+ }
+
+ public function isFemale(): bool
+ {
+ return $this->value === self::female;
+ }
+
+ public function isUnknown(): bool
+ {
+ return $this->value === self::unknown;
+ }
}
\ No newline at end of file
diff --git a/src/Common/Reason.php b/src/Common/Reason.php
index 6831a49..5e3c440 100644
--- a/src/Common/Reason.php
+++ b/src/Common/Reason.php
@@ -4,16 +4,26 @@
namespace B24io\Loyalty\SDK\Common;
-readonly class Reason
+class Reason
{
- public function __construct(
- public string $id,
- public string $code,
- public string $comment,
- )
+ /**
+ * @readonly
+ */
+ public string $id;
+ /**
+ * @readonly
+ */
+ public string $code;
+ /**
+ * @readonly
+ */
+ public string $comment;
+ public function __construct(string $id, string $code, string $comment)
{
+ $this->id = $id;
+ $this->code = $code;
+ $this->comment = $comment;
}
-
/**
* @return array
*/
diff --git a/src/Common/Requests/ItemsOrder.php b/src/Common/Requests/ItemsOrder.php
index eb9e2f8..7ba63f8 100644
--- a/src/Common/Requests/ItemsOrder.php
+++ b/src/Common/Requests/ItemsOrder.php
@@ -4,19 +4,37 @@
namespace B24io\Loyalty\SDK\Common\Requests;
-readonly class ItemsOrder
+class ItemsOrder
{
+ /**
+ * @readonly
+ */
+ public ?string $orderBy = null;
+ /**
+ * @readonly
+ */
+ public OrderDirection $direction;
+
+ /**
+ * @param string|null $orderBy
+ * @param OrderDirection|null $direction
+ */
public function __construct(
- public ?string $orderBy = null,
- public OrderDirection $direction = OrderDirection::desc)
+ ?string $orderBy = null,
+ ?OrderDirection $direction = null)
{
+ $this->orderBy = $orderBy;
+ if ($direction === null) {
+ $direction = OrderDirection::desc();
+ }
+ $this->direction = $direction;
}
public function toQueryParams(): string
{
return http_build_query([
'orderBy' => $this->orderBy,
- 'orderDirection' => $this->direction->value,
+ 'orderDirection' => (string)$this->direction,
]);
}
}
\ No newline at end of file
diff --git a/src/Common/Requests/OrderDirection.php b/src/Common/Requests/OrderDirection.php
index c8fe708..f46a737 100644
--- a/src/Common/Requests/OrderDirection.php
+++ b/src/Common/Requests/OrderDirection.php
@@ -4,8 +4,49 @@
namespace B24io\Loyalty\SDK\Common\Requests;
-enum OrderDirection: string
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
+
+class OrderDirection
{
- case asc = 'asc';
- case desc = 'desc';
+ private const asc = 'asc';
+ private const desc = 'desc';
+ private string $value;
+
+ public function __construct(string $directionCode)
+ {
+ if (!in_array($directionCode, [self::asc, self::desc], true)) {
+ throw new InvalidArgumentException(sprintf('Invalid direction code: %s', $directionCode));
+ }
+ $this->value = $directionCode;
+ }
+
+ public function __toString(): string
+ {
+ return $this->value;
+ }
+
+ public function equals(OrderDirection $direction): bool
+ {
+ return $this->value === (string)$direction;
+ }
+
+ public static function asc(): self
+ {
+ return new self(self::asc);
+ }
+
+ public static function desc(): self
+ {
+ return new self(self::desc);
+ }
+
+ public function isAsc(): bool
+ {
+ return $this->value === self::asc;
+ }
+
+ public function isDesc(): bool
+ {
+ return $this->value === self::desc;
+ }
}
\ No newline at end of file
diff --git a/src/Common/Requests/Transactions/ProcessTransactionByCardNumber.php b/src/Common/Requests/Transactions/ProcessTransactionByCardNumber.php
index 7e9b5e9..5f1fd10 100644
--- a/src/Common/Requests/Transactions/ProcessTransactionByCardNumber.php
+++ b/src/Common/Requests/Transactions/ProcessTransactionByCardNumber.php
@@ -6,29 +6,66 @@
use B24io\Loyalty\SDK\Common\Reason;
use B24io\Loyalty\SDK\Common\TransactionType;
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
use Money\Currencies\ISOCurrencies;
use Money\Currency;
use Money\Money;
use Money\Parser\DecimalMoneyParser;
use Symfony\Component\Uid\Uuid;
-readonly class ProcessTransactionByCardNumber
+class ProcessTransactionByCardNumber
{
+ /**
+ * @readonly
+ */
+ public Uuid $cardId;
+ /**
+ * @readonly
+ */
+ public string $cardNumber;
+ /**
+ * @readonly
+ */
+ public Money $amount;
+ /**
+ * @readonly
+ */
+ public TransactionType $type;
+ /**
+ * @readonly
+ */
+ public Uuid $contactId;
+ /**
+ * @readonly
+ */
+ public Reason $reason;
+ /**
+ * @readonly
+ */
+ public ?string $contactExternalId = null;
+
public function __construct(
- public Uuid $cardId,
- public string $cardNumber,
- public Money $amount,
- public TransactionType $type,
- public Uuid $contactId,
- public Reason $reason,
- public ?string $contactExternalId = null
- )
+ Uuid $cardId,
+ string $cardNumber,
+ Money $amount,
+ TransactionType $type,
+ Uuid $contactId,
+ Reason $reason,
+ ?string $contactExternalId = null)
{
+ $this->cardId = $cardId;
+ $this->cardNumber = $cardNumber;
+ $this->amount = $amount;
+ $this->type = $type;
+ $this->contactId = $contactId;
+ $this->reason = $reason;
+ $this->contactExternalId = $contactExternalId;
}
/**
* @param array{'card_id':string, 'card_number':string, 'transaction_amount':string, 'transaction_iso_currency_code':non-empty-string, 'transaction_type': non-empty-string, 'contact_id':non-empty-string, 'contact_external_id':string, 'transaction_reason_id':non-empty-string,'transaction_reason_code':non-empty-string,'transaction_reason_comment':string } $newTrx
* @return ProcessTransactionByCardNumber
+ * @throws InvalidArgumentException
*/
public static function initFromArray(array $newTrx): ProcessTransactionByCardNumber
{
@@ -38,7 +75,7 @@ public static function initFromArray(array $newTrx): ProcessTransactionByCardNum
Uuid::fromString($newTrx['card_id']),
$newTrx['card_number'],
$decimalMoneyParser->parse($newTrx['transaction_amount'], new Currency($newTrx['transaction_iso_currency_code'])),
- TransactionType::from($newTrx['transaction_type']),
+ new TransactionType($newTrx['transaction_type']),
Uuid::fromString($newTrx['contact_id']),
new Reason(
$newTrx['transaction_reason_id'],
diff --git a/src/Common/Result/Cards/CardItemResult.php b/src/Common/Result/Cards/CardItemResult.php
index bbe8545..5080841 100644
--- a/src/Common/Result/Cards/CardItemResult.php
+++ b/src/Common/Result/Cards/CardItemResult.php
@@ -5,6 +5,7 @@
namespace B24io\Loyalty\SDK\Common\Result\Cards;
use B24io\Loyalty\SDK\Common\Result\Contacts\ContactItemResult;
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
use B24io\Loyalty\SDK\Core\Result\AbstractItem;
use DateTimeImmutable;
use Money\Currency;
@@ -27,7 +28,12 @@
*/
class CardItemResult extends AbstractItem
{
- public function __get(int|string $offset)
+ /**
+ * @param int|string $offset
+ * @throws InvalidArgumentException
+ * @throws \Exception
+ */
+ public function __get($offset)
{
switch ($offset) {
case 'number':
@@ -40,7 +46,7 @@ public function __get(int|string $offset)
case 'percentage':
return new Percentage($this->data[$offset]);
case 'status':
- return CardStatus::from($this->data[$offset]);
+ return new CardStatus($this->data[$offset]);
case 'level':
if ($this->data['card_level'] === null) {
return null;
diff --git a/src/Common/Result/Cards/CardLevelItemResult.php b/src/Common/Result/Cards/CardLevelItemResult.php
index 7ce2c83..541b4d3 100644
--- a/src/Common/Result/Cards/CardLevelItemResult.php
+++ b/src/Common/Result/Cards/CardLevelItemResult.php
@@ -6,6 +6,7 @@
use B24io\Loyalty\SDK\Core\Result\AbstractItem;
use DateTimeImmutable;
+use Exception;
use MoneyPHP\Percentage\Percentage;
use Symfony\Component\Uid\Uuid;
@@ -22,7 +23,11 @@
*/
class CardLevelItemResult extends AbstractItem
{
- public function __get(int|string $offset)
+ /**
+ * @param int|string $offset
+ * @throws Exception
+ */
+ public function __get($offset)
{
switch ($offset) {
case 'nextLevelId':
diff --git a/src/Common/Result/Cards/CardStatus.php b/src/Common/Result/Cards/CardStatus.php
index 94003b7..d1ce8e5 100644
--- a/src/Common/Result/Cards/CardStatus.php
+++ b/src/Common/Result/Cards/CardStatus.php
@@ -4,9 +4,63 @@
namespace B24io\Loyalty\SDK\Common\Result\Cards;
-enum CardStatus: string
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
+
+class CardStatus
{
- case active = 'active';
- case blocked = 'blocked';
- case deleted = 'deleted';
+ private const active = 'active';
+ private const blocked = 'blocked';
+ private const deleted = 'deleted';
+ private string $value;
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ public function __construct(string $cardStatusCode)
+ {
+ if (!in_array($cardStatusCode, [self::active, self::blocked, self::deleted])) {
+ throw new InvalidArgumentException(sprintf('invalid card status code: %s', $cardStatusCode));
+ }
+ $this->value = $cardStatusCode;
+ }
+
+ public function __toString(): string
+ {
+ return $this->value;
+ }
+
+ public static function active(): self
+ {
+ return new self(self::active);
+ }
+
+ public static function blocked(): self
+ {
+ return new self(self::blocked);
+ }
+
+ public static function deleted(): self
+ {
+ return new self(self::deleted);
+ }
+
+ public function equals(CardStatus $cardStatus): bool
+ {
+ return $this->value === (string)$cardStatus;
+ }
+
+ public function isActive(): bool
+ {
+ return $this->value === self::active;
+ }
+
+ public function isDeleted(): bool
+ {
+ return $this->value === self::active;
+ }
+
+ public function isBlocked(): bool
+ {
+ return $this->value === self::active;
+ }
}
\ No newline at end of file
diff --git a/src/Common/Result/Contacts/ContactItemResult.php b/src/Common/Result/Contacts/ContactItemResult.php
index 73ce845..2c8d4c5 100644
--- a/src/Common/Result/Contacts/ContactItemResult.php
+++ b/src/Common/Result/Contacts/ContactItemResult.php
@@ -7,6 +7,7 @@
use B24io\Loyalty\SDK\Common\FullName;
use B24io\Loyalty\SDK\Common\Gender;
use B24io\Loyalty\SDK\Common\Result\Cards\CardItemResult;
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
use B24io\Loyalty\SDK\Core\Result\AbstractItem;
use DateTimeImmutable;
use DateTimeZone;
@@ -25,7 +26,11 @@
*/
class ContactItemResult extends AbstractItem
{
- public function __get(int|string $offset)
+ /**
+ * @param int|string $offset
+ * @throws InvalidArgumentException
+ */
+ public function __get($offset)
{
switch ($offset) {
case 'fullName':
@@ -43,7 +48,7 @@ public function __get(int|string $offset)
}
return new DateTimeImmutable($this->data[$offset]);
case 'gender':
- return Gender::from($this->data[$offset]);
+ return new Gender($this->data[$offset]);
case 'externalIds':
return $this->data['external_ids'];
case 'card':
diff --git a/src/Common/Result/Transactions/TransactionItemResult.php b/src/Common/Result/Transactions/TransactionItemResult.php
index 5fa28e8..8bf4fea 100644
--- a/src/Common/Result/Transactions/TransactionItemResult.php
+++ b/src/Common/Result/Transactions/TransactionItemResult.php
@@ -8,6 +8,7 @@
use B24io\Loyalty\SDK\Common\TransactionType;
use B24io\Loyalty\SDK\Core\Result\AbstractItem;
use DateTimeImmutable;
+use Exception;
use Money\Currency;
use Money\Money;
use Symfony\Component\Uid\Uuid;
@@ -23,7 +24,11 @@
*/
class TransactionItemResult extends AbstractItem
{
- public function __get(int|string $offset)
+ /**
+ * @param int|string $offset
+ * @throws Exception
+ */
+ public function __get($offset)
{
switch ($offset) {
case 'value':
@@ -32,7 +37,7 @@ public function __get(int|string $offset)
new Currency(($this->data[$offset]['currency']) ?? '')
);
case 'type':
- return TransactionType::from(str_replace('_transaction', '', $this->data[$offset]));
+ return new TransactionType(str_replace('_transaction', '', $this->data[$offset]));
case 'cardId':
return Uuid::fromString($this->data['card']['id']);
case 'cardNumber':
diff --git a/src/Common/TransactionType.php b/src/Common/TransactionType.php
index 2f881ba..d7cc9ef 100644
--- a/src/Common/TransactionType.php
+++ b/src/Common/TransactionType.php
@@ -4,8 +4,46 @@
namespace B24io\Loyalty\SDK\Common;
-enum TransactionType: string
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
+
+class TransactionType
{
- case accrual = 'accrual';
- case payment = 'payment';
+ private string $value;
+ private const accrual = 'accrual';
+ private const payment = 'payment';
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ public function __construct(string $value)
+ {
+ if (!in_array($value, [self::accrual, self::payment], true)) {
+ throw new InvalidArgumentException(sprintf('invalid transaction type code «%s» you must use %s or %s',
+ $value,
+ self::payment,
+ self::accrual
+ ));
+ }
+ $this->value = $value;
+ }
+
+ public function __toString(): string
+ {
+ return $this->value;
+ }
+
+ public function isEqual(self $transactionType): bool
+ {
+ return $this->value === (string)$transactionType;
+ }
+
+ public static function payment(): self
+ {
+ return new self(self::payment);
+ }
+
+ public static function accrual(): self
+ {
+ return new self(self::accrual);
+ }
}
\ No newline at end of file
diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php
index abc5ae2..41c11e0 100644
--- a/src/Core/ApiClient.php
+++ b/src/Core/ApiClient.php
@@ -18,7 +18,7 @@ class ApiClient implements ApiClientInterface
protected HttpClientInterface $client;
protected LoggerInterface $logger;
protected Credentials\Credentials $credentials;
- protected const SDK_VERSION = '3.0.0';
+ protected const SDK_VERSION = '3.2.0';
protected const SDK_USER_AGENT = 'b24io-loyalty-php-sdk';
public function __construct(Credentials\Credentials $credentials, HttpClientInterface $client, LoggerInterface $logger)
@@ -69,7 +69,7 @@ public function getResponse(
$this->logger->info(
'getResponse.start',
[
- 'context' => $context->name,
+ 'context' => $context,
'apiMethod' => $apiMethod,
'domainUrl' => $this->credentials->domainUrl,
'parameters' => $parameters,
@@ -85,7 +85,7 @@ public function getResponse(
$url = sprintf('%s%s/%s/%s',
$this->getCredentials()->domainUrl,
$this->getCredentials()->clientId->toRfc4122(),
- $context->name,
+ (string)$context,
$apiMethod);
if ($page !== null) {
if (parse_url($url, PHP_URL_QUERY) !== null) {
@@ -100,7 +100,7 @@ public function getResponse(
}
// auth
$headers = $this->getDefaultHeaders();
- if ($context === Context::admin && $this->getCredentials()->adminApiKey !== null) {
+ if ($context->isAdmin() && $this->getCredentials()->adminApiKey !== null) {
$headers['X-LOYALTY-API-KEY-ADMIN'] = $this->getCredentials()->adminApiKey->toRfc4122();
}
if ($idempotencyKey !== null) {
diff --git a/src/Core/Command.php b/src/Core/Command.php
index bf207b6..c92fd3f 100644
--- a/src/Core/Command.php
+++ b/src/Core/Command.php
@@ -8,8 +8,44 @@
use B24io\Loyalty\SDK\Core\Credentials\Context;
use Symfony\Component\Uid\Uuid;
-readonly class Command
+class Command
{
+ /**
+ * @var Context
+ * @readonly
+ */
+ public Context $context;
+ /**
+ * @var string
+ * @readonly
+ */
+ public string $httpMethod;
+ /**
+ * @var string
+ * @readonly
+ */
+ public string $apiMethod;
+ /**
+ * @var array
+ * @readonly
+ */
+ public array $parameters = [];
+ /**
+ * @var ItemsOrder|null
+ * @readonly
+ */
+ public ?ItemsOrder $itemsOrder = null;
+ /**
+ * @var int|null
+ * @readonly
+ */
+ public ?int $page = null;
+ /**
+ * @var Uuid|null
+ * @readonly
+ */
+ public ?Uuid $idempotencyKey = null;
+
/**
* @param Context $context
* @param string $httpMethod
@@ -20,14 +56,20 @@
* @param Uuid|null $idempotencyKey
*/
public function __construct(
- public Context $context,
- public string $httpMethod,
- public string $apiMethod,
- public array $parameters = [],
- public ?ItemsOrder $itemsOrder = null,
- public ?int $page = null,
- public ?Uuid $idempotencyKey = null
- )
+ Context $context,
+ string $httpMethod,
+ string $apiMethod,
+ array $parameters = [],
+ ?ItemsOrder $itemsOrder = null,
+ ?int $page = null,
+ ?Uuid $idempotencyKey = null)
{
+ $this->context = $context;
+ $this->httpMethod = $httpMethod;
+ $this->apiMethod = $apiMethod;
+ $this->parameters = $parameters;
+ $this->itemsOrder = $itemsOrder;
+ $this->page = $page;
+ $this->idempotencyKey = $idempotencyKey;
}
}
\ No newline at end of file
diff --git a/src/Core/Core.php b/src/Core/Core.php
index fc360a4..f11f0e7 100644
--- a/src/Core/Core.php
+++ b/src/Core/Core.php
@@ -47,8 +47,8 @@ public function call(Command $cmd): Response
'apiMethod' => $cmd->apiMethod,
'parameters' => $cmd->parameters,
'order' => [
- 'orderBy' => $cmd->itemsOrder?->orderBy,
- 'direction' => $cmd->itemsOrder?->direction,
+ 'orderBy' => $cmd->itemsOrder !== null ? $cmd->itemsOrder->orderBy : null,
+ 'direction' => $cmd->itemsOrder !== null ? $cmd->itemsOrder->direction : null,
],
]
);
@@ -76,7 +76,7 @@ public function call(Command $cmd): Response
//todo check with empty response size from server
$response = new Response($apiCallResponse,
new Command(
- Context::admin,
+ Context::admin(),
$cmd->httpMethod,
$cmd->apiMethod,
$cmd->parameters
diff --git a/src/Core/Credentials/Context.php b/src/Core/Credentials/Context.php
index 3046762..c47fdda 100644
--- a/src/Core/Credentials/Context.php
+++ b/src/Core/Credentials/Context.php
@@ -4,9 +4,68 @@
namespace B24io\Loyalty\SDK\Core\Credentials;
-enum Context: string
+use B24io\Loyalty\SDK\Core\Exceptions;
+use B24io\Loyalty\SDK\Core\Exceptions\InvalidArgumentException;
+
+class Context
{
- case admin = 'admin';
- case user = 'user';
- case default = '';
+ /**
+ * @var string
+ */
+ private string $value;
+ private const admin = 'admin';
+ private const user = 'user';
+ private const default = '';
+
+ /**
+ * @param string $value
+ * @throws InvalidArgumentException
+ */
+ public function __construct(string $value)
+ {
+ if (!in_array($value, [self::admin, self::user, self::default], true)) {
+ throw new Exceptions\InvalidArgumentException(sprintf('invalid context type «%s»', $value));
+ }
+ $this->value = $value;
+ }
+
+ public static function default(): self
+ {
+ return new self(self::default);
+ }
+
+ public static function user(): self
+ {
+ return new self(self::user);
+ }
+
+ public static function admin(): self
+ {
+ return new self(self::admin);
+ }
+
+ public function isDefault(): bool
+ {
+ return $this->value === self::default;
+ }
+
+ public function isUser(): bool
+ {
+ return $this->value === self::user;
+ }
+
+ public function isAdmin(): bool
+ {
+ return $this->value === self::admin;
+ }
+
+ public function __toString(): string
+ {
+ return $this->value;
+ }
+
+ public function equals(Context $context): bool
+ {
+ return $this->value === (string)$context;
+ }
}
\ No newline at end of file
diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php
index d413495..df9996b 100644
--- a/src/Core/Credentials/Credentials.php
+++ b/src/Core/Credentials/Credentials.php
@@ -6,12 +6,28 @@
use Symfony\Component\Uid\Uuid;
-readonly class Credentials
+class Credentials
{
+ /**
+ * @readonly
+ */
+ public string $domainUrl;
+ /**
+ * @readonly
+ */
+ public Uuid $clientId;
+ /**
+ * @readonly
+ */
+ public ?Uuid $adminApiKey;
+
public function __construct(
- public string $domainUrl,
- public Uuid $clientId,
- public ?Uuid $adminApiKey)
+ string $domainUrl,
+ Uuid $clientId,
+ ?Uuid $adminApiKey)
{
+ $this->domainUrl = $domainUrl;
+ $this->clientId = $clientId;
+ $this->adminApiKey = $adminApiKey;
}
}
\ No newline at end of file
diff --git a/src/Core/Exceptions/BadRequestException.php b/src/Core/Exceptions/BadRequestException.php
index f5d40c7..6c8c34f 100644
--- a/src/Core/Exceptions/BadRequestException.php
+++ b/src/Core/Exceptions/BadRequestException.php
@@ -15,7 +15,7 @@ public function __construct(
ApiProblem $apiProblem,
string $message = "",
int $code = 0,
- ?Throwable $previous = null,
+ ?Throwable $previous = null
)
{
parent::__construct($message, $code, $previous);
diff --git a/src/Core/Exceptions/InternalServerErrorException.php b/src/Core/Exceptions/InternalServerErrorException.php
index 18ac772..e355b0e 100644
--- a/src/Core/Exceptions/InternalServerErrorException.php
+++ b/src/Core/Exceptions/InternalServerErrorException.php
@@ -15,7 +15,7 @@ public function __construct(
ApiProblem $apiProblem,
string $message = "",
int $code = 0,
- ?Throwable $previous = null,
+ ?Throwable $previous = null
)
{
parent::__construct($message, $code, $previous);
diff --git a/src/Core/Response/ApiProblem.php b/src/Core/Response/ApiProblem.php
index 58ad605..a8cc209 100644
--- a/src/Core/Response/ApiProblem.php
+++ b/src/Core/Response/ApiProblem.php
@@ -4,16 +4,41 @@
namespace B24io\Loyalty\SDK\Core\Response;
-readonly class ApiProblem
+class ApiProblem
{
+ /**
+ * @readonly
+ */
+ public string $title;
+ /**
+ * @readonly
+ */
+ public string $type;
+ /**
+ * @readonly
+ */
+ public int $status;
+ /**
+ * @readonly
+ */
+ public string $detail;
+ /**
+ * @readonly
+ */
+ public string $instance;
+
public function __construct(
- public string $title,
- public string $type,
- public int $status,
- public string $detail,
- public string $instance,
- )
+ string $title,
+ string $type,
+ int $status,
+ string $detail,
+ string $instance)
{
+ $this->title = $title;
+ $this->type = $type;
+ $this->status = $status;
+ $this->detail = $detail;
+ $this->instance = $instance;
}
/**
diff --git a/src/Core/Response/DTO/Metadata.php b/src/Core/Response/DTO/Metadata.php
index f553ccb..6dce00d 100644
--- a/src/Core/Response/DTO/Metadata.php
+++ b/src/Core/Response/DTO/Metadata.php
@@ -8,16 +8,41 @@
use DateTimeImmutable;
use Exception;
-readonly class Metadata
+class Metadata
{
+ /**
+ * @readonly
+ */
+ public DateTimeImmutable $requestStartTime;
+ /**
+ * @readonly
+ */
+ public string $requestId;
+ /**
+ * @readonly
+ */
+ public Context $role;
+ /**
+ * @readonly
+ */
+ public float $duration;
+ /**
+ * @readonly
+ */
+ public string $message;
+
public function __construct(
- public DateTimeImmutable $requestStartTime,
- public string $requestId,
- public Context $role,
- public float $duration,
- public string $message
- )
+ DateTimeImmutable $requestStartTime,
+ string $requestId,
+ Context $role,
+ float $duration,
+ string $message)
{
+ $this->requestStartTime = $requestStartTime;
+ $this->requestId = $requestId;
+ $this->role = $role;
+ $this->duration = $duration;
+ $this->message = $message;
}
/**
@@ -29,7 +54,7 @@ public static function initFromArray(array $metadata): self
return new self(
new DateTimeImmutable($metadata['request_start_time']),
$metadata['request_id'],
- Context::from($metadata['role']),
+ new Context($metadata['role']),
$metadata['duration'],
$metadata['message']
);
diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php
index 0d4dcdc..25ce68f 100644
--- a/src/Core/Response/DTO/Pagination.php
+++ b/src/Core/Response/DTO/Pagination.php
@@ -4,18 +4,36 @@
namespace B24io\Loyalty\SDK\Core\Response\DTO;
-readonly class Pagination
+class Pagination
{
- public function __construct(
- public ?int $count,
- public ?int $total,
- public ?int $page,
- public ?int $pages,
- public ?int $pageSize,
- )
+ /**
+ * @readonly
+ */
+ public ?int $count;
+ /**
+ * @readonly
+ */
+ public ?int $total;
+ /**
+ * @readonly
+ */
+ public ?int $page;
+ /**
+ * @readonly
+ */
+ public ?int $pages;
+ /**
+ * @readonly
+ */
+ public ?int $pageSize;
+ public function __construct(?int $count, ?int $total, ?int $page, ?int $pages, ?int $pageSize)
{
+ $this->count = $count;
+ $this->total = $total;
+ $this->page = $page;
+ $this->pages = $pages;
+ $this->pageSize = $pageSize;
}
-
/**
* @param array $pagination
* @return self
diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php
index 0f34ed0..0c11475 100644
--- a/src/Core/Response/DTO/ResponseData.php
+++ b/src/Core/Response/DTO/ResponseData.php
@@ -4,15 +4,34 @@
namespace B24io\Loyalty\SDK\Core\Response\DTO;
-readonly class ResponseData
+class ResponseData
{
+ /**
+ * @readonly
+ * @var array $result
+ */
+ public array $result;
+ /**
+ * @readonly
+ */
+ public Metadata $metadata;
+ /**
+ * @readonly
+ */
+ public Pagination $pagination;
+
+ /**
+ * @param array $result
+ * @param Metadata $metadata
+ * @param Pagination $pagination
+ */
public function __construct(
- /**
- * @var array
- */
- public array $result,
- public Metadata $metadata,
- public Pagination $pagination)
+ array $result,
+ Metadata $metadata,
+ Pagination $pagination)
{
+ $this->result = $result;
+ $this->metadata = $metadata;
+ $this->pagination = $pagination;
}
}
\ No newline at end of file
diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php
index f4cfaac..7266227 100644
--- a/src/Core/Response/Response.php
+++ b/src/Core/Response/Response.php
@@ -6,7 +6,6 @@
use B24io\Loyalty\SDK\Core\Command;
use B24io\Loyalty\SDK\Core\Exceptions\BaseException;
-use B24io\Loyalty\SDK\Core\Exceptions\TransportException;
use B24io\Loyalty\SDK\Core\Response\DTO\Metadata;
use B24io\Loyalty\SDK\Core\Response\DTO\Pagination;
use Psr\Log\LoggerInterface;
@@ -15,13 +14,30 @@
class Response
{
+ /**
+ * @readonly
+ */
+ public ResponseInterface $httpResponse;
+ /**
+ * @readonly
+ */
+ public Command $apiCommand;
+ /**
+ * @readonly
+ */
+ private LoggerInterface $logger;
+ private ?DTO\ResponseData $responseData = null;
+
public function __construct(
- public readonly ResponseInterface $httpResponse,
- public readonly Command $apiCommand,
- private readonly LoggerInterface $logger,
- private ?DTO\ResponseData $responseData = null,
- )
+ ResponseInterface $httpResponse,
+ Command $apiCommand,
+ LoggerInterface $logger,
+ ?DTO\ResponseData $responseData = null)
{
+ $this->httpResponse = $httpResponse;
+ $this->apiCommand = $apiCommand;
+ $this->logger = $logger;
+ $this->responseData = $responseData;
}
/**
diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php
index 8365b89..d740a47 100644
--- a/src/Core/Result/AbstractItem.php
+++ b/src/Core/Result/AbstractItem.php
@@ -35,7 +35,10 @@ public function __construct(array $data)
$this->decimalMoneyParser = new DecimalMoneyParser(new ISOCurrencies());
}
- public function __isset(int|string $offset): bool
+ /**
+ * @param int|string $offset
+ */
+ public function __isset($offset): bool
{
return isset($this->data[$offset]);
}
@@ -46,7 +49,7 @@ public function __isset(int|string $offset): bool
* @return mixed
* @throws Exception
*/
- public function __get(int|string $offset)
+ public function __get($offset)
{
switch ($offset) {
case 'id':
@@ -76,7 +79,7 @@ public function __get(int|string $offset)
* @throws ImmutableResultViolationException
*
*/
- public function __set(int|string $offset, mixed $value)
+ public function __set($offset, $value)
{
throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset));
}
@@ -86,7 +89,7 @@ public function __set(int|string $offset, mixed $value)
*
* @throws ImmutableResultViolationException
*/
- public function __unset(int|string $offset)
+ public function __unset($offset)
{
throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset));
}
diff --git a/src/Infrastructure/Filesystem/TransactionsReader.php b/src/Infrastructure/Filesystem/TransactionsReader.php
index b510222..a586120 100644
--- a/src/Infrastructure/Filesystem/TransactionsReader.php
+++ b/src/Infrastructure/Filesystem/TransactionsReader.php
@@ -13,17 +13,23 @@
use Psr\Log\LoggerInterface;
use League\Csv;
-readonly class TransactionsReader
+class TransactionsReader
{
+ /**
+ * @readonly
+ */
+ private LoggerInterface $log;
/**
* @var array
+ * @readonly
*/
private array $transactionByCardNumberFileHeader;
public function __construct(
- private LoggerInterface $log
+ LoggerInterface $log
)
{
+ $this->log = $log;
$this->transactionByCardNumberFileHeader = [
'card_id',
'card_number',
diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php
index b4b0874..7a6ec0b 100644
--- a/src/Services/AbstractService.php
+++ b/src/Services/AbstractService.php
@@ -12,10 +12,22 @@
abstract class AbstractService
{
- public readonly CoreInterface $core;
- protected readonly LoggerInterface $log;
- protected readonly DecimalMoneyFormatter $decimalMoneyFormatter;
- protected readonly PhoneNumberUtil $phoneNumberUtil;
+ /**
+ * @readonly
+ */
+ public CoreInterface $core;
+ /**
+ * @readonly
+ */
+ protected LoggerInterface $log;
+ /**
+ * @readonly
+ */
+ protected DecimalMoneyFormatter $decimalMoneyFormatter;
+ /**
+ * @readonly
+ */
+ protected PhoneNumberUtil $phoneNumberUtil;
public function __construct(CoreInterface $core, LoggerInterface $log)
{
diff --git a/src/Services/Admin/Cards/Cards.php b/src/Services/Admin/Cards/Cards.php
index 5e6e766..ef45fa8 100644
--- a/src/Services/Admin/Cards/Cards.php
+++ b/src/Services/Admin/Cards/Cards.php
@@ -34,7 +34,7 @@ public function add(
{
return new AddedCardResult($this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_POST,
'cards',
[
@@ -45,9 +45,9 @@ public function add(
'currency' => $balance->getCurrency()->getCode()
],
'percentage' => (string)$percentage,
- 'status' => $cardStatus->value,
- 'card_level_id' => $cardLevelId?->toRfc4122(),
- 'affiliate_card_id' => $affiliateCardId?->toRfc4122(),
+ 'status' => (string)$cardStatus,
+ 'card_level_id' => ($nullsafeCardLevelId = $cardLevelId) ? $nullsafeCardLevelId->toRfc4122() : null,
+ 'affiliate_card_id' => ($nullsafeAffiliateCardId = $affiliateCardId) ? $nullsafeAffiliateCardId->toRfc4122() : null,
'barcode' => $barcode,
'external_id' => $externalId
],
@@ -63,7 +63,7 @@ public function getById(Uuid $id): CardItemResult
return new CardItemResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
sprintf('cards/%s', $id->toRfc4122()),
)
@@ -76,7 +76,7 @@ public function list(ItemsOrder $order = null, ?int $page = 1): CardsResult
return new CardsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'cards',
[],
@@ -95,7 +95,7 @@ public function count(): int
return (int)(new CardsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'cards',
[],
diff --git a/src/Services/Admin/Cards/CardsFetcher.php b/src/Services/Admin/Cards/CardsFetcher.php
index bbc8ce3..bc43f52 100644
--- a/src/Services/Admin/Cards/CardsFetcher.php
+++ b/src/Services/Admin/Cards/CardsFetcher.php
@@ -12,11 +12,12 @@
class CardsFetcher
{
- public function __construct(
- private Cards $cards,
- private LoggerInterface $logger
- )
+ private Cards $cards;
+ private LoggerInterface $logger;
+ public function __construct(Cards $cards, LoggerInterface $logger)
{
+ $this->cards = $cards;
+ $this->logger = $logger;
}
/**
diff --git a/src/Services/Admin/Contacts/Contacts.php b/src/Services/Admin/Contacts/Contacts.php
index 643c7f4..9e84590 100644
--- a/src/Services/Admin/Contacts/Contacts.php
+++ b/src/Services/Admin/Contacts/Contacts.php
@@ -32,7 +32,7 @@ class Contacts extends AbstractService
* @param PhoneNumber $mobilePhone
* @param DateTimeImmutable|null $birthdate
* @param array $externalIds
- * @return AddedContactResult
+ *@return AddedContactResult
*/
public function add(
FullName $fullName,
@@ -45,14 +45,14 @@ public function add(
{
return new AddedContactResult($this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_POST,
'contacts',
[
'full_name' => $fullName->toArray(),
'timezone' => $timezone->getName(),
- 'gender' => $gender->name,
- 'birthday' => $birthdate?->format('Y.m.d'),
+ 'gender' => (string)$gender,
+ 'birthday' => ($nullsafeBirthdate = $birthdate) ? $nullsafeBirthdate->format('Y.m.d') : null,
'mobile_phone' => $this->phoneNumberUtil->format($mobilePhone, PhoneNumberFormat::E164),
'external_ids' => $externalIds
],
@@ -67,7 +67,7 @@ public function getById(Uuid $id): ContactItemResult
return new ContactItemResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
sprintf('contacts/%s', $id->toRfc4122()),
)
@@ -88,7 +88,7 @@ public function list(
return new ContactsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
$url,
[],
@@ -112,7 +112,7 @@ public function count(?ContactsFilter $filter = null): int
return (int)(new ContactsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
$url,
[],
diff --git a/src/Services/Admin/Contacts/ContactsFetcher.php b/src/Services/Admin/Contacts/ContactsFetcher.php
index e649e73..854db3e 100644
--- a/src/Services/Admin/Contacts/ContactsFetcher.php
+++ b/src/Services/Admin/Contacts/ContactsFetcher.php
@@ -10,32 +10,34 @@
use Generator;
use Psr\Log\LoggerInterface;
-readonly class ContactsFetcher
+class ContactsFetcher
{
- public function __construct(
- private Contacts $contacts,
- private LoggerInterface $logger
- )
+ /**
+ * @readonly
+ */
+ private Contacts $contacts;
+ /**
+ * @readonly
+ */
+ private LoggerInterface $logger;
+ public function __construct(Contacts $contacts, LoggerInterface $logger)
{
+ $this->contacts = $contacts;
+ $this->logger = $logger;
}
/**
* @return Generator
* @throws BaseException
*/
- public function list(
- ?ContactsFilter $filter = null,
- ?ItemsOrder $order = null,
- ): Generator
+ public function list(?ContactsFilter $filter = null, ?ItemsOrder $order = null): Generator
{
$res = $this->contacts->list($filter);
-
$pages = $res->getCoreResponse()->getResponseData()->pagination->pages;
$this->logger->debug('ContactsFetcher.list.start', [
'total' => $res->getCoreResponse()->getResponseData()->pagination->total,
'pages' => $pages
]);
-
$contactCnt = 0;
for ($i = 1; $i <= $pages; $i++) {
$res = $this->contacts->list($filter, $order, $i);
diff --git a/src/Services/Admin/Main/Main.php b/src/Services/Admin/Main/Main.php
index 5ed0886..76660f0 100644
--- a/src/Services/Admin/Main/Main.php
+++ b/src/Services/Admin/Main/Main.php
@@ -16,7 +16,7 @@ class Main extends AbstractService
public function health(): Response
{
return $this->core->call(new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'health',
));
diff --git a/src/Services/Admin/Transactions/Transactions.php b/src/Services/Admin/Transactions/Transactions.php
index 8f5cc77..b885791 100644
--- a/src/Services/Admin/Transactions/Transactions.php
+++ b/src/Services/Admin/Transactions/Transactions.php
@@ -23,7 +23,7 @@ public function list(?int $page = 1): TransactionsResult
return new TransactionsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'transactions',
[],
@@ -39,7 +39,7 @@ public function getByCardNumber(string $cardNumber, ?int $page = 1): Transaction
return new TransactionsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
sprintf('transactions/with-card-number/%s', $cardNumber),
[],
@@ -54,11 +54,11 @@ public function processPaymentTransactionByCardNumber(string $cardNumber, Money
{
return new ProcessedTransactionResult($this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_POST,
sprintf('transactions/with-card-number/%s', $cardNumber),
[
- 'type' => TransactionType::payment->name,
+ 'type' => (string)TransactionType::payment(),
'bonus_points' => [
'amount' => $this->decimalMoneyFormatter->format($amount),
'currency' => $amount->getCurrency()->getCode(),
@@ -76,11 +76,11 @@ public function processAccrualTransactionByCardNumber(string $cardNumber, Money
{
return new ProcessedTransactionResult($this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_POST,
sprintf('transactions/with-card-number/%s', $cardNumber),
[
- 'type' => TransactionType::accrual->name,
+ 'type' => (string)TransactionType::accrual(),
'bonus_points' => [
'amount' => $this->decimalMoneyFormatter->format($amount),
'currency' => $amount->getCurrency()->getCode(),
@@ -102,7 +102,7 @@ public function count(): int
return (int)(new TransactionsResult(
$this->core->call(
new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'transactions',
[],
diff --git a/src/Services/Admin/Transactions/TransactionsFetcher.php b/src/Services/Admin/Transactions/TransactionsFetcher.php
index 58e1831..ec9d6cc 100644
--- a/src/Services/Admin/Transactions/TransactionsFetcher.php
+++ b/src/Services/Admin/Transactions/TransactionsFetcher.php
@@ -9,13 +9,20 @@
use Generator;
use Psr\Log\LoggerInterface;
-readonly class TransactionsFetcher
+class TransactionsFetcher
{
- public function __construct(
- private Transactions $transactions,
- private LoggerInterface $logger
- )
+ /**
+ * @readonly
+ */
+ private Transactions $transactions;
+ /**
+ * @readonly
+ */
+ private LoggerInterface $logger;
+ public function __construct(Transactions $transactions, LoggerInterface $logger)
{
+ $this->transactions = $transactions;
+ $this->logger = $logger;
}
/**
diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php
index 5674825..fe44eb0 100644
--- a/src/Services/ServiceBuilderFactory.php
+++ b/src/Services/ServiceBuilderFactory.php
@@ -15,15 +15,9 @@
use Symfony\Component\Uid\Uuid;
use Symfony\Contracts\HttpClient\HttpClientInterface;
-readonly class ServiceBuilderFactory
+class ServiceBuilderFactory
{
- public static function createAdminRoleServiceBuilder(
- string $apiEndpointUrl,
- string $apiClientId,
- string $apiAdminKey,
- LoggerInterface $logger,
- ?HttpClientInterface $httpClient = null,
- ): AdminServiceBuilder
+ public static function createAdminRoleServiceBuilder(string $apiEndpointUrl, string $apiClientId, string $apiAdminKey, LoggerInterface $logger, ?HttpClientInterface $httpClient = null): AdminServiceBuilder
{
return new AdminServiceBuilder(
self::getCore(
diff --git a/tests/.env.local b/tests/.env.local
deleted file mode 100644
index 8a906d8..0000000
--- a/tests/.env.local
+++ /dev/null
@@ -1,23 +0,0 @@
-# In all environments, the following files are loaded if they exist,
-# the latter taking precedence over the former:
-#
-# * .env contains default values for the environment variables needed by the app
-# * .env.local uncommitted file with local overrides
-# * .env.$APP_ENV committed environment-specific defaults
-# * .env.$APP_ENV.local uncommitted environment-specific overrides
-#
-# Real environment variables win over .env files.
-#
-# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
-#
-# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
-# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
-
-APP_ENV=dev
-# monolog log level
-INTEGRATION_TEST_LOG_LEVEL=100
-
-
-LOYALTY_API_ENDPOINT_URL=https://loyalty.b24.cloud
-LOYALTY_API_CLIENT_ID=e3fa28cd-e245-4e9c-9e98-fab2a37ac964
-LOYALTY_API_ADMIN_KEY=f0a71cb6-d4fd-440e-9971-cbd5e7c33590
diff --git a/tests/Integration/Core/ApiClientTest.php b/tests/Integration/Core/ApiClientTest.php
index 5cc0bab..6432679 100644
--- a/tests/Integration/Core/ApiClientTest.php
+++ b/tests/Integration/Core/ApiClientTest.php
@@ -19,7 +19,7 @@ class ApiClientTest extends TestCase
public function testCallUnknownMethod(): void
{
$res = $this->apiClient->getResponse(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'unknown');
$this->assertEquals(StatusCodeInterface::STATUS_NOT_FOUND, $res->getStatusCode());
@@ -28,11 +28,10 @@ public function testCallUnknownMethod(): void
public function testCallHealthMethod(): void
{
$res = $this->apiClient->getResponse(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'health');
$this->assertEquals(StatusCodeInterface::STATUS_OK, $res->getStatusCode());
- var_dump($res->toArray());
}
public function setUp(): void
diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php
index 93d5dfe..99d7ff0 100644
--- a/tests/Integration/Core/CoreTest.php
+++ b/tests/Integration/Core/CoreTest.php
@@ -20,7 +20,7 @@ public function testCallUnknownMethod(): void
{
$this->expectException(\B24io\Loyalty\SDK\Core\Exceptions\MethodNotFoundException::class);
$res = $this->core->call(new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'unknownMethod'
@@ -32,7 +32,7 @@ public function testCallUnknownMethod(): void
public function testCallHealthMethod(): void
{
$res = $this->core->call(new Command(
- Context::admin,
+ Context::admin(),
RequestMethodInterface::METHOD_GET,
'health'
diff --git a/tests/Integration/IntegrationTestsContextBuilder.php b/tests/Integration/IntegrationTestsContextBuilder.php
index 22cca9c..d03055f 100644
--- a/tests/Integration/IntegrationTestsContextBuilder.php
+++ b/tests/Integration/IntegrationTestsContextBuilder.php
@@ -36,7 +36,8 @@ public static function getCredentials(): Credentials
public static function getDefaultLogger(): LoggerInterface
{
$log = new Logger('loyalty-php-sdk-integration-test');
- $log->pushHandler(new StreamHandler($_ENV['INTEGRATION_TEST_LOG_FILE'], (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL']));
+ $logLevel = $_ENV['INTEGRATION_TEST_LOG_LEVEL'];
+ $log->pushHandler(new StreamHandler($_ENV['INTEGRATION_TEST_LOG_FILE'], $logLevel));
$log->pushProcessor(new MemoryUsageProcessor(true, true));
$log->pushProcessor(new IntrospectionProcessor());
diff --git a/tests/Integration/ServiceBuilderFactoryTest.php b/tests/Integration/ServiceBuilderFactoryTest.php
index 4aa5716..289be2b 100644
--- a/tests/Integration/ServiceBuilderFactoryTest.php
+++ b/tests/Integration/ServiceBuilderFactoryTest.php
@@ -24,7 +24,7 @@ public function testDefaultHttpClient(): void
$url,
[
'headers' => [
- 'X-LOYALTY-API-KEY-ADMIN' => $credentials->adminApiKey?->toRfc4122()
+ 'X-LOYALTY-API-KEY-ADMIN' => ($nullsafeVariable1 = $credentials->adminApiKey) ? $nullsafeVariable1->toRfc4122() : null
],
]
);
diff --git a/tests/Integration/Services/Admin/Cards/CardsFetcherTest.php b/tests/Integration/Services/Admin/Cards/CardsFetcherTest.php
index 2bc24fa..0f5a542 100644
--- a/tests/Integration/Services/Admin/Cards/CardsFetcherTest.php
+++ b/tests/Integration/Services/Admin/Cards/CardsFetcherTest.php
@@ -23,13 +23,13 @@ class CardsFetcherTest extends TestCase
*/
public function testCardsFetcher(): void
{
- $cardsCount = $this->sb->cardsScope()->cards()->count();
-
+ // in parallel, we can run tests for CRUD operations
$cardCnt = 0;
- foreach ($this->sb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc)) as $card) {
+ foreach ($this->sb->cardsScope()->fetcher()->list(new ItemsOrder('created', OrderDirection::desc())) as $card) {
$cardCnt++;
}
- $this->assertEquals($cardsCount, $cardCnt);
+
+ $this->assertGreaterThanOrEqual(0, $cardCnt);
}
public function setUp(): void
diff --git a/tests/Integration/Services/Admin/Cards/CardsTest.php b/tests/Integration/Services/Admin/Cards/CardsTest.php
index 2f18ef5..62761e8 100644
--- a/tests/Integration/Services/Admin/Cards/CardsTest.php
+++ b/tests/Integration/Services/Admin/Cards/CardsTest.php
@@ -51,7 +51,6 @@ public function testGetCardsListWithoutArguments(): void
/**
* @throws BaseException
- * @throws RandomException
* @throws NumberParseException
*/
public function testAddCard(): void
@@ -62,7 +61,7 @@ public function testAddCard(): void
$this->faker->lastName(),
),
new DateTimeZone('Europe/Moscow'),
- Gender::male,
+ Gender::male(),
$this->phoneNumberUtil->parse(
$this->faker->phoneNumber,
'RU'
@@ -73,7 +72,7 @@ public function testAddCard(): void
$cardNumber = (string)time();
$cardBalance = new Money(random_int(1000, 1000000), new Currency('RUB'));
$cardPercentage = new Percentage('5.5');
- $cardStatus = CardStatus::active;
+ $cardStatus = CardStatus::active();
$addedCard = $this->sb->cardsScope()->cards()->add(
$contactId,
@@ -155,7 +154,7 @@ public function testCardsListWithOrder(
public static function orderDataProvider(): Generator
{
yield 'order by created desc' => [
- new ItemsOrder('created', OrderDirection::desc),
+ new ItemsOrder('created', OrderDirection::desc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -186,69 +185,78 @@ static function (
null,
];
yield 'order by created asc' => [
- new ItemsOrder('created', OrderDirection::asc),
+ new ItemsOrder('created', OrderDirection::asc()),
static function (
ItemsOrder $itemsOrder,
/**
* @phpstan-param CardItemResult[] $cards
*/
array $cards) {
- $prev = null;
+ $prevCard = null;
foreach ($cards as $cnt => $card) {
- print($card->created->format('Y-m-d H:i:s') . PHP_EOL);
+ print(sprintf('%s | %s %s', $cnt, $card->number, $card->created->format('Y-m-d H:i:s') . PHP_EOL));
/**
* @var CardItemResult $card
*/
- if ($prev === null) {
- $prev = $card->created;
+ if ($prevCard === null) {
+ $prevCard = $card;
continue;
}
- if ($prev->getTimestamp() > $card->created->getTimestamp()) {
- self::fail(sprintf('Card #%d created at %s is not greater than previous card #%d created at %s',
+ if ($prevCard->created->getTimestamp() > $card->created->getTimestamp()) {
+ self::fail(sprintf('Card #%d with number %s created at %s (%s) is not greater than previous card #%d number %s created at %s (%s)',
$cnt,
+ $card->number,
$card->created->format('Y-m-d H:i:s'),
+ $card->created->getTimestamp(),
$cnt - 1,
- $prev->format('Y-m-d H:i:s')
+ $prevCard->number,
+ $prevCard->created->format('Y-m-d H:i:s'),
+ $prevCard->created->getTimestamp()
));
}
- $prev = $card->created;
+ $prevCard = $card;
}
},
null
];
yield 'order by modified desc' => [
- new ItemsOrder('modified', OrderDirection::desc),
+ new ItemsOrder('modified', OrderDirection::desc()),
static function (
ItemsOrder $itemsOrder,
/**
* @phpstan-param CardItemResult[] $cards
*/
array $cards) {
- $prev = null;
+ $prevCard = null;
+ print('order by modified desc' . PHP_EOL);
foreach ($cards as $cnt => $card) {
- print($card->modified->format('Y-m-d H:i:s') . PHP_EOL);
+ print(sprintf('%s | %s - %s', $cnt, $card->number, $card->modified->format('Y-m-d H:i:s')) . PHP_EOL);
/**
* @var CardItemResult $card
*/
- if ($prev === null) {
- $prev = $card->modified;
+ if ($prevCard === null) {
+ $prevCard = $card;
continue;
}
- if ($prev->getTimestamp() < $card->modified->getTimestamp()) {
- self::fail(sprintf('Card #%d modified at %s is not greater than previous card #%d modified at %s',
+ if ($prevCard->modified->getTimestamp() < $card->modified->getTimestamp()) {
+ self::fail(sprintf('Card %s #%d modified at %s(%s) is not greater than previous card %s #%d modified at %s (%s)',
$cnt,
+ $card->number,
$card->modified->format('Y-m-d H:i:s'),
+ $card->modified->getTimestamp(),
$cnt - 1,
- $prev->format('Y-m-d H:i:s')
+ $prevCard->number,
+ $prevCard->modified->format('Y-m-d H:i:s'),
+ $prevCard->modified->getTimestamp()
));
}
- $prev = $card->modified;
+ $prevCard = $card;
}
},
null
];
yield 'order by modified asc' => [
- new ItemsOrder('modified', OrderDirection::asc),
+ new ItemsOrder('modified', OrderDirection::asc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -279,7 +287,7 @@ static function (
null
];
yield 'order by balance desc' => [
- new ItemsOrder('balance', OrderDirection::desc),
+ new ItemsOrder('balance', OrderDirection::desc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -312,7 +320,7 @@ static function (
null
];
yield 'order by balance asc' => [
- new ItemsOrder('balance', OrderDirection::asc),
+ new ItemsOrder('balance', OrderDirection::asc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -320,6 +328,7 @@ static function (
*/
array $cards) {
$prev = null;
+ print('order by balance asc');
foreach ($cards as $cnt => $card) {
/**
* @var CardItemResult $card
@@ -344,12 +353,24 @@ static function (
null
];
yield 'wrong order by field' => [
- new ItemsOrder('balance1', OrderDirection::desc),
+ new ItemsOrder('balance1', OrderDirection::desc()),
null,
BadRequestException::class
];
}
+ /**
+ * @return void
+ * @throws BaseException
+ * @covers Cards::count()
+ * @testdox Test count cards method
+ */
+ public function testCount(): void
+ {
+ $cnt = $this->sb->cardsScope()->cards()->count();
+ $this->assertGreaterThan(0, $cnt);
+ }
+
public function setUp(): void
{
$this->sb = IntegrationTestsContextBuilder::getAdminServiceBuilder();
diff --git a/tests/Integration/Services/Admin/Contacts/ContactsFetcherTest.php b/tests/Integration/Services/Admin/Contacts/ContactsFetcherTest.php
index c8c62eb..0e54fad 100644
--- a/tests/Integration/Services/Admin/Contacts/ContactsFetcherTest.php
+++ b/tests/Integration/Services/Admin/Contacts/ContactsFetcherTest.php
@@ -23,14 +23,12 @@ class ContactsFetcherTest extends TestCase
*/
public function testCardsFetcher(): void
{
-
- $contactsCount = $this->sb->contactsScope()->contacts()->count();
-
+ // in parallel, we can run tests for CRUD operations
$itemCnt = 0;
- foreach ($this->sb->contactsScope()->fetcher()->list(null, new ItemsOrder('created', OrderDirection::desc)) as $item) {
+ foreach ($this->sb->contactsScope()->fetcher()->list(null, new ItemsOrder('created', OrderDirection::desc())) as $item) {
$itemCnt++;
}
- $this->assertEquals($contactsCount, $itemCnt);
+ $this->assertGreaterThanOrEqual(0, $itemCnt);
}
public function setUp(): void
diff --git a/tests/Integration/Services/Admin/Contacts/ContactsTest.php b/tests/Integration/Services/Admin/Contacts/ContactsTest.php
index bb1ef8c..65c17bb 100644
--- a/tests/Integration/Services/Admin/Contacts/ContactsTest.php
+++ b/tests/Integration/Services/Admin/Contacts/ContactsTest.php
@@ -46,7 +46,7 @@ public function testAdd(): void
$this->faker->lastName(),
),
new DateTimeZone('Europe/Moscow'),
- Gender::male,
+ Gender::male(),
$this->phoneNumberUtil->parse(
$this->faker->phoneNumber,
'RU'
@@ -119,7 +119,7 @@ public function testContactsListWithOrder(
public static function orderDataProvider(): Generator
{
yield 'order by created desc' => [
- new ItemsOrder('created', OrderDirection::desc),
+ new ItemsOrder('created', OrderDirection::desc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -150,7 +150,7 @@ static function (
null,
];
yield 'order by created asc' => [
- new ItemsOrder('created', OrderDirection::asc),
+ new ItemsOrder('created', OrderDirection::asc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -181,7 +181,7 @@ static function (
null
];
yield 'order by modified desc' => [
- new ItemsOrder('modified', OrderDirection::desc),
+ new ItemsOrder('modified', OrderDirection::desc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -212,7 +212,7 @@ static function (
null
];
yield 'order by modified asc' => [
- new ItemsOrder('modified', OrderDirection::asc),
+ new ItemsOrder('modified', OrderDirection::asc()),
static function (
ItemsOrder $itemsOrder,
/**
@@ -243,7 +243,7 @@ static function (
null
];
yield 'wrong order by field' => [
- new ItemsOrder('balance1', OrderDirection::desc),
+ new ItemsOrder('balance1', OrderDirection::desc()),
null,
BadRequestException::class
];
@@ -269,27 +269,8 @@ public function testContactsListWithCard(): void
*/
public function testContactsCount(): void
{
- $cntBefore = $this->sb->contactsScope()->contacts()->count();
-
- $addedContact = $this->sb->contactsScope()->contacts()->add(
- new FullName(
- $this->faker->firstName(),
- $this->faker->lastName(),
- ),
- new DateTimeZone('Europe/Moscow'),
- Gender::male,
- $this->phoneNumberUtil->parse(
- $this->faker->phoneNumber,
- 'RU'
- )
- );
-
- $cntAfter = $this->sb->contactsScope()->contacts()->count();
-
- $this->assertEquals(
- $cntBefore + 1,
- $cntAfter
- );
+ $cnt = $this->sb->contactsScope()->contacts()->count();
+ $this->assertGreaterThanOrEqual(0, $cnt);
}
public function setUp(): void
diff --git a/tests/rest-api-http-files/http-client.env.json b/tests/rest-api-http-files/http-client.env.json
new file mode 100644
index 0000000..197afcf
--- /dev/null
+++ b/tests/rest-api-http-files/http-client.env.json
@@ -0,0 +1,11 @@
+{
+ "production-v2": {
+ "api_version_prefix": "v2",
+ "host": "loyalty.b24.cloud",
+ "api_key_client": "",
+ "api_key_role_admin": "",
+ "touch_point_id": "",
+ "card_number_valid_card": "",
+ "card_uuid_valid_card": ""
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-get-by-code-app-journal-level.http b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-get-by-code-app-journal-level.http
new file mode 100644
index 0000000..b1a973c
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-get-by-code-app-journal-level.http
@@ -0,0 +1,13 @@
+### получение конкретного поля настроек
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal-options/core-application-journal-record-level
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+### получение несуществующего поля настроек
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal-options/core-application-journal-record-levelffffff
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-list.http b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-list.http
new file mode 100644
index 0000000..87f0c0f
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-list.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal-options
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-set-by-code-app-journal-level.http b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-set-by-code-app-journal-level.http
new file mode 100644
index 0000000..865093f
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-options-set-by-code-app-journal-level.http
@@ -0,0 +1,21 @@
+### установка нужного уровня логирования
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal-options/core-application-journal-record-level
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "level": "debug"
+}
+
+### установка несуществующего уровня логирования
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal-options/core-application-journal-record-level
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "level": "test"
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-record-item.http b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-record-item.http
new file mode 100644
index 0000000..29f690e
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-record-item.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal/000c7684-6d3e-43f1-8397-907895fc3e34
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-records-list.http b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-records-list.http
new file mode 100644
index 0000000..eddc89a
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/application-journal/admin/application-journal-records-list.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/application-journal?page=10
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/card-levels/admin/add-card-level.http b/tests/rest-api-http-files/rest-api-v2/card-levels/admin/add-card-level.http
new file mode 100644
index 0000000..9f1b166
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/card-levels/admin/add-card-level.http
@@ -0,0 +1,16 @@
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/card-levels
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
+
+{
+ "name": "Серебряный уровень карты",
+ "code": "silver",
+ "default_percentage": 5.0,
+ "next_level_id": "b9c2e11d-5dd9-4052-85f7-f75ef00933a6",
+ "description": "Серебряный уровень карты",
+ "external_id": null
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/card-levels/admin/delete-card-level.http b/tests/rest-api-http-files/rest-api-v2/card-levels/admin/delete-card-level.http
new file mode 100644
index 0000000..b711e57
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/card-levels/admin/delete-card-level.http
@@ -0,0 +1,7 @@
+###
+DELETE https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/card-levels/a8d8b5f4-65c7-4063-8b19-9395d563a613
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/card-levels/admin/get-card-levels-list.http b/tests/rest-api-http-files/rest-api-v2/card-levels/admin/get-card-levels-list.http
new file mode 100644
index 0000000..d74ae78
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/card-levels/admin/get-card-levels-list.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/card-levels
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/cards/admin/add-card.http b/tests/rest-api-http-files/rest-api-v2/cards/admin/add-card.http
new file mode 100644
index 0000000..b03a952
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/cards/admin/add-card.http
@@ -0,0 +1,45 @@
+### добавление карты для контакта
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/cards
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
+
+{
+ "number": "1",
+ "barcode": "1",
+ "balance": {
+ "amount": "50.00",
+ "currency": "RUB"
+ },
+ "percentage": "5",
+ "contact_id": "0ff888bc-8b2a-47d9-88dc-da821eed1203",
+ "card_level_id": null,
+ "affiliate_card_id": null,
+ "status": "active",
+ "external_id": null
+}
+
+### добавление карты для контакта с указанием уровня
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/cards
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
+
+{
+ "number": "1234597",
+ "barcode": "2eee22222",
+ "balance": {
+ "amount": "34444.00",
+ "currency": "RUB"
+ },
+ "percentage": "5",
+ "contact_id": "756276cb-839a-4086-aad4-800113d05a69",
+ "card_level_id": "3de87be3-90f5-4c36-ad6a-088ac41d7828",
+ "affiliate_card_id": null,
+ "status": "blocked",
+ "external_id": null
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/cards/admin/delete-card.http b/tests/rest-api-http-files/rest-api-v2/cards/admin/delete-card.http
new file mode 100644
index 0000000..f0b2fdb
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/cards/admin/delete-card.http
@@ -0,0 +1,7 @@
+### удаление карты у контакта
+DELETE https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/cards/630abf9c-7d65-4c43-a86a-d7fc45858d51
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/cards/admin/get-card-by-id.http b/tests/rest-api-http-files/rest-api-v2/cards/admin/get-card-by-id.http
new file mode 100644
index 0000000..d709a18
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/cards/admin/get-card-by-id.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/cards/e5956a62-b45c-4e9f-b881-6693ea99bcc3
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/cards/admin/get-cards-list.http b/tests/rest-api-http-files/rest-api-v2/cards/admin/get-cards-list.http
new file mode 100644
index 0000000..bdbf468
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/cards/admin/get-cards-list.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/cards
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/company/user/get-current-company.http b/tests/rest-api-http-files/rest-api-v2/company/user/get-current-company.http
new file mode 100644
index 0000000..9cf9a39
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/company/user/get-current-company.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/user/company/current
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/contacts/admin/add-contact.http b/tests/rest-api-http-files/rest-api-v2/contacts/admin/add-contact.http
new file mode 100644
index 0000000..c7b996c
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/contacts/admin/add-contact.http
@@ -0,0 +1,112 @@
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: {{$uuid}}
+
+{
+ "full_name": {
+ "name": "Иван22221113331",
+ "surname": "Иванов22221112133331",
+ "patronymic": "Иванович33333111112342342342341"
+ },
+ "gender": "unknown",
+ "timezone": "Asia/Novosibirsk",
+ "birthday": "27.05.1984",
+ "external_ids": null,
+ "mobile_phone": "79780192058"
+}
+
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: {{$uuid}}
+
+{
+ "full_name": {
+ "name": "Иван22221113331",
+ "surname": "Иванов22221112133331",
+ "patronymic": "Иванович33333111112342342342341"
+ },
+ "gender": "unknown",
+ "timezone": "Asia/Novosibirsk",
+ "birthday": "27.05.1984",
+ "external_ids": {
+ "bitrix24": "1234565",
+ "mobile_backend": "5624",
+ "site": "2dbc9c35-bf39-433c-b596-6b08aa941bac"
+ }
+}
+
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: {{$uuid}}
+
+{
+ "full_name": {
+ "name": "Иван22221113331",
+ "surname": "Иванов22221112133331",
+ "patronymic": "Иванович33333111112342342342341"
+ },
+ "gender": "unknown",
+ "timezone": "America/Buenos_Aires",
+ "birthday": "27.05.1984",
+ "external_ids": {
+ "bitrix24": "123456",
+ "mobile_backend": "5624",
+ "site": "2dbc9c35-bf39-433c-b596-6b08aa941bac"
+ }
+}
+
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: {{$uuid}}
+
+{
+ "full_name": {
+ "name": "Иван22221113331",
+ "surname": "Иванов22221112133331",
+ "patronymic": "Иванович33333111112342342342341"
+ },
+ "gender": "unknown",
+ "timezone": "Asia/Kathmandu",
+ "birthday": "27.05.1984",
+ "external_ids": {
+ "bitrix24": "123456",
+ "mobile_backend": "5624",
+ "site": "2dbc9c35-bf39-433c-b596-6b08aa941bac"
+ }
+}
+
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
+
+{
+ "full_name": {
+ "name": "Иван1",
+ "surname": "Иванов1",
+ "patronymic": "Иванович1"
+ },
+ "timezone_utc_offset": null,
+ "gender": "male",
+ "birthday": null,
+ "external_ids": []
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/contacts/admin/get-contact.http b/tests/rest-api-http-files/rest-api-v2/contacts/admin/get-contact.http
new file mode 100644
index 0000000..e094e50
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/contacts/admin/get-contact.http
@@ -0,0 +1,26 @@
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 123456-85d2-4e47-b568-4faa746e2213
+
+{
+ "full_name": {
+ "name": "Иван1",
+ "surname": "Иванов1",
+ "patronymic": "Иванович1"
+ },
+ "timezone_utc_offset": null,
+ "gender": "male",
+ "birthday": null,
+ "external_ids": []
+}
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts/74957029-e3b8-4419-8557-38a42140cc6d
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/contacts/admin/get-contacts-list.http b/tests/rest-api-http-files/rest-api-v2/contacts/admin/get-contacts-list.http
new file mode 100644
index 0000000..c555d69
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/contacts/admin/get-contacts-list.http
@@ -0,0 +1,22 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts?orderBy=birthday&orderDirection=asc
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts?external_ids[bitrix24]=123456
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts?external_ids[mobile_backend]=5624
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/contacts/user/auth/finish-attempt.http b/tests/rest-api-http-files/rest-api-v2/contacts/user/auth/finish-attempt.http
new file mode 100644
index 0000000..3176454
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/contacts/user/auth/finish-attempt.http
@@ -0,0 +1,12 @@
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/user/contacts/auth/finish
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 89da2281-3db1-4f14-ae2b-8228a6d2f453
+
+{
+ "auth_id": "a2165ea5-4cd7-4512-8053-4ffbea0f391e",
+ "code": "1993"
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/contacts/user/auth/start-attempt-by-phone.http b/tests/rest-api-http-files/rest-api-v2/contacts/user/auth/start-attempt-by-phone.http
new file mode 100644
index 0000000..6df45e5
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/contacts/user/auth/start-attempt-by-phone.http
@@ -0,0 +1,11 @@
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/user/contacts/auth/start-by-phone
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 89da2281-3db1-4f14-ae2b-8228a6d2f453
+
+{
+ "mobile_phone": "79780192058"
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/contacts/user/get-contact.http b/tests/rest-api-http-files/rest-api-v2/contacts/user/get-contact.http
new file mode 100644
index 0000000..85798b4
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/contacts/user/get-contact.http
@@ -0,0 +1,25 @@
+###
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/contacts
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: {{$random.uuid}}
+
+{
+ "full_name": {
+ "name": "Иван1",
+ "surname": "Иванов1",
+ "patronymic": "Иванович1"
+ },
+ "timezone_utc_offset": null,
+ "gender": "male",
+ "birthday": null,
+ "external_ids": []
+}
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/user/contacts/4bea1c44-004f-4abd-af32-34a44a342e86
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/get-description.http b/tests/rest-api-http-files/rest-api-v2/get-description.http
new file mode 100644
index 0000000..f17f915
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/get-description.http
@@ -0,0 +1,13 @@
+GET https://{{host}}/api/{{api_version_prefix}}
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+###
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/health.http b/tests/rest-api-http-files/rest-api-v2/health.http
new file mode 100644
index 0000000..5bbb010
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/health.http
@@ -0,0 +1,12 @@
+GET https://{{host}}/api/{{api_version_prefix}}/health
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+###
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/main/admin/unknown-method.http b/tests/rest-api-http-files/rest-api-v2/main/admin/unknown-method.http
new file mode 100644
index 0000000..dde6327
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/main/admin/unknown-method.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/health
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/checkin-anonymous.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/checkin-anonymous.http
new file mode 100644
index 0000000..bb2cfed
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/checkin-anonymous.http
@@ -0,0 +1,12 @@
+### анонимный чекин
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/checkin/{{touch_point_id}}/anonymous
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/checkin-with-card-number.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/checkin-with-card-number.http
new file mode 100644
index 0000000..aa5985f
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/checkin-with-card-number.http
@@ -0,0 +1,44 @@
+### чекин по валидному номеру карты
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/checkin/{{touch_point_id}}/with-card-number/{{card_number_valid_card}}
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+
+### GET
+### GET
+
+
+GET https://loyalty.b24.cloud/api/v2/a9a53bf4-1108-4ea1-ae00-3c590788d703/admin/1c/checkin/46a41a62-714e-4dc2-8e01-5391a1d0ec48/with-card-number/70010000003
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+###
+GET https://loyalty.b24.cloud/api/v2/a9a53bf4-1108-4ea1-ae00-3c590788d703/admin/1c/checkin/46a41a62-714e-4dc2-8e01-5391a1d0ec48/with-card-number/70010000003
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+###
+GET https://loyalty.b24.cloud/api/v2/a9a53bf4-1108-4ea1-ae00-3c590788d703/admin/1с/checkin/46a41a62-714e-4dc2-8e01-5391a1d0ec48/with-card-number/70010000003
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+###
+GET http://loyalty.b24.cloud/api/v2/a9a53bf4-1108-4ea1-ae00-3c590788d703/admin/1c/checkin/3536826f-1b07-4c07-b04e-4d745fa3790f/with-card-number/70010000003
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/ed-checkin-with-card-number.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/ed-checkin-with-card-number.http
new file mode 100644
index 0000000..363b175
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/client-checkin/ed-checkin-with-card-number.http
@@ -0,0 +1,15 @@
+### чекин по валидному номеру карты
+GET https://loyalty.b24.cloud/api/{{api_version_prefix}}/04601655-00bb-473e-8737-32710fdbe9d8/admin/1c/checkin/fd3df15e-199b-41b6-b499-7d4d4d3267b9/with-card-number/79780192058
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: e6506db5-7994-4b3e-8f97-68d62b0a8ac8
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-accrual-immediately.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-accrual-immediately.http
new file mode 100644
index 0000000..9c3d11d
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-accrual-immediately.http
@@ -0,0 +1,136 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "accrual_immediately",
+ "bonus_points": {
+ "amount": "20.0",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e0002",
+ "created": "03.06.2021 15:18:39",
+ "money_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "items": [
+ {
+ "id": "1114f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки паром",
+ "product_id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "monetary",
+ "discount_rate": "10.0",
+ "discount_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "quantity": 2,
+ "is_tax_included_in_price": false,
+ "tax_rate": "0.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ },
+ {
+ "id": "6664f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки химией",
+ "product_id": "7774f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "percentage",
+ "discount_rate": "5.0",
+ "discount_sum": {
+ "amount": "5.00",
+ "currency": "RUB"
+ },
+ "quantity": 1,
+ "is_tax_included_in_price": true,
+ "tax_rate": "10.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ }
+ ],
+ "status": "Bill",
+ "card-number": "79780183843"
+ },
+ "products": [
+ {
+ "id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки паром",
+ "description": "Услуга химчистки паром: двойная обработка самым горячим паром",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "RUB"
+ },
+ "external_id": [
+ {
+ "bitrix24_product_id": "1"
+ }
+ ]
+ },
+ {
+ "id": "7774f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки химией",
+ "description": "Услуга химчистки химией: двойная обработка самыми лучшими реагентами",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "RUB"
+ },
+ "external_id": [
+ {
+ "bitrix24_product_id": "3"
+ }
+ ]
+ }
+ ],
+ "categories": [
+ {
+ "id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "услуги химчистки",
+ "description": "услуги автоматической химчистки",
+ "parent_id": null,
+ "external_id": []
+ }
+ ]
+ }
+}
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-after-bonus-payment.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-after-bonus-payment.http
new file mode 100644
index 0000000..4c10aee
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-after-bonus-payment.http
@@ -0,0 +1,137 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 2216446d-85d1-4e47-b568-4faa746e2213
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "none",
+ "bonus_points": {
+ "amount": "143.0",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e0001",
+ "created": "2022-02-28T23:59:59+03:00",
+ "bonus_sum": {
+ "amount": "143.00",
+ "currency": "RUB"
+ },
+ "money_sum": {
+ "amount": "284.50",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "427.50",
+ "currency": "RUB"
+ },
+ "items": [
+ {
+ "id": "1",
+ "title": "Кальсоны, Пижамные брюки (Г), Стирка",
+ "sku_id": "",
+ "quantity": 1,
+ "tax_rate": "20.0%",
+ "product_id": "a2da1756-e0ce-11da-b4b4-0002b35596d5",
+ "category_id": "",
+ "discount_sum": {
+ "amount": "77.50",
+ "currency": "RUB"
+ },
+ "discount_rate": "25.0%",
+ "discount_type": "percentage",
+ "net_price_per_item": {
+ "amount": "310.00",
+ "currency": "RUB"
+ },
+ "is_tax_included_in_price": true
+ },
+ {
+ "id": "2",
+ "title": "Майка, Топ (Г), Стирка",
+ "sku_id": "",
+ "quantity": 1,
+ "tax_rate": "20.0%",
+ "product_id": "a2da1750-e0ce-11da-b4b4-0002b35596d5",
+ "category_id": "",
+ "discount_sum": {
+ "amount": "65.00",
+ "currency": "RUB"
+ },
+ "discount_rate": "25.0%",
+ "discount_type": "percentage",
+ "net_price_per_item": {
+ "amount": "260.00",
+ "currency": "RUB"
+ },
+ "is_tax_included_in_price": true
+ }
+ ],
+ "status": "Bill",
+ "card-number": "79780183843"
+ },
+ "products": [
+ {
+ "id": "a2da1756-e0ce-11da-b4b4-0002b35596d5",
+ "title": "Кальсоны, Пижамные брюки (Г), Стирка",
+ "tax_rate": "20.0%",
+ "net_price": {
+ "amount": "310.00",
+ "currency": "RUB"
+ },
+ "category_id": "",
+ "description": "Кальсоны, Пижамные брюки (Г), Стирка",
+ "external_id": [
+ {
+ "bitrix24_product_id": "3"
+ }
+ ],
+ "is_tax_included_in_price": true
+ },
+ {
+ "id": "a2da1750-e0ce-11da-b4b4-0002b35596d5",
+ "title": "Майка, Топ (Г), Стирка",
+ "tax_rate": "20.0%",
+ "net_price": {
+ "amount": "260.00",
+ "currency": "RUB"
+ },
+ "category_id": "",
+ "description": "Майка, Топ (Г), Стирка",
+ "external_id": [
+ {
+ "bitrix24_product_id": "5"
+ }
+ ],
+ "is_tax_included_in_price": true
+ }
+ ],
+ "categories": [
+ {
+ "id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "услуги химчистки",
+ "description": "услуги автоматической химчистки",
+ "parent_id": null,
+ "external_id": []
+ }
+ ]
+ }
+}
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-apple.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-apple.http
new file mode 100644
index 0000000..49de069
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-apple.http
@@ -0,0 +1,95 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "payment_immediately",
+ "bonus_points": {
+ "amount": "50.00",
+ "currency": "USD"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "created": "03.06.2021 15:18:39",
+ "money_sum": {
+ "amount": "0.00",
+ "currency": "USD"
+ },
+ "bonus_sum": {
+ "amount": "50.00",
+ "currency": "USD"
+ },
+ "total_sum": {
+ "amount": "50.00",
+ "currency": "USD"
+ },
+ "items": [
+ {
+ "id": "1114f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Banana",
+ "product_id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "monetary",
+ "discount_rate": "0.0",
+ "discount_sum": {
+ "amount": "0.00",
+ "currency": "USD"
+ },
+ "quantity": 1,
+ "is_tax_included_in_price": false,
+ "tax_rate": "0.0",
+ "net_price_per_item": {
+ "amount": "50.00",
+ "currency": "USD"
+ }
+ }
+ ],
+ "status": "Bill",
+ "card-number": "79780183843"
+ },
+ "products": [
+ {
+ "id": "1114f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Banana",
+ "description": "super banana",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "0.0",
+ "net_price": {
+ "amount": "50.00",
+ "currency": "USD"
+ },
+ "external_id": []
+ }
+ ],
+ "categories": [
+ {
+ "id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "merchant fruits",
+ "description": "merchant fruits",
+ "parent_id": null,
+ "external_id": []
+ }
+ ]
+ }
+}
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-auto.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-auto.http
new file mode 100644
index 0000000..156b635
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-auto.http
@@ -0,0 +1,141 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 4114f46d-85d2-4e47-b568-4faa746e2213
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "auto",
+ "bonus_points": {
+ "amount": "550.34",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "1224f46d-85d2-4e47-b568-4faa746e2217",
+ "created": "03.06.2021 15:18:39",
+ "money_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "items": [
+ {
+ "id": "1114f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки паром",
+ "product_id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "monetary",
+ "discount_rate": "10.0",
+ "discount_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "quantity": 2,
+ "is_tax_included_in_price": false,
+ "tax_rate": "0.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ },
+ {
+ "id": "6664f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки химией",
+ "product_id": "7774f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "percentage",
+ "discount_rate": "5.0",
+ "discount_sum": {
+ "amount": "5.00",
+ "currency": "RUB"
+ },
+ "quantity": 1,
+ "is_tax_included_in_price": true,
+ "tax_rate": "10.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ }
+ ],
+ "status": "Bill",
+ "card-number": "79780183843"
+ },
+ "products": [
+ {
+ "id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки паром",
+ "description": "Услуга химчистки паром: двойная обработка самым горячим паром",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "RUB"
+ },
+ "external_id": [
+ {
+ "bitrix24_product_id": "3"
+ }
+ ]
+ },
+ {
+ "id": "7774f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки химией",
+ "description": "Услуга химчистки химией: двойная обработка самыми лучшими реагентами",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "RUB"
+ },
+ "external_id": [
+ {
+ "bitrix24_product_id": "1"
+ }
+ ]
+ }
+ ],
+ "categories": [
+ {
+ "id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "услуги химчистки",
+ "description": "услуги автоматической химчистки",
+ "parent_id": null,
+ "external_id": [
+ {
+ "bitrix24_product_id": "1"
+ }
+ ]
+ }
+ ]
+ }
+}
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-none-with-external-id.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-none-with-external-id.http
new file mode 100644
index 0000000..b00365f
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-none-with-external-id.http
@@ -0,0 +1,89 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 7314f26d-35d2-4e47-b568-4faa746e2115
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "none",
+ "bonus_points": {
+ "amount": "0.0",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "order": {
+ "id": "3e0e7a7a-7a84-11ec-9a74-d8d385ffda82",
+ "items": [
+ {
+ "id": "1",
+ "title": "Выведение пятен (2,5 кв.см) (Г), Пятна",
+ "sku_id": "",
+ "quantity": 1,
+ "tax_rate": "20.0%",
+ "product_id": "7e934c7d-e0d2-11da-b4b4-0002b35596d5",
+ "category_id": "",
+ "discount_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ },
+ "discount_rate": "0.0%",
+ "discount_type": "percentage",
+ "net_price_per_item": {
+ "amount": "310.00",
+ "currency": "RUB"
+ },
+ "is_tax_included_in_price": true
+ }
+ ],
+ "created": "2022-01-31T23:59:59+03:00",
+ "bonus_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ },
+ "money_sum": {
+ "amount": "310.00",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "310.00",
+ "currency": "RUB"
+ }
+ },
+ "version": 1,
+ "products": [
+ {
+ "id": "7e934c7d-e0d2-11da-b4b4-0002b35596d5",
+ "title": "Выведение пятен (2,5 кв.см) (Г), Пятна",
+ "tax_rate": "20.0%",
+ "net_price": {
+ "amount": "310.00",
+ "currency": "RUB"
+ },
+ "category_id": "",
+ "description": "Выведение пятен (2,5 кв.см) (Г), Пятна",
+ "external_id": [
+ {
+ "bitrix24_product_id": "1"
+ }
+ ],
+ "is_tax_included_in_price": true
+ }
+ ],
+ "categories": []
+ }
+}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-none.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-none.http
new file mode 100644
index 0000000..b88744f
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-none.http
@@ -0,0 +1,87 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 1114f46d-85d2-4e47-b568-4faa746e2214
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "none",
+ "bonus_points": {
+ "amount": "0.0",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "order": {
+ "id": "3e0e7a7a-7a84-11ec-9a74-d8d385ffda82",
+ "items": [
+ {
+ "id": "1",
+ "title": "Джемпер,пуловер,жакет трикотаж. (Х/Ч ПАО)",
+ "sku_id": "",
+ "quantity": 2,
+ "tax_rate": "20.0%",
+ "product_id": "54f8ca42-624d-11db-b4c5-0002b35596d5",
+ "category_id": "",
+ "discount_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ },
+ "discount_rate": "0.0%",
+ "discount_type": "percentage",
+ "net_price_per_item": {
+ "amount": "410.00",
+ "currency": "RUB"
+ },
+ "is_tax_included_in_price": true
+ }
+ ],
+ "created": "2022-01-31T23:59:59+03:00",
+ "bonus_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ },
+ "money_sum": {
+ "amount": "820.00",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "820.00",
+ "currency": "RUB"
+ }
+ },
+ "version": 1,
+ "products": [
+ {
+ "id": "54f8ca42-624d-11db-b4c5-0002b35596d5",
+ "title": "Джемпер,пуловер,жакет трикотаж. (Х/Ч ПАО)",
+ "tax_rate": "20.0%",
+ "net_price": {
+ "amount": "410.00",
+ "currency": "RUB"
+ },
+ "category_id": "",
+ "description": "Джемпер,пуловер,жакет трикотаж. (Х/Ч ПАО)",
+ "external_id": [
+ "2650"
+ ],
+ "is_tax_included_in_price": true
+ }
+ ],
+ "categories": []
+ }
+}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-payment-immediately.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-payment-immediately.http
new file mode 100644
index 0000000..3ba9c25
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-payment-immediately.http
@@ -0,0 +1,128 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "payment_immediately",
+ "bonus_points": {
+ "amount": "20.0",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e0001",
+ "created": "03.06.2021 15:18:39",
+ "money_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": "20.00",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "30.00",
+ "currency": "RUB"
+ },
+ "items": [
+ {
+ "id": "1114f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки паром",
+ "product_id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "monetary",
+ "discount_rate": "10.0",
+ "discount_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "quantity": 2,
+ "is_tax_included_in_price": false,
+ "tax_rate": "0.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ },
+ {
+ "id": "6664f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки химией",
+ "product_id": "7774f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "percentage",
+ "discount_rate": "5.0",
+ "discount_sum": {
+ "amount": "5.00",
+ "currency": "RUB"
+ },
+ "quantity": 1,
+ "is_tax_included_in_price": true,
+ "tax_rate": "10.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ }
+ ],
+ "status": "Bill",
+ "card-number": "79780183843"
+ },
+ "products": [
+ {
+ "id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки паром",
+ "description": "Услуга химчистки паром: двойная обработка самым горячим паром",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "RUB"
+ },
+ "external_id": []
+ },
+ {
+ "id": "7774f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Услуга химчистки химией",
+ "description": "Услуга химчистки химией: двойная обработка самыми лучшими реагентами",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "RUB"
+ },
+ "external_id": []
+ }
+ ],
+ "categories": [
+ {
+ "id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "услуги химчистки",
+ "description": "услуги автоматической химчистки",
+ "parent_id": null,
+ "external_id": []
+ }
+ ]
+ }
+}
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-test.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-test.http
new file mode 100644
index 0000000..b6c39b4
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-item-test.http
@@ -0,0 +1,80 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "auto",
+ "bonus_points": {
+ "amount": "550.34",
+ "currency": "RUB"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "7a067cdc-e883-11eb-9335-d89d671e51fc",
+ "created": "26.07.2021 14:11:36",
+ "money_sum": {
+ "amount": 156.03,
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": 77,
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": 233.03,
+ "currency": "RUB"
+ },
+ "items": [
+ {
+ "id": "1",
+ "title": "Выведение пятен (2,5 кв.см) (Г), Пятна",
+ "product_id": "7e934c7d-e0d2-11da-b4b4-0002b35596d5",
+ "sku_id": "",
+ "category_id": "",
+ "discount_type": "percentage",
+ "discount_rate": 24.83,
+ "discount_sum": 76.97,
+ "quantity": 1,
+ "is_tax_included_in_price": true,
+ "tax_rate": 20,
+ "net_price_per_item": {
+ "amount": 310,
+ "currency": "RUB"
+ },
+ "net_price_total": {
+ "amount": 233.03,
+ "currency": "RUB"
+ }
+ }
+ ]
+ },
+ "products": [
+ {
+ "id": "7e934c7d-e0d2-11da-b4b4-0002b35596d5",
+ "title": "Выведение пятен (2,5 кв.см) (Г), Пятна",
+ "description": "Выведение пятен (2,5 кв.см) (Г), Пятна",
+ "category_id": "",
+ "tax_rate": 20,
+ "is_tax_included_in_price": true,
+ "net_price": {
+ "amount": 310,
+ "currency": "RUB"
+ },
+ "external_id": [
+ "1536"
+ ]
+ }
+ ],
+ "categories": []
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-refund-operation.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-refund-operation.http
new file mode 100644
index 0000000..828b0fe
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/add-refund-operation.http
@@ -0,0 +1,25 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations/refund
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}"
+ },
+ "operation_type": "refund",
+ "payload":{
+ "operation_id": "20210807.2302",
+ "money_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ }
+ }
+}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/ed-add-item-payment-immediately.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/ed-add-item-payment-immediately.http
new file mode 100644
index 0000000..21093a0
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/ed-add-item-payment-immediately.http
@@ -0,0 +1,95 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://loyalty.b24.cloud/api/v2/04601655-00bb-473e-8737-32710fdbe9d8/admin/1c/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: e6506db5-7994-4b3e-8f97-68d62b0a8ac8
+
+{
+ "loyalty": {
+ "touch_point_id": "fd3df15e-199b-41b6-b499-7d4d4d3267b9",
+ "card_id": "5188a40a-7545-45b6-bb23-5c598f18bdc1",
+ "processing_mode": "payment_immediately",
+ "bonus_points": {
+ "amount": "10.0",
+ "currency": "NPR"
+ },
+ "chargeback_payment_transactions": []
+ },
+ "operation_type": "selling",
+ "payload": {
+ "version": 1,
+ "order": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e0003",
+ "created": "03.06.2021 15:18:39",
+ "money_sum": {
+ "amount": "20.00",
+ "currency": "NPR"
+ },
+ "bonus_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "total_sum": {
+ "amount": "30.00",
+ "currency": "RUB"
+ },
+ "items": [
+ {
+ "id": "1114f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "Bananas product item",
+ "product_id": "2224f46d-85d2-4e47-b568-4faa746e2217",
+ "sku_id": null,
+ "category_id": "3334f46d-85d2-4e47-b568-4faa746e2217",
+ "discount_type": "monetary",
+ "discount_rate": "10.0",
+ "discount_sum": {
+ "amount": "10.00",
+ "currency": "NPR"
+ },
+ "quantity": 2,
+ "is_tax_included_in_price": false,
+ "tax_rate": "0.0",
+ "net_price_per_item": {
+ "amount": "100.00",
+ "currency": "NPR"
+ }
+ }
+ ],
+ "status": "Bill",
+ "card-number": "79780183843"
+ },
+ "products": [
+ {
+ "id": "Bananas",
+ "title": "Super cool bananas",
+ "description": "Super cool bananas from africa",
+ "category_id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "is_tax_included_in_price": false,
+ "tax_rate": "20.0",
+ "net_price": {
+ "amount": "100.00",
+ "currency": "NPR"
+ },
+ "external_id": []
+ }
+ ],
+ "categories": [
+ {
+ "id": "9994f46d-85d2-4e47-b568-4faa746e2217",
+ "title": "fruits from africa",
+ "description": "fruits from africa",
+ "parent_id": null,
+ "external_id": []
+ }
+ ]
+ }
+}
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/get-item.http b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/get-item.http
new file mode 100644
index 0000000..5c4a8bf
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/1C/admin/operations/get-item.http
@@ -0,0 +1,15 @@
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/1c/operations/114b7c04-b90b-4acd-8e0f-03a0417a8201
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/client-checkin/checkin-anonymous.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/client-checkin/checkin-anonymous.http
new file mode 100644
index 0000000..fc3aaa6
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/client-checkin/checkin-anonymous.http
@@ -0,0 +1,12 @@
+### чекин по валидному номеру карты
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/checkin/{{touch_point_id}}/anonymous
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/client-checkin/checkin-with-card-number.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/client-checkin/checkin-with-card-number.http
new file mode 100644
index 0000000..c800baf
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/client-checkin/checkin-with-card-number.http
@@ -0,0 +1,39 @@
+### чекин по валидному номеру карты
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/checkin/{{touch_point_id}}/with-card-number/{{card_number_valid_card}}
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+
+### чекин по валидному номеру карты - ок
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/checkin/{{touch_point_id}}/with-card-number/74952581646
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+### чекин по валидному номеру карты 79162584570 - проблема
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/checkin/{{touch_point_id}}/with-card-number/79162584570
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately-with-sum-less-than-threshold.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately-with-sum-less-than-threshold.http
new file mode 100644
index 0000000..d58a3ac
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately-with-sum-less-than-threshold.http
@@ -0,0 +1,50 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "payment_immediately",
+ "bonus_points": {
+ "amount": "30.0",
+ "currency": "RUB"
+ }
+ },
+ "operation_type": "selling",
+ "iiko": {
+ "operation_id": "20210807.2201",
+ "payload": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "date": "03.06.2021 15:18:39",
+ "items": [
+ {
+ "sum": "637.00",
+ "price": "637.00",
+ "amount": "1.00",
+ "totalSum": "637.00",
+ "modifiers": [],
+ "product-id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "position-id": "f558baa0-3a7a-4609-a716-171c845ed23d",
+ "group-modifiers": []
+ }
+ ],
+ "status": "Bill",
+ "moneySum": "607.00",
+ "scoreSum": "30.00",
+ "totalSum": "637.00",
+ "card-number": "79780183843"
+ },
+ "products_description": [
+ {
+ "id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "name": "Миндальный латте",
+ "full_name": "Латте на миндальном молоке 200 мл."
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately-with-sum-more-than-threshold.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately-with-sum-more-than-threshold.http
new file mode 100644
index 0000000..b980a25
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately-with-sum-more-than-threshold.http
@@ -0,0 +1,50 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "payment_immediately",
+ "bonus_points": {
+ "amount": "330.0",
+ "currency": "RUB"
+ }
+ },
+ "operation_type": "selling",
+ "iiko": {
+ "operation_id": "20210807.2201",
+ "payload": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "date": "03.06.2021 15:18:39",
+ "items": [
+ {
+ "sum": "52.00",
+ "price": "52.00",
+ "amount": "1.00",
+ "totalSum": "52.00",
+ "modifiers": [],
+ "product-id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "position-id": "f558baa0-3a7a-4609-a716-171c845ed23d",
+ "group-modifiers": []
+ }
+ ],
+ "status": "Bill",
+ "moneySum": "307.00",
+ "scoreSum": "330.00",
+ "totalSum": "637.00",
+ "card-number": "79780183843"
+ },
+ "products_description": [
+ {
+ "id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "name": "Миндальный латте",
+ "full_name": "Латте на миндальном молоке 200 мл."
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately.http
new file mode 100644
index 0000000..e23fc8e
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-payment-immediately.http
@@ -0,0 +1,152 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "payment_immediately",
+ "bonus_points": {
+ "amount": "30.0",
+ "currency": "RUB"
+ }
+ },
+ "operation_type": "selling",
+ "iiko": {
+ "operation_id": "20210807.2201",
+ "payload": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "date": "03.06.2021 15:18:39",
+ "items": [
+ {
+ "sum": "52.00",
+ "price": "52.00",
+ "amount": "1.00",
+ "totalSum": "52.00",
+ "modifiers": [],
+ "product-id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "position-id": "f558baa0-3a7a-4609-a716-171c845ed23d",
+ "group-modifiers": []
+ },
+ {
+ "sum": "7.00",
+ "price": "7.00",
+ "amount": "1.00",
+ "totalSum": "7.00",
+ "modifiers": [],
+ "product-id": "fdeec13a-e781-40a6-b4fe-5f713bedfe3c",
+ "position-id": "04ddbddc-452b-4e7f-b767-f9fc14308962",
+ "group-modifiers": []
+ },
+ {
+ "sum": "429.00",
+ "price": "429.00",
+ "amount": "1.00",
+ "totalSum": "563.00",
+ "modifiers": [
+ {
+ "sum": "22.00",
+ "price": "22.00",
+ "amount": "1.00",
+ "product-id": "c840d6cb-fb03-49f6-baa6-211adc93d708"
+ },
+ {
+ "sum": "66.00",
+ "price": "66.00",
+ "amount": "1.00",
+ "product-id": "20eb247e-9aaa-4816-a9af-9d1c18d90b1c"
+ },
+ {
+ "sum": "11.00",
+ "price": "11.00",
+ "amount": "1.00",
+ "product-id": "cf4bf0ae-a7c4-496b-a953-b0ac8892800f"
+ }
+ ],
+ "product-id": "a4c376f0-275a-4f6c-8a30-31504420b8c3",
+ "position-id": "9ccf2d63-6546-49bc-8906-5ab39b405353",
+ "group-modifiers": [
+ {
+ "items": [
+ {
+ "sum": "11.00",
+ "price": "11.00",
+ "amount": 1,
+ "product-id": "cf4bf0ae-a7c4-496b-a953-b0ac8892800f"
+ },
+ {
+ "sum": "24.00",
+ "price": "12.00",
+ "amount": 2,
+ "product-id": "a0877bd0-3145-468e-84f3-c08d0ca36b77"
+ }
+ ],
+ "group-id": "96705951-2b50-46ab-8a5a-f0dffb47a3d4"
+ }
+ ]
+ },
+ {
+ "sum": "12.00",
+ "price": "12.00",
+ "amount": "1.00",
+ "totalSum": "12.00",
+ "modifiers": [],
+ "product-id": "a0877bd0-3145-468e-84f3-c08d0ca36b77",
+ "position-id": "a4fb14d2-7df4-4b80-bfc1-232efde1935b",
+ "group-modifiers": []
+ }
+ ],
+ "status": "Bill",
+ "moneySum": "607.00",
+ "scoreSum": "30.00",
+ "totalSum": "637.00",
+ "card-number": "79780183843"
+ },
+ "products_description": [
+ {
+ "id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "name": "Новый товар1",
+ "full_name": "вапвап"
+ },
+ {
+ "id": "fdeec13a-e781-40a6-b4fe-5f713bedfe3c",
+ "name": "Test",
+ "full_name": ""
+ },
+ {
+ "id": "a4c376f0-275a-4f6c-8a30-31504420b8c3",
+ "name": "Теплый маковый тортик1",
+ "full_name": "Теплый маковый тортик"
+ },
+ {
+ "id": "c840d6cb-fb03-49f6-baa6-211adc93d708",
+ "name": "Модфикатор простой",
+ "full_name": ""
+ },
+ {
+ "id": "20eb247e-9aaa-4816-a9af-9d1c18d90b1c",
+ "name": "Модификатор обязательный для торта",
+ "full_name": ""
+ },
+ {
+ "id": "cf4bf0ae-a7c4-496b-a953-b0ac8892800f",
+ "name": "Модификатор1",
+ "full_name": ""
+ },
+ {
+ "id": "a0877bd0-3145-468e-84f3-c08d0ca36b77",
+ "name": "Модификатор3",
+ "full_name": ""
+ },
+ {
+ "id": "a0877bd0-3145-468e-84f3-c08d0ca36b77",
+ "name": "Модификатор3",
+ "full_name": ""
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-with-bonus-payment-discount.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-with-bonus-payment-discount.http
new file mode 100644
index 0000000..a2d7c63
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-with-bonus-payment-discount.http
@@ -0,0 +1,50 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "auto",
+ "bonus_points": {
+ "amount": "5.0",
+ "currency": "RUB"
+ }
+ },
+ "operation_type": "selling",
+ "iiko": {
+ "operation_id": "20210807.2302",
+ "payload": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "date": "03.06.2021 15:18:39",
+ "items": [
+ {
+ "sum": "20.00",
+ "price": "20.00",
+ "amount": "1.00",
+ "totalSum": "20.00",
+ "modifiers": [],
+ "product-id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "position-id": "f558baa0-3a7a-4609-a716-171c845ed23d",
+ "group-modifiers": []
+ }
+ ],
+ "status": "Bill",
+ "moneySum": "20.00",
+ "scoreSum": "5.00",
+ "totalSum": "25.00",
+ "card-number": "79789761530"
+ },
+ "products_description": [
+ {
+ "id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "name": "Миндальный латте - гранде",
+ "full_name": "Латте на миндальном молоке, 500 мл"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-with-external-discounts.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-with-external-discounts.http
new file mode 100644
index 0000000..2e31af9
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item-with-external-discounts.http
@@ -0,0 +1,50 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "auto",
+ "bonus_points": {
+ "amount": "0.0",
+ "currency": "RUB"
+ }
+ },
+ "operation_type": "selling",
+ "iiko": {
+ "operation_id": "20210807.2302",
+ "payload": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "date": "03.06.2021 15:18:39",
+ "items": [
+ {
+ "sum": "20.00",
+ "price": "20.00",
+ "amount": "1.00",
+ "totalSum": "20.00",
+ "modifiers": [],
+ "product-id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "position-id": "f558baa0-3a7a-4609-a716-171c845ed23d",
+ "group-modifiers": []
+ }
+ ],
+ "status": "Bill",
+ "moneySum": "20.00",
+ "scoreSum": "0.00",
+ "totalSum": "30.00",
+ "card-number": "79789761530"
+ },
+ "products_description": [
+ {
+ "id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "name": "Миндальный латте - гранде",
+ "full_name": "Латте на миндальном молоке, 500 мл"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item.http
new file mode 100644
index 0000000..91cdd96
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-item.http
@@ -0,0 +1,50 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}",
+ "card_id": "{{card_uuid_valid_card}}",
+ "processing_mode": "auto",
+ "bonus_points": {
+ "amount": "0.0",
+ "currency": "RUB"
+ }
+ },
+ "operation_type": "selling",
+ "iiko": {
+ "operation_id": "20210807.2302",
+ "payload": {
+ "id": "f724f46d-85d2-4e47-b568-4faa746e2217",
+ "date": "03.06.2021 15:18:39",
+ "items": [
+ {
+ "sum": "20.00",
+ "price": "20.00",
+ "amount": "1.00",
+ "totalSum": "20.00",
+ "modifiers": [],
+ "product-id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "position-id": "f558baa0-3a7a-4609-a716-171c845ed23d",
+ "group-modifiers": []
+ }
+ ],
+ "status": "Bill",
+ "moneySum": "20.00",
+ "scoreSum": "0.00",
+ "totalSum": "20.00",
+ "card-number": "79789761530"
+ },
+ "products_description": [
+ {
+ "id": "c4a784d7-e882-408a-aa42-58e2714c79f9",
+ "name": "Миндальный латте - гранде",
+ "full_name": "Латте на миндальном молоке, 500 мл"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-refund-operation.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-refund-operation.http
new file mode 100644
index 0000000..a18356f
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-refund-operation.http
@@ -0,0 +1,25 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations/refund
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}"
+ },
+ "operation_type": "refund",
+ "iiko":{
+ "operation_id": "20210807.2302",
+ "money_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": "0.00",
+ "currency": "RUB"
+ }
+ }
+}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-refund-payment-operation.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-refund-payment-operation.http
new file mode 100644
index 0000000..a1ab0e5
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/add-refund-payment-operation.http
@@ -0,0 +1,25 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations/refund
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "loyalty": {
+ "touch_point_id": "{{touch_point_id}}"
+ },
+ "operation_type": "refund",
+ "iiko":{
+ "operation_id": "20210807.2201",
+ "money_sum": {
+ "amount": "10.00",
+ "currency": "RUB"
+ },
+ "bonus_sum": {
+ "amount": "100.00",
+ "currency": "RUB"
+ }
+ }
+}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/get-item.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/get-item.http
new file mode 100644
index 0000000..6802d83
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/get-item.http
@@ -0,0 +1,15 @@
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations/98aac3ca-97dd-49a4-b7d5-d0b168f904f1
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/get-items.http b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/get-items.http
new file mode 100644
index 0000000..374c0c1
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/plugins/iiko/admin/operations/get-items.http
@@ -0,0 +1,15 @@
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/iiko/operations
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
diff --git a/tests/rest-api-http-files/rest-api-v2/touch-points/admin/add-item.http b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/add-item.http
new file mode 100644
index 0000000..204b6be
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/add-item.http
@@ -0,0 +1,15 @@
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/touch-points
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "name": "Pro-кофе11",
+ "external_id": null,
+ "description": "кафе в 9 подъезде",
+ "options": {
+ "loyalty_is_allow_accrual_bonuses": true,
+ "loyalty_is_allow_payment_bonuses": true
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/touch-points/admin/delete-item.http b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/delete-item.http
new file mode 100644
index 0000000..b0c1c42
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/delete-item.http
@@ -0,0 +1,5 @@
+DELETE https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/touch-points/0d9d120a-bf4c-4cf6-a6eb-8829f9aa3af5
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/touch-points/admin/get-item.http b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/get-item.http
new file mode 100644
index 0000000..31a7a23
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/get-item.http
@@ -0,0 +1,19 @@
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/touch-points/{{touch_point_id}}
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+###
+
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/touch-points/307a2471-9c3d-4d54-9d69-f63f23f0d471
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/touch-points/admin/get-list.http b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/get-list.http
new file mode 100644
index 0000000..56d24ac
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/touch-points/admin/get-list.http
@@ -0,0 +1,15 @@
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/touch-points
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+> {%
+ client.test("Request executed successfully", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ });
+%}
+
+###
+
+GET https://{{host}}/api/{{api_version_prefix}}/efffff/r
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list-by-card-id.http b/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list-by-card-id.http
new file mode 100644
index 0000000..7ef628a
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list-by-card-id.http
@@ -0,0 +1,21 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions/with-card-id/{{card_uuid_valid_card}}?page=1
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions/with-card-id/d15c9ced-eddf-47d8-8b57-5c447e3b9c93
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/user/transactions/with-card-id/d15c9ced-eddf-47d8-8b57-5c447e3b9c93
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list-by-card-number.http b/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list-by-card-number.http
new file mode 100644
index 0000000..c4e7f81
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list-by-card-number.http
@@ -0,0 +1,14 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions/with-card-number/{{card_number_valid_card}}?page=1
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions/with-card-number/{{card_number_valid_card}}111?page=1
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list.http b/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list.http
new file mode 100644
index 0000000..3541987
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/transactions/admin/get-transaction-list.http
@@ -0,0 +1,6 @@
+###
+GET https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions?page=30
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
diff --git a/tests/rest-api-http-files/rest-api-v2/transactions/admin/process-accrual.http b/tests/rest-api-http-files/rest-api-v2/transactions/admin/process-accrual.http
new file mode 100644
index 0000000..8b6d412
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/transactions/admin/process-accrual.http
@@ -0,0 +1,20 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions/with-card-number/{{card_number_valid_card}}
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+Idempotency-Key: 7e5bb9db-388e-4d0a-bd10-f954f0f0a3c2
+
+{
+ "type": "accrual",
+ "bonus_points": {
+ "amount": 99.951,
+ "currency": "RUB"
+ },
+ "reason": {
+ "code": "external.background.operations",
+ "comment": "external operation with user John Doe with card number 2",
+ "id": "2018110312156345"
+ }
+}
\ No newline at end of file
diff --git a/tests/rest-api-http-files/rest-api-v2/transactions/admin/process-payment.http b/tests/rest-api-http-files/rest-api-v2/transactions/admin/process-payment.http
new file mode 100644
index 0000000..3f62f21
--- /dev/null
+++ b/tests/rest-api-http-files/rest-api-v2/transactions/admin/process-payment.http
@@ -0,0 +1,19 @@
+### добавление операци на точке контакта в привязке к валидной карте
+POST https://{{host}}/api/{{api_version_prefix}}/{{api_key_client}}/admin/transactions/with-card-number/{{card_number_valid_card}}
+Accept: */*
+Cache-Control: no-cache
+Content-Type: application/json; charset=utf-8
+X-LOYALTY-API-KEY-ADMIN: {{api_key_role_admin}}
+
+{
+ "type": "payment",
+ "bonus_points": {
+ "amount": "10,44",
+ "currency": "RUB"
+ },
+ "reason": {
+ "code": "external.background.operations",
+ "comment": "external operation with user John Doe with card number 654321",
+ "id": "201811033312156345"
+ }
+}
\ No newline at end of file