Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 851

Přidáno uživatelem Jiří Sviták před více než 13 roky(ů)

Zacleneni transakcniho zpracovani financnich prevodu vcetne dalsich vylepseni a rychlostni optimalizaci financi do hlavni vetve. Pridan i licencni soubor GNU/GPLv3.

Zobrazit rozdíly:

freenetis/trunk/kohana/license.txt
Freenetis - open source information system for managing community
based networks. It provides features like payment management, user
and device management, services management etc.
Copyright (C) 2008-2011 Tomas Dulik, Michal Kliment, Jiri Svitak,
Roman Sevcik, Ondrej Fibich, Petr Danek, Marek Rozehnal
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
freenetis/trunk/kohana/application/i18n/cs_CZ/texts.php
'after you\'ve done that, you can continue' => 'Poté, co tak učiníte, můžete pokračovat.',
'agree' => 'Souhlas',
'all' => 'Všichni',
'all accounts now have correct balances, %d accounts had incorrect balances' => 'Všechny účty teď mají správné zůstatky, %d účtů mělo chybné zůstatky.',
'all ip addresses of member' => 'všem IP adresám člena',
'all redirected' => 'Všichni přesměrovaní',
'all transfers' => 'Všechny převody',
......
'back to all subnets' => 'Zpět na seznam podsítí',
'back to bank account' => 'Zpět na bankovní účet',
'back to bank accounts' => 'Zpět na bankovní účty',
'back to bank statement' => 'Zpět na bankovní výpis',
'back to bank statements' => 'Zpět na bankovní výpisy',
'back to bank templates' => 'Zpět na bankovní šablony',
'back to day book' => 'Zpět na účetní deník',
......
'bad variable symbol format' => 'Špatný formát variabilního symbolu.',
'bad voip number interval format' => 'Špatný formát VoIP čísel',
'balance' => 'Stav',
'balance to year' => 'Zůstatek k roku',
'balance from date' => 'Zůstatek od data',
'balance to date' => 'Zůstatek do data',
'bank account' => 'Bankovní účet',
'bank account id' => 'ID bankovního účtu',
'bank account name' => 'Název bankovního účtu',
......
'bank info' => 'Údaje platby',
'bank interest' => 'Bankovní úrok',
'bank interests' => 'Bankovní úroky',
'bank statement contains items that were already imported' => 'Bankovní výpis obsahuje položky, které již byly importovány.',
'bank statement has been successfully deleted' => 'Bankovní výpis byl úspěšně smazán.',
'bank statement has been successfully updated' => 'Bankovní výpis byl úspěšně upraven.',
'bank statements' => 'Bankovní výpisy',
......
'entrance date' => 'Datum vstupu',
'entrance_date' => 'Datum vstupu',
'entrance fee' => 'Vstupní příspěvek',
'entrance fee has been successfully deducted' => 'Vstupní příspěvek byl úspěšně stržen.',
'entrance fee have to be a number' => 'Vstupní příspěvk musí být číslo',
'entrance fees have been successfully deducted' => 'Vstupní příspěvky byly úspěšně strženy.',
'entrance fees have been successfully deducted, %d new transfers created' => 'Vstupní příspěvky byly úspěšně strženy, vytvořeno %d nových převodů.',
'entrance fees have been successfully recalculated, %d transfers deleted, %d new transfers created' => 'Vstupní příspěvek byl úspěšně stržen, smazáno %d převodů, vytvořeno %d nových převodů.',
'enum type has been successfully added' => 'Výčet byl úspěšně přidán',
'enum type has been successfully deleted' => 'Výčet byl úspěšně smazán',
'enum type has been successfully updated' => 'Výčet byl úspěšně aktualizován',
......
'error - wrong arguments' => 'Chyba - špatné argumenty',
'error - wrong data' => 'Chyba - špatná data',
'error - amount has to be positive' => 'Chyba - částka musí být kladná.',
'error - cannot add bank transfer' => 'Chyba - nelze přidat bankovní převod.',
'error - cannot add message' => 'Chyba - nelze přidat zprávu.',
'error - cannot assign transfer' => 'Chyba - nelze přiřadit převod.',
'error - cannot complete registration' => 'Chyba - Nelze dokončit registraci',
'error - cannot delete bank statement' => 'Chyba - nelze smazat bankovní výpis.',
'error - cannot load intelligent selection' => 'Chyba - nelze načíst inteligentní výběr',
......
'execution time' => 'Doba provádění',
'executive counsil' => 'Správní rada',
'expenditure-earning' => 'Výdej-Příjem',
'expenses' => 'Výdaje',
'export of registration' => 'Export přihlášky',
'export to xls' => 'Exportovat do XLS',
'export to csv (utf-8)' => 'Exportovat do CSV (utf-8)',
......
'fee or penalty comment' => 'Komentář k poplatku/pokutě',
'fee type' => 'Typ poplatku',
'fees' => 'Poplatky',
'fees have been successfully deducted' => 'Členské příspěvky byly úspěšně strženy.',
'fees have been successfully recounted' => 'Členské příspěvky byly úspěšně přepočítány.',
'fees have been successfully deducted, %d new transfers created' => 'Členské příspěvky byly úspěšně strženy, vytvořeno %d nových převodů.',
'fees have been successfully recalculated, %d deleted transfers, %d created new transfers' => 'Členské příspěvky byly úspěšně přepočítány, smazáno %d převodů, vytvořeno %d nových převodů.',
'fees have not been set!' => 'Členské příspěvky nebyly nastaveny!',
'fifth-degree certified engineers' => 'Certifikování technici pátého stupně',
'file' => 'Soubor',
......
'ignore whitelist' => 'Ignorovat whitelist',
'import dhcp export from mikrotik' => 'Import exportu DHCP z Mikrotiku',
'import has been successfully finished' => 'Import byl úspěšně dokončen.',
'import has failed' => 'Import selhal.',
'import new invoice' => 'Import nové faktury',
'import private contact' => 'Importovat soukromé kontakty',
'import contact from server funanbol' => 'Importovat kontakty ze serveru Funanbol',
......
'in hours' => 'V hodinách',
'inactive' => 'Neaktivní',
'inbound' => 'Příchozí',
'incomes' => 'Příjmy',
'incoming member payment' => 'Příchozí členské příspěvky',
'incoming member payment in the period' => 'Příchozí členské příspěvky v období',
'increase of members' => 'Přírůstek členů',
......
'read-only tariff cannot be deleted' => 'Tarif pouze pro čtení nelze mazat.',
'read-only tariff cannot be edited' => 'Tarif pouze pro čtení nelze editovat.',
'really delete this account' => 'Opravdu smazat tento účet',
'recalculate account balances' => 'Přepočítat zůstatky na účtech',
'recipient information' => 'Informace o příjemci',
'received member fees' => 'Přijaté členské příspěvky',
'received' => 'Přijatá',
......
'specific symbol' => 'Specifický symbol',
'start amount' => 'Počáteční částka',
'static ip' => 'Statická IP',
'statistics' => 'Statistiky',
'state' => 'Stav',
'statement' => 'Výpis',
'statement number' => 'Číslo výpisu',
......
'suffix has to start with slash character and has to end with slash character' => 'Přípona musí začínat lomítkem a musí končit lomítkem.',
'suggest amount' => 'Navrhovaná částka',
'sum' => 'Součet',
'summary' => 'Sumarizace',
'summary' => 'Shrnutí',
'supplier' => 'Dodavatel',
'suppliers account' => 'Účet dodavatelů',
'surname' => 'Příjmení',
freenetis/trunk/kohana/application/i18n/cs_CZ/help.php
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This array contains czech help and hints to specific fields in tables and forms.
* @author Jiri Svitak
* @license <http://www.gnu.org/licenses/> GNU/GPLv3
*/
$lang = array
(
'access_to_system' => 'Určuje, zda-li má uživatel možnost přihlásit se do systému Freenetis a zda má možnost využívat služeb Radius serveru napojeného na Freenetis, tedy například VPN, aktivní prvky sítě, volání z VoIP účtu atd.',
'accounting_system' => 'Účetní osnova je hlavní pomocník pro účetního sdružení. Zobrazuje sumu peněz na účtu z pohledu účetní osnovy. Ve výchozím stavu je to částka za celou dobu fungování sdružení, lze ovšem vyfiltrovat rok, např. 2011, nebo konkrétní měsíc, např. 2011-02.',
'accounting_system' => 'Účetní osnova je hlavní pomocník pro účetního sdružení. Zobrazuje sumu peněz na účtu z pohledu účetní osnovy. Ve výchozím stavu je to částka za celou dobu fungování sdružení, lze ovšem vyfiltrovat převody za zvolené období, např. od data 2009-01-01 do data 2009-12-31.',
'add_new_bank_transfer' => 'Umožňuje přidat ručně nový bankovní převod, který ma zdrojový i cílový účet. Typicky jde o fakturu nebo členský příspěvek. V běžném provozu využívejte automatický import výpisů. Ruční přidávání je tu pouze z důvodu, že byla potřeba dát do systému staré platby, které již byly jen v textovém formátu a nebylo možné je parsovat.',
'add_new_bank_transfer_without_counteraccount' => 'Umožňuje přidat bankovní převod bez protiúčtu, jde typicky o vklad, úrok bance apod. V běžném provozu využívejte automatický import výpisů. Ruční přidávání je tu pouze z důvodu, že byla potřeba dát do systému staré platby, které již nebylo možné parsovat.',
'add_new_transfer' => 'Zobrazí formulář, který umožňuje hospodáři sdružení přidat libovolný převod mezi dvěma podvojnými účty. Účetní korektnost tohoto zásahu je ovšem v zodpovědnosti účetního.',
'add_from_account' => 'Umožňuje poslat peníze z účtu na jiný účet. Například člen může poslat peníze na projektový účet na podporu nějakého projektu nebo jinému členovi, např. zaplatit rodičům internet, pokud mají samostatnou přípojku.',
'application_password' => 'Aplikační heslo slouží uživateli pro přihlášení ke službám, které jsou závislé na Radius serveru, jako například VPN, aktivní prvky sítě atd. Toto heslo je v databázi uloženo v otevřené podobě.',
......
'password' => 'Uživatelské heslo musí obsahovat alespoň 8 znaků a musí obsahovat alespoň jedno písmeno nebo číslici.',
'payed_to' => 'Datum, do kdy máte zaplaceny členské příspěvky. Včas před tímto datem byste měli zaplatit členské příspěvky. V případě, že jste s kreditem v mínusu, tak zaplaťte co nejdříve, jinak budete zablokováni.',
'project_subaccounts' => 'Projektový účet 221103 pro účetního představuje jeden účet. Zde jsou ovšem rozepsány všechny projektové podúčty z pohledu Freenetisu. Každý člen má právo vytvořit svůj projekt, který je v souladu se stanovami sdružení, může jít například o nějakou akci nebo školení. Cílem takovéhoto projektového podúčtu je, aby ostatní členové měli možnost zakladateli projektu přispět peníze ze svého kreditního účtu na realizaci projektu.',
'recount_fees' => 'Pro primární strhávání členských příspěvků používejte funkci pro globální strhávání členských příspěvků v Účetním deníku. Tuto funkci používejte opatrně a to jen v případě, že máte správně strženy všechny členské příspěvky pro všechny členy od založení sdružení až po současné datum. Pak můžete tomuto členovi přepočítat stržení členských příspěvků v případě, že u něj došlo k nutnosti je přepočítat, např. chybné datum vstupu, vznikla nutnost přidat přerušení členství apod.',
'recount_entrance_fees' => 'Pro primární strhávání vstupních příspěvků používejte funkci pro globální strhávání v účetním deníku. Tuto funkci používejte jen v případě, že došlo k nějakému omylu, například, že měl zaplatit vstupní a pak se ukázalo, že nemusel.',
'recalculate_account_balances' => 'Primárním zdrojem o stavu financí v systému jsou převody. Zůstatky na účtech byly dříve pokaždé počítány na požádání z převodů. Nyní si každý účet ukládá svůj zůstatek kvůli vyšší rychlosti. Tuto funkci použijete v případě přechodu na verzi systému, která tuto optimalizaci obsahuje.',
'recalculate_fees' => 'Pro primární strhávání členských příspěvků používejte funkci pro globální strhávání členských příspěvků v Účetním deníku. Tuto funkci používejte opatrně a to jen v případě, že máte správně strženy všechny členské příspěvky pro všechny členy od založení sdružení až po současné datum. Pak můžete tomuto členovi přepočítat stržení členských příspěvků v případě, že u něj došlo k nutnosti je přepočítat, např. chybné datum vstupu, vznikla nutnost přidat přerušení členství apod.',
'recalculate_entrance_fees' => 'Pro primární strhávání vstupních příspěvků používejte funkci pro globální strhávání v účetním deníku. Tuto funkci používejte jen v případě, že došlo k nějakému omylu, například, že měl zaplatit vstupní a pak se ukázalo, že nemusel.',
'unidentified_transfers' => 'Neidentifikované platby jsou všechny příchozí bankovní platby, které nebyl náš systém schopen z různých důvodů automaticky rozpoznat. Typicky se jedná o platby s chybným variabilním symbolem. Pokud zde svoji platbu najdete, pak kontaktujte hospodáře sdružení pro její správné přiřazení.',
'variable_symbol' => 'Variabilní symbol slouží k jednoznačnému určení příchozí platby člena.'
);
freenetis/trunk/kohana/application/models/bank_transfer.php
CONCAT(dba.account_nr, '/', dba.bank_nr) AS dba_number,
m2.id AS dba_member_id, m2.name AS dba_member_name,
t.id, t.origin_id, t.destination_id, t.datetime, t.creation_datetime, t.text, t.amount,
bt.id AS bt_id, bt.variable_symbol, bt.constant_symbol, bt.specific_symbol
bt.id AS bt_id, bt.variable_symbol, bt.constant_symbol, bt.specific_symbol, bt.bank_statement_id
FROM transfers t
JOIN bank_transfers bt ON t.id = bt.transfer_id
LEFT JOIN bank_accounts oba ON oba.id = bt.origin_id
......
AND bt.variable_symbol $cond_vs";
return $this->db->query($q);
}
}
?>
freenetis/trunk/kohana/application/models/member.php
m.id, m.registration, m.name,
s.street, ap.street_number, t.town, t.quarter,
m.variable_symbol, a.id AS aid,
(q2.inbound - q2.outbound) AS balance,
a.balance,
m.redirect
FROM members m
LEFT JOIN address_points ap ON m.address_point_id = ap.id
LEFT JOIN streets s ON ap.street_id = s.id
LEFT JOIN towns t ON ap.town_id = t.id
LEFT JOIN accounts a ON a.member_id = m.id AND m.id <> 1
LEFT JOIN
(
SELECT q1.id, q1.inbound, IFNULL(SUM(t.amount),0) AS outbound
FROM
(
SELECT a.id, IFNULL(SUM(t.amount),0) AS inbound
FROM accounts a
LEFT JOIN transfers t ON t.destination_id = a.id
GROUP BY a.id
) q1
LEFT JOIN transfers t ON t.origin_id = q1.id
GROUP BY q1.id
) q2 ON q2.id = a.id
$where
ORDER BY $order_by $order_by_direction
LIMIT $limit_from, $limit_results"
freenetis/trunk/kohana/application/models/account.php
$where .= 'account_attribute_id = '.Account_attribute_Model::$credit;
else
$where .= 'account_attribute_id <> '.Account_attribute_Model::$project.
' AND account_attribute_id <> '.Account_attribute_Model::$credit;
$datetime1 = '';
$datetime2 = '';
' AND account_attribute_id <> '.Account_attribute_Model::$credit;
// default datetime of transfers
$datetime_from_t1 = " AND t1.datetime >= '0000-00-00'";
$datetime_to_t1 = " AND t1.datetime <= '9999-12-31'";
$datetime_from_t2 = " AND t2.datetime >= '0000-00-00'";
$datetime_to_t2 = " AND t2.datetime <= '9999-12-31'";
foreach ($filter_values as $key => $value)
{
if ($key != 'submit' && $key != 'datetime')
if ($key == 'name')
{
$where .= ' AND ';
if ($key == 'name')
$where .= "a.name LIKE '%".$value."%' COLLATE utf8_general_ci";
$where .= "a.name LIKE '%".$value."%' COLLATE utf8_general_ci";
}
if ($key == 'datetime')
if ($key == 'datetime_from')
{
$datetime1 = " AND t1.datetime LIKE '%".$value."%' COLLATE utf8_general_ci";
$datetime2 = " AND t2.datetime LIKE '%".$value."%' COLLATE utf8_general_ci";
$datetime_from_t1 = " AND t1.datetime >= '$value'";
$datetime_from_t2 = " AND t2.datetime >= '$value'";
}
if ($key == 'datetime_to')
{
$datetime_to_t1 = " AND t1.datetime <= '$value'";
$datetime_to_t2 = " AND t2.datetime <= '$value'";
}
}
// query
return $this->db->query("
......
IFNULL(SUM(amount), 0) AS outbound
FROM accounts a
LEFT JOIN members m ON m.id = a.member_id
LEFT JOIN transfers t1 ON a.id = t1.origin_id $datetime1
LEFT JOIN transfers t1 ON a.id = t1.origin_id $datetime_from_t1 $datetime_to_t1
$where
GROUP BY a.id
) q1
LEFT JOIN transfers t2 ON q1.id = t2.destination_id $datetime2
$where
LEFT JOIN transfers t2 ON q1.id = t2.destination_id $datetime_from_t2 $datetime_to_t2
GROUP BY q1.id
) q2
ORDER BY $order_by $order_by_direction
......
' AND account_attribute_id <> '.Account_attribute_Model::$credit;
foreach ($filter_values as $key => $value)
{
if ($key != 'submit' && $key != 'datetime')
if ($key == 'name')
{
$where .= ' AND ';
if ($key == 'name')
$where .= "a.name LIKE '%".$value."%' COLLATE utf8_general_ci";
$where .= "a.name LIKE '%".$value."%' COLLATE utf8_general_ci";
}
}
return $this->db->query("
......
public function get_accounts_to_deduct($date)
{
return $this->db->query("
SELECT a.id, m.entrance_date, m.leaving_date,
SELECT a.id, a.balance, m.entrance_date, m.leaving_date,
IF(mf.fee IS NOT NULL, 1, 0) fee_is_set,
mf.fee,
mf.readonly AS fee_readonly,
mf.name AS fee_name
mf.name AS fee_name,
IF(t.id IS NULL, 0, t.id) AS transfer_id
FROM accounts a
JOIN members m ON a.member_id = m.id
LEFT JOIN enum_types e ON e.id = m.type
......
ORDER BY member_id, priority) q
GROUP BY q.member_id
) mf ON m.id = mf.member_id
LEFT JOIN transfers t ON t.origin_id = a.id AND t.type = ".Transfer_Model::$deduct_member_fee." AND t.datetime = '$date'
WHERE m.id <> 1 AND m.entrance_date < '$date'
AND (m.leaving_date = '0000-00-00'
OR (m.leaving_date <> '0000-00-00' AND m.leaving_date > '$date'))
......
");
}
/**
* Function deletes deducting transfers of given account.
* @author Jiri Svitak
* @param $account_id
* @return unknown_type
*/
public function delete_deduct_transfers_of_account($account_id)
{
$this->db->query("DELETE FROM transfers WHERE type = ".Transfer_Model::$deduct_member_fee."
AND origin_id = $account_id");
}
/**
* Gets information important to correctly deduct fees. Used for recounting
......
* @author Jiri Svitak
* @param unknown_type $account_id
*/
function get_account_to_recount_entrance_fees($account_id)
function get_account_to_recalculate_entrance_fees($account_id)
{
return $this->db->query("
SELECT a.id, m.entrance_fee, m.debt_payment_rate, m.entrance_date, t.id AS transfer_id, t.amount
SELECT a.id, m.entrance_fee, m.debt_payment_rate, m.entrance_date
FROM accounts a
JOIN members m ON a.member_id = m.id AND m.id <> 1
LEFT JOIN transfers t ON t.origin_id = a.id AND t.type = ".Transfer_Model::$deduct_entrance_fee."
WHERE a.account_attribute_id = ".Account_attribute_Model::$credit." AND a.id = $account_id
");
}
/**
* Function deletes member fee deducting transfers of given account.
* @author Jiri Svitak
* @param $account_id
* @return unknown_type
*/
public function delete_deduct_transfers_of_account($account_id)
{
$transfers = ORM::factory('transfer')->where(array('type' => Transfer_Model::$deduct_member_fee,
'origin_id' => $account_id))->find_all();
$transfers_count = 0;
foreach ($transfers as $transfer)
{
$transfers_count++;
if (!$transfer->delete())
throw new ErrorException();
}
// recalculate balance of current credit account
if (!$this->recalculate_account_balance_of_account($account_id))
throw new ErrorException();
// recalculate balance of operating account
$operating = ORM::factory('account')->where(array('account_attribute_id' => Account_attribute_Model::$operating))->find();
if (!$this->recalculate_account_balance_of_account($operating->id))
throw new ErrorException();
return $transfers_count;
}
/**
* Function deletes entrance fee deducting transfers of given account.
* @author Jiri Svitak
* @param $account_id
......
*/
public function delete_entrance_deduct_transfers_of_account($account_id)
{
$this->db->query("DELETE FROM transfers WHERE type = ".Transfer_Model::$deduct_entrance_fee."
AND origin_id = $account_id");
$transfers = ORM::factory('transfer')->where(array('type' => Transfer_Model::$deduct_entrance_fee,
'origin_id' => $account_id))->find_all();
$transfers_count = 0;
foreach ($transfers as $transfer)
{
$transfers_count++;
if (!$transfer->delete())
throw new ErrorException();
}
// recalculate balance of current credit account
if (!$this->recalculate_account_balance_of_account($account_id))
throw new ErrorException();
// recalculate balance of operating account
$operating = ORM::factory('account')->where(array('account_attribute_id' => Account_attribute_Model::$infrastructure))->find();
if (!$this->recalculate_account_balance_of_account($operating->id))
throw new ErrorException();
return $transfers_count;
}
......
ORDER BY d.buy_date ASC
");
}
/**
* Recalculates all account balances.
* @author Jiri Svitak
* @return int count of accounts with corrected balances
*/
public function recalculate_account_balances()
{
$accounts = $this->db->query("
SELECT q2.*, (inbound - outbound) AS calculated_balance
FROM
(
SELECT q1.*, IFNULL(SUM(amount), 0) AS inbound
FROM
(
SELECT a.*, IFNULL(SUM(amount), 0) AS outbound
FROM accounts a
LEFT JOIN members m ON m.id = a.member_id
LEFT JOIN transfers t1 ON a.id = t1.origin_id
GROUP BY a.id
) q1
LEFT JOIN transfers t2 ON q1.id = t2.destination_id
GROUP BY q1.id
) q2
");
// create update sql query
$sql = "UPDATE accounts SET balance = CASE id ";
// incorrect balances
$incorrect_balances = 0;
// array of ids to change
$ids = array();
foreach ($accounts as $account)
{
if ($account->balance != $account->calculated_balance)
{
$incorrect_balances++;
$sql .= "WHEN $account->id THEN $account->calculated_balance ";
$ids[] = $account->id;
}
}
// are there some accounts with incorrect balances? save correct balances
if ($incorrect_balances > 0)
{
$ids_with_commas = implode(',', $ids);
$sql .= "END WHERE id IN ($ids_with_commas)";
$db = new Database();
$db->query($sql);
}
return $incorrect_balances;
}
/**
* Recalculates account balance of single account.
* @author Jiri Svitak
* @param <type> $account_id
*/
public function recalculate_account_balance_of_account($account_id)
{
$account_model = new Account_Model();
$balance = $account_model->get_account_balance($account_id);
return $this->db->query("UPDATE accounts SET balance = '$balance' WHERE id = $account_id");
}
}
freenetis/trunk/kohana/application/models/account_attribute.php
public function get_accounting_system($limit_from = 0, $limit_results = 20, $order_by = 'id', $order_by_direction = 'asc', $filter_values = array())
{
$where = '';
$datetime1 = '';
$datetime2 = '';
$datetime_from_t1 = " AND t1.datetime >= '0000-00-00'";
$datetime_to_t1 = " AND t1.datetime <= '9999-12-31'";
$datetime_from_t2 = " AND t2.datetime >= '0000-00-00'";
$datetime_to_t2 = " AND t2.datetime <= '9999-12-31'";
foreach ($filter_values as $key => $value)
{
if ($key == 'name')
{
$where = " WHERE aa.name LIKE '%".$value."%' COLLATE utf8_general_ci";
}
if ($key == 'datetime')
if ($key == 'datetime_from')
{
$datetime1 = " AND t1.datetime LIKE '%".$value."%' COLLATE utf8_general_ci";
$datetime2 = " AND t2.datetime LIKE '%".$value."%' COLLATE utf8_general_ci";
$datetime_from_t1 = " AND t1.datetime >= '$value'";
$datetime_from_t2 = " AND t2.datetime >= '$value'";
}
if ($key == 'datetime_to')
{
$datetime_to_t1 = " AND t1.datetime <= '$value'";
$datetime_to_t2 = " AND t2.datetime <= '$value'";
}
}
// query
return $this->db->query("
......
(SELECT a.id, a.account_attribute_id
FROM accounts a
) q0
LEFT JOIN transfers t1 ON q0.id = t1.origin_id $datetime1
LEFT JOIN transfers t1 ON q0.id = t1.origin_id $datetime_from_t1 $datetime_to_t1
GROUP BY q0.id
) q1
LEFT JOIN transfers t2 ON q1.id = t2.destination_id $datetime2
LEFT JOIN transfers t2 ON q1.id = t2.destination_id $datetime_from_t2 $datetime_to_t2
GROUP BY q1.id
) q2
) q3 ON aa.id = q3.account_attribute_id
freenetis/trunk/kohana/application/models/transfer.php
<?php
<?php
class Transfer_Model extends ORM
{
protected $belongs_to = array('origin' => 'account', 'destination' => 'account');
......
else
return NULL;
}
/**
* @author Jiri Svitak
* @param <type> $origin_id origin account id
* @param <type> $destination_id destination account id
* @param <type> $previous_transfer_id previous transfer id, useful for transfer groups
* @param <type> $member_id transaction owner id
* @param <type> $user_id id of user who added transfer
* @param <type> $type type of transfer, see Transfer_Model
* @param <type> $datetime accounting datetime of transfer
* @param <type> $creation_datetime datetime of transfer creation
* @param <type> $text transfer text
* @param <type> $amount amount of transfer
* @throws ErrorException when failed transfer insert, origin or destination account update
*/
public static function insert_transfer($origin_id, $destination_id, $previous_transfer_id,
$member_id, $user_id, $type, $datetime, $creation_datetime, $text, $amount)
{
// insert new transfer
$transfer = new Transfer_Model();
$transfer->origin_id = $origin_id;
$transfer->destination_id = $destination_id;
$transfer->previous_transfer_id = $previous_transfer_id;
$transfer->member_id = $member_id;
$transfer->user_id = $user_id;
$transfer->type = $type;
$transfer->datetime = $datetime;
$transfer->creation_datetime = $creation_datetime;
$transfer->text = $text;
$transfer->amount = $amount;
if (!$transfer->save())
throw new ErrorException();
// update balance of origin account
$oa = new Account_Model($origin_id);
$oa->balance -= $amount;
if (!$oa->save())
throw new ErrorException();
// update balance of destination account
$da = new Account_Model($destination_id);
$da->balance += $amount;
if (!$da->save())
throw new ErrorException();
return $transfer->id;
}
/**
* Edits transfers safely with change of dependent account balance.
* @author Jiri Svitak
* @param <type> $id
* @param <type> $text
* @param <type> $amount
*/
public static function edit_transfer($id, $text, $amount)
{
// update transfer
$transfer = new Transfer_Model($id);
$transfer->text = $text;
$transfer->amount = $amount;
if (!$transfer->save())
throw new ErrorException();
// update balance of origin account
$oa = new Account_Model($transfer->origin_id);
$oa->balance -= $amount;
if (!$oa->save())
throw new ErrorException();
// update balance of destination account
$da = new Account_Model($transfer->destination_id);
$da->balance += $amount;
if (!$da->save())
throw new ErrorException();
}
/**
* Safely deletes transfer.
* @author Jiri Svitak
* @param <type> $id
*/
public static function delete_transfer($id)
{
$transfer = new Transfer_Model($id);
// update balance of origin account
$oa = new Account_Model($transfer->origin_id);
$oa->balance += $transfer->amount;
if (!$oa->save())
throw new ErrorException();
// update balance of destination account
$da = new Account_Model($transfer->destination_id);
$da->balance -= $transfer->amount;
if (!$da->save())
throw new ErrorException();
// delete transfer
if (!$transfer->delete())
throw new ErrorException();
}
}
?>
freenetis/trunk/kohana/application/controllers/transfers.php
* Handles double-entry transfers and special actions with transfers like deducting fees etc.
*
* @author Jiri Svitak
* @license GNU/GPL
* @TODO Several methods use database transaction processing, but it seems that Kohana (?) uses
* in one run multiple database connections, so these transactions are not fully fuctional (ROLLBACK).
* @license <http://www.gnu.org/licenses/> GNU/GPLv3
*
*/
class Transfers_Controller extends Controller
{
// used for storing id of origin account for callback function
protected $origin;
/**
* @author Jiri Svitak
* By default, it redirects user to day book - list of all double-entry transfers.
......
{
if (!$this->acl_check_view('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
$this->session->del('ssAccount_id');
// get new selector
if (is_numeric($this->input->get('record_per_page')))
$limit_results = (int) $this->input->get('record_per_page');
......
{
Controller::error(ACCESS);
}
$this->session->set('ssAccount_id', $account_id);
// gets grid settings
if (is_numeric($this->input->get('record_per_page')))
$limit_results = (int) $this->input->get('record_per_page');
......
$balance = $inbound = $outbound = 0;
if (count($transfers) > 0)
{
// inbound and outbound amount of money are calculated from transfers of account
$inbound = $transfers->current()->inbound;
$outbound = $transfers->current()->outbound;
$balance = $inbound - $outbound;
// balance is not calculated, fast redundant value from account itself is used
$balance = $account->balance;
}
// headline
$headline = url_lang::lang('texts.Transfers of double-entry account');
......
if ($account->account_attribute_id == Account_attribute_Model::$credit)
{
if ($this->acl_check_edit('Accounts_Controller', 'transfers'))
$grid->add_new_button(url_lang::base().'transfers/recount_fees/'.$account->id, url_lang::lang('texts.Recount of member fees'), array('onclick' => 'return potvrd(\''.url_lang::lang('texts.Are you sure you want to recount fees of this member').'\')'), help::hint('recount_fees'));
$grid->add_new_button(url_lang::base().'transfers/recalculate_fees/'.$account->id, url_lang::lang('texts.Recount of member fees'), array('onclick' => 'return potvrd(\''.url_lang::lang('texts.Are you sure you want to recount fees of this member').'\')'), help::hint('recalculate_fees'));
if ($this->acl_check_edit('Accounts_Controller', 'transfers'))
$grid->add_new_button(url_lang::base().'transfers/recount_entrance_fees/'.$account->id, url_lang::lang('texts.Recount of entrance fees'), array('onclick' => 'return potvrd(\''.url_lang::lang('texts.Are you sure you want to recount entrance fees of this member').'\')'), help::hint('recount_entrance_fees'));
$grid->add_new_button(url_lang::base().'transfers/recalculate_entrance_fees/'.$account->id, url_lang::lang('texts.Recount of entrance fees'), array('onclick' => 'return potvrd(\''.url_lang::lang('texts.Are you sure you want to recount entrance fees of this member').'\')'), help::hint('recalculate_entrance_fees'));
}
$grid->order_field('id')->label('ID');
//$grid->order_field('trans_type')->label(url_lang::lang('texts.Type'))->bool(array(url_lang::lang('texts.Inbound'),url_lang::lang('texts.Outbound')));
......
{
$form_data[$key] = htmlspecialchars($value);
}
$transfer = new Transfer_Model();
$transfer->origin_id = $form_data['oname'];
$transfer->destination_id = $form_data['aname'];
$transfer->user_id = $this->session->get('user_id');
$transfer->datetime = date('Y-m-d', $form_data['datetime']);
$transfer->creation_datetime = date('Y-m-d H:i:s');
$transfer->text = $form_data['text'];
$transfer->amount = $form_data['amount'];
if ($transfer->save())
try
{
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully added'));
url::redirect(url_lang::base().'transfers/show_by_account/'.$origin_account_id);
$db = new Transfer_Model();
$db->transaction_start();
Transfer_Model::insert_transfer($form_data['oname'], $form_data['aname'], null,
null, $this->session->get('user_id'), null, date('Y-m-d', $form_data['datetime']),
date('Y-m-d H:i:s'), $form_data['text'], $form_data['amount']);
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully added.'));
}
catch (ErrorException $e)
{
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Error - cannot add new transfer.'));
}
url::redirect(url_lang::base().'transfers/show_by_account/'.$origin_account_id);
}
//if ($this->acl_check_view('Members_Controller','members', $origin_account->member_id))
......
$accounts = $account_model->get_some_doubleentry_account_names();
$origin_accounts = $accounts;
$dst_accounts = $accounts;
foreach ($dst_accounts as $dst_account)
{
$arr_dst_accounts[$dst_account->id] = $dst_account->name.' '.$dst_account->id.' ('.$dst_account->addr.')';
......
{
$form_data[$key] = htmlspecialchars($value);
}
$transfer = new Transfer_Model();
$transfer->origin_id = $form_data['oname'];
$transfer->destination_id = $form_data['aname'];
$transfer->user_id = $this->session->get('user_id');
$transfer->datetime = date('Y-m-d', $form_data['datetime']);
$transfer->creation_datetime = date('Y-m-d H:i:s');
$transfer->text = $form_data['text'];
$transfer->amount = $form_data['amount'];
if ($transfer->save())
try
{
$db = new Transfer_Model();
$db->transaction_start();
Transfer_Model::insert_transfer($form_data['oname'], $form_data['aname'], null,
null, $this->session->get('user_id'), null, date('Y-m-d', $form_data['datetime']),
date('Y-m-d H:i:s'), $form_data['text'], $form_data['amount']);
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully added.'));
}
catch (ErrorException $e)
{
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully added'));
url::redirect(url_lang::base().'transfers/show_all');
}
url::redirect(url_lang::base().'transfers/show_all');
}
$links[] = html::anchor(url_lang::base().'transfers/show_all', url_lang::lang('texts.Back to day book'));
$headline = url_lang::lang('texts.Add new transfer');
$view = new View('main');
......
{
if (!isset($origin_account))
Controller::warning(PARAMETER);
$billing = new Billing();
$account= ORM::factory('account')->where('id', $origin_account)->find();
if (!$billing->has_driver() || ($billing->get_account($account->member_id) == null))
Controller::error(RECORD);
if (isset($origin_account)) { // transfer from specific account ?
$this->origin = $origin_account; // save for callback function valid_amount_to_send
$origin_acc = new Account_Model($origin_account);
......
$origin_acc = new Account_Model(); // yes = create object of all accounts
$dst_accounts = $origin_accounts = $origin_acc->get_some_doubleentry_account_names();
}
$arr_orig_accounts[$origin_acc->id] =
"$origin_acc->name - ".url_lang::lang('texts.Account ID')." $origin_acc->name - "
.url_lang::lang('texts.Member ID')." $origin_acc->member_id";
// form
$form = new Forge(url_lang::base().'transfers/add_voip/'.$origin_account, '', 'POST', array('id' => 'article_form'));
$form->set_attr('class', 'form_class')->set_attr('method', 'post');
......
special::required_forge_style($form, ' *', 'required');
if ($form->validate())
{
// default destination account
$operating = ORM::factory('account')->where('account_attribute_id', Account_attribute_Model::$operating)->find();
$text = url_lang::lang('texts.Recharging of VoIP credit');
$form_data = $form->as_array();
foreach($form_data as $key => $value)
{
$form_data[$key] = htmlspecialchars($value);
}
$transfer = new Transfer_Model();
$transfer->origin_id = $form_data['oname'];
$transfer->destination_id = $operating->id;
$transfer->user_id = $this->session->get('user_id');
$transfer->type = Transfer_Model::$deduct_voip_unnaccounted_fee;
$transfer->datetime = date('Y-m-d', $form_data['datetime']);
$transfer->creation_datetime = date('Y-m-d H:i:s', time());
$transfer->text = $text;
$transfer->amount = $form_data['amount'];
if ($transfer->save())
try
{
$db = new Transfer_Model();
$db->transaction_start();
Transfer_Model::insert_transfer($form_data['oname'], $operating->id, null,
null, $this->session->get('user_id'), Transfer_Model::$deduct_voip_unnaccounted_fee,
date('Y-m-d', $form_data['datetime']),
date('Y-m-d H:i:s'), $text, $form_data['amount']);
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully added.'));
}
catch (ErrorException $e)
{
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully added'));
url::redirect(url_lang::base().'transfers/show_by_account/'.$origin_account);
}
url::redirect(url_lang::base().'transfers/show_by_account/'.$origin_account);
}
if ($this->acl_check_view('Members_Controller','members', $account->member_id))
$links[] = html::anchor(url_lang::base().'members/show/'.$account->member_id, url_lang::lang('texts.Back to the member'));
$links[] = html::anchor(url_lang::base().'transfers/show_by_account/'.$origin_account, url_lang::lang('texts.Back to transfers of account'));
$headline = url_lang::lang('texts.Add new VoIP transfer');
$info[] = url_lang::lang('texts.Information').' : '.url_lang::lang('texts.Transfer will be effected within 15 minutes.');
$view = new View('main');
$view->title = $headline;
$view->content = new View('form');
......
{
if (!isset($transfer_id))
Controller::warning(PARAMETER);
$ssAccount_id = $this->session->get('ssAccount_id');
// access rights
if (!$this->acl_check_edit('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
......
if($form->validate())
{
$form_data = $form->as_array();
$transfer->text = htmlspecialchars($form_data['text']);
$transfer->amount = htmlspecialchars($form_data['amount']);
unset($form_data);
if ($transfer->save())
try
{
$db = new Transfer_Model();
$db->transaction_start();
Transfer_Model::edit_transfer($transfer_id, htmlspecialchars($form_data['text']), htmlspecialchars($form_data['amount']));
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Transfer has been successfully updated.'));
else
url::redirect(url_lang::base().'transfers/show/'.$transfer_id);
}
catch (ErrorException $e)
{
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Error - cant update transfer.'));
if ($ssAccount_id)
url::redirect(url_lang::base().'transfers/show_by_account/'.$ssAccount_id);
else
url::redirect(url_lang::base().'transfers/show_all');
url::redirect(url_lang::base().'transfers/show/'.$transfer_id);
}
}
else
{
$headline = url_lang::lang('texts.Editing of transfer');
$links[] = html::anchor(url_lang::base().'transfers/show_by_account/'.$ssAccount_id, url_lang::lang('texts.Back to transfers of account'));
$view = new View('main');
$view->title = $headline;
$view->content = new View('form');
$view->content->headline = $headline;
$view->content->form = $form->html();
if ($ssAccount_id)
$view->content->link_back = html::anchor(url_lang::base().'transfers/show_by_account/'.$ssAccount_id, url_lang::lang('texts.Back to transfers of account'));
else
$view->content->link_back = html::anchor(url_lang::base().'transfers/show_all', url_lang::lang('texts.Back to day book'));
$view->content->link_back = implode (' | ', $links);
$view->render(TRUE);
}
}
/**
* Deducts fees of all members in one month. Instead of one transfer per year this function deducts
* one transfer per month. It is possible to recount member fees by deleting previous
* member fee transfers and creating new ones.
* Deducts fees of all members in one month. If deduct transfer for one month and
* account is found, then it is ignored and skipped.
* @author Jiri Svitak
* @return unknown_type
*/
......
// access rights
if (!$this->acl_check_new('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
// content of dropdown for months
for ($i = 1; $i <= 12; $i++)
$arr_months[$i] = $i;
......
$form->dropdown('month')->label(url_lang::lang('texts.Month').':')->rules('required')->options($arr_months)->selected($current_month)->callback(array($this, 'valid_default_fee'));
$form->submit('submit')->value(url_lang::lang('texts.Deduct'));
special::required_forge_style($form, ' *', 'required');
// form validation
if ($form->validate())
{
// access rights
if (!$this->acl_check_new('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
$form_data = $form->as_array();
foreach($form_data as $key => $value)
$form_data[$key] = htmlspecialchars($value);
// preparation
$created_transfers_count = 0;
$total_amount = 0;
$date = date('Y-m-d', mktime(0, 0, 0, $form_data['month'], 15, $arr_years[$form_data['year']]));
$creation_datetime = date('Y-m-d H:i:s');
$user_id = $this->session->get('user_id');
// finds default fee
$fee_model = new Fee_Model();
$fee = $fee_model->get_default_fee_by_date_type($date, 'regular member fee');
if ($fee && $fee->id)
{
$default_fee = $fee->fee;
}
else
throw new Kohana_User_Exception(url_lang::lang('texts.Fatal error'), url_lang::lang('texts.Fees have not been set!'));
// test if there exist already deduct transfer for given month
$transfer = ORM::factory('transfer')->
like(array('type' => Transfer_Model::$deduct_member_fee, 'datetime' => $date))->find_all();
if (count($transfer) > 0)
{
$this->session->set_flash('message', url_lang::lang('texts.This month has been already deducted!'));
$this->session->set_flash('message', url_lang::lang('texts.Fees have not been set!'));
url::redirect(url_lang::base().'transfers/show_all');
}
$operating = ORM::factory('account')->
where('account_attribute_id', Account_attribute_Model::$operating)->find();
$text = url_lang::lang('texts.Deduction of member fee');
$database = new Database();
$account_model = new Account_Model();
$accounts = $account_model->get_accounts_to_deduct($date);
$save_successful = true;
foreach ($accounts as $account)
try
{
$transfer = new Transfer_Model();
$transfer->origin_id = $account->id;
$transfer->destination_id = $operating->id;
$transfer->user_id = $this->session->get('user_id');
$transfer->type = Transfer_Model::$deduct_member_fee;
$transfer->datetime = $date;
$transfer->creation_datetime = $creation_datetime;
$transfer->text = $text;
if ($account->fee_is_set)
$db = new Transfer_Model();
$db->transaction_start();
// first sql for inserting transfers
$sql_insert = "INSERT INTO transfers (origin_id, destination_id, previous_transfer_id, member_id, user_id, type, datetime, creation_datetime, text, amount) VALUES ";
$values = array();
// second sql for updating accounts
$sql_update = "UPDATE accounts SET balance = CASE id ";
$ids = array();
// main cycle
foreach ($accounts as $account)
{
$transfer->amount = $account->fee;
$transfer->text = ($account->fee_readonly) ? $text.' - '.url_lang::lang('texts.'.$account->fee_name) : $text.' - '.$account->fee_name;
// no deduct transfer for this date and account generated? then create one
if ($account->transfer_id == 0)
{
$text = url_lang::lang('texts.Deduction of member fee');
if ($account->fee_is_set)
{
$amount = $account->fee;
$text = ($account->fee_readonly) ? $text.' - '.url_lang::lang('texts.'.$account->fee_name) : $text.' - '.$account->fee_name;
}
else
{
$amount = $default_fee;
}
// is amount bigger than zero?
if ($amount > 0)
{
// insert
$values[] = "($account->id, $operating->id, NULL, NULL, $user_id, ".Transfer_Model::$deduct_member_fee.", '$date', '$creation_datetime', '$text', $amount)";
// update
$sql_update .= "WHEN $account->id THEN ".($account->balance - $amount)." ";
$ids[] = $account->id;
$total_amount += $amount;
$created_transfers_count++;
}
}
}
else
if ($created_transfers_count > 0)
{
$transfer->amount = $default_fee;
$transfer->text = $text;
// single query for inserting transfers
$sql_insert .= implode(",", $values);
if (!$database->query($sql_insert))
throw new ErrorException();
// single query for updating credit account balances
$ids_with_commas = implode(",", $ids);
$sql_update .= "END WHERE id IN ($ids_with_commas)";
if (!$database->query($sql_update))
throw new ErrorException();
// update also balance of operating account
if (!$account_model->recalculate_account_balance_of_account($operating->id))
throw new ErrorException();
}
if (!$transfer->save())
$save_successful = false;
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Fees have been successfully deducted, %d new transfers created.', $created_transfers_count));
}
if ($save_successful)
catch(ErrorException $e)
{
$this->session->set_flash('message', url_lang::lang('texts.Fees have been successfully deducted.'));
}
else
{
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Error - some fees have not been deducted.'));
}
url::redirect(url_lang::base().'transfers/show_all');
......
}
/**
* Function recounts wrong deducted fees of given account of member.
* Function recalculates wrong deducted fees of given account of member.
* @author Jiri Svitak
* @return unknown_type
*/
function recount_fees($account_id = 0)
function recalculate_fees($account_id = 0)
{
// access control
if (!$this->acl_check_new('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
$account = new Account_Model($account_id);
// account doesn't exist
if (!$account->id)
Controller::error(RECORD);
// finds default fee
$fee_model = new Fee_Model();
$transfer = new Transfer_Model();
// finds member's entrance date
$entrance_date = date_parse($account->member->entrance_date);
$year = $entrance_date['year'];
$month = $entrance_date['month'];
$day = $entrance_date['day'];
// round entrance date
if ($day >= 15)
if ($day > 15)
{
$month++;
if ($month > 12)
{
$year++;
$month = 1;
}
}
// finds member's leaving date
if ($account->member->leaving_date != '0000-00-00')
{
$max_date = date_parse($account->member->leaving_date);
}
else
{
// find datetime of las deduct fee
$last_datetime = $transfer->find_last_transfer_datetime_by_type(Transfer_Model::$deduct_member_fee);
// find datetime of last deduct fee
$transfer_model = new Transfer_Model();
$last_datetime = $transfer_model->find_last_transfer_datetime_by_type(Transfer_Model::$deduct_member_fee);
if ($last_datetime)
$max_date = date_parse($last_datetime);
else
$max_date = date_parse(date('Y-m-d'));
}
$max_day = $max_date['day'];
$max_month = $max_date['month'];
$max_year = $max_date['year'];
// round max date
if ($max_day >= 15)
if ($max_day > 15)
{
$max_month++;
if ($max_month > 12)
{
$max_year++;
$max_month = 1;
}
}
// finds operating account
$operating = ORM::factory('account')->
where('account_attribute_id', Account_attribute_Model::$operating)->find();
// text of transfers
$text = url_lang::lang('texts.Deduction of member fee');
// creation datetime of transfers
$creation_datetime = date('Y-m-d H:i:s');
// deleting of old deduct transfer of member
$account->delete_deduct_transfers_of_account($account_id);
$save_successful = true;
$max_date = date('Y-m-d', mktime(0, 0, 0, $max_month, 15, $max_year));
while (($date = date('Y-m-d', mktime(0, 0, 0, $month, 15, $year))) < $max_date)
try
{
// finds default regular member fee for this month
$fee = $fee_model->get_default_fee_by_date_type($date, 'regular member fee');
if ($fee && $fee->id)
$default_fee = $fee->fee;
else
throw new Kohana_User_Exception(url_lang::lang('texts.Fatal error'), url_lang::lang('texts.Fees have not been set!'));
// creating new deduct transfer
$transfer->clear();
$transfer->origin_id = $account->id;
$transfer->destination_id = $operating->id;
$transfer->user_id = $this->session->get('user_id');
$transfer->type = Transfer_Model::$deduct_member_fee;
$transfer->datetime = $date;
$transfer->creation_datetime = $creation_datetime;
// finds regular member fee for this member and this month
$fee = $fee_model->get_fee_by_member_date_type($account->member_id, $date, 'regular member fee');
// it exists
if ($fee && $fee->id)
$db = new Transfer_Model();
$db->transaction_start();
// deleting old deduct transfer of member
$deleted_transfers_count = $account->delete_deduct_transfers_of_account($account_id);
$created_transfers_count = 0;
$max_date = date('Y-m-d', mktime(0, 0, 0, $max_month, 15, $max_year));
while (($date = date('Y-m-d', mktime(0, 0, 0, $month, 15, $year))) <= $max_date)
{
$transfer->amount = $fee->fee;
// translate only read-only fee names
$transfer->text = ($fee->readonly) ? $text.' - '.url_lang::lang('texts.'.$fee->name) : $text.' - '.$fee->name;
$text = url_lang::lang('texts.Deduction of member fee');
// finds default regular member fee for this month
$fee = $fee_model->get_default_fee_by_date_type($date, 'regular member fee');
if ($fee && $fee->id)
$default_fee = $fee->fee;
else
throw new ErrorException(url_lang::lang('texts.Fatal error'), url_lang::lang('texts.Fees have not been set!'));
// finds regular member fee for this member and this month
$fee = $fee_model->get_fee_by_member_date_type($account->member_id, $date, 'regular member fee');
// it exists
if ($fee && $fee->id)
{
$amount = $fee->fee;
// translate only read-only fee names
$text = ($fee->readonly) ? $text.' - '.url_lang::lang('texts.'.$fee->name) : $text.' - '.$fee->name;
}
// it doesn't exist - uses default fee
else
{
$amount = $default_fee;
}
if ($amount > 0)
{
$created_transfers_count++;
Transfer_Model::insert_transfer($account->id, $operating->id, null, null,
$this->session->get('user_id'), Transfer_Model::$deduct_member_fee,
$date, $creation_datetime, $text, $amount);
}
// iterate to next month
$month++;
if ($month == 13)
{
$month = 1;
$year++;
}
}
// it doesn't exist - uses default fee
else
{
$transfer->amount = $default_fee;
$transfer->text = $text;
}
if (!$transfer->save())
$save_successful = false;
$year += floor($month/12);
$month %= 12;
$month++;
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Fees have been successfully recalculated, %d deleted transfers, %d created new transfers.', array(0 => $deleted_transfers_count, 1=> $created_transfers_count)));
}
if ($save_successful)
$this->session->set_flash('message', url_lang::lang('texts.Fees have been successfully recounted.'));
else
catch (ErrorException $e)
{
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Error - some fees have not been recounted.'));
}
url::redirect(url_lang::base().'transfers/show_by_account/'.$account_id);
}
......
if (!$this->acl_check_new('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
// preparation
$created_transfers_count = 0;
$creation_datetime = date('Y-m-d H:i:s');
//$current_date = date::get_middle_of_month(date('Y-m-d'));
$current_date = date('Y-m-d');
......
$transfer_model = new Transfer_Model();
// gets all credit accounts, tries to find also existing transfer
$credit_accounts = $account_model->get_accounts_to_deduct_entrance_fees();
// large amount of database inserts, transaction processing is necessary
$db = new Database();
$db->query("START TRANSACTION;");
$save_successful = true;
foreach($credit_accounts as $ca)
try
{
// if member's entrance fee is 0, then no transfer is generated
if ($ca->entrance_fee == 0)
continue;
// are there some deduct transfers?
if (empty($ca->transfer_id))
$db = new Transfer_Model();
$db->transaction_start();
foreach($credit_accounts as $ca)
{
// no deduct entrance fee transfer means that nothing is already paid
$already_paid = 0;
$latest_date = '0001-01-01';
}
else
{
// some transfers already exist, then their total amount is calculated
$eftransfers = $transfer_model->get_entrance_fee_transfers_of_account($ca->id);
$already_paid = $eftransfers->current()->total_amount;
$latest_date = $eftransfers->current()->datetime;
$latest_date = substr($latest_date, 0, strpos($latest_date, ' '));
}
// is already whole entrance fee paid?
if ($already_paid >= $ca->entrance_fee)
continue;
// entrance fee is not wholy paid, calculate debt
$debt = $ca->entrance_fee - $already_paid;
// entrance date of current member
$entrance = date_parse($ca->entrance_date);
$eyear = $entrance['year'];
$emonth = $entrance['month'];
$eday = $entrance['day'];
if ($eday > 15)
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
}
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, 15, $eyear));
// while debt is greater than zero and date of instalment is lower than current date
while ($debt > 0 && $date < $current_date)
{
// is debt still greater than one monthly instalment?
if ($debt > $ca->debt_payment_rate)
// if member's entrance fee is 0, then no transfer is generated
if ($ca->entrance_fee == 0)
continue;
// are there some deduct transfers?
if (empty($ca->transfer_id))
{
// one monthly instalment is deducted
$amount = $ca->debt_payment_rate;
// if debt pay rate is zero, then whole amount of debt is deducted
if ($amount <= 0)
$amount = $debt;
// no deduct entrance fee transfer means that nothing is already paid
$already_paid = 0;
$latest_date = '0001-01-01';
}
else
{
// rest of the debt is deducted
$amount = $debt;
// some transfers already exist, then their total amount is calculated
$eftransfers = $transfer_model->get_entrance_fee_transfers_of_account($ca->id);
$already_paid = $eftransfers->current()->total_amount;
$latest_date = $eftransfers->current()->datetime;
$latest_date = substr($latest_date, 0, strpos($latest_date, ' '));
}
// only one transfer per month - older transfers cannot be duplicated
if ($date > $latest_date)
{
// decrease amount of debt due to size of one instalment
$debt -= $amount;
// create new transfer
$transfer = new Transfer_Model();
$transfer->origin_id = $ca->id;
$transfer->destination_id = $infrastructure->id;
$transfer->user_id = $this->session->get('user_id');
$transfer->type = Transfer_Model::$deduct_entrance_fee;
$transfer->datetime = $date;
$transfer->creation_datetime = $creation_datetime;
$transfer->text = url_lang::lang('texts.Entrance fee');
$transfer->amount = $amount;
if (!$transfer->save())
$save_successful = false;
}
// iterate to next month
$emonth++;
// is already whole entrance fee paid?
if ($already_paid >= $ca->entrance_fee)
continue;
// entrance fee is not wholy paid, calculate debt
$debt = $ca->entrance_fee - $already_paid;
// entrance date of current member
$entrance = date_parse($ca->entrance_date);
$eyear = $entrance['year'];
$emonth = $entrance['month'];
$eday = $entrance['day'];
if ($eday > 15)
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
$eyear++;
}
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, 15, $eyear));
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, 15, $eyear));
// while debt is greater than zero and date of instalment is lower than current date
while ($debt > 0 && $date < $current_date)
{
// is debt still greater than one monthly instalment?
if ($debt > $ca->debt_payment_rate)
{
// one monthly instalment is deducted
$amount = $ca->debt_payment_rate;
// if debt pay rate is zero, then whole amount of debt is deducted
if ($amount <= 0)
$amount = $debt;
}
else
{
// rest of the debt is deducted
$amount = $debt;
}
// only one transfer per month - older transfers cannot be duplicated
if ($date > $latest_date)
{
// decrease amount of debt due to size of one instalment
$debt -= $amount;
// create new transfer
Transfer_Model::insert_transfer($ca->id, $infrastructure->id, null, null,
$this->session->get('user_id'), Transfer_Model::$deduct_entrance_fee,
$date, $creation_datetime, url_lang::lang('texts.Entrance fee'), $amount);
$created_transfers_count++;
}
// iterate to next month
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
}
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, 15, $eyear));
}
}
$db->transaction_commit();
$this->session->set_flash('message', url_lang::lang('texts.Entrance fees have been successfully deducted, %d new transfers created.', $created_transfers_count));
}
if ($save_successful)
catch(ErrorException $e)
{
$db->query("COMMIT;");
$this->session->set_flash('message', url_lang::lang('texts.Entrance fees have been successfully deducted.'));
}
else
{
$db->query("ROLLBACK;");
$db->transaction_rollback();
$this->session->set_flash('message', url_lang::lang('texts.Error - cant deduct entrance fee.'));
}
url::redirect(url_lang::base().'transfers/show_all');
}
/**
* Recounts transfer of one member credit account. Used only in special cases, like changing entrance date.
* Recounts transfer of one member credit account.
* Used only in special cases, like changing entrance date.
* @author Jiri Svitak
* @param $account_id
*/
function recount_entrance_fees($account_id)
function recalculate_entrance_fees($account_id)
{
// access rights
if (!$this->acl_check_new('Accounts_Controller', 'transfers'))
......
$account_model = new Account_Model($account_id);
if ($account_model->id == 0)
Controller::error(RECORD);
... Rozdílový soubor je zkrácen, protože jeho délka přesahuje max. limit.

Také k dispozici: Unified diff