Снятие абонентской платы в дебитовых договорах

Материал из BiTel WiKi

(Различия между версиями)
Перейти к: навигация, поиск
м
 
(8 промежуточных версий не показаны.)
Строка 4: Строка 4:
В начале дня, до начисление абонентской платы, генерируется событие таймера с flag=1.   
В начале дня, до начисление абонентской платы, генерируется событие таймера с flag=1.   
По этому событию запускается скрипт проверки баланса. Если текущий баланс договора не позволяет списать абонентскую плату,  
По этому событию запускается скрипт проверки баланса. Если текущий баланс договора не позволяет списать абонентскую плату,  
-
то договор приостанавливается с комментарием "Недостаточно средств" добавляется в группу "Недостаточно средств".
+
то договор приостанавливается с комментарием "Недостаточно средств" и добавляется в группу "Недостаточно средств".
Далее для договоров, входящих к группу "Недостаточно средств", при приходе платежа делается проверка. Если текущий баланс позволяет списать абонентскую плату, то статус договора меняется на "активен" с комментарием "Автоматически после оплаты" и договор исключается из группы "Недостаточно средств". Так же для договоров, входящих в группу "Недостаточно средств", есть возможность выполнить доп. действие "Принудительно разблокировать договор". Если его выполнить, то статус договора будет изменен на "активен" с комментарием "Принудительно из доп. действия" и договор будет исключен из группы "Недостаточно средств".
Далее для договоров, входящих к группу "Недостаточно средств", при приходе платежа делается проверка. Если текущий баланс позволяет списать абонентскую плату, то статус договора меняется на "активен" с комментарием "Автоматически после оплаты" и договор исключается из группы "Недостаточно средств". Так же для договоров, входящих в группу "Недостаточно средств", есть возможность выполнить доп. действие "Принудительно разблокировать договор". Если его выполнить, то статус договора будет изменен на "активен" с комментарием "Принудительно из доп. действия" и договор будет исключен из группы "Недостаточно средств".
Строка 41: Строка 41:
contract_status_manager  = new ContractStatusManager(con);
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
status = contract_status_manager.getStatus(cid, DateNow);
-
contract_status = status.getStatus();
+
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
if (status != null)
 +
{
 +
  contract_status = status.getStatus();
 +
}
if (contract_status == null)
if (contract_status == null)
Строка 66: Строка 70:
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
re_check_abn = con.prepareStatement(query_check_abn);
re_check_abn = con.prepareStatement(query_check_abn);
-
ResultSet re_check_abn = re_check_abn.executeQuery();
+
rs_check_abn = re_check_abn.executeQuery();
-
while (re_check_abn.next())
+
while (rs_check_abn.next())
{
{
-
if (re_check_abn.getString(1) == null)
+
if (rs_check_abn.getString(1) == null)
{
{
abn_count = "1";
abn_count = "1";
Строка 75: Строка 79:
else
else
{
{
-
abn_count = re_check_abn.getString(1);
+
abn_count = rs_check_abn.getString(1);
};
};
};
};
Строка 122: Строка 126:
if (calc_mode.indexOf("month") != -1 && day != 1)
if (calc_mode.indexOf("month") != -1 && day != 1)
{
{
-
//абонплату за месяц снимаем проверяем только 1-ого числа
+
//абонплату за месяц снимаем только 1-ого числа
-
return;
+
-
};
+
-
if (calc_mode.indexOf("day") != -1 && (cost_type != 0 || calc_type != 1))
+
-
{
+
-
error ("Неверные параметры тарифа");
+
return;
return;
};
};
Строка 208: Строка 207:
contract_status_manager  = new ContractStatusManager(con);
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
status = contract_status_manager.getStatus(cid, DateNow);
-
contract_status = status.getStatus();
+
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
if (status != null)
 +
{
 +
  contract_status = status.getStatus();
 +
}
if (contract_status == null)
if (contract_status == null)
Строка 228: Строка 231:
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
re_check_abn = con.prepareStatement(query_check_abn);
re_check_abn = con.prepareStatement(query_check_abn);
-
ResultSet re_check_abn = re_check_abn.executeQuery();
+
rs_check_abn = re_check_abn.executeQuery();
-
while (re_check_abn.next())
+
while (rs_check_abn.next())
{
{
-
if (re_check_abn.getString(1) == null)
+
if (rs_check_abn.getString(1) == null)
{
{
abn_count = "1";
abn_count = "1";
Строка 237: Строка 240:
else
else
{
{
-
abn_count = re_check_abn.getString(1);
+
abn_count = rs_check_abn.getString(1);
};
};
};
};
Строка 277: Строка 280:
{
{
error ("Параметры абонплаты не найдены");
error ("Параметры абонплаты не найдены");
-
return;
 
-
};
 
-
if (calc_mode.indexOf("day") != -1 && (cost_type != 0 || calc_type != 1))
 
-
{
 
-
error ("Неверные параметры тарифа");
 
return;
return;
};
};
if (calc_mode.indexOf("day") != -1)
if (calc_mode.indexOf("day") != -1)
{
{
 +
//При снятии абонплаты за день клиент должен оплатить как минимум за 30 дней
cost = cost*abn_count*30;
cost = cost*abn_count*30;
};
};
Строка 357: Строка 356:
contract_status_manager  = new ContractStatusManager(con);
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
status = contract_status_manager.getStatus(cid, DateNow);
-
contract_status = status.getStatus();
+
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
if (status != null)
 +
{
 +
  contract_status = status.getStatus();
 +
}
if (contract_status == null)
if (contract_status == null)
Строка 404: Строка 407:
};
};
</source>
</source>
 +
 +
 +
 +
В новой версии билинга (4.6) эти скрипты не работают. Пришлось немного изменить, чтобы заработали. В яве не
 +
спец, поэтому пошел по простому пути, просто обошел некоторые условия. Может кто-то поможет их поправить, чтобы
 +
работало полностью со всеми условиями.
 +
 +
Вот исправленные скрипты с ремарками там, где я менял код:
 +
 +
'''Событие "Таймер"'''
 +
<source lang="java">
 +
import java.sql.*;
 +
import java.util.*;
 +
 +
// Мои добавления
 +
import bitel.billing.server.ipn.bean.*;
 +
import ru.bitel.bgbilling.server.util.ModuleSetup;
 +
//
 +
 +
import bitel.billing.server.contract.bean.*;
 +
import bitel.billing.server.tariff.*;
 +
import bitel.billing.server.util.*;
 +
import bitel.billing.common.KernelConst;
 +
 +
// код услуги
 +
sid = 25;
 +
// код экземпляра модуля
 +
mid = 15;
 +
//Группа "Недостаточно средств"
 +
GROUP_ERROR_BALANCE = 16;
 +
 +
if( event.getFlag() != 1 ) {
 +
    return;
 +
};
 +
 +
cid = event.getContractID();
 +
DateNow = new GregorianCalendar();
 +
contract = new ContractManager(con).getContractByID(cid);
 +
if (contract == null){
 +
return;
 +
};
 +
BalanceMode = contract.getBalanceMode();
 +
if (BalanceMode == 0){
 +
//Пропускаем тех кто работает по факту
 +
return;
 +
};
 +
contract_status_manager  = new ContractStatusManager(con);
 +
status = contract_status_manager.getStatus(cid, DateNow);
 +
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
if (status != null)
 +
{
 +
  contract_status = status.getStatus();
 +
}
 +
 +
if (contract_status == null)
 +
{
 +
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
};
 +
if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE)
 +
{
 +
//Пропускаем не активные договора
 +
return;
 +
};
 +
 +
date_str=TimeUtils.format(DateNow, "yyyy-MM-dd");
 +
 +
//Проверяем привязана ли услуга "абонплата"
 +
abn_count = "0";
 +
query_check_abn =
 +
" SELECT npay_service_object_"+mid+".col"+
 +
" FROM contract_service"+
 +
"  LEFT JOIN npay_service_object_"+mid+
 +
"  ON (contract_service.id=npay_service_object_"+mid+".csid)"+
 +
" WHERE (contract_service.date1 is NULL OR contract_service.date1<='"+date_str+"') AND"+
 +
" (contract_service.date2 is NULL OR contract_service.date2>='"+date_str+"') AND"+
 +
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
 +
re_check_abn = con.prepareStatement(query_check_abn);
 +
rs_check_abn = re_check_abn.executeQuery();
 +
while (rs_check_abn.next())
 +
{
 +
if (rs_check_abn.getString(1) == null)
 +
{
 +
abn_count = "1";
 +
}
 +
else
 +
{
 +
abn_count = rs_check_abn.getString(1);
 +
};
 +
};
 +
////Это условие, почему-то, не работало и abn_count не было равно 1, даже когда абонплата была привязана
 +
/// к договору.
 +
abn_count = "1";
 +
///
 +
abn_count = Double.parseDouble(abn_count);
 +
if (abn_count == 0)
 +
{
 +
//Услуга не найдена.
 +
return;
 +
};
 +
 +
day_str=TimeUtils.format(DateNow, "dd");
 +
day = Double.parseDouble(day_str);
 +
 +
cost = null;
 +
cost_type = null;
 +
calc_mode = null;
 +
calc_type = null;
 +
// поиск параметров абонплаты
 +
tts = new ContractManager( con ).getRealtimeTariffTreeSet( cid, DateNow, "npay", mid, true );
 +
for( TariffModuleTree tree : tts.getTreeList( DateNow ) )
 +
{
 +
req_cost = new TariffRequest();
 +
req_cost.setRequestParam( "action", "calculate" );
 +
req_cost.setRequestParam( "sid", sid );
 +
req_cost.setRequestParam( "month_days", 1 );
 +
req_cost.setRequestParam( "period_days", 1 );
 +
req_cost.setRequestParam( "time",  DateNow);
 +
tree.processRequest( req_cost );
 +
cost = (Double)req_cost.getResponseParam( "cost" );
 +
cost_type = req_cost.getResponseParam( "cost_type" );
 +
 +
req_calc_mode = new TariffRequest();
 +
req_calc_mode.setRequestParam( "action", "reset" );
 +
req_calc_mode.setRequestParam( "sid", sid );
 +
req_calc_mode.setRequestParam( "time",  DateNow);
 +
tree.processRequest( req_calc_mode );
 +
calc_mode = (String)req_calc_mode.getResponseParam( "calc_mode" );
 +
calc_type = req_calc_mode.getResponseParam( "calc_type" );
 +
};
 +
 +
if (cost == null || calc_mode == null)
 +
{
 +
error ("Параметры абонплаты не найдены");
 +
return;
 +
};
 +
if (calc_mode.indexOf("month") != -1 && day != 1)
 +
{
 +
//абонплату за месяц снимаем только 1-ого числа
 +
return;
 +
};
 +
if (cost == 0)
 +
{
 +
return;
 +
};
 +
 +
cost = cost*abn_count;
 +
print ("cid="+cid);
 +
balance = new BalanceUtils(con);
 +
contract_balance = balance.getBalance (new Date(), cid);
 +
contract_limit = contract.getBalanceLimit();
 +
print ("contract_balance="+contract_balance); 
 +
print ("contract_limit="+contract_limit); 
 +
print ("contract_abn="+cost);
 +
 +
// Тут я просто изменил под себя, т.е. клиент может вносить любую сумму
 +
contract_balance_new = contract_balance + cost - cost;
 +
contract_limit_new = cost / 30;
 +
print ("contract_balance_new="+contract_balance_new);
 +
print ("contract_limit_new="+contract_limit_new);
 +
if (contract_balance_new >= contract_limit + contract_limit_new)
 +
{
 +
print ("Balance OK");
 +
}
 +
else
 +
{
 +
print ("Balance error");
 +
///
 +
 +
contract_groups = contract.getGroups();
 +
contract_groups = contract_groups | 1L<<GROUP_ERROR_BALANCE;
 +
 +
query = "UPDATE contract SET gr=? WHERE id=?";
 +
psUpdate = con.prepareStatement( query );
 +
psUpdate.setLong( 1, contract_groups );
 +
psUpdate.setInt( 2, cid );
 +
psUpdate.executeUpdate();
 +
 +
ContractStatus status = new ContractStatus();
 +
status.setContractId( cid );
 +
status.setDate1( DateNow );
 +
status.setDate2( null );
 +
status.setStatus( KernelConst.CONTRACT_STATUS_SUSPENDED );
 +
status.setComment( "Недостаточно средств" );
 +
 +
// Тут выдавало ошибку, просто убрал
 +
//      status.setUserId( 0 );
 +
 +
contract_status_manager.changeStatus( status );
 +
 +
// Тут не менялось состояние шлюза, добавил код с форума
 +
 +
// Переводим шлюз в статус "заблокирован"
 +
modset = new ModuleSetup(con, 1);
 +
(new IPNContractStatusManager(con, 1, modset)).changeStatus(cid, 2, 0, true);
 +
};
 +
</source>
 +
 +
'''Событие "Приход тлатежа"'''
 +
 +
<source lang="java">
 +
 +
import java.sql.*;
 +
import java.util.*;
 +
 +
import bitel.billing.server.contract.bean.*;
 +
 +
// Мои добавления
 +
import bitel.billing.server.ipn.bean.*;
 +
//
 +
 +
import bitel.billing.server.tariff.*;
 +
import bitel.billing.server.util.*;
 +
import bitel.billing.common.KernelConst;
 +
import ru.bitel.bgbilling.server.util.ModuleSetup;
 +
 +
// код услуги
 +
sid = 25;
 +
// код экземпляра модуля
 +
mid = 15;
 +
//Группа "Недостаточно средств"
 +
GROUP_ERROR_BALANCE = 16;
 +
 +
DateNow = new GregorianCalendar();
 +
cid = event.getContractID();
 +
contract = new ContractManager(con).getContractByID(cid);
 +
contract_groups = contract.getGroups();
 +
if ((contract_groups & (1L<<GROUP_ERROR_BALANCE)) == 0)
 +
{
 +
return;
 +
};
 +
 +
BalanceMode = contract.getBalanceMode();
 +
if (BalanceMode == 0){
 +
//Пропускаем тех кто работает по факту
 +
return;
 +
};
 +
 +
contract_status_manager  = new ContractStatusManager(con);
 +
status = contract_status_manager.getStatus(cid, DateNow);
 +
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
if (status != null)
 +
{
 +
  contract_status = status.getStatus();
 +
}
 +
 +
if (contract_status == null)
 +
{
 +
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
 +
};
 +
 +
date_str=TimeUtils.format(DateNow, "yyyy-MM-dd");
 +
 +
//Проверяем привязана ли услуга "абонплата"
 +
abn_count = "0";
 +
query_check_abn =
 +
" SELECT npay_service_object_"+mid+".col"+
 +
" FROM contract_service"+
 +
"  LEFT JOIN npay_service_object_"+mid+
 +
"  ON (contract_service.id=npay_service_object_"+mid+".csid)"+
 +
" WHERE (contract_service.date1 is NULL OR contract_service.date1<='"+date_str+"') AND"+
 +
" (contract_service.date2 is NULL OR contract_service.date2>='"+date_str+"') AND"+
 +
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
 +
re_check_abn = con.prepareStatement(query_check_abn);
 +
rs_check_abn = re_check_abn.executeQuery();
 +
while (rs_check_abn.next())
 +
{
 +
if (rs_check_abn.getString(1) == null)
 +
{
 +
abn_count = "1";
 +
}
 +
else
 +
{
 +
abn_count = rs_check_abn.getString(1);
 +
};
 +
};
 +
////Это условие, почему-то, не работало и abn_count не было равно 1, даже когда абонплата была привязана
 +
/// к договору.
 +
abn_count = "1";
 +
///
 +
abn_count = Double.parseDouble(abn_count);
 +
if (abn_count == 0)
 +
{
 +
//Услуга не найдена.
 +
return;
 +
};
 +
 +
cost = null;
 +
cost_type = null;
 +
calc_mode = null;
 +
calc_type = null;
 +
// поиск параметров абонплаты
 +
tts = new ContractManager( con ).getRealtimeTariffTreeSet( cid, DateNow, "npay", mid, true );
 +
for( TariffModuleTree tree : tts.getTreeList( DateNow ) )
 +
{
 +
req_cost = new TariffRequest();
 +
req_cost.setRequestParam( "action", "calculate" );
 +
req_cost.setRequestParam( "sid", sid );
 +
req_cost.setRequestParam( "month_days", 1 );
 +
req_cost.setRequestParam( "period_days", 1 );
 +
req_cost.setRequestParam( "time",  DateNow);
 +
tree.processRequest( req_cost );
 +
cost = (Double)req_cost.getResponseParam( "cost" );
 +
cost_type = req_cost.getResponseParam( "cost_type" );
 +
 +
req_calc_mode = new TariffRequest();
 +
req_calc_mode.setRequestParam( "action", "reset" );
 +
req_calc_mode.setRequestParam( "sid", sid );
 +
req_calc_mode.setRequestParam( "time",  DateNow);
 +
tree.processRequest( req_calc_mode );
 +
calc_mode = (String)req_calc_mode.getResponseParam( "calc_mode" );
 +
calc_type = req_calc_mode.getResponseParam( "calc_type" );
 +
};
 +
 +
if (cost == null || calc_mode == null)
 +
{
 +
error ("Параметры абонплаты не найдены");
 +
return;
 +
};
 +
if (calc_mode.indexOf("day") != -1)
 +
{
 +
//При снятии абонплаты за день клиент должен оплатить как минимум за 30 дней
 +
 +
cost = cost*abn_count;
 +
// cost = cost*abn_count*30;
 +
};
 +
if (calc_mode.indexOf("month") != -1)
 +
{
 +
cost = cost*abn_count;
 +
};
 +
print ("cid="+cid);
 +
balance = new BalanceUtils(con);
 +
contract_balance = balance.getBalance (new Date(), cid);
 +
contract_limit = contract.getBalanceLimit();
 +
print ("contract_balance="+contract_balance); 
 +
print ("contract_limit="+contract_limit); 
 +
print ("contract_abn="+cost);
 +
 +
// Тут я просто изменил под себя, т.е. клиент может вносить любую сумму
 +
contract_balance_new = contract_balance + cost - cost;
 +
 +
print ("contract_balance_new="+contract_balance_new);
 +
 +
if (contract_balance_new >= contract_limit)
 +
 +
{
 +
print ("Balance OK");
 +
 +
contract_groups = contract_groups & ~(1L<<GROUP_ERROR_BALANCE);
 +
 +
query = "UPDATE contract SET gr=? WHERE id=?";
 +
psUpdate = con.prepareStatement( query );
 +
psUpdate.setLong( 1, contract_groups );
 +
psUpdate.setInt( 2, cid );
 +
psUpdate.executeUpdate();
 +
 +
if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE)
 +
{
 +
ContractStatus status = new ContractStatus();
 +
status.setContractId( cid );
 +
status.setDate1( DateNow );
 +
status.setDate2( null );
 +
status.setStatus( KernelConst.CONTRACT_STATUS_ACTIVE );
 +
status.setComment( "Автоматически после оплаты" );
 +
 +
 +
// Тут выдавало ошибку, просто убрал
 +
// status.setUserId( 0 );
 +
 +
contract_status_manager.changeStatus( status );
 +
 +
// Тут не менялось состояние шлюза, добавил код с форума
 +
 +
// Переводим шлюз в статус "открыт"
 +
modset = new ModuleSetup(con, 1);
 +
(new IPNContractStatusManager(con, 1, modset)).changeStatus(cid, 0, 0, true);
 +
 +
};
 +
}
 +
else
 +
{
 +
print ("Balance error");
 +
};
 +
</source>
 +
 +
 +
Остальные два скрипта не смотрел, не использую пока.
 +
Буду признателен, если автор скриптов подправит их более профессионально.

Текущая версия на 11:06, 26 сентября 2009

Приведу пример набора скриптов, для снятия абонентской платы в договорах, работающий по предоплате.

Описание: В начале дня, до начисление абонентской платы, генерируется событие таймера с flag=1. По этому событию запускается скрипт проверки баланса. Если текущий баланс договора не позволяет списать абонентскую плату, то договор приостанавливается с комментарием "Недостаточно средств" и добавляется в группу "Недостаточно средств". Далее для договоров, входящих к группу "Недостаточно средств", при приходе платежа делается проверка. Если текущий баланс позволяет списать абонентскую плату, то статус договора меняется на "активен" с комментарием "Автоматически после оплаты" и договор исключается из группы "Недостаточно средств". Так же для договоров, входящих в группу "Недостаточно средств", есть возможность выполнить доп. действие "Принудительно разблокировать договор". Если его выполнить, то статус договора будет изменен на "активен" с комментарием "Принудительно из доп. действия" и договор будет исключен из группы "Недостаточно средств".

Событие "Таймер"

import java.sql.*;
import java.util.*;
 
import bitel.billing.server.contract.bean.*;
import bitel.billing.server.tariff.*;
import bitel.billing.server.util.*;
import bitel.billing.common.KernelConst; 
 
// код услуги
sid = 23;
// код экземпляра модуля
mid = 7;
//Группа "Недостаточно средств"
GROUP_ERROR_BALANCE = 19;
 
if( event.getFlag() != 1 ) {
    return;
};
 
cid = event.getContractID();
DateNow = new GregorianCalendar();
contract = new ContractManager(con).getContractByID(cid);
if (contract == null){
	return;
};
BalanceMode = contract.getBalanceMode();
if (BalanceMode == 0){
	//Пропускаем тех кто работает по факту
	return;
};
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
if (status != null)
{
   contract_status = status.getStatus();
}
 
if (contract_status == null)
{
	contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
};
if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE) 
{
	//Пропускаем не активные договора
	return;
};
 
date_str=TimeUtils.format(DateNow, "yyyy-MM-dd"); 
 
//Проверяем привязана ли услуга "абонплата"
abn_count = "0";
query_check_abn = 
" SELECT npay_service_object_"+mid+".col"+
" FROM contract_service"+
"   LEFT JOIN npay_service_object_"+mid+
"   ON (contract_service.id=npay_service_object_"+mid+".csid)"+
" WHERE (contract_service.date1 is NULL OR contract_service.date1<='"+date_str+"') AND"+
" (contract_service.date2 is NULL OR contract_service.date2>='"+date_str+"') AND"+
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
re_check_abn = con.prepareStatement(query_check_abn);
rs_check_abn = re_check_abn.executeQuery();
while (rs_check_abn.next())
{
	if (rs_check_abn.getString(1) == null)
	{
		abn_count = "1";
	}
	else
	{
		abn_count = rs_check_abn.getString(1);
	};
};
abn_count = Double.parseDouble(abn_count);
if (abn_count == 0)
{
	//Услуга не найдена.
	return;
};
 
day_str=TimeUtils.format(DateNow, "dd"); 
day = Double.parseDouble(day_str);
 
cost = null;
cost_type = null;
calc_mode = null;
calc_type = null;
// поиск параметров абонплаты
tts = new ContractManager( con ).getRealtimeTariffTreeSet( cid, DateNow, "npay", mid, true );
for( TariffModuleTree tree : tts.getTreeList( DateNow ) )
{
	req_cost = new TariffRequest();
	req_cost.setRequestParam( "action", "calculate" );
	req_cost.setRequestParam( "sid", sid );
	req_cost.setRequestParam( "month_days", 1 );
	req_cost.setRequestParam( "period_days", 1 );
	req_cost.setRequestParam( "time",  DateNow);
	tree.processRequest( req_cost );
	cost = (Double)req_cost.getResponseParam( "cost" );
	cost_type = req_cost.getResponseParam( "cost_type" );
 
	req_calc_mode = new TariffRequest();
	req_calc_mode.setRequestParam( "action", "reset" );
	req_calc_mode.setRequestParam( "sid", sid );
	req_calc_mode.setRequestParam( "time",  DateNow);
	tree.processRequest( req_calc_mode );
	calc_mode = (String)req_calc_mode.getResponseParam( "calc_mode" );
	calc_type = req_calc_mode.getResponseParam( "calc_type" );
};
 
if (cost == null || calc_mode == null)
{
	error ("Параметры абонплаты не найдены");
	return;
};
if (calc_mode.indexOf("month") != -1 && day != 1)
{
	//абонплату за месяц снимаем только 1-ого числа
	return;
};
if (cost == 0)
{
	return;
};
 
cost = cost*abn_count;
print ("cid="+cid);
balance = new BalanceUtils(con);
contract_balance = balance.getBalance (new Date(), cid);
contract_limit = contract.getBalanceLimit();
print ("contract_balance="+contract_balance);  
print ("contract_limit="+contract_limit);  
print ("contract_abn="+cost);
contract_balance_new = contract_balance - cost;
print ("contract_balance_new="+contract_balance_new);
if (contract_balance_new >= contract_limit)
{
	print ("Balance OK");
}
else
{
	print ("Balance error");
 
	contract_groups = contract.getGroups();
	contract_groups = contract_groups | 1L<<GROUP_ERROR_BALANCE;
 
	query = "UPDATE contract SET gr=? WHERE id=?";
	psUpdate = con.prepareStatement( query );
	psUpdate.setLong( 1, contract_groups );
	psUpdate.setInt( 2, cid );
	psUpdate.executeUpdate();
 
	ContractStatus status = new ContractStatus();
	status.setContractId( cid );
	status.setDate1( DateNow	 );
	status.setDate2( null );
	status.setStatus( KernelConst.CONTRACT_STATUS_SUSPENDED );
	status.setComment( "Недостаточно средств" );
	status.setUserId( 0 );
	contract_status_manager.changeStatus( status ); 	
};

Событие "Приход тлатежа"

import java.sql.*;
import java.util.*;
 
import bitel.billing.server.contract.bean.*;
import bitel.billing.server.tariff.*;
import bitel.billing.server.util.*;
import bitel.billing.common.KernelConst; 
 
// код услуги
sid = 23;
// код экземпляра модуля
mid = 7;
//Группа "Недостаточно средств"
GROUP_ERROR_BALANCE = 19;
 
DateNow = new GregorianCalendar();
cid = event.getContractID();
contract = new ContractManager(con).getContractByID(cid);
contract_groups = contract.getGroups();
if ((contract_groups & (1L<<GROUP_ERROR_BALANCE)) == 0)
{
	return;
};
 
BalanceMode = contract.getBalanceMode();
if (BalanceMode == 0){
	//Пропускаем тех кто работает по факту
	return;
};
 
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
if (status != null)
{
   contract_status = status.getStatus();
}
 
if (contract_status == null)
{
	contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
};
 
date_str=TimeUtils.format(DateNow, "yyyy-MM-dd"); 
 
//Проверяем привязана ли услуга "абонплата"
abn_count = "0";
query_check_abn = 
" SELECT npay_service_object_"+mid+".col"+
" FROM contract_service"+
"   LEFT JOIN npay_service_object_"+mid+
"   ON (contract_service.id=npay_service_object_"+mid+".csid)"+
" WHERE (contract_service.date1 is NULL OR contract_service.date1<='"+date_str+"') AND"+
" (contract_service.date2 is NULL OR contract_service.date2>='"+date_str+"') AND"+
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
re_check_abn = con.prepareStatement(query_check_abn);
rs_check_abn = re_check_abn.executeQuery();
while (rs_check_abn.next())
{
	if (rs_check_abn.getString(1) == null)
	{
		abn_count = "1";
	}
	else
	{
		abn_count = rs_check_abn.getString(1);
	};
};
abn_count = Double.parseDouble(abn_count);
if (abn_count == 0)
{
	//Услуга не найдена.
	return;
};
 
cost = null;
cost_type = null;
calc_mode = null;
calc_type = null;
// поиск параметров абонплаты
tts = new ContractManager( con ).getRealtimeTariffTreeSet( cid, DateNow, "npay", mid, true );
for( TariffModuleTree tree : tts.getTreeList( DateNow ) )
{
	req_cost = new TariffRequest();
	req_cost.setRequestParam( "action", "calculate" );
	req_cost.setRequestParam( "sid", sid );
	req_cost.setRequestParam( "month_days", 1 );
	req_cost.setRequestParam( "period_days", 1 );
	req_cost.setRequestParam( "time",  DateNow);
	tree.processRequest( req_cost );
	cost = (Double)req_cost.getResponseParam( "cost" );
	cost_type = req_cost.getResponseParam( "cost_type" );
 
	req_calc_mode = new TariffRequest();
	req_calc_mode.setRequestParam( "action", "reset" );
	req_calc_mode.setRequestParam( "sid", sid );
	req_calc_mode.setRequestParam( "time",  DateNow);
	tree.processRequest( req_calc_mode );
	calc_mode = (String)req_calc_mode.getResponseParam( "calc_mode" );
	calc_type = req_calc_mode.getResponseParam( "calc_type" );
};
 
if (cost == null || calc_mode == null)
{
	error ("Параметры абонплаты не найдены");
	return;
};
if (calc_mode.indexOf("day") != -1)
{
	//При снятии абонплаты за день клиент должен оплатить как минимум за 30 дней
	cost = cost*abn_count*30;
};
if (calc_mode.indexOf("month") != -1)
{
	cost = cost*abn_count;
};
print ("cid="+cid);
balance = new BalanceUtils(con);
contract_balance = balance.getBalance (new Date(), cid);
contract_limit = contract.getBalanceLimit();
print ("contract_balance="+contract_balance);  
print ("contract_limit="+contract_limit);  
print ("contract_abn="+cost);
contract_balance_new = contract_balance - cost;
print ("contract_balance_new="+contract_balance_new);
 
if (contract_balance_new >= contract_limit)
{
	print ("Balance OK");
 
	contract_groups = contract_groups & ~(1L<<GROUP_ERROR_BALANCE);
 
	query = "UPDATE contract SET gr=? WHERE id=?";
	psUpdate = con.prepareStatement( query );
	psUpdate.setLong( 1, contract_groups );
	psUpdate.setInt( 2, cid );
	psUpdate.executeUpdate();
 
	if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE) 
	{
		ContractStatus status = new ContractStatus();
		status.setContractId( cid );
		status.setDate1( DateNow	 );
		status.setDate2( null );
		status.setStatus( KernelConst.CONTRACT_STATUS_ACTIVE );
		status.setComment( "Автоматически после оплаты" );
		status.setUserId( 0 );
		contract_status_manager.changeStatus( status ); 	
	};
}
else
{
	print ("Balance error");
};

Событие "Обработка доп. действия для договора"

import java.sql.*;
import java.util.*;
 
import bitel.billing.server.contract.bean.*;
import bitel.billing.common.KernelConst; 
 
if (event.getActionId() != 21) 
{ 
	print("skipped");
	return; 
}
 
//Группа "Недостаточно средств"
GROUP_ERROR_BALANCE = 19;
 
DateNow = new GregorianCalendar();
cid = event.getContractID();
contract = new ContractManager(con).getContractByID(cid);
contract_groups = contract.getGroups();
 
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
if (status != null)
{
   contract_status = status.getStatus();
}
 
if (contract_status == null)
{
	contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
};
 
contract_groups = contract_groups & ~(1L<<GROUP_ERROR_BALANCE);
 
query = "UPDATE contract SET gr=? WHERE id=?";
psUpdate = con.prepareStatement( query );
psUpdate.setLong( 1, contract_groups );
psUpdate.setInt( 2, cid );
psUpdate.executeUpdate();
 
if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE) 
{
	ContractStatus status = new ContractStatus();
	status.setContractId( cid );
	status.setDate1( DateNow	 );
	status.setDate2( null );
	status.setStatus( KernelConst.CONTRACT_STATUS_ACTIVE );
	status.setComment( "Принудительно из доп. действия" );
	status.setUserId( 0 );
	contract_status_manager.changeStatus( status ); 	
};

Событие "Получить список доп. действия для договора"

import bitel.billing.server.contract.bean.*;
 
//Группа "Недостаточно средств"
GROUP_ERROR_BALANCE = 19;
 
cid = event.getContractID(); 
contract = new ContractManager(con).getContractByID(cid);
contract_groups = contract.getGroups();
 
contract_is_group_error_balance = (contract_groups & (1L<<GROUP_ERROR_BALANCE)) > 0;
 
if (contract_is_group_error_balance)
{
	event.addAction( 21, "Принудительно разблокировать договор" );
};


В новой версии билинга (4.6) эти скрипты не работают. Пришлось немного изменить, чтобы заработали. В яве не спец, поэтому пошел по простому пути, просто обошел некоторые условия. Может кто-то поможет их поправить, чтобы работало полностью со всеми условиями.

Вот исправленные скрипты с ремарками там, где я менял код:

Событие "Таймер"

import java.sql.*;
import java.util.*;
 
// Мои добавления
import bitel.billing.server.ipn.bean.*;
import ru.bitel.bgbilling.server.util.ModuleSetup;
// 
 
import bitel.billing.server.contract.bean.*;
import bitel.billing.server.tariff.*;
import bitel.billing.server.util.*;
import bitel.billing.common.KernelConst; 
 
// код услуги
sid = 25;
// код экземпляра модуля
mid = 15;
//Группа "Недостаточно средств"
GROUP_ERROR_BALANCE = 16;
 
if( event.getFlag() != 1 ) {
    return;
};
 
cid = event.getContractID();
DateNow = new GregorianCalendar();
contract = new ContractManager(con).getContractByID(cid);
if (contract == null){
	return;
};
BalanceMode = contract.getBalanceMode();
if (BalanceMode == 0){
	//Пропускаем тех кто работает по факту
	return;
};
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
if (status != null)
{
   contract_status = status.getStatus();
}
 
if (contract_status == null)
{
	contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
};
if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE) 
{
	//Пропускаем не активные договора
	return;
};
 
date_str=TimeUtils.format(DateNow, "yyyy-MM-dd"); 
 
//Проверяем привязана ли услуга "абонплата"
abn_count = "0";
query_check_abn = 
" SELECT npay_service_object_"+mid+".col"+
" FROM contract_service"+
"   LEFT JOIN npay_service_object_"+mid+
"   ON (contract_service.id=npay_service_object_"+mid+".csid)"+
" WHERE (contract_service.date1 is NULL OR contract_service.date1<='"+date_str+"') AND"+
" (contract_service.date2 is NULL OR contract_service.date2>='"+date_str+"') AND"+
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
re_check_abn = con.prepareStatement(query_check_abn);
rs_check_abn = re_check_abn.executeQuery();
while (rs_check_abn.next())
{
	if (rs_check_abn.getString(1) == null)
	{
		abn_count = "1";
	}
	else
	{
		abn_count = rs_check_abn.getString(1);
	};
};
////Это условие, почему-то, не работало и abn_count не было равно 1, даже когда абонплата была привязана
/// к договору. 
abn_count = "1";
///
abn_count = Double.parseDouble(abn_count);
if (abn_count == 0)
{
	//Услуга не найдена.
	return;
};
 
day_str=TimeUtils.format(DateNow, "dd"); 
day = Double.parseDouble(day_str);
 
cost = null;
cost_type = null;
calc_mode = null;
calc_type = null;
// поиск параметров абонплаты
tts = new ContractManager( con ).getRealtimeTariffTreeSet( cid, DateNow, "npay", mid, true );
for( TariffModuleTree tree : tts.getTreeList( DateNow ) )
{
	req_cost = new TariffRequest();
	req_cost.setRequestParam( "action", "calculate" );
	req_cost.setRequestParam( "sid", sid );
	req_cost.setRequestParam( "month_days", 1 );
	req_cost.setRequestParam( "period_days", 1 );
	req_cost.setRequestParam( "time",  DateNow);
	tree.processRequest( req_cost );
	cost = (Double)req_cost.getResponseParam( "cost" );
	cost_type = req_cost.getResponseParam( "cost_type" );
 
	req_calc_mode = new TariffRequest();
	req_calc_mode.setRequestParam( "action", "reset" );
	req_calc_mode.setRequestParam( "sid", sid );
	req_calc_mode.setRequestParam( "time",  DateNow);
	tree.processRequest( req_calc_mode );
	calc_mode = (String)req_calc_mode.getResponseParam( "calc_mode" );
	calc_type = req_calc_mode.getResponseParam( "calc_type" );
};
 
if (cost == null || calc_mode == null)
{
	error ("Параметры абонплаты не найдены");
	return;
};
if (calc_mode.indexOf("month") != -1 && day != 1)
{
	//абонплату за месяц снимаем только 1-ого числа
	return;
};
if (cost == 0)
{
	return;
};
 
cost = cost*abn_count;
print ("cid="+cid);
balance = new BalanceUtils(con);
contract_balance = balance.getBalance (new Date(), cid);
contract_limit = contract.getBalanceLimit();
print ("contract_balance="+contract_balance);  
print ("contract_limit="+contract_limit);  
print ("contract_abn="+cost);
 
// Тут я просто изменил под себя, т.е. клиент может вносить любую сумму
contract_balance_new = contract_balance + cost - cost;
contract_limit_new = cost / 30;
print ("contract_balance_new="+contract_balance_new);
print ("contract_limit_new="+contract_limit_new);
if (contract_balance_new >= contract_limit + contract_limit_new)
{
	print ("Balance OK");
}
else
{
	print ("Balance error");
///
 
	contract_groups = contract.getGroups();
	contract_groups = contract_groups | 1L<<GROUP_ERROR_BALANCE;
 
	query = "UPDATE contract SET gr=? WHERE id=?";
	psUpdate = con.prepareStatement( query );
	psUpdate.setLong( 1, contract_groups );
	psUpdate.setInt( 2, cid );
	psUpdate.executeUpdate();
 
	ContractStatus status = new ContractStatus();
	status.setContractId( cid );
	status.setDate1( DateNow	 );
	status.setDate2( null );
	status.setStatus( KernelConst.CONTRACT_STATUS_SUSPENDED );
	status.setComment( "Недостаточно средств" );
 
// Тут выдавало ошибку, просто убрал	
//      status.setUserId( 0 );
 
	contract_status_manager.changeStatus( status ); 	
 
// Тут не менялось состояние шлюза, добавил код с форума
 
	// Переводим шлюз в статус "заблокирован" 
	modset = new ModuleSetup(con, 1); 
	(new IPNContractStatusManager(con, 1, modset)).changeStatus(cid, 2, 0, true);
};

Событие "Приход тлатежа"

import java.sql.*;
import java.util.*;
 
import bitel.billing.server.contract.bean.*;
 
// Мои добавления
import bitel.billing.server.ipn.bean.*;
//
 
import bitel.billing.server.tariff.*;
import bitel.billing.server.util.*;
import bitel.billing.common.KernelConst; 
import ru.bitel.bgbilling.server.util.ModuleSetup;
 
// код услуги
sid = 25;
// код экземпляра модуля
mid = 15;
//Группа "Недостаточно средств"
GROUP_ERROR_BALANCE = 16;
 
DateNow = new GregorianCalendar();
cid = event.getContractID();
contract = new ContractManager(con).getContractByID(cid);
contract_groups = contract.getGroups();
if ((contract_groups & (1L<<GROUP_ERROR_BALANCE)) == 0)
{
	return;
};
 
BalanceMode = contract.getBalanceMode();
if (BalanceMode == 0){
	//Пропускаем тех кто работает по факту
	return;
};
 
contract_status_manager  = new ContractStatusManager(con);
status = contract_status_manager.getStatus(cid, DateNow);
contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
if (status != null)
{
   contract_status = status.getStatus();
}
 
if (contract_status == null)
{
	contract_status = KernelConst.CONTRACT_STATUS_ACTIVE;
};
 
date_str=TimeUtils.format(DateNow, "yyyy-MM-dd"); 
 
//Проверяем привязана ли услуга "абонплата"
abn_count = "0";
query_check_abn = 
" SELECT npay_service_object_"+mid+".col"+
" FROM contract_service"+
"   LEFT JOIN npay_service_object_"+mid+
"   ON (contract_service.id=npay_service_object_"+mid+".csid)"+
" WHERE (contract_service.date1 is NULL OR contract_service.date1<='"+date_str+"') AND"+
" (contract_service.date2 is NULL OR contract_service.date2>='"+date_str+"') AND"+
" contract_service.sid='"+sid+"' AND contract_service.cid='"+cid+"'";
re_check_abn = con.prepareStatement(query_check_abn);
rs_check_abn = re_check_abn.executeQuery();
while (rs_check_abn.next())
{
	if (rs_check_abn.getString(1) == null)
	{
		abn_count = "1";
	}
	else
	{
		abn_count = rs_check_abn.getString(1);
	};
};
////Это условие, почему-то, не работало и abn_count не было равно 1, даже когда абонплата была привязана
/// к договору. 
abn_count = "1";
///
abn_count = Double.parseDouble(abn_count);
if (abn_count == 0)
{
	//Услуга не найдена.
	return;
};
 
cost = null;
cost_type = null;
calc_mode = null;
calc_type = null;
// поиск параметров абонплаты
tts = new ContractManager( con ).getRealtimeTariffTreeSet( cid, DateNow, "npay", mid, true );
for( TariffModuleTree tree : tts.getTreeList( DateNow ) )
{
	req_cost = new TariffRequest();
	req_cost.setRequestParam( "action", "calculate" );
	req_cost.setRequestParam( "sid", sid );
	req_cost.setRequestParam( "month_days", 1 );
	req_cost.setRequestParam( "period_days", 1 );
	req_cost.setRequestParam( "time",  DateNow);
	tree.processRequest( req_cost );
	cost = (Double)req_cost.getResponseParam( "cost" );
	cost_type = req_cost.getResponseParam( "cost_type" );
 
	req_calc_mode = new TariffRequest();
	req_calc_mode.setRequestParam( "action", "reset" );
	req_calc_mode.setRequestParam( "sid", sid );
	req_calc_mode.setRequestParam( "time",  DateNow);
	tree.processRequest( req_calc_mode );
	calc_mode = (String)req_calc_mode.getResponseParam( "calc_mode" );
	calc_type = req_calc_mode.getResponseParam( "calc_type" );
};
 
if (cost == null || calc_mode == null)
{
	error ("Параметры абонплаты не найдены");
	return;
};
if (calc_mode.indexOf("day") != -1)
{
	//При снятии абонплаты за день клиент должен оплатить как минимум за 30 дней
 
	cost = cost*abn_count;
//	cost = cost*abn_count*30;
};
if (calc_mode.indexOf("month") != -1)
{
	cost = cost*abn_count;
};
print ("cid="+cid);
balance = new BalanceUtils(con);
contract_balance = balance.getBalance (new Date(), cid);
contract_limit = contract.getBalanceLimit();
print ("contract_balance="+contract_balance);  
print ("contract_limit="+contract_limit);  
print ("contract_abn="+cost);
 
// Тут я просто изменил под себя, т.е. клиент может вносить любую сумму
contract_balance_new = contract_balance + cost - cost;
 
print ("contract_balance_new="+contract_balance_new);
 
if (contract_balance_new >= contract_limit)
 
{
	print ("Balance OK");
 
	contract_groups = contract_groups & ~(1L<<GROUP_ERROR_BALANCE);
 
	query = "UPDATE contract SET gr=? WHERE id=?";
	psUpdate = con.prepareStatement( query );
	psUpdate.setLong( 1, contract_groups );
	psUpdate.setInt( 2, cid );
	psUpdate.executeUpdate();
 
	if (contract_status != KernelConst.CONTRACT_STATUS_ACTIVE) 
	{
		ContractStatus status = new ContractStatus();
		status.setContractId( cid );
		status.setDate1( DateNow	 );
		status.setDate2( null );
		status.setStatus( KernelConst.CONTRACT_STATUS_ACTIVE );
		status.setComment( "Автоматически после оплаты" );
 
 
// Тут выдавало ошибку, просто убрал	
//		status.setUserId( 0 );
 
		contract_status_manager.changeStatus( status ); 	
 
// Тут не менялось состояние шлюза, добавил код с форума
 
		// Переводим шлюз в статус "открыт" 
		modset = new ModuleSetup(con, 1); 
		(new IPNContractStatusManager(con, 1, modset)).changeStatus(cid, 0, 0, true);
 
	};
}
else
{
	print ("Balance error");
};


Остальные два скрипта не смотрел, не использую пока. Буду признателен, если автор скриптов подправит их более профессионально.

Личные инструменты