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

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

(Различия между версиями)
Перейти к: навигация, поиск
м
 
(7 промежуточных версий не показаны.)
Строка 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");
};


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

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