* indent fix

* added some more reoccuring pos info
This commit is contained in:
Danyi Dávid 2017-10-01 13:39:18 +02:00
parent 65a5757df9
commit 1ee6969b0e

View File

@ -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];
}
} }