Организация системы отслеживания и отключения КТВ должников на BGBS с использованием CRM плагина

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

Версия от 05:36, 25 сентября 2008; Admin (Обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Ставится задача автоматического массового выявления, оповещения и отключения должников по КТВ.

В планировщике заданий добавляем генерацию события таймера. Событие генерируется каждые сутки в 0 часов 1 минуту.

Изображение:ktv_debt_fix_timer.png

Общий алгоритм работы следующий:

  1. Раз в месяц по таймеру запускается задача выявления должников. В параметрах договоров-должников проставляется дата фиксации долга и создается задача на обзвон должников.
  2. Далее производится обзвон (либо разнос квитанций), задачи помечаются выполненными и обрабатываются.
  3. Следюущая обработка события таймера зафиксировав выполненную задачу обзвона и констатировав, что долг еще есть - создает задачу на отключение должника.
  4. При обработке задачи отключения должника автоматически закрывается абонентская плата, устанавливается группа договора долг.

Типы задач:

  1. Отключение должника (код 3 в данном примере)
  2. Обзвон должника (код 23 в данном примере)
  3. Подключение должника (код 24 в данном примере)

В справочнике групп решения CRM могут быть определены одна или несколько групп, группа может определяться в з

Необходимые параметры договора:

  1. Адрес, тип Адрес (код 9) в данном примере
  2. Дата фиксации долга, тип Дата (код 34 в данном примере)

Необходимые группы договоров:

  1. Должник - пометка договора, октлюченного за долг (код группы 15 в данном примере)

В меню Автоматизация=>Скрипты поведения добавляем обработчик данного события.

import java.sql.*;
import java.util.*;
 
import bitel.billing.server.contract.bean.*;
import bitel.billing.server.script.bean.event.*;
import bitel.billing.server.util.*;
import ru.bitel.bgbilling.plugins.crm.server.dao.*;
import ru.bitel.bgbilling.plugins.crm.common.model.*;
 
/* В зависимости от квартала клиента возможн
*/
int getTaskGroup() {
    result = 0;
 
    query = 
        "SELECT quarter.gid 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() ) {
        result = rs.getInt( 1 );
    }
 
    return result;
}
 
 
DISCONNECT_TASK = 3;
CALL_TASK = 23;
 
DEBT_FIX_PARAM = 34; 
 
TASK_ADDRESS_PARAM = 9;   
DAYS_AFTER_CALL = 3;
 
DEFAULT_GROUP = 8;
 
GROUP_DOLG = 15;
GROUP_ERKC = 43;
GROUP_USL_RAST = 21;
GROUP_VIP = 12;
 
MONTHLY_CHARGE = 130;
MONTHLY_CHARGE_CHEAP = 105;
 
ERKC_ACTIVE_DATE_PARAM = 52;
 
 
cid = event.getContractID();
time = event.getGenerateTime();
 
print( "cid=" + cid );
 
if( event.getFlag() != 1 ) {
    print( "Flag != 1, skipping.." );
    return;
}
 
bu = new BalanceUtils( con );   
rtm = new RegisterTaskManager( con );
cm = new ContractManager( con );
cpu = new ContractParamUtils( con );
tm = new ContractTariffManager( con );
 
contract = cm.getContractByID( cid );
 
// Проверки ---------------------------------------------------------------------------------------------------------------
 
// Договора ЕРКЦ не контролируются на долги, ЕРКЦ занимается этим сам
erkcGroup = ( contract.getGroups() & (1L<<GROUP_ERKC) ) > 0;
 
if( erkcGroup ) {
    print( "erkc group" );
    erkcActiveDate = cpu.getDateParam( cid, ERKC_ACTIVE_DATE_PARAM );
    if ( erkcActiveDate == null ) {
        error( "ERKC Activation Date is not set" );
        return;
    }
    else {
        if ( time.before( erkcActiveDate ) ) {
            print( "ERKC is not yet activated. Activation date: " + erkcActiveDate.get( Calendar.DAY_OF_MONTH ) + "." + ( erkcActiveDate.get( Calendar.MONTH ) + 1 ) + "." + erkcActiveDate.get( Calendar.YEAR ) );
        }
        else {
            print( "ERKC activated. No debts controlled" );
            //return;
        }
    }
}
 
// Условно расторгнутые
uslRastorg = ( contract.getGroups() & (1L<<GROUP_USL_RAST) ) > 0;
if( uslRastorg ) {
    print( "usl rastorg group" );
    return;
}
 
// Должники
dolgGroup = ( contract.getGroups() & (1L<<GROUP_DOLG) ) > 0;
if( dolgGroup ) {
    print( "dolg group" );
    return;
}
 
// VIP-клиенты
vipGroup = ( contract.getGroups() & (1L<<GROUP_VIP) ) > 0;
if( vipGroup ) {
    print( "vip group" );
    return;
}
 
// Кредитные договора
if( contract.getBalanceMode() == Contract.CREDIT_BALANCE_MODE ) {
    print( "credit mode" );
    return;
}
 
// Конец проверок ---------------------------------------------------------------------------------------------------------
 
debt = false; 
 
float balance = bu.getBalance( time, cid );
 
// Выбираем лимит под тариф
tp = tm.getContractTariff( cid, time );
if( tp == null ) {
    error("no active tariff plans" );
    return;
}
tpid = tp.getTariffPlanID();
 
switch( tpid ) {
    case 10:
      monthlyCharge = MONTHLY_CHARGE;
      break;
    case 12:
      monthlyCharge = MONTHLY_CHARGE_CHEAP;
      break;
    case 14:
      monthlyCharge = MONTHLY_CHARGE_CHEAP;
      break;
    default:
      monthlyCharge = MONTHLY_CHARGE;
      break;
}
 
// до 20-го числа за должников считаем тех, у кого баланс меньше 3-х абонок,
// после 20-го -- меньше 2-х абонок
if( time.get( Calendar.DATE ) < 20 ) {
    print("do 20");
    if( balance < - 3 * monthlyCharge + .01 ) {
        debt = true;
    }
}
else {
    print("posle 20");
    if( balance < - 2 * monthlyCharge + .01 ) {
        debt = true;
    }
}
 
 
if( erkcGroup ) {
	if( balance < - 6 * monthlyCharge + .01 ) {
		debt = true;
		print( "Debug ERKC < 6 month debt" );
	}
}
 
if( !debt ) {   
    return;
}
 
 
 
fixDate = cpu.getDateParam( cid, DEBT_FIX_PARAM );
if( fixDate == null ) {
   fixDate = (Calendar)time.clone();
   cpu.setDateParam( cid, DEBT_FIX_PARAM, fixDate );
}
 
print(  "fixDate=" +  TimeUtils.formatDate( fixDate ) );
 
callTask = null;
disconnectTask = null;
 
taskList = rtm.getAfterDateTaskList( cid, fixDate );
for( RegisterTask task : taskList )
{
   if( task.getTypeID() == CALL_TASK )
   {
     callTask = task;
   }
 
   if( task.getTypeID() == DISCONNECT_TASK )
   {
    disconnectTask = task;
   }
}
 
print( "callTask = " + callTask + "; disconnectTask = " + disconnectTask );
 
// долг есть а задачи на обзвон нет
if( callTask == null )
{
   callTask = new RegisterTask();    
 
   callTask.setContractID( cid );
   callTask.setAddressParamID( TASK_ADDRESS_PARAM );
 
   callTask.setOpenTime( time );
   callTask.setOpenUserID( 0 );
 
   callTask.setTypeID( CALL_TASK );
   callTask.setComment( "Долг: " + Utils.formatCost( balance ) ) ;
 
   groupId = getTaskGroup();
   if( groupId <= 0 )        
   {
         qroupId = DEFAULT_GROUP;
   } 
 
   callTask.setGroupID( groupId );
 
   print( "creating call task" )  ;
   rtm.updateTask( "new", callTask );
}
// статус задачи открыт - обновляем информацию о долге
else if ( callTask.getStatus() == RegisterTask.STATUS_OPEN  ) {
    callTask.setComment( "Долг: " + Utils.formatCost( balance ) ) ;
    rtm.updateTask(  String.valueOf( callTask.getID() ), callTask ); 
}
// задача дозвона выполнена
else if ( callTask.getStatus() == RegisterTask.STATUS_CLOSED ) {
    // задачи на отключения нет
	if( erkcGroup ) {
		print( "For ERKC orders don't need taks for turn off" ) ;
		return;
	}
    if ( disconnectTask == null ) {
        // после обзвона прошел срок
        if ( TimeUtils.daysDelta( callTask.getExecuteDate(), time ) >= DAYS_AFTER_CALL ) {
           disconnectTask = new RegisterTask();
 
           disconnectTask.setContractID( cid );
           disconnectTask.setAddressParamID( TASK_ADDRESS_PARAM );
 
           disconnectTask.setOpenTime( time );
           disconnectTask.setOpenUserID( 0 );
 
           disconnectTask.setTypeID( DISCONNECT_TASK );
 
           groupId = getTaskGroup();
           if( groupId <= 0 ) {
                 groupId = DEFAULT_GROUP;
           } 
 
           disconnectTask.setGroupID( groupId ); 
           disconnectTask.setComment( "Долг: " + Utils.formatCost( balance ) ) ;
 
           print( "creating disconnect task." );
           rtm.updateTask( "new", disconnectTask );
        }
    }
    // открыта задача на отключение
    else if ( disconnectTask.getStatus() == RegisterTask.STATUS_OPEN ) {
        disconnectTask.setComment( "Долг: " + Utils.formatCost( balance ) ) ;
        rtm.updateTask(  String.valueOf( disconnectTask.getID() ), disconnectTask );
    }
}
Личные инструменты