Пример автоматизации подключения новых клиентов
Материал из BiTel WiKi
Приведу пример автоматизации работ, связанных с подключением новых абонентов.
Общая схема работы.
Оператор заключает договора на интернет или телефонию.
При создании договора, стоимость подключения автоматически прописывается в параметре договора и в персональном тарифе. Стоимость подключения, указанная в параметре договора, используется при печати договора и при определении определении минимальной суммы оплаты, после которой начнется процедура подключения. Стоимость подключения, указанная в персональном тарифе, списывается со счета абонента после окончания процедуры подключения.
Для физических лиц, стоимость подключения берется из глобального тарифа для услуг RSCM с кодами 17("Подключение - Интернет") и 29 ("Подключение - Телефонии"). А для юридических лиц всегда 0 р. Оператор, при необходимости, может изменить стоимость подключения.
При создании статус договора переводится с состояние "Приостановлен".
После создания и заполнения данных договора оператор должен принять решение. Он должен добавить договора в очередь "Ожидание оплаты подключения" или в очередь "Ожидание подключения". Происходит это через доп. действия договора.
При попадании в очередь "Ожидание оплаты подключения" договор помещается в группу "Ожидание оплаты подключения" с кодом 17. Для договоров, входящих в группу "Ожидание оплаты подключения" при приходе платежа делается проверка. Если баланс договора (после занесения платежа) больше или равен стоимости подключения, прописанной в параметрах договора, то договора автоматически помещается в очередь "Ожидание подключения" и исключается из группы "Ожидание оплаты подключения". Если баланс договора меньше стоимости подключения, то в CRM создается задача, в которого говориться что оплата не достаточна и необходимо известить об этом абонента.
Событие "Договор создан" (Создание персонального тарифа на подключение)
import java.sql.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import bitel.billing.server.contract.bean.*; import bitel.billing.server.tariff.*; import bitel.billing.server.util.*; import bitel.billing.server.script.bean.event.*; import bitel.billing.server.service.bean.*; import bitel.billing.server.contract.bean.*; RSCM_ID = 9; // код модуля RSCM VPN_ID = 1; // код модуля VPN IPN_ID = 4; // код модуля IPN PHONE_ID = 5; // код модуля Телефония INTERNET_COST_NODE = 12293;// код узла, где хранится цена за подключение Интернета PHONE_COST_NODE = 12295; // код узла, где хранится цена за подключение Телефона INTERNET_SERVICE_ID = 17; // код услуги "Подключение - Интернет" PHONE_SERVICE_ID = 29; // код услуги "Подключение - Телефон" PID_CONNECT_COST = 46; // код параметра договора "Стоимость подключения" createPT(title, cost_node, service_id) { print("Start creating tariff [" + title + "]"); // создать ПТ pt = new PersonalTariff(); pt.setContractId(cid); pt.setTitle(title); ptm.updatePersonalTariff(pt); // получить treeID tid = pt.getId(); pt = ptm.getPersonalTariff(tid); treeId = pt.getTreeId(); print("Tariff created. TreeId: " + String.valueOf(treeId) ); // сгенерировать lm lm = new Date().getTime(); // добавить запись в module_tariff_tree и получить ее Id ps = con.prepareStatement( "INSERT INTO module_tariff_tree (mid, tree_id, lm) VALUES (?, ?, ?)" ); ps.setInt( 1, RSCM_ID ); ps.setInt( 2, treeId ); ps.setLong( 3, lm ); rs = ps.executeUpdate(); print("INSERT INTO module_tariff_tree (mid, tree_id)" + "VALUES (" + String.valueOf(RSCM_ID) + "," + String.valueOf(treeId) +")"); rs = con.prepareStatement( "select LAST_INSERT_ID()" ).executeQuery(); rs.next(); mttId = rs.getInt(1); print("mtree_id: " + String.valueOf(mttId)); // получить максимальное значение pos из mtree_node ps = con.prepareStatement( "SELECT MAX(pos) FROM mtree_node" ); rs = ps.executeQuery(); rs.next(); newpos = rs.getInt(1) + 1; print("mtree_node.pos: " + String.valueOf(newpos)); // корневая запись запись в mtree_node ps = con.prepareStatement( "insert into mtree_node (parent_node, mtree_id, type, pos) values (0, ?, 'root', ?)" ); ps.setInt( 1, mttId ); ps.setInt( 2, newpos ); rs = ps.executeUpdate(); print("insert into mtree_node (parent_node, mtree_id, type, pos)" + "VALUES (0," + String.valueOf(mttId) + ",'root'," + String.valueOf(newpos) +")"); // услуга ps = con.prepareStatement( "insert into mtree_node (parent_node, mtree_id, type, data) values (LAST_INSERT_ID(), ?, 'service', ?)" ); ps.setInt( 1, mttId ); ps.setInt( 2, service_id ); rs = ps.executeUpdate(); print("insert into mtree_node (parent_node, mtree_id, type, data)" + "values (LAST_INSERT_ID()," + String.valueOf(mttId) + ",'service'," + String.valueOf(INTERNET_SERVICE_ID) +")"); cid = event.getContractID(); cm = new ContractManager(con); contract = cm.getContractByID(cid); cpu = new ContractParamUtils( con ); // Получить стоимость из глобального тарифного плана "_Подключение", если физик if (contract.getFc() == 0) { ps = con.prepareStatement( "SELECT data FROM mtree_node WHERE id=?" ); ps.setInt( 1, cost_node ); rs = ps.executeQuery(); rs.next(); cost = rs.getString(1); } // стоимость равна нулю, если юрик else { cost = "cost&0.0%col&1"; } // Установить стоимость ps = con.prepareStatement( "insert into mtree_node (parent_node, mtree_id, type, data) values (LAST_INSERT_ID(), ?, 'cost', ?)" ); ps.setInt( 1, mttId ); ps.setString( 2, cost ); rs = ps.executeUpdate(); print("insert into mtree_node (parent_node, mtree_id, type, data)" + "values (LAST_INSERT_ID()," + String.valueOf(mttId) + ",'cost','" + String.valueOf(cost) +"')"); // Прописать стоимость в параметре договора Pattern pattern = Pattern.compile("cost&(\\d+)\\.\\d+%"); Matcher matcher = pattern.matcher(cost); try{ if (matcher.find()) { costValue = matcher.group(1); cpu.setStringParam( cid, PID_CONNECT_COST, costValue ); } } catch (Exception exception) { error("Get connection cost:" + exception.getMessage()); } } //_________________________________________________________________________________________________________ cid = event.getContractID(); ptm = new PersonalTariffManager( con ); csm = new ContractServiceManager( con ); msu = new ModuleAndServiceUtils( con ); // ищем услуги в модуле RSCM inetConnect = false; phoneConnect = false; services = msu.getContractService(cid, RSCM_ID); for ( int i = 0; i < services.size() ; i++ ) { service = services.get(i); if (service.getId() == INTERNET_SERVICE_ID) { inetConnect = true; } if (service.getId() == PHONE_SERVICE_ID) { phoneConnect = true; } } // Интернет if (inetConnect) { createPT("Подключение - Интернет", INTERNET_COST_NODE, INTERNET_SERVICE_ID); } // Телефон if (phoneConnect) { createPT("Подключение - Телефон", PHONE_COST_NODE, PHONE_SERVICE_ID); }
Событие "Договор создан" (Приостановка договора)
import bitel.billing.server.script.bean.event.*; import bitel.billing.server.contract.bean.*; cid = event.getContractID(); contract = event.getContract(); print(contract); csm = new ContractStatusManager(con); cs = new ContractStatus(); cs.setContractId(cid); cs.setDate1(contract.getDate1()); cs.setStatus(4); csm.changeStatus(cs);
Событие "Получение списка доп. действий для договора"
import bitel.billing.server.contract.bean.*; //Группа ожидания оплаты подключения GROUP_EP = 17; //Группа ожидания подключения GROUP_EC = 18; //Параметр, в котором прописана дата начала предоставления услуг PARAM_START_DATE = 49; cid = event.getContractID(); contract = new ContractManager(con).getContractByID(cid); contract_groups = contract.getGroups(); contract_param_utils = new ContractParamUtils( con ); contract_is_group_ep = (contract_groups & (1L<<GROUP_EP)) > 0; contract_is_group_ec = (contract_groups & (1L<<GROUP_EC)) > 0; contract_start_date = contract_param_utils.getDateParam( cid, PARAM_START_DATE ); if (contract_start_date == null && !contract_is_group_ep && !contract_is_group_ec) { event.addAction( 15, "Добавить договор в очередь \"ожидание оплаты подключения\"" ); }; if (contract_start_date == null && !contract_is_group_ec) { event.addAction( 16, "Добавить договор в очередь \"ожидание подключения\"" ); };
Событие "Обработка доп. действия для договора" (Добавление договора в очередь "Ожидание оплаты подключения")
import java.sql.*; import java.util.*; import bitel.billing.server.contract.bean.*; if (event.getActionId() != 15) { print("skipped"); return; } //Группа ожидания оплаты подключения GROUP_EP = 17; cid = event.getContractID(); contract = new ContractManager(con).getContractByID(cid); contract_groups = contract.getGroups(); contract_groups = contract_groups | 1L<<GROUP_EP; query = "UPDATE contract SET gr=? WHERE id=?"; psUpdate = con.prepareStatement( query ); psUpdate.setLong( 1, contract_groups ); psUpdate.setInt( 2, cid ); psUpdate.executeUpdate();
Событие "Обработка доп. действия для договора" (Добавление договора в очередь "Ожидание подключения")
import java.sql.*; import java.util.*; import bitel.billing.server.contract.bean.*; import bitel.billing.server.contract.object.bean.*; import ru.bitel.bgbilling.plugins.crm.server.dao.*; import ru.bitel.bgbilling.plugins.crm.common.model.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; private getObject (cid) { object_manager = new ObjectManager(con); contract_objects = object_manager.getObjectList(cid); for( ContractObject object : contract_objects ) { return object.getId(); }; return null; } private getTargetDate() { day = 0; if (contract_fc == 0){ day = 60; }; if (contract_fc == 1){ day = 14; }; CalendarTargetDate = Calendar.getInstance(); CalendarTargetDate.add( Calendar.DAY_OF_YEAR, day ); TargetDate = new Date(CalendarTargetDate.getTime().getTime()); return TargetDate; } private getTaskType() { if (contract_type == 1){ return 3; }; if (contract_type == 2){ return 4; }; } private getTaskGroup() { return 3; } private GetCRMComment() { query_crm_comment = "SELECT comment FROM contract_comment WHERE LOWER(subject) LIKE '%crm%' AND cid='"+cid+"';"; ps_crm_comment = con.prepareStatement(query_crm_comment); rs_crm_comment = ps_crm_comment.executeQuery(); if ( rs_crm_comment.next() ) { return rs_crm_comment.getString(1); } else { return "Задача создана автоматически"; } } if (event.getActionId() != 16) { print("skipped"); return; } //Группа ожидания оплаты подключения GROUP_EP = 17; //Группа ожидания подключения GROUP_EC = 18; //Группа Интернет GROUP_INTERNET = 14; //Группа Телефония GROUP_PHONE = 7; EventDate = new Date(); cid = event.getContractID(); contract = new ContractManager(con).getContractByID(cid); contract_firma = contract.getFirmID(); contract_groups = contract.getGroups(); contract_type = 0; // contract_type = 1 - интернет // contract_type = 2 - телефония if ((contract_groups & (1L<<GROUP_INTERNET)) > 0) { contract_type = 1; } else if ((contract_groups & (1L<<GROUP_PHONE)) > 0) { contract_type = 2; } else { return; }; contract_fc = contract.getFc(); contract_groups = contract_groups & ~(1L<<GROUP_EP); contract_groups = contract_groups | 1L<<GROUP_EC; query = "UPDATE contract SET gr=? WHERE id=?"; psUpdate = con.prepareStatement( query ); psUpdate.setLong( 1, contract_groups ); psUpdate.setInt( 2, cid ); psUpdate.executeUpdate(); //Ищем задачу на подключение filter = new RegisterTaskManager.TaskFilter(); filter.cid = cid; filter.types = Integer.toString(getTaskType()); register_task_manager = new RegisterTaskManager( con ); task_count = register_task_manager.getTaskCount(filter); object = getObject(cid); if (task_count == 0 && object != null){ RegisterTask task = new RegisterTask(); task.setContractID( cid ); task.setTypeID( getTaskType() ); task.setGroupID( getTaskGroup() ); task.setOpenUserID( 0 ) ; task.setOpenTime( EventDate ); task.setComment( GetCRMComment() ); task.setAddressParamID( 2 ); task.setAddressObjectId( object ); task.setTargetDate(getTargetDate()); register_task_manager.updateTask( "new", task ); };
Событие "Приход платежа" (Проверка оплаты подключения)
import java.sql.*; import java.util.*; import bitel.billing.server.contract.bean.*; import bitel.billing.server.util.*; import bitel.billing.server.contract.object.bean.*; import ru.bitel.bgbilling.plugins.crm.server.dao.*; import ru.bitel.bgbilling.plugins.crm.common.model.*; import bitel.billing.server.model.*; private getObject (cid) { object_manager = new ObjectManager(con); contract_objects = object_manager.getObjectList(cid); for( ContractObject object : contract_objects ) { return object.getId(); }; return null; } private getTargetDate() { day = 0; if (contract_fc == 0){ day = 60; }; if (contract_fc == 1){ day = 14; }; CalendarTargetDate = Calendar.getInstance(); CalendarTargetDate.add( Calendar.DAY_OF_YEAR, day ); TargetDate = new Date(CalendarTargetDate.getTime().getTime()); return TargetDate; } private getTaskType() { if (contract_type == 1){ return 3; }; if (contract_type == 2){ return 4; }; } private getTaskGroup() { return 3; } private GetCRMComment() { query_crm_comment = "SELECT comment FROM contract_comment WHERE LOWER(subject) LIKE '%crm%' AND cid='"+cid+"';"; ps_crm_comment = con.prepareStatement(query_crm_comment); rs_crm_comment = ps_crm_comment.executeQuery(); if ( rs_crm_comment.next() ) { return rs_crm_comment.getString(1); } else { return "Задача создана автоматически"; } } //Параметр, в котором прописана стоимость подключения PARAM_CONNECT_PAY = 46; //Группа ожидания оплаты подключения GROUP_EP = 17; //Группа ожидания подключения GROUP_EC = 18; //Группа Интернет GROUP_INTERNET = 14; //Группа Телефония GROUP_PHONE = 7; EventDate = new Date(); cid = event.getContractID(); contract = new ContractManager(con).getContractByID(cid); contract_firma = contract.getFirmID(); contract_groups = contract.getGroups(); contract_type = 0; // contract_type = 1 - интернет // contract_type = 2 - телефония if ((contract_groups & (1L<<GROUP_INTERNET)) > 0) { contract_type = 1; } else if ((contract_groups & (1L<<GROUP_PHONE)) > 0) { contract_type = 2; } else { return; }; contract_fc = contract.getFc(); contract_param_utils = new ContractParamUtils( con ); contract_balance_utils = new BalanceUtils(con); contract_balance = contract_balance_utils.getBalance (EventDate, cid); contract_limit = contract.getBalanceLimit(); if ((contract_groups & (1L<<GROUP_EP)) > 0) { //Проверяем оплатили подключение или нет connect_pay = Double.parseDouble(contract_param_utils.getStringParam( cid, PARAM_CONNECT_PAY )); if (connect_pay > 0 && contract_balance >= connect_pay) { //Клиент оплатил, можно делать!!! contract_groups = contract_groups & ~(1L<<GROUP_EP); contract_groups = contract_groups | 1L<<GROUP_EC; query = "UPDATE contract SET gr=? WHERE id=?"; psUpdate = con.prepareStatement( query ); psUpdate.setLong( 1, contract_groups ); psUpdate.setInt( 2, cid ); psUpdate.executeUpdate(); //Ищем задачу на подключение filter = new RegisterTaskManager.TaskFilter(); filter.cid = cid; filter.types = Integer.toString(getTaskType()); register_task_manager = new RegisterTaskManager( con ); task_count = register_task_manager.getTaskCount(filter); object = getObject(cid); if (task_count == 0 && object != null){ RegisterTask task = new RegisterTask(); task.setContractID( cid ); task.setTypeID( getTaskType() ); task.setGroupID( getTaskGroup() ); task.setOpenUserID( 0 ) ; task.setOpenTime( EventDate ); task.setComment( GetCRMComment() ); task.setAddressParamID( 2 ); task.setAddressObjectId( object ); task.setTargetDate(getTargetDate()); register_task_manager.updateTask( "new", task ); }; } else { register_task_manager = new RegisterTaskManager( con ); object = getObject(cid); RegisterTask task = new RegisterTask(); task.setContractID( cid ); task.setTypeID( 11 ); task.setGroupID( 6 ); task.setOpenUserID( 0 ) ; task.setOpenTime( EventDate ); task.setComment( "Недостаточная оплата.\nТекущий баланс: "+contract_balance+"\nСтоимость подключения: " + connect_pay); task.setAddressParamID( 2 ); task.setAddressObjectId( object ); task.setTargetDate( EventDate ); register_task_manager.updateTask( "new", task ); };
Продолжение следует...