Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 1929

Přidáno uživatelem Ondřej Fibich před více než 11 roky(ů)

Novinky:
- implementace automatickeho strhavani (refs #467)
- samostatne nastaveni pro finance

Zobrazit rozdíly:

freenetis/branches/1.1/media/css/style.css
color: #EC7A04;
text-decoration:none;
}
.deprecated {
text-decoration: line-through ! important;
}
/* ----#end HEADLINES------ */
/* ------------------------ */
freenetis/branches/1.1/application/i18n/cs_CZ/texts.php
'author' => 'Autor',
'author fee' => 'Autorský poplatek',
'autocomplete of gps coords' => 'Automatické doplnění GPS souřadnic',
'automatically deduction is enabled, this operation should be use only if automatical deduction has failed' => 'Automatické strhávání je aktivní, tato operace by měla být použita pouze v případě selhání automatického strhávání.',
'automatically fill in gps coordinates' => 'Automaticky doplnit GPS souřadnice',
'automatically import admins' => 'Automaticky přidat správce oblastí',
'automatically load mac address' => 'Automaticky načti MAC adresu',
......
'deduct' => 'Strhnout',
'deduct day' => 'Den stržení',
'deduct entrance fee' => 'Strhnout vstupní příspěvek',
'deduct fees automatically' => 'Strhnout příspěvky automaticky',
'deduction of member fee' => 'Stržení členského příspěvku',
'deduction of member fees' => 'Stržení členských příspěvků',
'deduction of device repayments' => 'Stržení splátek zařízení',
......
'device admins' => 'Správci zařízení',
'device engineers' => 'Technici zařízení',
'device detail' => 'Detail zařízení',
'device fees deducted automatically (in sum %d)' => 'Splátky zařízení strženy (celkem %d)',
'device fees have been successfully deducted, %d new transfers created' => 'Splátky zařízení byly úspěšně strženy, vytvořeno %d nových převodů.',
'device has been successfully deleted' => 'Zařízení bylo úspěšně smazáno.',
'device has been successfully removed from monitoring' => 'Zařízení bylo úspěšně odebráno z monitoringu.',
......
'entrance_date' => 'Datum vstupu',
'entrance fee' => 'Vstupní příspěvek',
'entrance fee have to be a number' => 'Vstupní příspěvek musí být číslo',
'entrance fees deducted automatically (in sum %d)' => 'Vstupní příspěvky strženy automaticky (celkem %d)',
'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ů.',
'entrance fee repayments' => 'Splátky vstupního příspěvku',
......
'error - some fees have not been recounted' => 'Chyba - některé členské příspěvky nebyly přepočítány.',
'error - some fees have not been deducted' => 'Chyba - některé členské příspěvky nebyly strženy.',
'error - voip not enabled' => 'Chyba - VoIP není povoleno',
'error during automatical deduction of members fees, please use manual deduction of fees' => 'Chyba během automatického strhávání členských příspěvků, proveďte prosím stržení manuálně',
'error during automatical deduction of entrance fees, please use manual deduction of fees' => 'Chyba během automatického strhávání vstupních příspěvků, proveďte prosím stržení manuálně',
'error during automatical deduction of device fees, please use manual deduction of fees' => 'Chyba během automatického strhávání splátek zařízení, proveďte prosím stržení manuálně',
'error: parameter ID is required!' => 'Chyba: parametr ID je povinný!',
'etc' => 'apod',
'ethernet' => 'Ethernetové',
......
'filter query has been successfully unset as default' => 'Dotaz filtru byl úspěšně zrušen jako výchozí.',
'filters' => 'Filtry',
'finances' => 'Finance',
'finance settings' => 'Nastavení financí',
'financial state of member' => 'Finanční stav člena',
'fio settings' => 'Nastavení Fio',
'first-degree certified engineers' => 'Certifikovaní technici prvního stupně',
......
'member fee' => 'Členský příspěvek',
'member fee deduction' => 'Stržení členského příspěvku',
'member fees' => 'Členské příspěvky',
'member fees deducted automatically (in sum %d)' => 'Členské příspěvky strženy automaticky (celkem %d)',
'member fees nr' => 'Počet členských příspěvků',
'member fee payment by cash' => 'Platba členského příspěvku hotově',
'member has been successfully added' => 'Člen byl úspěšně přidán.',
......
'value for earning' => 'Hodnota pro příjem',
'value has not been entered' => 'Hodnota nebyla zadána.',
'variable symbol' => 'Variabilní symbol',
'variable symbol settings' => 'Nastavení variabilních symbolů',
'variable_symbol' => 'Variabilní symbol',
'variable symbols' => 'Variabilní symboly',
'variable symbol already exists in database' => 'Variabilní symbol už existuje v databázi.',
freenetis/branches/1.1/application/i18n/cs_CZ/help.php
'debtor_boundary' => 'Hranice pro dlužníka udává, kdy začnou být přesměrováváni dlužníci kvůli neplacení na příslušnou zprávu. Například pokud je hranice 0, pak je přesměrován každý s kreditem (zůstatkem) -1 a menším. Toto přesměrování si člen nemůže sám zrušit. Je mu zrušeno automaticky, jakmile je jeho kredit opět vyšší než hranice. Toto ale může trvat i týden, než přijde platba a je importován výpis. Pro dočasné povolení přístupu na internet existuje dočasná bílá listina.',
'deduct_day' => 'Den v měsící ve kterém jsou strženy měsíční přízpěvky, splátky vstupního přízpěvku a splátky zařízení. Nastavte hodnotu od 1 do 31, pokud bude mít měsíc míň než 31 dní a hodnota nastavena na větší počet, bude hodnota automaticky v daný měsíc snížena na počet dní v měsíci.',
'deduct_entrance_fees' => 'Již bez formuláře po kliknutí a potvrzení se provede nezávisle na čase stržení vstupního příspěvku všech členů, kteří mají nastavenou nějakou výši vstupního příspěvku, případně mají nastavenu splátku. Pak jsou splátky strženy jen do aktuálního data. Tuto operaci je opět dobré provádět jednou měsíčně od %d. dne měsíce. Jednou stržený vstupní příspěvek je při dalším strhávání ignorován.',
'deduct_fees_automatically_enabled' => 'Pokud je povoleno členské i vstupní přispěvky jsou automaticky strhávány CRONem. Strhávání probíhá krátce po půlnoci %d. dne v měsíci.',
'deduct_member_fees' => 'Zobrazí formulář, který nabídne měsíc a rok pro stržení členských příspěvků. Strhávání členských příspěvků není automatizované a je třeba ho provádět jednou měsíčně, nejlépe od %d. dne měsíce hospodářem sdružení. Výsledkem bude, že pro daný měsíc všem členům podle jejich tarifu buden stržen členský příspěvek.',
'deduct_device_repayments' => 'Provede stržení splátek zařízení. Jedná se o zařízení, která si člen koupil od sdružení. Pokud ve vašem sdružení neprovádíte prodej zařízení na splátky, patrně tuto možnost nevyužijete.',
'device_admin_users_filter' => 'Umožnuje vyfiltrovat pouze zařízení určité uživatele. Ti jsou zapsané ve tvaru ID člena - jméno příjmení uživatele.',
freenetis/branches/1.1/application/i18n/en_US/help.php
'debtor_boundary' => 'The boundaries for the borrower indicates they begin to be redirected to the borrowers due to non-payment of an appropriate message. For example, if the border is 0, then is forwarded to each credit (balance) -1 and smaller. This redirection is not himself a member cancel. He canceled automatically as soon as his credentials again higher than the threshold. But this may take a week to come is imported and paid listing. To temporarily allow access to the Internet, there is a temporary white list.',
'deduct_day' => 'Day of the month in which monthly fees, entrance fee and device fees are deducted. Set the value from 1 to 31.',
'deduct_entrance_fees' => 'Even without the form and click the confirmation is carried out independently of the time tearing down initial contribution of all members who have a set amount of initial contribution, or have a set payment. Then the payments are deducted only to the current date. This operation is again well done on a monthly basis since %d day of the month. Once stripped initial contribution is ignored in further entrainment.',
'deduct_fees_automatically_enabled' => 'If enabled then members and entrance fees are automatically deducted by CRON. Deduction take place shortly after midnight of the %th day of month.',
'deduct_member_fees' => 'Form appears, which offers a month and year to tear down the membership fee. Entrainment of membership fees is not automatic and must be carried out once a month, preferably in the %dth day of month by landlord associations. The result is that for a given month to all members according to their tariff driven demolished membership fee.',
'deduct_device_repayments' => 'Performs demolition equipment payments. It is a device that you bought from member associations. If your association do not carry on installment sale of equipment, probably will not use this option.',
'device_admin_users_filter' => 'Allows to filter out only certain user devices. They are written in the form of a member ID - name surname of user.',
freenetis/branches/1.1/application/helpers/money.php
*/
class Money
{
/**
* Formats given amount of money.
*
* @author Ondrej Fibich
* @param double $amount
* @return string Formated money string
*/
public static function format($amount)
{
return str_replace(' ', ' ', number_format($amount, 2, ',', ' '));
}
/**
* Finds all payments by given payment rate
freenetis/branches/1.1/application/models/log_queue.php
* Creates new log.
*
* @param type $type Type of error
* @param type $description Decription of error
* @param type $exception_backtrace [optional - empty by default]
* @param type $created_at [optional - default current datetime]
* @param string $description Decription of error
* @param Exception $exception_backtrace [optional - empty by default]
* @param string $created_at [optional - default current datetime]
* @return Log_queue_Model Created model or null on error during saving
*/
protected static function log($type, $description,
......
/**
* Creates new fatal error log.
*
* @param type $description Decription of error
* @param type $exception_backtrace [optional - empty by default]
* @param type $created_at [optional - default current datetime]
* @param string $description Decription of error
* @param Exception $exception_backtrace [optional - empty by default]
* @param string $created_at [optional - default current datetime]
* @return Log_queue_Model Created model
*/
public static function ferror($description,
......
/**
* Creates new error log.
*
* @param type $description Decription of error
* @param type $exception_backtrace [optional - empty by default]
* @param type $created_at [optional - default current datetime]
* @param string $description Decription of error
* @param Exception $exception_backtrace [optional - empty by default]
* @param string $created_at [optional - default current datetime]
* @return Log_queue_Model Created model
*/
public static function error($description,
......
/**
* Creates new warning log.
*
* @param type $description Decription of error
* @param type $exception_backtrace [optional - empty by default]
* @param type $created_at [optional - default current datetime]
* @param string $description Decription of error
* @param Exception $exception_backtrace [optional - empty by default]
* @param string $created_at [optional - default current datetime]
* @return Log_queue_Model Created model
*/
public static function warn($description,
......
/**
* Creates new info log.
*
* @param type $description Decription of error
* @param type $exception_backtrace [optional - empty by default]
* @param type $created_at [optional - default current datetime]
* @param string $description Decription of error
* @param Exception $exception_backtrace [optional - empty by default]
* @param string $created_at [optional - default current datetime]
* @return Log_queue_Model Created model
*/
public static function info($description,
freenetis/branches/1.1/application/controllers/transfers.php
$filter_form->as_sql(array('datetime', 'amount', 'text')),
$filter_form->as_sql(array('oa_name', 'da_name', 'transfer'))
);
//die(debug::printr($model_transfer->get_last_sql_query()));
$headline = __('Day book');
$grid = new Grid(url_lang::base() . 'transfers', null, array
......
if ($this->acl_check_edit('Accounts_Controller', 'transfers'))
{
$deduct_day = (Settings::get('deduct_day') + 1) % 32;
$link_opt = array();
// automaticall deduction
if (Settings::get('deduct_fees_automatically_enabled'))
{
$auto_m = 'Automatically deduction is enabled, this operation ' .
'should be use only if automatical deduction has failed.';
$link_opt = array
(
'title' => __($auto_m),
'class' => 'deprecated help'
);
}
$grid->add_new_button(
'transfers/add', __('Add new transfer'),
array(), help::hint('add_new_transfer')
......
$grid->add_new_button(
'transfers/deduct_fees', __('Deduction of member fees'),
array(), help::hint('deduct_member_fees', $deduct_day)
$link_opt, help::hint('deduct_member_fees', $deduct_day)
);
$m = __('Are you sure you want to deduct all entrance fees');
......
$grid->add_new_button(
'transfers/deduct_entrance_fees',
__('Deduction of entrance fees'),
array('onclick' => 'return window.confirm(\'' . $m . '?\')'),
$link_opt + array('onclick' => 'return window.confirm(\'' . $m . '?\')'),
help::hint('deduct_entrance_fees', $deduct_day)
);
......
$grid->add_new_button(
'transfers/deduct_device_fees',
__('Deduction of device repayments'),
array('onclick' => 'return window.confirm(\'' . $m . '?\')'),
$link_opt + array('onclick' => 'return window.confirm(\'' . $m . '?\')'),
help::hint('deduct_device_repayments')
);
}
......
$view->title = $headline;
$view->breadcrumbs = $headline;
$view->content = new View('show_all');
$view->content->headline = $headline . ' ' . help::hint('day_book');
$view->content->headline = $headline . ' ' . help::hint('day_book');
$view->content->table = $grid;
$view->render(TRUE);
}
......
* Deducts fees of all members in one month. If deduct transfer for one month and
* account is found, then it is ignored and skipped.
*
* @todo rewrite SQL to models
* @author Jiri Svitak
* @return unknown_type
*/
......
->callback(array($this, 'valid_default_fee'));
$form->submit('Deduct');
// form validation
if ($form->validate())
{
// access rights
if (!$this->acl_check_new('Accounts_Controller', 'transfers'))
Controller::error(ACCESS);
$form_data = $form->as_array();
// preparation
$month = $form_data['month'];
$year = $arr_years[$form_data['year']];
$deduct_day = date::get_deduct_day_to($month, $year);
$created_transfers_count = 0;
$total_amount = 0;
$date = date('Y-m-d', mktime(0, 0, 0, $month, $deduct_day, $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
{
status::error('Fees have not been set!');
url::redirect('transfers/show_all');
}
$operating = ORM::factory('account')->where(
'account_attribute_id', Account_attribute_Model::OPERATING
)->find();
$database = Database::instance();
$account_model = new Account_Model();
$accounts = $account_model->get_accounts_to_deduct($date);
// perform deduction
try
{
$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)
{
// no deduct transfer for this date and account generated? then create one
if ($account->transfer_id == 0)
{
$text = __('Deduction of member fee');
if ($account->fee_is_set)
{
$amount = $account->fee;
$text = ($account->fee_readonly) ? $text . ' - ' .
__('' . $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 " . num::decimal_point($account->balance - $amount) . " ";
$ids[] = $account->id;
$total_amount += $amount;
$created_transfers_count++;
}
}
}
if ($created_transfers_count > 0)
{
// single query for inserting transfers
$sql_insert .= implode(",", $values);
if (!$database->query($sql_insert))
throw new Exception();
// 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 Exception();
// update also balance of operating account
if (!$account_model->recalculate_account_balance_of_account($operating->id))
throw new Exception();
}
$db->transaction_commit();
$count = self::worker_deduct_members_fees($month, $year, $user_id);
status::success(
'Fees have been successfully deducted, %d new transfers created.',
TRUE, array($created_transfers_count)
TRUE, array($count)
);
}
catch (Exception $e)
{
$db->transaction_rollback();
Log::add_exception($e);
status::error('Error - some fees have not been deducted.');
url::redirect('transfers/show_all');
}
url::redirect('transfers/show_all');
// end
url::redirect('transfers/show_all');
}
if (Settings::get('deduct_fees_automatically_enabled'))
{
$m = 'Automatically deduction is enabled, this operation should be ' .
'use only if automatical deduction has failed';
status::mwarning($m);
}
$breadcrumbs = breadcrumbs::add()
->link('transfers/show_all', 'Day book')
......
$view->breadcrumbs = $breadcrumbs->html();
$view->content = new View('form');
$view->content->headline = __('Deduction of member fees');
$view->content->form = $form->html();
$view->content->form = $form->html();
$view->render(TRUE);
}
......
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('Y-m-d');
$infrastructure = ORM::factory('account')->where(
'account_attribute_id', Account_attribute_Model::INFRASTRUCTURE
)->find();
$account_model = new Account_Model();
$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();
// perform
try
{
$db = new Transfer_Model();
$db->transaction_start();
foreach ($credit_accounts as $ca)
{
// if member is not member yet, then no deduct is made (fixes #324)
if (empty($ca->entrance_date) || ($ca->entrance_date == '0000-00-00'))
continue;
// 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))
{
// 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'];
$deduct_eday = date::get_deduct_day_to($emonth, $eyear);
if ($eday > $deduct_eday)
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
}
$deduct_eday2 = date::get_deduct_day_to($emonth, $eyear);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, $deduct_eday2, $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, __('Entrance fee'), $amount
);
$created_transfers_count++;
}
// iterate to next month
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
}
$deduct_eday3 = date::get_deduct_day_to($emonth, $eyear);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, $deduct_eday3, $eyear));
}
}
$db->transaction_commit();
$c = self::worker_deduct_entrance_fees($this->session->get('user_id'));
status::success(
'Entrance fees have been successfully deducted, '.
'%d new transfers created.', TRUE, $created_transfers_count
'%d new transfers created.', TRUE, $c
);
}
catch (Exception $e)
{
$db->transaction_rollback();
Log::add_exception($e);
status::error('Error - cant deduct entrance fee.');
}
// end
url::redirect('transfers/show_all');
}
......
// access rights
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');
$operating = ORM::factory('account')->where(
'account_attribute_id', Account_attribute_Model::OPERATING
)->find();
$account_model = new Account_Model();
// gets all credit accounts
$credit_accounts = $account_model->get_accounts_to_deduct_device_fees();
// perform
try
{
$db = new Transfer_Model();
$db->transaction_start();
foreach ($credit_accounts as $ca)
{
// total amount of already repaied transfers
$already_paid = $account_model->get_amount_of_device_fees($ca->id);
// is all device repayments already paid?
if ($already_paid >= $ca->total_price)
continue;
// device repayment is not wholy paid, calculate debt
$debt = $ca->total_price - $already_paid;
// gets all devices including their buy dates and payment rates
$devices = $account_model->get_devices_of_account($ca->id);
// gets buy date of the first device
$buy_date = date_parse($devices->current()->buy_date);
$year = $buy_date['year'];
$month = $buy_date['month'];
$day = date::get_deduct_day_to($month, $year);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $month, $day, $year));
// while debt is greater than zero and date of instalment is lower than current date
while ($debt > 0 && $date < date('Y-m-d'))
{
//echo "date $date<br>";
// calculate total payment rate for current month
$payment_rate = 0;
foreach ($devices as $device)
{
// find finishing date of repayments for given device
$bd = date_parse($device->buy_date);
$y = $bd['year'];
$m = $bd['month'];
$dd = date::get_deduct_day_to($m, $y);
$d = date('Y-m-d', mktime(0, 0, 0, $m, $dd, $y));
// payments
$payments = 0;
while ($device->price > $payments)
{
$payments += $device->payment_rate;
// iterate to next month
$m++;
if ($m == 13)
{
$m = 1;
$y++;
}
// getting boundary date - 15th day in the month
$dd = date::get_deduct_day_to($m, $y);
$d = date('Y-m-d', mktime(0, 0, 0, $m, $dd, $y));
//echo "payments $payments<br>";
}
//echo "buy date $device->buy_date, current date $date, end date $d<br>";
// is current date between buying of device and date of its full repayment?
if ($device->buy_date <= $date && $date <= $d)
$payment_rate += $device->payment_rate;
//echo "payment rate $payment_rate<br>";
}
// is debt still greater than one monthly instalment?
if ($debt > $payment_rate)
{
$amount = $payment_rate;
}
else
{
$amount = $debt;
}
//echo "<strong>date $date, amount $amount</strong><br>";
// decrease amount of debt due to size of one instalment
$debt -= $amount;
$transfers = $db->get_device_fee_transfers_of_account_and_date($ca, $date);
if ($amount > 0 && count($transfers) == 0)
{
Transfer_Model::insert_transfer(
$ca->id, $operating->id, null, null,
$this->session->get('user_id'),
Transfer_Model::DEDUCT_DEVICE_FEE, $date,
$creation_datetime, __('Device repayments'),
$amount
);
$created_transfers_count++;
}
// iterate to next month
$month++;
if ($month == 13)
{
$month = 1;
$year++;
}
$day = date::get_deduct_day_to($month, $year);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $month, $day, $year));
}
}
$db->transaction_commit();
$c = self::worker_deduct_devices_fees($this->session->get('user_id'));
status::success(
'Device fees have been successfully deducted, %d '.
'new transfers created.', TRUE, $created_transfers_count
'new transfers created.', TRUE, $c
);
}
catch (Exception $e)
{
$db->transaction_rollback();
Log::add_exception($e);
status::error('Error - cant deduct device fee.');
}
// end
url::redirect('transfers/show_all');
}
......
));
}
}
/**
* Deduct member fees in given year and month if not deducted already.
*
* @author Jiri Svitak, Ondrej Fibich
* @param integer $month Month of deduction
* @param integer $year Year of deduction
* @param integer $user_id Who is deducting
* @return integer Created transfers count
* @throws Exception On any error
*/
public static function worker_deduct_members_fees($month, $year, $user_id)
{
$deduct_day = date::get_deduct_day_to($month, $year);
$created_transfers_count = 0;
$total_amount = 0;
$date = date('Y-m-d', mktime(0, 0, 0, $month, $deduct_day, $year));
$creation_datetime = date('Y-m-d H:i:s');
// 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 Exception('Fees have not been set!');
}
$operating = ORM::factory('account')->where(
'account_attribute_id', Account_attribute_Model::OPERATING
)->find();
$database = Database::instance();
$account_model = new Account_Model();
$accounts = $account_model->get_accounts_to_deduct($date);
try
{
$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)
{
// no deduct transfer for this date and account generated? then create one
if ($account->transfer_id == 0)
{
$text = __('Deduction of member fee');
if ($account->fee_is_set)
{
$amount = $account->fee;
$text = ($account->fee_readonly) ? $text . ' - ' .
__('' . $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 "
. num::decimal_point($account->balance - $amount)
. " ";
$ids[] = $account->id;
$total_amount += $amount;
$created_transfers_count++;
}
}
}
if ($created_transfers_count > 0)
{
// single query for inserting transfers
$sql_insert .= implode(",", $values);
if (!$database->query($sql_insert))
throw new Exception();
// 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 Exception();
// update also balance of operating account
if (!$account_model->recalculate_account_balance_of_account($operating->id))
throw new Exception();
}
$db->transaction_commit();
}
catch (Exception $e)
{
$db->transaction_rollback();
throw $e;
}
return $created_transfers_count;
}
/**
* Deduct entrance fees.
*
* @author Jiri Svitak, Ondrej Fibich
* @param integer $user_id Who is deducting
* @param integer $date Date of deduction [optional - default NOW]
* @return integer Created transfers count
* @throws Exception On any error
*/
public static function worker_deduct_entrance_fees($user_id, $date = NULL)
{
// date param
if ($date == NULL)
{
$current_date = date('Y-m-d');
}
else
{
$current_date = $date;
}
// preparation
$created_transfers_count = 0;
$creation_datetime = date('Y-m-d H:i:s');
$infrastructure = ORM::factory('account')->where(
'account_attribute_id', Account_attribute_Model::INFRASTRUCTURE
)->find();
$account_model = new Account_Model();
$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();
try
{
$db = new Transfer_Model();
$db->transaction_start();
foreach ($credit_accounts as $ca)
{
// if member is not member yet, then no deduct is made (fixes #324)
if (empty($ca->entrance_date) || ($ca->entrance_date == '0000-00-00'))
continue;
// 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))
{
// 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'];
$deduct_eday = date::get_deduct_day_to($emonth, $eyear);
if ($eday > $deduct_eday)
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
}
$deduct_eday2 = date::get_deduct_day_to($emonth, $eyear);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, $deduct_eday2, $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,
$user_id, Transfer_Model::DEDUCT_ENTRANCE_FEE, $date,
$creation_datetime, __('Entrance fee'), $amount
);
$created_transfers_count++;
}
// iterate to next month
$emonth++;
if ($emonth == 13)
{
$emonth = 1;
$eyear++;
}
$deduct_eday3 = date::get_deduct_day_to($emonth, $eyear);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $emonth, $deduct_eday3, $eyear));
}
}
$db->transaction_commit();
return $created_transfers_count;
}
catch (Exception $e)
{
$db->transaction_rollback();
throw $e;
}
}
/**
* Deduct device fees.
*
* @author Jiri Svitak, Ondrej Fibich
* @param integer $user_id Who is deducting
* @return integer Created transfers count
* @throws Exception On any error
*/
public static function worker_deduct_devices_fees($user_id)
{
// preparation
$created_transfers_count = 0;
$creation_datetime = date('Y-m-d H:i:s');
$operating = ORM::factory('account')->where(
'account_attribute_id', Account_attribute_Model::OPERATING
)->find();
$account_model = new Account_Model();
// gets all credit accounts
$credit_accounts = $account_model->get_accounts_to_deduct_device_fees();
try
{
$db = new Transfer_Model();
$db->transaction_start();
foreach ($credit_accounts as $ca)
{
// total amount of already repaied transfers
$already_paid = $account_model->get_amount_of_device_fees($ca->id);
// is all device repayments already paid?
if ($already_paid >= $ca->total_price)
continue;
// device repayment is not wholy paid, calculate debt
$debt = $ca->total_price - $already_paid;
// gets all devices including their buy dates and payment rates
$devices = $account_model->get_devices_of_account($ca->id);
// gets buy date of the first device
$buy_date = date_parse($devices->current()->buy_date);
$year = $buy_date['year'];
$month = $buy_date['month'];
$day = date::get_deduct_day_to($month, $year);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $month, $day, $year));
// while debt is greater than zero and date of instalment is lower than current date
while ($debt > 0 && $date < date('Y-m-d'))
{
//echo "date $date<br>";
// calculate total payment rate for current month
$payment_rate = 0;
foreach ($devices as $device)
{
// find finishing date of repayments for given device
$bd = date_parse($device->buy_date);
$y = $bd['year'];
$m = $bd['month'];
$dd = date::get_deduct_day_to($m, $y);
$d = date('Y-m-d', mktime(0, 0, 0, $m, $dd, $y));
// payments
$payments = 0;
while ($device->price > $payments)
{
$payments += $device->payment_rate;
// iterate to next month
$m++;
if ($m == 13)
{
$m = 1;
$y++;
}
// getting boundary date - 15th day in the month
$dd = date::get_deduct_day_to($m, $y);
$d = date('Y-m-d', mktime(0, 0, 0, $m, $dd, $y));
//echo "payments $payments<br>";
}
//echo "buy date $device->buy_date, current date $date, end date $d<br>";
// is current date between buying of device and date of its full repayment?
if ($device->buy_date <= $date && $date <= $d)
$payment_rate += $device->payment_rate;
//echo "payment rate $payment_rate<br>";
}
// is debt still greater than one monthly instalment?
if ($debt > $payment_rate)
{
$amount = $payment_rate;
}
else
{
$amount = $debt;
}
//echo "<strong>date $date, amount $amount</strong><br>";
// decrease amount of debt due to size of one instalment
$debt -= $amount;
$transfers = $db->get_device_fee_transfers_of_account_and_date($ca, $date);
if ($amount > 0 && count($transfers) == 0)
{
Transfer_Model::insert_transfer(
$ca->id, $operating->id, null, null,
$user_id, Transfer_Model::DEDUCT_DEVICE_FEE, $date,
$creation_datetime, __('Device repayments'),
$amount
);
$created_transfers_count++;
}
// iterate to next month
$month++;
if ($month == 13)
{
$month = 1;
$year++;
}
$day = date::get_deduct_day_to($month, $year);
// getting boundary date - 15th day in the month
$date = date('Y-m-d', mktime(0, 0, 0, $month, $day, $year));
}
}
$db->transaction_commit();
return $created_transfers_count;
}
catch (Exception $e)
{
$db->transaction_rollback();
throw $e;
}
}
}
freenetis/branches/1.1/application/controllers/scheduler.php
*
* @param string $method
* @param Exception $e
* @param boolean $log_queue Also log to log queue (database)?
*/
private static function log_error($method, Exception $e)
private static function log_error($method, Exception $e, $log_queue = TRUE)
{
// get humanize method
$method = str_replace('|', ' ' . __('or') . ' ', $method);
......
$e->getLine()
);
// log to database
Log_queue_Model::error($text, $e->getTraceAsString());
if ($log_queue)
{
Log_queue_Model::error($text, $e->getTraceAsString());
}
// log to file
Log::add('error', $text);
}
......
self::log_error('update_ulogd', $e);
}
// fee deduction (monthly)
self::fee_deduction();
// set state of module (last activation time)
Settings::set('cron_state', date('Y-m-d H:i:s'));
}
/**
* Deduct all fees automatically if enabled
*
* @author Ondrej Fibich
*/
private static function fee_deduction()
{
if (Settings::get('deduct_fees_automatically_enabled') &&
intval(date('j')) == intval(Settings::get('deduct_day')))
{
// preparations
$association = new Member_Model(Member_Model::ASSOCIATION);
$user_id = $association->get_main_user();
// members fees (at deduct date 3 minutes after midnight)
if (date('H:i') == '00:03')
{
try
{
// perform
$c = Transfers_Controller::worker_deduct_members_fees(
date('m'), date('Y'), $user_id
);
// info to logs
$m = __('Member fees deducted automatically (in sum %d)', $c);
Log_queue_Model::info($m);
}
catch (Exception $e)
{
$m = __('Error during automatical deduction of members fees,' .
'please use manual deduction of fees');
self::log_error($m, $e, FALSE);
Log_queue_Model::error($m, $e);
}
}
// entrance fees (at deduct date 5 minutes after midnight)
if (date('H:i') == '00:05')
{
try
{
// perform
$c = Transfers_Controller::worker_deduct_entrance_fees($user_id);
// info to logs
$m = __('Entrance fees deducted automatically (in sum %d)', $c);
Log_queue_Model::info($m);
}
catch (Exception $e)
{
$m = __('Error during automatical deduction of entrance fees,' .
'please use manual deduction of fees');
self::log_error($m, $e, FALSE);
Log_queue_Model::error($m, $e);
}
}
// device deduct fees (at deduct date 7 minutes after midnight)
if (date('H:i') == '00:07')
{
try
{
// perform
$c = Transfers_Controller::worker_deduct_devices_fees($user_id);
// info to logs
$m = __('Device fees deducted automatically (in sum %d)', $c);
Log_queue_Model::info($m);
}
catch (Exception $e)
{
$m = __('Error during automatical deduction of device fees,' .
'please use manual deduction of fees');
self::log_error($m, $e, FALSE);
Log_queue_Model::error($m, $e);
}
}
}
}
/**
* @author Jiri Svitak
*/
// public function fio_import_daily()
// private function fio_import_daily()
// {
// //try
// {
freenetis/branches/1.1/application/controllers/settings.php
if ($this->acl_check_edit('Settings_Controller', 'system'))
{
$this->sections['system'] = __('System');
$this->sections['finance'] = __('Finance');
$this->sections['approval'] = __('Approval');
$this->sections['email'] = __('Email');
......
->options($countries)
->selected(Settings::get('default_country'))
->style('width:200px');
// currency
$this->form->input('currency')
->rules('length[3,40]|required')
->value(Settings::get('currency'));
$this->form->radio('grid_hide_on_first_load')
->label('Hide grid on its first load')
......
->label('Minimal password level')
->rules('required')
->selected(Settings::get('security_password_level'));
$this->form->group('Finance');
$this->form->dropdown('variable_key_generator_id')
->options(array(NULL => '') + Variable_Key_Generator::get_drivers_for_dropdown())
->label('Algorithm for generation of variable symbols')
->selected(Variable_Key_Generator::get_active_driver())
->style('width:200px');
$this->form->submit('Save');
// form validate
......
}
/**
* Settings of finance variables
*
* @author Ondrej Fibich
*/
public function finance()
{
// access control
if (!$this->acl_check_edit('Settings_Controller', 'system'))
Controller::error(ACCESS);
// creating of new forge
$this->form = new Forge('settings/finance');
$this->form->group('Finance settings');
$this->form->input('currency')
->rules('length[3,40]|required')
->value(Settings::get('currency'));
$deduct_day = Settings::get('deduct_day');
$this->form->checkbox('deduct_fees_automatically_enabled')
->value('1')
->checked(Settings::get('deduct_fees_automatically_enabled'))
->label(__('Deduct fees automatically') . ' ' .
help::hint('deduct_fees_automatically_enabled', $deduct_day));
$this->form->group('Variable symbol settings');
$this->form->dropdown('variable_key_generator_id')
->options(array(NULL => '') + Variable_Key_Generator::get_drivers_for_dropdown())
->label('Algorithm for generation of variable symbols')
->selected(Variable_Key_Generator::get_active_driver())
->style('width:200px');
$this->form->submit('Save');
// form validate
if ($this->form->validate())
{
$form_data = $this->form->as_array(FALSE);
$issaved = true;
foreach ($form_data as $name => $value)
{
$issaved = $issaved && Settings::set($name, $value);
}
if ($issaved)
// if all action were succesfull
{
status::success('System variables have been successfully updated.');
}
else
// if not
{
status::error('System variables havent been successfully updated.');
}
url::redirect('settings/finance');
}
$view = new View('main');
$view->title = __('Settings') . ' - ' . __('Finance');
$view->content = new View('settings/main');
$view->content->current = 'finance';
$view->content->content = $this->form->html();
$view->content->headline = __('Finance');
$view->render(TRUE);
}
/**
* Settings for QoS
*/
public function qos()
freenetis/branches/1.1/application/views/devices/show.php
<?php if ($device->price): ?>
<tr>
<th><?php echo __('Price') ?></th>
<td><?php echo $device->price ?></td>
<td><?php echo money::format($device->price) ?></td>
</tr>
<tr>
<th><?php echo __('Monthly payment rate') ?></th>
<td><?php echo $device->payment_rate ?></td>
<td><?php echo money::format($device->payment_rate) ?></td>
</tr>
<?php endif; ?>
<?php if ($device->buy_date != '' && $device->buy_date != '1970-01-01'): ?>

Také k dispozici: Unified diff