* koin service and cli stuff added

This commit is contained in:
Danyi Dávid
2017-09-05 23:04:28 +02:00
parent 946d00ff93
commit 8184c1e07d
15 changed files with 801 additions and 55 deletions

View File

@@ -0,0 +1,241 @@
<?php
namespace App\Service;
use App\Entity\Sms;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
class KoinService
{
const BASE_URI = 'https://www.koin.hu';
const DEFAULT_EXPENSE = 'Egyéb kiadás';
/**
* 1 - date
* 2 - time
* 3 - amount contains dot as thousand separator
* 4 - currency
* 5 - pos info
*/
const OTP_SMS_PATTERN = '/([0-9]{6}) ([0-9]{1,2}:[0-9]{1,2}) K[áà]rty[áà]s v[áà]s[áà]rl[áà]s/z[áà]rol[áà]s: -([0-9.]+) ([A-Z]{2,3}); (.*?); K[áà]rtyasz[áà]m: ...[0-9]{4}; Egyenleg: \+[0-9.]+ HUF - OTPdirekt/msi';
/**
* @var array
*/
private $config;
/**
* @var Client
*/
private $httpClient;
/**
* @var string
*/
private $csrfParam;
/**
* @var string
*/
private $csrfToken;
/**
* @var array
*/
private $expenseCategories = [];
/**
* @var array
*/
private $incomeCategories = [];
public function __construct(Client $httpClient, array $config)
{
$this->config = $config;
$this->httpClient = $httpClient;
}
/**
* @param Sms $sms
*/
public function onReceiveSms(Sms $sms)
{
if (false !== preg_match(self::OTP_SMS_PATTERN, $sms->getText(), $otpMatches)) {
$datePart = implode("-", sscanf($otpMatches[1], '%2c%2c%2c'));
$this->saveTransaction(
intval(str_replace(".","", $otpMatches[3])),
$otpMatches[4],
"20${datePart} ${otpMatches['2']}",
$this->getExpenseCategory($otpMatches[5]),
$this->getExpenseTags($otpMatches[5])
);
}
}
/**
* @param string $posInfo
* @return string
*/
private function getExpenseCategory(string $posInfo): string
{
return self::DEFAULT_EXPENSE;
}
/**
* @param string $posInfo
* @return array
*/
private function getExpenseTags(string $posInfo): array
{
return [];
}
/**
* @param int $amount
* @param string $currency
* @param string $date
* @param string $category
* @param array $tags
* @return int
*/
public function saveTransaction(int $amount, string $currency = 'HUF', string $date, string $category, array $tags): int
{
$pageData = $this->login($this->config['koin.user'], $this->config['koin.pass']);
$this->loadFormData($pageData->getBody());
return $this->postData(
$amount,
$currency,
$date,
$this->getCategoryId($category),
$this->getTagsString($tags)
);
}
/**
* @param string $user
* @param string $pass
* @return \Psr\Http\Message\ResponseInterface
*/
private function login(string $user, string $pass): ResponseInterface
{
$httpResponse = $this->httpClient->get(self::BASE_URI);
$body = $httpResponse->getBody();
$this->getCsrfToken($body);
$httpResponse = $this->httpClient
->post(self::BASE_URI . "/site/login", [
'form_params' => [
$this->csrfParam => $this->csrfToken,
'LoginForm[email]' => $user,
'LoginForm[pass]' => $pass,
'LoginForm[rememberMe]' => 0,
],
]);
return $httpResponse;
}
/**
* @param $htmlData
*/
private function loadFormData($htmlData)
{
$documentXpath = $this->getCsrfToken($htmlData);
/** @var \DOMNodeList $expenseOptionElements */
$expenseOptionElements = $documentXpath->query('//select[@id="transactioncreate-category_id"]/optgroup[@label="Kiadás"]/option');
/** @var \DOMNodeList $incomeOptionElements */
$incomeOptionElements = $documentXpath->query('//select[@id="transactioncreate-category_id"]/optgroup[@label="Bevétel"]/option');
/** @var \DOMElement $element */
foreach ($expenseOptionElements as $element) {
$this->expenseCategories[$element->nodeValue] = $element->getAttribute("value");
}
/** @var \DOMElement $element */
foreach ($incomeOptionElements as $element) {
$this->incomeCategories[$element->nodeValue] = $element->getAttribute("value");
}
}
/**
* Parse csrf from html
*
* @param $html
* @return \DOMXPath
*/
private function getCsrfToken($html): \DOMXPath
{
$xmlErrorHandling = libxml_use_internal_errors(TRUE);
$domDocument = new \DOMDocument();
$domDocument->loadHTML($html);
libxml_clear_errors();
libxml_use_internal_errors($xmlErrorHandling);
$documentXpath = new \DOMXPath($domDocument);
/** @var \DOMElement $paramElement */
$paramElement = $documentXpath->query('//meta[@name="csrf-param"]')->item(0);
/** @var \DOMElement $tokenElement */
$tokenElement = $documentXpath->query('//meta[@name="csrf-token"]')->item(0);
$this->csrfParam = $paramElement->getAttribute("content");
$this->csrfToken = $tokenElement->getAttribute("content");
return $documentXpath;
}
/**
* @param int $amount
* @param string $currency
* @param string $date
* @param string $category
* @param string $tags
* @return int
*/
private function postData(int $amount, string $currency = 'HUF', string $date, string $category, string $tags): int
{
$saveResponse = $this->httpClient
->post(self::BASE_URI . "/main/save-transaction", [
'form_params' => [
$this->csrfParam => $this->csrfToken,
'TransactionCreate[category_id]' => $category,
'TransactionCreate[value]' => $amount,
'TransactionCreate[currency]' => $currency,
'TransactionCreate[imgKey]' => "",
'TransactionCreate[tagData]' => $tags,
'TransactionCreate[date]' => $date,
],
]);
return $saveResponse->getStatusCode();
}
/**
* @param array $tags
* @return string
*/
private function getTagsString(array $tags): string
{
return implode(';', $tags);
}
/**
* @param string $category
* @return string
*/
private function getCategoryId(string $category): string
{
if(in_array($category, array_keys($this->expenseCategories))) {
return $this->expenseCategories[$category];
}
return $this->expenseCategories[self::DEFAULT_EXPENSE];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Service;
use GuzzleHttp\Client;
use Interop\Container\ContainerInterface;
class KoinServiceFactory
{
public function __invoke(ContainerInterface $container)
{
$httpClient = new Client([
'cookies' => true,
]);
$config = $container->get('config');
return new KoinService($httpClient, $config);
}
}

View File

@@ -13,6 +13,7 @@ class SmsStoreServiceFactory
public function __invoke(ContainerInterface $container)
{
$em = $container->get('doctrine.entity_manager.orm_default');
return new SmsStoreService($em);
}
}