* indent fix
* added some more reoccuring pos info
This commit is contained in:
parent
65a5757df9
commit
1ee6969b0e
@ -12,263 +12,352 @@ use Zend\EventManager\Event;
|
|||||||
class KoinService
|
class KoinService
|
||||||
{
|
{
|
||||||
|
|
||||||
const BASE_URI = 'https://www.koin.hu';
|
const BASE_URI = 'https://www.koin.hu';
|
||||||
const DEFAULT_EXPENSE = 'Egyéb kiadás';
|
const DEFAULT_EXPENSE = 'Egyéb kiadás';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1 - date
|
* 1 - date
|
||||||
* 2 - time
|
* 2 - time
|
||||||
* 3 - amount contains dot as thousand separator
|
* 3 - amount contains dot as thousand separator
|
||||||
* 4 - currency
|
* 4 - currency
|
||||||
* 5 - pos info
|
* 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#msiu';
|
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#msiu';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Client
|
* @var Client
|
||||||
*/
|
*/
|
||||||
private $httpClient;
|
private $httpClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $csrfParam;
|
private $csrfParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $csrfToken;
|
private $csrfToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $expenseCategories = [];
|
private $expenseCategories = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $incomeCategories = [];
|
private $incomeCategories = [];
|
||||||
|
|
||||||
|
|
||||||
public function __construct(Client $httpClient, array $config)
|
public function __construct(Client $httpClient, array $config)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->httpClient = $httpClient;
|
$this->httpClient = $httpClient;
|
||||||
}
|
|
||||||
|
|
||||||
public function onReceiveSmsListener(Event $event)
|
|
||||||
{
|
|
||||||
$this->onReceiveSms($event->getParam('sms'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Sms $sms
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function onReceiveSms(Sms $sms)
|
|
||||||
{
|
|
||||||
if (1 === ($matchStatus = 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}",
|
|
||||||
$this->getExpenseCategory($otpMatches[5]),
|
|
||||||
$this->getExpenseTags($otpMatches[5])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $matchStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $posInfo
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function getExpenseCategory(string $posInfo): string
|
|
||||||
{
|
|
||||||
if(false !== strpos($posInfo, "TESCO")) {
|
|
||||||
return 'Bevásárlás';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(false !== strpos($posInfo, "MCDHU")) {
|
public function onReceiveSmsListener(Event $event)
|
||||||
return 'Étel';
|
{
|
||||||
|
$this->onReceiveSms($event->getParam('sms'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(false !== strpos($posInfo, "GYOGYSZER")) {
|
/**
|
||||||
return 'Egészség';
|
* @param Sms $sms
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function onReceiveSms(Sms $sms)
|
||||||
|
{
|
||||||
|
if (1 === ($matchStatus = 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}",
|
||||||
|
$this->getExpenseCategory($otpMatches[5]),
|
||||||
|
$this->getExpenseTags($otpMatches[5])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $matchStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::DEFAULT_EXPENSE;
|
/**
|
||||||
}
|
* @param string $posInfo
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getExpenseCategory(string $posInfo): string
|
||||||
|
{
|
||||||
|
if (false !== strpos($posInfo, "STOCZEK ETTEREM")) {
|
||||||
|
return 'Étel';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (false !== strpos($posInfo, "BKK AUTOMATA")) {
|
||||||
* @param string $posInfo
|
return 'Közlekedés';
|
||||||
* @return array
|
}
|
||||||
*/
|
|
||||||
private function getExpenseTags(string $posInfo): array
|
|
||||||
{
|
|
||||||
$tags = [];
|
|
||||||
|
|
||||||
if(false !== strpos($posInfo, "TESCO")) {
|
if (false !== strpos($posInfo, "TESCO")) {
|
||||||
$tags[] = 'Tesco';
|
return 'Bevásárlás';
|
||||||
}
|
}
|
||||||
if(false !== strpos($posInfo, "MCDHU")) {
|
|
||||||
$tags[] = 'Junk food';
|
if (false !== strpos($posInfo, "SPAR MAGYARORSZAG")) {
|
||||||
}
|
return 'Étel';
|
||||||
if(false !== strpos($posInfo, "GYOGYSZER")) {
|
}
|
||||||
$tags[] = 'Gyógyszer';
|
|
||||||
|
if (false !== strpos($posInfo, "SZLOVàK ABC")) {
|
||||||
|
return 'Bevásárlás';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "MCDHU")) {
|
||||||
|
return 'Étel';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "OSMANI DÖNER KEBAB")) {
|
||||||
|
return 'Étel';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "Princess Bakery")) {
|
||||||
|
return 'Étel';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "PIROG-DA")) {
|
||||||
|
return 'Étel';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "GYOGYSZER")) {
|
||||||
|
return 'Egészség';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "GOOGLE *Google Music")) {
|
||||||
|
return 'Szórakozás';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "Aqua Electromax")) {
|
||||||
|
return 'Szórakozás';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return self::DEFAULT_EXPENSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tags[] = 'Auto';
|
/**
|
||||||
return $tags;
|
* @param string $posInfo
|
||||||
}
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getExpenseTags(string $posInfo): array
|
||||||
|
{
|
||||||
|
$tags = [];
|
||||||
|
|
||||||
/**
|
if (false !== strpos($posInfo, "SCIENCE PARK ÉTTEREM")) {
|
||||||
* @param int $amount
|
$tags[] = 'Science Park';
|
||||||
* @param string $currency
|
$tags[] = 'Menza';
|
||||||
* @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());
|
if (false !== strpos($posInfo, "STOCZEK ETTEREM")) {
|
||||||
return $this->postData(
|
$tags[] = "Stoczek";
|
||||||
$amount,
|
$tags[] = "Menza";
|
||||||
$currency,
|
}
|
||||||
$date,
|
|
||||||
$this->getCategoryId($category),
|
|
||||||
$this->getTagsString($tags)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (false !== strpos($posInfo, "BKK AUTOMATA")) {
|
||||||
* @param string $user
|
$tags[] = "Bérlet";
|
||||||
* @param string $pass
|
$tags[] = "BKV";
|
||||||
* @return \Psr\Http\Message\ResponseInterface
|
}
|
||||||
*/
|
|
||||||
private function login(string $user, string $pass): ResponseInterface
|
|
||||||
{
|
|
||||||
$httpResponse = $this->httpClient->get(self::BASE_URI);
|
|
||||||
|
|
||||||
$body = $httpResponse->getBody();
|
if (false !== strpos($posInfo, "SPAR MAGYARORSZAG")) {
|
||||||
|
$tags[] = 'Spar';
|
||||||
|
}
|
||||||
|
|
||||||
$this->getCsrfToken($body);
|
if (false !== strpos($posInfo, "TESCO")) {
|
||||||
|
$tags[] = 'Tesco';
|
||||||
|
}
|
||||||
|
|
||||||
$httpResponse = $this->httpClient
|
if (false !== strpos($posInfo, "SZLOVàK ABC")) {
|
||||||
->post(self::BASE_URI . "/site/login", [
|
$tags[] = 'Szlovák ABC';
|
||||||
'form_params' => [
|
}
|
||||||
$this->csrfParam => $this->csrfToken,
|
|
||||||
'LoginForm[email]' => $user,
|
|
||||||
'LoginForm[pass]' => $pass,
|
|
||||||
'LoginForm[rememberMe]' => 0,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
return $httpResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (false !== strpos($posInfo, "MCDHU")) {
|
||||||
* @param $htmlData
|
$tags[] = 'Junk food';
|
||||||
*/
|
}
|
||||||
private function loadFormData($htmlData)
|
|
||||||
{
|
|
||||||
$documentXpath = $this->getCsrfToken($htmlData);
|
|
||||||
|
|
||||||
/** @var \DOMNodeList $expenseOptionElements */
|
if (false !== strpos($posInfo, "OSMANI DÖNER KEBAB")) {
|
||||||
$expenseOptionElements = $documentXpath->query('//select[@id="transactioncreate-category_id"]/optgroup[@label="Kiadás"]/option');
|
$tags[] = 'Kebab';
|
||||||
/** @var \DOMNodeList $incomeOptionElements */
|
$tags[] = 'Junk food';
|
||||||
$incomeOptionElements = $documentXpath->query('//select[@id="transactioncreate-category_id"]/optgroup[@label="Bevétel"]/option');
|
}
|
||||||
|
|
||||||
/** @var \DOMElement $element */
|
if (false !== strpos($posInfo, "Princess Bakery")) {
|
||||||
foreach ($expenseOptionElements as $element) {
|
$tags[] = 'Pricess Bakery';
|
||||||
$this->expenseCategories[$element->nodeValue] = $element->getAttribute("value");
|
$tags[] = 'Junk food';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "PIROG-DA")) {
|
||||||
|
$tags[] = 'Pirog-da';
|
||||||
|
$tags[] = 'Junk food';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "GYOGYSZER")) {
|
||||||
|
$tags[] = 'Gyógyszer';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "GOOGLE *Google Music")) {
|
||||||
|
$tags[] = 'Google play';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($posInfo, "Aqua Electromax")) {
|
||||||
|
$tags[] = 'Aqua';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags[] = 'Auto';
|
||||||
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \DOMElement $element */
|
/**
|
||||||
foreach ($incomeOptionElements as $element) {
|
* @param int $amount
|
||||||
$this->incomeCategories[$element->nodeValue] = $element->getAttribute("value");
|
* @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)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse csrf from html
|
* @param string $user
|
||||||
*
|
* @param string $pass
|
||||||
* @param $html
|
* @return \Psr\Http\Message\ResponseInterface
|
||||||
* @return \DOMXPath
|
*/
|
||||||
*/
|
private function login(string $user, string $pass): ResponseInterface
|
||||||
private function getCsrfToken($html): \DOMXPath
|
{
|
||||||
{
|
$httpResponse = $this->httpClient->get(self::BASE_URI);
|
||||||
$xmlErrorHandling = libxml_use_internal_errors(TRUE);
|
|
||||||
$domDocument = new \DOMDocument();
|
|
||||||
$domDocument->loadHTML($html);
|
|
||||||
libxml_clear_errors();
|
|
||||||
libxml_use_internal_errors($xmlErrorHandling);
|
|
||||||
|
|
||||||
$documentXpath = new \DOMXPath($domDocument);
|
$body = $httpResponse->getBody();
|
||||||
/** @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->getCsrfToken($body);
|
||||||
$this->csrfToken = $tokenElement->getAttribute("content");
|
|
||||||
|
|
||||||
return $documentXpath;
|
$httpResponse = $this->httpClient
|
||||||
}
|
->post(self::BASE_URI . "/site/login", [
|
||||||
|
'form_params' => [
|
||||||
/**
|
$this->csrfParam => $this->csrfToken,
|
||||||
* @param int $amount
|
'LoginForm[email]' => $user,
|
||||||
* @param string $currency
|
'LoginForm[pass]' => $pass,
|
||||||
* @param string $date
|
'LoginForm[rememberMe]' => 0,
|
||||||
* @param string $category
|
],
|
||||||
* @param string $tags
|
]);
|
||||||
* @return int
|
return $httpResponse;
|
||||||
*/
|
}
|
||||||
private function postData(int $amount, string $currency = 'HUF', string $date, string $category, string $tags): int
|
|
||||||
{
|
/**
|
||||||
$saveResponse = $this->httpClient
|
* @param $htmlData
|
||||||
->post(self::BASE_URI . "/main/save-transaction", [
|
*/
|
||||||
'form_params' => [
|
private function loadFormData($htmlData)
|
||||||
$this->csrfParam => $this->csrfToken,
|
{
|
||||||
'TransactionCreate[category_id]' => $category,
|
$documentXpath = $this->getCsrfToken($htmlData);
|
||||||
'TransactionCreate[value]' => $amount,
|
|
||||||
'TransactionCreate[currency]' => $currency,
|
/** @var \DOMNodeList $expenseOptionElements */
|
||||||
'TransactionCreate[imgKey]' => "",
|
$expenseOptionElements = $documentXpath->query('//select[@id="transactioncreate-category_id"]/optgroup[@label="Kiadás"]/option');
|
||||||
'TransactionCreate[tagData]' => $tags,
|
/** @var \DOMNodeList $incomeOptionElements */
|
||||||
'TransactionCreate[date]' => $date,
|
$incomeOptionElements = $documentXpath->query('//select[@id="transactioncreate-category_id"]/optgroup[@label="Bevétel"]/option');
|
||||||
],
|
|
||||||
]);
|
/** @var \DOMElement $element */
|
||||||
|
foreach ($expenseOptionElements as $element) {
|
||||||
return $saveResponse->getStatusCode();
|
$this->expenseCategories[$element->nodeValue] = $element->getAttribute("value");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @var \DOMElement $element */
|
||||||
* @param array $tags
|
foreach ($incomeOptionElements as $element) {
|
||||||
* @return string
|
$this->incomeCategories[$element->nodeValue] = $element->getAttribute("value");
|
||||||
*/
|
}
|
||||||
private function getTagsString(array $tags): string
|
}
|
||||||
{
|
|
||||||
return implode(';', $tags);
|
/**
|
||||||
}
|
* Parse csrf from html
|
||||||
|
*
|
||||||
/**
|
* @param $html
|
||||||
* @param string $category
|
* @return \DOMXPath
|
||||||
* @return string
|
*/
|
||||||
*/
|
private function getCsrfToken($html): \DOMXPath
|
||||||
private function getCategoryId(string $category): string
|
{
|
||||||
{
|
$xmlErrorHandling = libxml_use_internal_errors(TRUE);
|
||||||
if(in_array($category, array_keys($this->expenseCategories))) {
|
$domDocument = new \DOMDocument();
|
||||||
return $this->expenseCategories[$category];
|
$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];
|
||||||
}
|
}
|
||||||
return $this->expenseCategories[self::DEFAULT_EXPENSE];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user