Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 2254

Přidáno uživatelem Ondřej Fibich před téměř 11 roky(ů)

Release 1.0.12

Zobrazit rozdíly:

freenetis/tags/1.0.12/version.php
<?php defined('SYSPATH') or die('No direct script access.');
/*
* This file is part of open source system FreenetIS
* and it is released under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*
*/
/**
* The current version of FreenetIS.
* This value must be changed by developers in a new release of FreenetIS.
*/
define('FREENETIS_VERSION', '1.0.12');
freenetis/tags/1.0.12/application/libraries/Version.php
<?php defined('SYSPATH') or die('No direct script access.');
/*
* This file is part of open source system FreenetIS
* and it is released under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*
*/
/**
* Class for versioning of FreenetIS. Manages source code and database versions
* and it performs database upgrade.
*
* @author Ondrej Fibich
* @see Controller
*/
class Version
{
/**
* Regex for valitadation of versions
*/
const VERSION_REGEX = '^(([0-9]+\.[0-9]+\.[0-9]+)(~(alpha|beta|dev|rc)[0-9]*)?)$';
/**
* Gets version of Freenetis code
*
* @return string Version
*/
public static function get_version()
{
if (!defined('FREENETIS_VERSION'))
{
require 'version.php';
if (!self::is_valid_version(FREENETIS_VERSION))
{
throw new ErrorException('Wrong version format in version.php');
}
}
return FREENETIS_VERSION;
}
/**
* Gets version of Freenetis database
*
* @param $cache May be value returned from cache [optional]
* @return string Version
*/
public static function get_db_version($cache = TRUE)
{
return Settings::get('db_schema_version', $cache);
}
/**
* Check if the version of database is equal
*
* @return boolean true if versions are equal
*/
public static function is_db_up_to_date()
{
// old type of DB upgrades? => always false
if (is_numeric(self::get_db_version(FALSE)))
{
return false;
}
// new type
return (self::fn_version_compare() == 0);
}
/**
* Compares version of FreenetIS and its database
*
* @return integer -1 if the FreenetIS version is lower than the database
* version, 0 if they are equal, and 1 if the second is lower
*/
private static function fn_version_compare()
{
return self::compare(self::get_version(), self::get_db_version());
}
/**
* Checks if given version is in correct format
*
* @param string $version Version to check
* @return boolean true if it is, false otherwise
*/
private static function is_valid_version($version)
{
return mb_eregi(self::VERSION_REGEX, $version);
}
/**
* Compares two valid versions of FreenetIS
*
* @param string $version1
* @param string $version2
* @return integer -1 if the first version is lower than the second
* version, 0 if they are equal, and 1 if the second is lower
* @throws InvalidArgumentException On invalid version
*/
public static function compare($version1, $version2)
{
if (!self::is_valid_version($version1))
{
throw new InvalidArgumentException('Wrong version1 format: ' . $version1);
}
if (!self::is_valid_version($version2))
{
throw new InvalidArgumentException('Wrong version2 format: ' . $version2);
}
$version1_parts = explode('~', $version1);
$version2_parts = explode('~', $version2);
$cmp = 0;
if (($cmp = version_compare($version1_parts[0], $version2_parts[0])) == 0)
{
if (!isset($version1_parts[1]) && !isset($version2_parts[1]))
{
return 0;
}
else if (!isset($version1_parts[1]))
{
return 1;
}
else if (!isset($version2_parts[1]))
{
return -1;
}
$order = array('dev', 'alpha', 'beta', 'rc');
$order1 = NULL;
$order2 = NULL;
$i = 0;
foreach ($order as $type)
{
if (text::starts_with($version1_parts[1], $type))
{
$order1 = $i;
}
if (text::starts_with($version2_parts[1], $type))
{
$order2 = $i;
}
$i++;
}
if (($cmp = $order1 - $order2) == 0)
{
$number1 = substr($version1_parts[1], mb_strlen($order[$order1]));
$number2 = substr($version2_parts[1], mb_strlen($order[$order2]));
return intval($number1) - intval($number2);
}
}
return $cmp;
}
/**
* Makes database updates if there are any.
*
* Updates are located at /db_upgrades. Each upgrade has a name that consist
* of 'upgrade' and version (similar to version in /version.php).
*
* If any error occure during an upgrade. A location of the error is stored
* in the config DB table in a form of a midpoint. The upgrade starts from
* the stored midpoind in the next attempt to do the upgrade.
* Midpoint for before function is a number lower than zero and for after
* function is it a number greater than a count of SQL commands in the upgrade.
*
* @throws Database_Downgrate_Exception
* On not allowed database downgrade. (e.g. FN: 1.0.0 - DB: 1.1.0)
*
* @throws Old_Mechanism_Exception
* On old upgrade mechanism
*
* @throws Exception On any other error
*/
public static function make_db_up_to_date()
{
// detect downgrade (not on invalid DB verion - possibility of upgrade
// from old system)
if (self::is_valid_version(self::get_db_version()) &&
self::fn_version_compare() < 0)
{
throw new Database_Downgrate_Exception();
}
// database connection
$db = Database::instance();
// gets all files in /db_upgrades dir
$files = scandir('db_upgrades');
// array of available verisons
$versions = array();
// regex for file
$regex = '^upgrade_' . rtrim(ltrim(self::VERSION_REGEX, '^'), '$') . '\.php$';
// filter files
foreach ($files as $file)
{
// remove invalid files (wrong name) and value replace by version
if (!mb_eregi($regex, $file, $r))
{
continue;
}
// get version
$version = $r[1];
// remove old already installed upgrades and future upgrades
if (self::compare($version, self::get_version()) > 0 || (
!is_numeric(self::get_db_version()) &&
self::compare($version, self::get_db_version(FALSE)) <= 0
))
{
continue;
}
// add to available versions
$versions[] = $version;
}
// sort files according to version
usort($versions, 'Version::compare');
// midpoint
$midpoint = Settings::get('upgrade_midpoint_error', FALSE);
// make upgrades
foreach ($versions as $version)
{
Log::add('debug', 'Starting upgrade ' . $version);
// include include file
require 'db_upgrades/upgrade_' . $version . '.php';
// check if the upgrade is equvivalent to the current DB version
if (isset($upgrade_equal_to[$version]))
{
if (!is_array($upgrade_equal_to[$version]))
{
$upgrade_equal_to[$version] = array($upgrade_equal_to[$version]);
}
if (in_array(self::get_db_version(), $upgrade_equal_to[$version]))
{
Log::add('debug', 'Upgrade ' . $version . ' skipping (' . self::get_db_version() . ')');
// it is => so skip it
Settings::set('db_schema_version', $version);
Settings::set('upgrade_midpoint_error', '');
continue;
}
}
// check if old style is in use
if (is_numeric(self::get_db_version()) && self::get_db_version() > 0)
{
// not possible, inform user
throw new Old_Mechanism_Exception();
}
// transform version to version which may be used at PHP functions
$f_version = str_replace(array('~', '.'), array('_', '_'), $version);
// function names
$f_before = 'upgrade_' . $f_version . '_before';
$f_after = 'upgrade_' . $f_version . '_after';
// make update
try
{
// upgrade function before
if (function_exists($f_before) && (!is_numeric($midpoint) || $midpoint < 0))
{
try
{
Log::add('debug', 'Upgrade ' . $version . ' trigger before');
if (!call_user_func($f_before))
{
throw new Exception($f_before);
}
$midpoint = NULL;
}
catch (Exception $ex)
{
Settings::set('upgrade_midpoint_error', -1);
throw $ex;
}
}
else if ($midpoint < 0)
{
$midpoint = NULL;
}
// upgrade SQL
if (isset($upgrade_sql[$version]))
{
$qindex = is_numeric($midpoint) ? intval($midpoint) : 0;
// each item of array (SQL)
for (; $qindex < count($upgrade_sql[$version]); $qindex++)
{
try
{
Log::add('debug', 'Upgrade ' . $version . ' performing SQL command: ' . $qindex);
$db->query($upgrade_sql[$version][$qindex]);
}
catch (Exception $ex)
{
Settings::set('upgrade_midpoint_error', $qindex);
throw $ex;
}
}
}
// upgrade function after
if (function_exists($f_after))
{
try
{
Log::add('debug', 'Upgrade ' . $version . ' trigger after');
if (!call_user_func($f_after))
{
throw new Exception($f_after);
}
$midpoint = NULL;
}
catch (Exception $ex)
{
$top_e = count($upgrade_sql[$version]) + 1000;
Settings::set('upgrade_midpoint_error', $top_e);
throw $ex;
}
}
// clean memory
if (isset($upgrade_sql[$version]))
{
unset($upgrade_sql[$version]);
}
if (isset($upgrade_equal_to[$version]))
{
unset($upgrade_equal_to[$version]);
}
// set up db schema
Settings::set('db_schema_version', $version);
// clean midpoint if not cleaned
if (Settings::get('upgrade_midpoint_error') !== '')
{
Settings::set('upgrade_midpoint_error', '');
}
Log::add('debug', 'Upgrade ' . $version . ' complete');
}
catch (Exception $e)
{
$message = 'Upgrade DB: ' . $version . '<br /><br />'
. 'Function: ' . $e->getMessage() . '<br />'
. 'Last SQL command: ' . $db->last_query();
throw new Exception($message);
}
}
// set current version (optimalization if version has no DB update)
Settings::set('db_schema_version', self::get_version());
}
}
/**
* Exception that reflects state of not allowed downgration of database.
*/
class Database_Downgrate_Exception extends Exception
{
}
/**
* Exception that reflects state of old mechanism for updating of the database
* structure that cannot be automatically turned to new mechanism.
*/
class Old_Mechanism_Exception extends Exception
{
}
freenetis/tags/1.0.12/application/libraries/importers/Raiffeisenbank/Parser_Ebanka.php
<?php defined('SYSPATH') or die('No direct script access.');
/*
* This file is part of open source system FreenetIS
* and it is released under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*
*/
require_once 'Parser_Html_Table.php';
require_once 'RB_Importer.php';
require_once 'RB_Exception.php';
/**
* Parser_Ebanka is a parser for getting data from bank account transaction listing
* in the HTML format used by the Czech bank called "Ebanka" (now Raiffeisen Bank).
*
* The parsing is a bit peculiar, because Ebanka uses different format for
* listings that are visible to general public (the "transparent" listing used
* by NGOV non-profit organizations) and different format for regular listing used in the
* ebanking application.
* This parser autodetects these two formats and parses the data according to it.
*
* Benchmarks:
* Machine: Notebook FSC Lifebook S7110, CPU: Pentium T2400 @ 1.8 GHz
* Win XP SP2, Apache 2.2.3, PHP 5.2.0
* Regular listing with 136 table rows (1 week listing): time=0.1 sec, memory=205 kB
* Regular listing with 2175 table rows (whole year listing): time=1.6 sec, memory=205 kB
* Transparent listing with 467 table rows: time=0.14 sec, memory=122 kB
*
*
* @author Tomas <Dulik at unart dot cz>
* @version 1.0
*/
class Parser_Ebanka extends Parser_Html_Table
{
/**
* Poslední řetězec před začátkem hlavní <TABLE>
*/
const START_STRING="Pohyby na";
/**
* U běžných (netransparentních) výpisů
*/
const YEAR_STRING="Bankovn";
/**
* String before account
*/
const ACCOUNT_STRING="IBAN:";
/**
* Rok výpisu ze záhlaví výpisu
*
* @var string|mixed
*/
protected $year = false;
/**
* Obsahuje jméno funkce, která se má zavolat poté, co naparsujeme
* 1 kompletní řádek HTML tabulky.
*
* Callback funkce, kterou můžeme volat např. pro uložení
* každého řádku výpisu do DB.
*
* @see set_callback
* @var string|mixed
*/
protected $callback;
/**
* $result je vkládán do 1. parametru $callback funkce,
* která přes něj předává jeden řádek výsledku.
*
* Pokud $result není nastaven funkcí set_callback,
* pak jde je nastaven na instanci std_class
*
* @var object
*/
protected $result;
/**
*
* Function parses date from and to of the statement and statement number.
*
* @author Tomas Dulik, Jiri Svitak
*/
protected function get_statement_number_and_interval()
{
// code added by jsvitak, parsing date from and to
// hledej první "." v datumu
while (($pos = strpos($this->buffer, "<")) === false &&
$this->get_line());
if ($pos === false)
{
throw new RB_Exception("Nemůžu najít první znak '.' v řetězci ' za [období] ...'");
}
$toPos = substr($this->buffer, 0, $pos);
$parts = explode(' ', $toPos);
// parse statement number
$this->statement_number = intval($parts[3]);
// parse date from and to
$dates = explode('/', end($parts));
$from_arr = array_map('intval', explode('.', $dates[0]));
// save year for transfer creation purposes
$this->year = $from_arr[2];
$from_timestamp = mktime(0, 0, 0, $from_arr[1], $from_arr[0], $from_arr[2]);
// save date from
$this->from = date('Y-m-d', $from_timestamp);
// date to is set
if (isset($dates[1]))
{
$to_arr = array_map('intval', explode(".", $dates[1]));
$to_timestamp = mktime(0, 0, 0, $to_arr[1], $to_arr[0], $to_arr[2]);
// save date to
$this->to = date('Y-m-d', $to_timestamp);
}
else
// date to is not set, date from will be used
$this->to = $this->from;
}
/**
* Sets account number
*/
protected function get_cislo_uctu()
{
while (($czPos = stripos($this->buffer, "CZ")) === false &&
$this->get_line()); // hledej lomítko
if ($czPos === false)
{
throw new RB_Exception("Nemůžu najít 'CZ' v IBAN čísle účtu");
}
else
{
$this->bank_nr = substr($this->buffer, $czPos + 4, 4);
$account_nr = (int) substr($this->buffer, $czPos + 8, 16);
$this->account_nr = "$account_nr";
}
}
protected function get_balances()
{
$this->find_tags_and_trim(array(iconv("utf-8", "windows-1250", "Počáteční zůstatek"), self::START_STRING));
$this->find_tag_and_trim("\"RIGHT\">");
$raw_amount = substr($this->buffer, 0, strpos($this->buffer, "<"));
if ($raw_amount == "&nbsp;")
{
$this->find_tag_and_trim("\"RIGHT\">");
$raw_amount = substr($this->buffer, 0, strpos($this->buffer, "<"));
}
$this->opening_balance = str_replace(" ", "", $raw_amount);
//echo $this->opening_balance;
$this->find_tags_and_trim(array(iconv("utf-8", "windows-1250", "Konečný zůstatek"), self::START_STRING));
$this->find_tag_and_trim("\"RIGHT\">");
$raw_amount = substr($this->buffer, 0, strpos($this->buffer, "<"));
if ($raw_amount == "&nbsp;")
{
$this->find_tag_and_trim("\"RIGHT\">");
$raw_amount = substr($this->buffer, 0, strpos($this->buffer, "<"));
}
$this->closing_balance = str_replace(" ", "", $raw_amount);
//echo $this->closing_balance;
//echo $this->buffer;
//die();
}
/**
* Gets amount
*
* @param string $field
* @return string
*/
protected function get_amount($field)
{
$field = strip_tags($field);
$field = str_replace(array(" ", " "), "", $field);
return strtr($field, ",", ".");
}
/**
* V posledním sloupci HTML výpisu ebanka dává tyto poplatky: Poplatek, směna, zpráva.
* Poplatky jsou odděleny značkami <br>, u transp. výpisu <br/>
*
* @param $field
* @param $transparent
* @return ineteger součet všech poplatků generovaných pro daný řádek
*/
protected function get_fee($field, $transparent)
{
$field = str_replace(array(" ", " "), "", $field);
$field = strtr($field, ",", ".");
if ($transparent)
{
$br_tag = "<br/>";
}
else
{
$br_tag = "<br>";
}
$arr = preg_split("/<br>/si", $field);
$fee = 0;
foreach ($arr as $value)
{
$fee += $value;
}
return $fee;
}
/**
* Gets data from transparent
*/
protected function get_data_from_transparent()
{
$res = $this->result;
if ($res == NULL)
{
$res = new stdClass();
}
$first = true;
$line_nr = 0;
$rb_importer = new RB_Importer();
do
{
$status = $this->get_table_rows();
$nr = count($this->matches[1]);
$fields = str_replace(array("\r", "\n", "\t"), "", $this->matches[1]);
for ($i = 0; $i < $nr; $i++)
{
$field_nr = $i % 6;
$field = $fields[$i];
switch ($field_nr)
{
case 0: // příklad: 31.08.2008<br/>06:1
$arr = explode("<br/>", $field);
$arrDate = explode(".", $arr[0]);
$res->date_time = $arrDate[0];
break;
case 1: // Poznámky<br/>Název účtu plátce
$field = html_entity_decode($field, ENT_QUOTES, "UTF-8");
$arr = explode("<br/>", $field);
$res->comment = $arr[0];
$res->name = $arr[1];
break;
case 2: //2x za sebou datum odepsání<br/>typ platby
$arr = explode("<br/>", $field);
$res->type = html_entity_decode($arr[2], ENT_QUOTES, "UTF-8");
break;
case 3:
$arr = explode("<br/>", $field); //VS<br/>KS<br/>SS
$res->variable_symbol = (int) $arr[0];
$res->constant_symbol = $arr[1];
$res->specific_symbol = (int) $arr[2];
break;
case 4:
$res->amount = $this->get_amount($field); // částka
break;
case 5:
$res->fee = $this->get_fee($field, TRUE); // fee
$line_nr++;
$res->number = $line_nr;
//ted uz muzeme ulozit ziskane data do databaze:
//if (isset($this->callback))
// call_user_func($this->callback, $res);
$rb_importer->store_transfer_ebanka($res);
break;
} // switch
} // for
} while ($status !== false);
}
/**
* Gets data from regular
*/
protected function get_data_from_regular()
{
$res = $this->result;
if ($res == NULL)
{
$res = new stdClass();
}
$first = true;
$rb_importer = new RB_Importer();
do
{
if (($status = $this->get_table_rows()) !== FALSE)
{
$nr = count($this->matches[1]);
$fields = str_replace(array("\r", "\n", "\t"), "", $this->matches[1]);
if ($first)
{
$i = 7;
$first = false;
}
else
{
$i = 0;
}
for (; $i < $nr; $i++)
{
$field_nr = $i % 7;
$field = $fields[$i];
// odstraneni &nbsp;
$field = html_entity_decode($field, ENT_QUOTES, "UTF-8");
$field = str_replace(" ", "", $field);
switch ($field_nr)
{
case 0: // číslo výpisu, každý měsíc od 1 do N
if (!is_numeric($field))
{
ob_flush();
flush();
throw new RB_Exception("Parser error: " .
"očekával jsem číslo výpisu, ale dostal jsem:<br/>\n" . $field .
"<br/> \nPoslední správně načtený řádek výpisu má číslo " . $res->number .
"<br/> \nCelý vstupní buffer je: <br/>\n" . htmlentities($this->buffer)
//,E_USER_ERROR
);
}
$res->number = $field;
break;
case 1: // datum a čas příklad: 08.08.<br>06:11
$arr = preg_split("/<br>/si", $field);
if (count($arr) < 2)
{
throw new RB_Exception("Parser error: " .
"očekávám datum/čas jako dd.mm.&lt;br&gt;hh:mm ale dostal jsem:<br/>\n" . $field .
"<br/> \nPoslední správně načtený řádek výpisu má číslo " . $res->number .
"<br/> \nCelý vstupní buffer je: <br/>\n" . htmlentities($this->buffer), E_USER_ERROR);
}
else
{
$arrDate = explode(".", $arr[0]);
if (count($arrDate) < 2)
throw new RB_Exception("Parser error: " .
"očekávám datum jako dd.mm. ale dostal jsem:<br/>\n" . $arr[0] .
"<br/> \nPoslední správně načtený řádek výpisu má číslo " . $res->number .
"<br/> \nCelý vstupní buffer je: <br/>\n" . htmlentities($this->buffer), E_USER_ERROR);
$res->date_time = $this->year . "-" . $arrDate[1] . "-" . $arrDate[0] . " " . $arr[1];
}
break;
case 2: // Poznámky<br>Název účtu a<br>číslo účtu plátce
$arr = preg_split("/<br>/si", $field); // dělelní dle <BR> nebo <br>
if (isset($arr[0]))
{
$res->comment = $arr[0];
}
if (isset($arr[1]))
{
$res->name = $arr[1];
}
if (isset($arr[2]))
{
$account_arr = explode("/", $arr[2]);
if (isset($account_arr[0]))
{
$res->account_nr = $account_arr[0];
}
if (isset($account_arr[1]))
{
$res->account_bank_nr = $account_arr[1];
}
}
break;
case 3: //datum odepsání<br><br>typ platby
$arr = preg_split("/<br>/si", $field);
$res->type = $arr[2];
break;
case 4: //SS<br>VS<br>KS
$arr = preg_split("/<br>/si", $field);
$res->variable_symbol = $arr[1];
$res->constant_symbol = $arr[2];
$res->specific_symbol = $arr[0];
break;
case 5: // částka
$res->amount = $this->get_amount($field);
break;
case 6: // fee
$res->fee = $this->get_fee($field, FALSE);
//if (isset($this->callback)) call_user_func($this->callback, $res);
$rb_importer->store_transfer_ebanka($res);
/**
* ted uz muzeme ulozit ziskane data do databaze:
*/
break;
}
}
}
// dělej dokud nenajdeš konec souboru nebo tabulky
} while ($status !== false && $this->table_end == false);
}
/**
* Parses url
*
* @param string $url
* @param integer $account_id
*/
public function parse($url, $account_id=NULL)
{
$this->open($url);
$this->get_charset();
// Now: search for the begining of the table or the date
$found = $this->find_tags_and_trim(array
(
self::YEAR_STRING, self::ACCOUNT_STRING, self::START_STRING
));
switch ($found)
{
case 0: // období výpisu nalezeno = standardní (netransparentní) výpis
$transparent = false;
$this->get_statement_number_and_interval();
// zkus ještě najít číslo účtu
$found = $this->find_tags_and_trim(array(self::ACCOUNT_STRING, self::START_STRING));
$this->get_cislo_uctu();
// najdi počáteční a konečný zůstatek
$this->get_balances();
/*
// chyba (toto by nikdy nemělo nastat)
if ($found == 2)
{
throw new RB_Exception("Nemohu najít začátek tabulky: '" . self::START_STRING . "'");
}
// našel jsem START_STRING => číslo účtu nemám, konec switch-e
else if ($found == 1)
{
break;
}
*
*/
//else goto case 1: protože jsem našel číslo účtu
$found = $this->find_tag_and_trim(self::START_STRING);
break;
case 1: //nalezeno číslo účtu,
$this->get_cislo_uctu();
// najdi začátek výpisu
$found = $this->find_tag_and_trim(self::START_STRING);
// chyba (toto by nikdy nemělo nastat)
if ($found === false)
{
throw new RB_Exception("Nemohu najít začátek tabulky: '" . self::START_STRING . "'");
}
break;
case 2: //nalezen start tabulky s výpisy, což znamená, že
// období výpisu nenalezeno => transparentní výpis
$transparent = true;
// jako rok doplň aktuální rok
$this->year = date("Y");
break;
case 3:
throw new RB_Exception("Nemohu najít začátek tabulky nebo datum/rok");
break;
};
if ($transparent)
{
$this->get_data_from_transparent();
}
else
{
$this->get_data_from_regular();
}
fclose($this->file);
}
}
freenetis/tags/1.0.12/application/libraries/importers/Raiffeisenbank/RB_Statistics.php
<?php
/*
* This file is part of open source system FreenetIS
* and it is released under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*
*/
class RB_Statistics {}
?>
freenetis/tags/1.0.12/application/libraries/importers/Raiffeisenbank/RB_Exception.php
<?php
/*
* This file is part of open source system FreenetIS
* and it is released under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*
*/
/**
* Raiffeisen bank importer exception
* @author Jiri Svitak
*/
class RB_Exception extends Exception {}
?>
freenetis/tags/1.0.12/application/libraries/importers/Raiffeisenbank/RB_Importer.php
<?php defined('SYSPATH') or die('No direct script access.');
/*
* This file is part of open source system FreenetIS
* and it is released under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*
*/
require_once "RB_Statistics.php";
require_once APPPATH."libraries/importers/Duplicity_Exception.php";
/**
* Raiffeisenbank importer, saves listing items into Freenetis database
*/
class RB_Importer
{
/**
* Parsed bank account
*
* @var ORM
*/
public static $parsed_bank_acc;
/**
* Bank statement id
*
* @var integer
*/
public static $bank_statement_id;
/**
* User id
*
* @var integer
*/
public static $user_id;
/**
* Datetime
*
* @var string
*/
public static $time_now;
/**
* Funkce store_transfers_ebanka se používá jako callback funkce pro Parser_Ebanka.
* Třída Parser_Ebanka tuto funkci volá s každou načtenou položkou výpisu.
* Jednotlivé položky se pak uvnitř této funkce ukládají do databáze.
* Viz http://wiki.freenetis.slfree.net/index.php/Soubor:Hospodareni.pdf
*
* @author Tomas Dulik, Jiri Svitak
* @param data - objekt s následujícími položkami:
* parsed_acc_nr => 184932848 //cislo parsovaneho uctu
* parsed_acc_bank_nr=> 2400 //cislo banky parsovaneho uctu
* number => 1 //cislo vypisu
* date_time => 2008-03-25 05:40 //datum a cas
* comment => Rozpis polozek uveden v soupisu prevodu
* name => CESKA POSTA, S.P.
* account_nr => 160987123
* account_bank_nr = 0300
* type => Příchozí platba
* variable_symbol => 9081000001
* constant_symbol => 998
* specific_symbol => 9876543210
* amount => 720.00
* fee => -6.90
*
*/
public function store_transfer_ebanka($data = null)
{
// param check
if (!$data || !is_object($data))
{
Controller::warning(PARAMETER);
}
/** zde jsou statické objekty, jejichž instance tvořím jen jednou u importu prvního řádku
* výpisu (šetříme paměť...)
* */
static $acc_model, $bank_acc_model, $member_model, $fee_model, $parsed_acc;
static $bank_interests, $bank_fees, $time_deposits_interests, $time_deposits;
static $suppliers, $operating, $member_fees, $cash;
static $first_pass = true;
$this->stats = new stdClass();
$this->stats->linenr++;
if ($first_pass)
{ // dostavame prvni radek vypisu?
$this->stats = new RB_Statistics();
$this->time_now = date("Y-m-d H:i:s");
$member_model = new Member_Model(); // vytvorime vsechny instance, ktere potrebujeme i pro dalsi radky
$acc_model = new Account_Model();
$bank_acc_model = new Bank_account_Model();
$fee_model = new Fee_Model();
$ebank_nrs = array("2400", "5500");
if (!isset(self::$parsed_bank_acc))
{ // mame jiz parsovany ucet v DB?
// (tato promenna bude nastavena pouze pokud se parsuje
// ucet zvoleny v gridu uzivatelem)
// parsovany ucet dopredu nezname. Je v parsovanem vypisu?
// (je, pokud to neni transparentni vypis ebanky)
// this should never happen! Freenetis should not create some new accounts
// without admin's aware! Bank account of association should always
// already be in the database (jsvitak)
echo "parsed_bank_acc not set";
die();
if (isset($data->parsed_acc_nr) && isset($data->parsed_acc_bank_nr))
{
if (in_array($data->parsed_acc_bank_nr, $ebank_nrs))
// u ebanky probehla zmena kodu banky...
$bank_nr = "5500 (2400)";
else
$bank_nr = $data->parsed_acc_bank_nr;
self::$parsed_bank_acc = ORM::factory('bank_account')
->where(array
(
'account_nr' => $data->parsed_acc_nr,
'bank_nr' => $bank_nr
))->find();
if (!self::$parsed_bank_acc->id)
{ // parsovany ucet zatim neexistuje?
// tak si ho vytvorime
$acc_name = "$data->parsed_acc_nr/$bank_nr";
$parsed_acc = Account_Model::create(
Account_attribute_Model::BANK, $acc_name, 1
);
self::$parsed_bank_acc = Bank_account_Model::create(
$acc_name, $data->parsed_acc_nr, $bank_nr, 1
);
$parsed_acc->add(self::$parsed_bank_acc);
}
}
else
{ // if (isset($data->parsed_acc_nr) ... ve výpisu není číslo parsovaného účtu = kritická chyba
status::error('The parsed account is unknown.');
return;
}
}
else if (isset($data->parsed_acc_nr) && isset($data->parsed_acc_bank_nr) &&
!(
$data->parsed_acc_nr == self::$parsed_bank_acc->account_nr && // cisla uctu odpovidaji
(
$data->parsed_acc_bank_nr == self::$parsed_bank_acc->bank_nr || // cisla bank odpovidaji nebo
in_array($data->parsed_acc_bank_nr, $ebank_nrs) && // jsou obe 2400 nebo 5500
in_array(self::$parsed_bank_acc->bank_nr, $ebank_nrs)
)
))
{
throw new Kohana_User_Exception('Chyba', 'Importovaný výpis není z vybraného účtu!');
}
// @todo tato chyba nema byt Exception, ale normalni hlášení
if (!isset($parsed_acc))
{
$parsed_acc = self::$parsed_bank_acc->get_related_account_by_attribute_id(
Account_attribute_Model::BANK
);
if ($parsed_acc === FALSE)
// tohle by normálně nemělo nastat.
// může se to stát pouze pokud někdo smaže vazbu bank. účet sdružení
// s podvojným účtem přes tabulku accounts_bank_accounts
{
throw new Kohana_User_Exception(
'Kritická chyba',
'V tabulce accounts_bank_accounts chybí vazba ' .
'bankovního a podvojného účtu sdružení'
);
}
}
// Teď potřebujeme najít nebo vytvořit speciální podvojné účty k parsovanému bank. učtu:
$spec_accounts = array
(
Account_attribute_Model::BANK_INTERESTS => array
(
"bank_interests",
"Úroky z $parsed_acc->name",
),
Account_attribute_Model::TIME_DEPOSITS_INTERESTS => array
(
"time_deposits_interests",
"Úroky z termín. vkladů $parsed_acc->name",
),
Account_attribute_Model::TIME_DEPOSITS => array
(
"time_deposits",
"Termínované vklady $parsed_acc->name",
),
Account_attribute_Model::BANK_FEES => array
(
"bank_fees",
"Poplatky z $parsed_acc->name",
)
);
foreach ($spec_accounts as $accnt_attr => $name)
{
$spec_acc = self::$parsed_bank_acc->get_related_account_by_attribute_id(
$accnt_attr
);
if (!$spec_acc || !$spec_acc->id)
{ // pokud spec. ucet neexistuje, pak si jej vytvorime
$spec_acc = Account_Model::create($accnt_attr, $name[1], 1);
$spec_acc->add(self::$parsed_bank_acc);
$spec_acc->save();
}
${$name[0]} = $spec_acc;
}
$suppliers = ORM::factory('account')
->where('account_attribute_id', Account_attribute_Model::SUPPLIERS)
->find();
$member_fees = ORM::factory('account')
->where('account_attribute_id', Account_attribute_Model::MEMBER_FEES)
->find();
$operating = ORM::factory('account')
->where('account_attribute_id', Account_attribute_Model::OPERATING)
->find();
$cash = ORM::factory('account')
->where('account_attribute_id', Account_attribute_Model::CASH)
->find();
if (!$suppliers->id || !$member_fees->id || !$operating->id)
{
throw new Kohana_User_Exception(
'Kritická chyba',
'V DB chybí účet member_fees, suppliers nebo operating'
);
}
$first_pass = FALSE;
}
if (!empty($data->fee))
{
$fee = abs($data->fee);
$this->stats->bank_fees+= - $data->fee;
$this->stats->bank_fees_nr++;
}
// ********************** Tak a jdeme tvořit transakce *********************
$vs = trim($data->variable_symbol);
if (empty($data->amount))
{
// ****** Bankovní poplatky: ebanka má v řádku výpisu pouze poplatek, ale castka==0
// vytvoříme transakci "bankovní poplatek z 221000 (bank. účty) na 549001 (bank. poplatky)
//a bankovní transakci z parsovaného účtu na null. Přiřadíme ji sdružení (member_id=1).
if (empty($data->comment))
$data->comment = $data->type;
if ($data->fee < 0)
{
$this->create_transfers(
$parsed_acc, $bank_fees, $fee, self::$parsed_bank_acc, null, $data, 1
);
}
else // poplatek>0 - storno poplatku (stalo se 1x v celé historii našeho sdružení)
{
$this->create_transfers(
$bank_fees, $parsed_acc, $fee, self::$parsed_bank_acc, null, $data, 1
);
}
}
// castka je nenulova:
else if (empty($data->fee) && stripos($data->type, "rok") !== FALSE)
{
// ***** úroky u ebanky: amount!=0, fee==0, type je "Úrok", "Kladný úrok", "Převedení úroku po kapitalizaci TV"
// Vytvoříme transakci z 644000 nebo 655000 (uroky) na 221000
// a bankovní transakci z null na parsovaný účet. Přiřadíme ji sdružení (member_id=1)
if (empty($vs)) // běžný úrok? (644000)
{
$this->create_transfers(
$bank_interests, $parsed_acc, $data->amount, null, self::$parsed_bank_acc, $data, 1
);
}
else // úrok z termínovaného vkladu (655000)
{
$this->create_transfers(
$time_deposits_interests, $parsed_acc, $data->amount, null, self::$parsed_bank_acc, $data, 1
);
}
$this->stats->interests += $data->amount;
$this->stats->interests_nr++;
}
else
{
// ****** nejběžnější případ:
// - členský příspěvek, platba faktury dodavatelum, termín. vklad, výběr hotovosti ******
// Nejdriv zkusím najít majitele bankovního protiúčtu
$ks = trim($data->constant_symbol);
$term_vklad = ($ks == "968");
$member_model->clear();
$member = $member_model;
if (!$term_vklad && $data->amount > 0 && !empty($vs))
{ //u čl. příspěvků zkusíme najít původce:
// členský příspěvek nebo příjem z faktury odběrateli
// @todo zpracování jiných typů VS u člen. příspěvků (např. ID+CRC16)
// uvedl člen u teto platby jako variabilni symbol (VS) svůj telefon ?
$variable_symbol_model = new Variable_Symbol_Model();
$member = $variable_symbol_model->where('variable_symbol',$vs)->find()->account->member;
if (!$member->id)
{
$member = $member_model;
$this->stats->unidentified_transfers++;
}
}
// else { // if platba přijaté faktury - majitele účtu najdeme dle VS na faktuře, až budeme mít modul přijatých faktur}
// ***Tady si vytvorime instanci účtu clena (nebo dodavatele) z prave nacteneho vypisu:
$bank_acc = $bank_acc_model->where(array
(
'account_nr' => $data->account_nr,
'bank_nr' => $data->account_bank_nr
))->find();
if (!$bank_acc->id)
{ // bank. ucet clena neexistuje, tak si ho vytvorime
$bank_acc->clear();
$bank_acc->set_logger(FALSE);
//term. vklad je vždy způsoben sdružením
$member_idd = ($term_vklad ? 1 : $member->id);
$bank_acc->member_id = $member_idd != 0 ? $member_idd : NULL;
$bank_acc->name = $data->name;
$bank_acc->account_nr = $data->account_nr;
$bank_acc->bank_nr = $data->account_bank_nr;
$bank_acc->save();
$this->stats->new_bank_accounts++;
//tuto vazbu bych tvořil jen pokud bych chtěl evidovat pohyby na bank. účtech členů
// $bank_acc->add_account($member_fees);
}
if ($data->amount < 0)
{
$amount = abs($data->amount);
if ($term_vklad)
{ // převod peněz na účet term. vkladu
$id = $this->create_transfers(
$parsed_acc, $time_deposits, $amount,
self::$parsed_bank_acc, $bank_acc,
$data, $member->id, null
);
$this->stats->time_deposits+=$amount;
$this->stats->time_deposits_nr++;
}
else
{
if (stripos($data->type, "hotovost") !== FALSE)
{ // výběr do pokladny ?
$id = $this->create_transfers(
$parsed_acc, $cash, $amount,
self::$parsed_bank_acc, null,
$data, $member->id, null
);
$this->stats->cash_drawn+=$amount;
$this->stats->cash_drawn_nr++;
}
else
{
// úhrada faktury - z 221000 (bank. účet) na 321000 (dodavatelé)
// pokud se předtím nepodařilo najít majitele dle VS
if (!$member->id && $bank_acc->member_id)
{ // zkusím ho vzít odsud
$member = $member_model->find($bank_acc->member_id);
}
$id = $this->create_transfers(
$parsed_acc, $suppliers, $amount,
self::$parsed_bank_acc, $bank_acc,
$data, $member->id
);
$this->stats->invoices+=$amount;
$this->stats->invoices_nr++;
}
} // if ($term_vklad) ... else
if (!empty($fee))
{
// je tam bankovní poplatek - vytvoříme:
// - podvojnou transakci z 221000 (bank. účty) na 549001 (bank. poplatky)
// - bankovní transakci z parsovaného účtu na null
$data->comment = "Bank. poplatek" . (!empty($data->comment) ? " ($data->comment)" : "");
$this->create_transfers(
$parsed_acc, $bank_fees, $fee,
self::$parsed_bank_acc, null,
$data, $member->id, $id
);
}
}
else
{ // $data->amount > 0
if ($term_vklad)
{ // stažení peněz z účtu term. vkladu
$id = $this->create_transfers(
$time_deposits, $parsed_acc,
$data->amount, $bank_acc, self::$parsed_bank_acc,
$data, $member->id, null
);
$this->stats->time_deposits_drawn+=$data->amount;
$this->stats->time_deposits_drawn_nr++;
}
else
{
// členský příspěvek - vytvoříme:
// - podvojnou transakci z 684000 na 221000
// - bankovní transakci z bank. účtu člena na bank. účet sdružení
$id = $this->create_transfers(
$member_fees, $parsed_acc, $data->amount,
$bank_acc, self::$parsed_bank_acc,
$data, $member->id
);
if (!empty($fee))
{
// bankovní poplatek - vytvoříme:
// - podvojnou transakci z 221000 (bank. účty) na 549001 (bank. poplatky)
// - bankovní transakci z parsovaného účtu na null
$data->comment = "Bank. poplatek" . (!empty($data->comment) ? " ($data->comment)" : "");
$this->create_transfers(
$parsed_acc, $bank_fees, $fee,
self::$parsed_bank_acc, null, $data,
$member->id, $id
);
// naše správní rada si vymyslela, že poplatek budeme dotovat z operačního účtu
// (pokud máte ve správní radě rozumnější lidi, tak tento řádek zakomentujte :-)
$this->create_transfer(
$operating, $parsed_acc,
abs($data->fee), $data->date_time,
"Bank. poplatek hrazený sdružením",
$member->id, $id
);
}
if ($member->id)
{ // původce je známý?
// **** převedeme peníze členovi na jeho účet s kreditem
// ten účet ale musíme najít nebo vytvořit:
$credit_acc = $acc_model->where(array
(
'member_id' => $member->id,
'account_attribute_id' => Account_attribute_Model::CREDIT)
)->find();
if (!$credit_acc->id)
{
$credit_acc->clear();
$credit_acc->set_logger(FALSE);
$credit_acc->account_attribute_id = Account_attribute_Model::CREDIT;
$credit_acc->member_id = $member->id;
/**
* @todo Jirka pri tvorbe uctu jako jmeno uctu pouziva
* prijmeni jmeno majitele. To se mi tady nechce programovat,
* protoze se jen tezko muze stat, ze by kreditni ucet neexistoval
*/
$credit_acc->name = $member->name;
$credit_acc->save();
}
$this->create_transfer(
$parsed_acc, $acc_model, $data->amount,
$data->date_time, "Přiřazení platby",
$member->id, $id
);
// teď se podíváme, jestli v té době sdružení
// účtovalo poplatek za zpracování platby:
$fee = $fee_model->get_by_date_type(
$data->date_time, 'transfer fee'
);
if (is_object($fee) && $fee->id) // ano? Pak poplatek strhneme z účtu
{
$this->create_transfer(
... Rozdílový soubor je zkrácen, protože jeho délka přesahuje max. limit.

Také k dispozici: Unified diff