- PVSM.RU - https://www.pvsm.ru -
Пару недель назад в одном из проектов возник вопрос об интеграции CRM с API Банка Тинькофф. В частности, речь шла о получении выписки по банковскому счету.
В активе имелось:
В ходе гуглежа были также найдены отзывы о том, что настройка API банка Тинькофф дело весьма занимательное и нетривиальное (см. статью на banki.ru «API Тинькофф — мы слишком глупы для этого» [3]).
Да, пришлось малость повозиться, поэтому, дабы сэкономить время другим товарищам по цеху, была написана данная статья.
Отмечу, что API банка Тинькофф использует Oauth 2.0 для авторизации.
Зачем же нужен openapi.tinkoff.ru?
Приступим. В разделе «SSO Авторизация», кликнем на «how/Hide», и затем /secure/token#refresh-token («Выдача токена по рефреш токену»), в качестве параметра выбираем grant_type, далее в поле refresh_token (его можно получить в Личном кабинете пользователя). Жмем кнопку «Try it out!» Результатом этих действий является получение такой важной вещи как access_token (т.е. openapi.tinkoff.ru демонстрирует возможность ее получения).
Далее смотрим раздел «Счета и платежи», кликаем /partner/company/{INN}/excerpt («Получение выписки»). Изучаем, какие параметры необходимы для того чтобы ее заполучить: Authorization, INN, accountNumber, from, till.
Authorization — догадываемся, что Authorization это не что иное как access_token, который был получен нами в разделе «SSO Авторизация»;
INN — ИНН организации для которой настраиваем API;
from — с какого дня (период выписки);
till — по какой день (период выписки).
Таким образом (смотрим матчасть Oauth 2.0), получение данных выписки происходит в два этапа — сначала получаем access_token, затем имея на руках access_token, получаем данные этой самой выписки. Отлично. Алгоритм ясен, пишем код (параметры доступа в коде значения для $user, $pass, $refresh_token, $inn, $accountNumber — в приведенном ниже коде изменены, по понятным причинам).
Создадим следующие файлы:
Итак, смотрим код и комментарии к нему!
Файл настроек — StartSettings.php:
$host = '127.0.0.1';
$db = 'bank';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
$user="IKu0jn98kllkI90kklii"; //20 символов
$pass="ds4234SDFsdfsdijoijslkkdjfoIOi"; //30 символов
$refresh_token='dsfh345kljlkjsdf098sdfkljklj098sdfkklKKLjhjihiKL90909llkrre5345dfFDDFretertERTERETfdgd==';// 88 символов
$inn = '750151513135';
$accountNumber = '40802810300000121212';//20 символов
$from_year = '1980';
$from_month = '01';
$from_day = '01';
$till_year = date('Y');
$till_month = date('m');
$till_day = date('d');
Файл стартовый — Start.php:
session_start();
error_reporting(E_ALL);
include 'StartSettings.php';
include 'TinkoffInsertData.php';
TinkoffInsertData($user,$pass,$refresh_token, $inn, $accountNumber, $from_year, $from_month, $from_day, $till_year, $till_month, $till_day, $pdo);
$stmt = $pdo->prepare("INSERT INTO `bank`.`dateofwork` (dateofwork) VALUES (NOW())");
$stmt->execute();
Файл постинга/парсинга данных в/из API — TinkoffInsertData.php:
function TinkoffInsertData($user,$pass,$refresh_token, $inn, $accountNumber, $from_year, $from_month, $from_day, $till_year, $till_month, $till_day, $pdo){
//Первый этап - поход джедаев за access_token
$from_date = $from_year."-".$from_month."-".$from_day.'%2B03%3A00%3A00';
$till_date = $till_year."-".$till_month."-".$till_day.'%2B03%3A00%3A00';
$params=['grant_type'=>'refresh_token',
'refresh_token'=>$refresh_token
];
$headers = [
'POST /secure/token HTTP/1.1',
'Content-Type: application/x-www-form-urlencoded'
];
$curlURL='https://sso.tinkoff.ru/secure/token';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$curlURL);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
$curl_res = curl_exec($ch);
if($curl_res) {
$server_output = json_decode($curl_res);
}
//Считываем access_token - он нужен для реализации 2 этапа
$access_token_pos_start = strpos ($curl_res, 'access_token', 0);
$access_token_pos_start = $access_token_pos_start + 15;
$token_type_pos_start = strpos ($curl_res, "token_type", 0);
$access_token = mb_substr($curl_res, $access_token_pos_start, ($token_type_pos_start-$access_token_pos_start-3));
//Ура!.... мы сделали это.....
//По желанию, можете расскомментировать данный sleep, но в принципе работает и без него
//sleep(1);
//Второй этап - поход джедаев за данными
$params=[
'Authorization'=>$access_token,
'INN'=>$inn,
'accountNumber'=>$accountNumber
];
$headers = [
'Authorization: Bearer '.$access_token
];
$curlURL='https://sme-partner.tinkoff.ru/api/v1/partner/company/'.$inn.'/excerpt?accountNumber='.$accountNumber.'&from='.$from_date.'&till='.$till_date;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$curlURL);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
$curl_res = curl_exec($ch);
if($curl_res) {
$server_output = json_decode($curl_res);
}
$IE_Edge_pos_start = strpos ($curl_res, 'IE=Edge', 0);
$IE_Edge_pos_start = $IE_Edge_pos_start + 7;
$tinkoff_json = mb_substr($curl_res, $IE_Edge_pos_start);
$tinkoff_json = trim($tinkoff_json);
$tinkoff_json = json_decode($tinkoff_json);
//а тот ли счет мы считываем, собсно ;)
foreach ($tinkoff_json as $k=>$v){
if($k=='accountNumber'){
if(!($v==$accountNumber)) die('not that accountNumber');
}
}
//$tinkoff_array - записываем данные из json в массив
foreach ($tinkoff_json as $k=>$v){
if($k=='operation'){
$i=0;
foreach ($v as $t=>$s){
foreach ($s as $e=>$f){
$tinkoff_array[$i][$e]=$f;
}
$i++;
}
}
}
//заливаем данные из $tinkoff_array в базу данных
for ($i=0;$i<count($tinkoff_array);$i++){
$temp_id = $pdo->query("SELECT count(*) FROM `justtin`.`tinkoff` WHERE id=".$tinkoff_array[$i]['id'].";")->fetchColumn();
if ($temp_id==0){
if (Get_highly_likely_is_number_bill($tinkoff_array[$i]['paymentPurpose'])!=""){
$stmt = $pdo->prepare("INSERT INTO `justtin`.`tinkoff` (id, date, amount, drawDate, payerName, payerInn, payerAccount, payerCorrAccount, payerBic, payerBank, chargeDate, recipient, recipientInn, recipientAccount, recipientCorrAccount, recipientBic, recipientBank, operationType, uin, paymentPurpose, creatorStatus, payerKpp, executionOrder, date_of_save) VALUES (:id, :date, :amount, :drawDate, :payerName, :payerInn, :payerAccount, :payerCorrAccount, :payerBic, :payerBank, :chargeDate, :recipient, :recipientInn, :recipientAccount, :recipientCorrAccount, :recipientBic, :recipientBank, :operationType, :uin, :paymentPurpose, :creatorStatus, :payerKpp, :executionOrder, NOW())");
$stmt->bindParam(':id', $tinkoff_array[$i]['id']);
$stmt->bindParam(':date', $tinkoff_array[$i]['date']);
$stmt->bindParam(':amount', $tinkoff_array[$i]['amount']);
$stmt->bindParam(':drawDate', $tinkoff_array[$i]['drawDate']);
$stmt->bindParam(':payerName', $tinkoff_array[$i]['payerName']);
$stmt->bindParam(':payerInn', $tinkoff_array[$i]['payerInn']);
$stmt->bindParam(':payerAccount', $tinkoff_array[$i]['payerAccount']);
$stmt->bindParam(':payerCorrAccount', $tinkoff_array[$i]['payerCorrAccount']);
$stmt->bindParam(':payerBic', $tinkoff_array[$i]['payerBic']);
$stmt->bindParam(':payerBank', $tinkoff_array[$i]['payerBank']);
$stmt->bindParam(':chargeDate', $tinkoff_array[$i]['chargeDate']);
$stmt->bindParam(':recipient', $tinkoff_array[$i]['recipient']);
$stmt->bindParam(':recipientInn', $tinkoff_array[$i]['recipientInn']);
$stmt->bindParam(':recipientAccount', $tinkoff_array[$i]['recipientAccount']);
$stmt->bindParam(':recipientCorrAccount', $tinkoff_array[$i]['recipientCorrAccount']);
$stmt->bindParam(':recipientBic', $tinkoff_array[$i]['recipientBic']);
$stmt->bindParam(':recipientBank', $tinkoff_array[$i]['recipientBank']);
$stmt->bindParam(':operationType', $tinkoff_array[$i]['operationType']);
$stmt->bindParam(':uin', $tinkoff_array[$i]['uin']);
$stmt->bindParam(':paymentPurpose', $tinkoff_array[$i]['paymentPurpose']);
$stmt->bindParam(':creatorStatus', $tinkoff_array[$i]['creatorStatus']);
$stmt->bindParam(':payerKpp', $tinkoff_array[$i]['payerKpp']);
$stmt->bindParam(':executionOrder', $tinkoff_array[$i]['executionOrder']);
$stmt->execute();
}
}
}
}
Читателям: надеюсь, данный материал поможет в монетизации ваших веб-сервисов и сервисов ваших заказчиков. Да прибудет с вами сила!
Ребятам из техподдержки Банка Тинькофф: надеюсь, данная статья снизит нагрузку на вас! Удачи!
Автор: optimusqp
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/301031
Ссылки в тексте:
[1] openapi.tinkoff.ru: https://openapi.tinkoff.ru/
[2] 24386_policy.pdf: https://yadi.sk/i/IpquznN4kmq-lw
[3] «API Тинькофф — мы слишком глупы для этого»: http://www.banki.ru/services/responses/bank/response/10176688/
[4] StartSettings.php: https://yadi.sk/d/JtlGNqOcdHxOyQ
[5] Start.php: https://yadi.sk/d/SPy3k4dEHcy6gw
[6] TinkoffInsertData.php: https://yadi.sk/d/1D0BG2Y_RdP7nQ
[7] bank.sql: https://yadi.sk/d/vUc8cqK62kHG1Q
[8] Источник: https://habr.com/post/431908/?utm_campaign=431908
Нажмите здесь для печати.