Организация системы отслеживания и отключения КТВ должников на BGBS с использованием CRM плагина
Материал из BiTel WiKi
// В зависимости от квартала клиента // возможна передача различных групп решения int getTaskGroup() {
quarter = ""; query = "SELECT quarter.title FROM contract_parameter_type_2 AS cp " + " LEFT JOIN address_house AS house ON cp.hid=house.id " + " LEFT JOIN address_quarter AS quarter ON house.quarterid=quarter.id " + " WHERE cp.cid=? AND cp.pid=?"; ps = con.prepareStatement( query ); ps.setInt( 1, cid ); ps.setInt( 2, TASK_ADDRESS_PARAM ); rs = ps.executeQuery(); if( rs.first() ) { quarter = rs.getString( 1 ); }
result = 0;
if( guarter.equals( "1" ) ) { result = GROUP_1; } else { result = GROUP_2; } return result;
}
// коды групп решения задач GROUP_1 = 1; GROUP_2 = 2;
DISCONNECT_TASK = 3; CALL_TASK = 23;
CONNECT_TASK = 24;
TASK_ADDRESS_PARAM = 9; GROUP_DOLG = 15;
// коды параметров договора ФИО и Телефон FIO_PARAM = "1"; PHONE_PARAM = 2;
DEBT_FIX_PARAM = 34;
DEBT_LIMIT = 260; // минимальная сумма баланса, после которой подключать BALANCE_BORDER = 164.99f;
cpu = new ContractParamUtils( con ); contractManager = new ContractManager( con ); taskManager = new RegisterTaskManager( con ); bu = new BalanceUtils( con );
balance = bu.getBalance( time, cid ); contract = contractManager.getContractByID( cid );
dolgGroup = (contract.getGroups() & (1<<GROUP_DOLG) ) > 0; print( "dolg group => " + dolgGroup );
// оплатил должник - можно подлкючать if( dolgGroup && balance > BALANCE_BORDER ) {
// есть не закрытая задача "подключение должника" connectTask = false;
filter = new RegisterTaskManager.TaskFilter(); filter.types = String.valueOf( CONNECT_TASK ); filter.cid = cid;
activeTasks = taskManager.getNoClosedTaskList( cid ); for( RegisterTask task : activeTasks ) { // задача не закрыта либо закрыта но не обработана if( task.getStatus() != RegisterTask.STATUS_CLOSED || !task.isProcessed() ) { connectTask = true; print( "1" ); break; } }
print( "connectTask => " + connectTask ); // создание задачи на подключение if( !connectTask ) { RegisterTask task = new RegisterTask(); task.setContractID( cid ); task.setTypeID( CONNECT_TASK );
groupId = getTaskGroup(); task.setGroupID( groupId ); task.setOpenUserID( 0 ) ; task.setOpenTime( event.getGenerateTime() ); task.setComment( "" ); task.setAddressParamID( TASK_ADDRESS_PARAM );
taskManager.updateTask( "new", task );
//отправка письма на почту filter = new RegisterTaskManager.TaskFilter(); filter.id = task.getID(); filter.fioParams = FIO_PARAM; filter.phoneParam = PHONE_PARAM; filter.processed = -1; filter.orders = new ArrayList(); print( "filter = " + filter + "; taskManager = " + taskManager ); personalTask = taskManager.getTaskList( filter, new Page( 1, 1 ) ).get( 0 ); message = new StringBuffer( 300 ); message.append( contract.getTitle() ); message.append( " " ); message.append( personalTask.getStreet() ); message.append( " " ); message.append( personalTask.getHouse() ); message.append( " " ); message.append( personalTask.getFlat() ); new MailMsg( setup ).sendMessageEx( "disp@disp.com", "Оплатил должник", message.toString(), "text/plain" ); // print( "Sending to mail.." ); }
} // работающий клиент else {
if( balance <= - ( DEBT_LIMIT - 1 ) ) { print( "it's debt" ); return; } // закрытие активных задач на дозвон и отключение должника List activeTasks = taskManager.getNoClosedTaskList( cid ); for( RegisterTask task : activeTasks ) { // собственно закрытие таких задач if( ( task.getTypeID() == DISCONNECT_TASK && task.getStatus() == RegisterTask.STATUS_OPEN ) || (task.getTypeID() == CALL_TASK && task.getStatus() != RegisterTask.STATUS_CLOSED ) ) { task.setResolution( task.getResolution() + "\nОплатил " + TimeUtils.formatDate( time ) ); task.setCloseUserID( 0 ); task.setCloseTime( time ); task.setExecuteDate( time ); task.setGroupID( DEFAULT_GROUP ); task.setStatus( RegisterTask.STATUS_CLOSED ); taskManager.updateTask( String.valueOf( task.getID() ), task ); print( "Closing DISCONNECT and CALL task: " + task.getID() ); } // если принятая задача на отключение - отправка письма if( task.getTypeID() == DISCONNECT_TASK && task.getStatus() == RegisterTask.STATUS_ACCEPTED ) {
print( "The task already has an ACCEPTED status." );
//отправка письма на почту filter = new RegisterTaskManager.TaskFilter(); filter.id = task.getID(); filter.fioParams = FIO_PARAM; filter.phoneParam = PHONE_PARAM; filter.processed = -1; filter.orders = new ArrayList(); personalTask = taskManager.getTaskList( filter, new Page( 1, 1 ) ).get( 0 ); message = new StringBuffer( 300 ); message.append( personalTask.getStreet() ); message.append( " " ); message.append( personalTask.getHouse() ); message.append( " " ); message.append( personalTask.getFlat() ); message.append( " " ); message.append( personalTask.getContract() ); new MailMsg( setup ).sendMessageEx( "disp@disp.com", "Оплатил отключаемый", message.toString(), "text/plain" ); print( "Send message Pay in disconnect" ); } } print( "Deleting debt fix date.." ); cpu.deleteDateParam( cid, DEBT_FIX_PARAM );
} </source>
Для не оплативших в течении указанного количества дней после выполненной задачи обзвона должников создаются задачи на Отключение должника. Они могут быть распечатаны в виде нарядов монтажникам, для чего используется шаблон отчета журнала задач Отчет по подключению (файл выложен выше в статье). Этот же шаблон можно использовать при создании нарядов на подключение.
Выполненные задачи помечаются выполненными и обрабатываются оператором. При обработке задач отрабатывает скрипт для задач типа Подключение должника и Отключение должника.
import java.sql.*; import java.util.*; import bitel.billing.server.contract.bean.*; import bitel.billing.server.util.*; import ru.bitel.bgbilling.plugins.crm.server.dao.*; import ru.bitel.bgbilling.plugins.crm.common.model.*; import bitel.billing.server.model.*; DISCONNECT_TASK = 3; CONNECT_TASK = 24; // группа должник GROUP_DOLG = 15; // группа "пенсионер" GROUP_PENS = 34; // код услуги "абонплата" SERVICE_PAY = 2; // код услуги "абонплата долг" SERVICE_PAY_DOLG = 3; // код услуги "абонплата пенсионеров" SERVICE_PAY_PENS = 8; // код расхода "за повторное включение" RECONNECT_CHARGE = 5; DEBT_FIX_PARAM = 34; // сумма расхода за повторное включение RECONNECT_SUM = 75; BALANCE_BORDER = 164.99f; ADDRESS_PARAM = 9; FIO_PARAM = "1"; PHONE_PARAM = 2; cid = event.getContractID(); task = event.getTask(); // В зависимости от квартала клиента // возможна передача различных групп решения int getTaskGroup() { quarter = ""; query = "SELECT quarter.title FROM contract_parameter_type_2 AS cp " + " LEFT JOIN address_house AS house ON cp.hid=house.id " + " LEFT JOIN address_quarter AS quarter ON house.quarterid=quarter.id " + " WHERE cp.cid=? AND cp.pid=?"; ps = con.prepareStatement( query ); ps.setInt( 1, cid ); ps.setInt( 2, TASK_ADDRESS_PARAM ); rs = ps.executeQuery(); if( rs.first() ) { quarter = rs.getString( 1 ); } result = 0; if( guarter.equals( "1" ) ) { result = GROUP_1; } else { result = GROUP_2; } return result; } // коды групп решения задач GROUP_1 = 1; GROUP_2 = 2; report = event.getReport(); serviceManager = new ContractServiceManager( con ); cu = new ContractUtils( con ); cpu = new ContractParamUtils( con ); chm = new ChargeManager( con ); contractManager = new ContractManager( con ); bu = new BalanceUtils( con ); taskManager = new RegisterTaskManager( con ); if( task.getTypeID() != DISCONNECT_TASK && task.getTypeID() != CONNECT_TASK ) { print( "This task type does't processing.." ); return; } if( task.getStatus() != RegisterTask.STATUS_CLOSED ) { report.append( cu.getContractTitle( cid, true ) ); report.append( " => задача не закрыта\n" ); return; } Calendar date = task.getExecuteDate(); if( date == null ) { report.append( cu.getContractTitle( cid, true ) ); report.append( " => не установлена дата исполнения\n" ); error( "executeDate == null" ); return; } beforeDay = task.getExecuteDate().clone(); beforeDay.add( Calendar.DAY_OF_YEAR, -1 ); // перечень услуг на дату services = serviceManager.getContractServiceList( cid, date ); contract = contractManager.getContractByID( cid ); dolgGroup = (contract.getGroups() & (1<<GROUP_DOLG) ) > 0; print( "dolg group => " + dolgGroup ); pensGroup = (contract.getGroups() & (1L<<GROUP_PENS) ) > 0; print( "pens group => " + pensGroup ); // отключение должника if( task.getTypeID() == DISCONNECT_TASK ) { if( dolgGroup ) { report.append( cu.getContractTitle( cid, true ) ); report.append( " => у договора уже стоит группа долг\n" ); return; } for( ContractService service : services ) { // закрытие абонплаты if( service.getServiceID() == SERVICE_PAY || service.getServiceID() == SERVICE_PAY_PENS ) { service.setDate2( beforeDay ); serviceManager.updateContractService( String.valueOf( service.getID() ), service ); } } // открытие абонплаты "долг" cs = new ContractService(); cs.setContractID( cid ); cs.setServiceID( SERVICE_PAY_DOLG ); cs.setDate1( task.getExecuteDate() ); cs.setComment( "Установлена скриптом" ); serviceManager.updateContractService( "new", cs ); // установка группы "долг" cpu.setGroup( cid, GROUP_DOLG ); // если баланс позволяет - сразу открытие задачи "Подключение должника" balance = bu.getBalance( new GregorianCalendar(), cid ); print( "balance=" + balance ); if( balance >= BALANCE_BORDER ) { // есть не закрытая задача "подключение должника" connectTask = false; List activeTasks = taskManager.getNoClosedTaskList( cid ); for( RegisterTask task : activeTasks ) { print( "task type: " + task.getTypeID() ) ; if( task.getTypeID() == CONNECT_TASK ) { connectTask = true; break; } } print( "connectTask => " + connectTask ); // создание задачи на подключение if( !connectTask ) { task = new RegisterTask(); task.setContractID( cid ); task.setTypeID( CONNECT_TASK ); task.setGroupID( getTaskGroup() ); task.setOpenUserID( 0 ) ; task.setOpenTime( event.getGenerateTime() ); task.setComment( "" ); task.setAddressParamID( ADDRESS_PARAM ); taskManager.updateTask( "new", task ); report.append( cu.getContractTitle( cid, true ) ); report.append( " => создана задача на подключение\n" ); //отправка письма на почту filter = new RegisterTaskManager.TaskFilter(); filter.id = task.getID(); filter.fioParams = FIO_PARAM; filter.phoneParam = PHONE_PARAM; filter.processed = -1; filter.orders = new ArrayList(); personalTask = taskManager.getTaskList( filter, new Page( 1, 1 ) ).get( 0 ); message = new StringBuffer( 300 ); message.append( personalTask.getStreet() ); message.append( " " ); message.append( personalTask.getHouse() ); message.append( " " ); message.append( personalTask.getFlat() ); message.append( " " ); message.append( personalTask.getContract() ); new MailMsg( setup ).sendMessageEx( "bill@ufanet.ru;disp@ufanet.ru;setks@ufanet.ru", "Оплатил отключенный", message.toString(), "text/plain" ); print( "Send message Pay in disconnect process" ); } } } // подключение должника else if( task.getTypeID() == CONNECT_TASK ) { if( !dolgGroup ) { report.append( cu.getContractTitle( cid, true ) ); report.append( " => у договора нет группы долг\n" ); return; } for( ContractService service : services ) { // закрытие абонплаты "долг" if( service.getServiceID() == SERVICE_PAY_DOLG ) { service.setDate2( beforeDay ); serviceManager.updateContractService( String.valueOf( service.getID() ), service ); } } // открытие абонплаты cs = new ContractService(); cs.setContractID( cid ); if( pensGroup ) { cs.setServiceID( SERVICE_PAY_PENS ); } else { cs.setServiceID( SERVICE_PAY ); } cs.setDate1( task.getExecuteDate() ); cs.setComment( "Установлена скриптом" ); serviceManager.updateContractService( "new", cs ); // снятие расхода за повторное подключение charge = new Charge(); charge.setContractID( cid ); charge.setChargeTypeID( RECONNECT_CHARGE ); charge.setSumma( RECONNECT_SUM ); charge.setDate( task.getExecuteDate() ); charge.setComment( "Установлена скриптом" ); chm.updateCharge( "new", charge ); print( "setting charge" ); bu.updateBalance( task.getExecuteDate(), cid ); // сброс группы "Должник" cpu.unsetGroup( cid, GROUP_DOLG ); cpu.deleteDateParam( cid, DEBT_FIX_PARAM ); } task.setProcessed( true );
Когда клиент отключен за долг у него устанавливается абонплата Долг с нулевой ценой. Разумного требованию этому нет, сделано с точки зрения аналитики базы. При обработке задач скрипт выдает отчет по ошибкам и нестыковкам оператору.