Синхронизация услуг договора в соответствии с тарифными планами
Материал из BiTel WiKi
Akhmat (Обсуждение | вклад) |
Zavndw (Обсуждение | вклад) |
||
(22 промежуточные версии не показаны) | |||
Строка 1: | Строка 1: | ||
+ | == Описание скрипта == | ||
Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. | Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. | ||
Алгоритм коротко таков: | Алгоритм коротко таков: | ||
Строка 13: | Строка 14: | ||
из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно! | из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно! | ||
+ | upd 14.04.2010 | ||
+ | Добавлен метод | ||
+ | notSynchronizeServices(sids) ; | ||
+ | в котором указывается список услуг, через запятую, которую не надо синхронизровать. | ||
+ | Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов. | ||
---- | ---- | ||
+ | == Версия 5.0 == | ||
+ | {{Актуальность Версии|версия=5.0}} | ||
<source lang="java"> | <source lang="java"> | ||
import java.sql.*; | import java.sql.*; | ||
Строка 29: | Строка 37: | ||
public void onEvent( event, setup, con, conSlave ) | public void onEvent( event, setup, con, conSlave ) | ||
{ | { | ||
- | print( event ) ; | + | //print( event ) ; |
int NPAY_MID = 8 ; | int NPAY_MID = 8 ; | ||
SidsSynchroManager sidman = new SidsSynchroManager() ; | SidsSynchroManager sidman = new SidsSynchroManager() ; | ||
int cid = event.getContractID() ; | int cid = event.getContractID() ; | ||
- | sidman.setDebugMode(0) ; | + | //sidman.setDebugMode(0) ; |
- | // | + | sidman.notSynchronizeServices("11,21,41,42,44");//Указываем список сервисов, которые не хотим, чтобы синхронизировались |
- | sidman.setDeleteNonNeeded(1) ; | + | sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем. |
- | sidman.setNpayMid(NPAY_MID) ; | + | sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат |
sidman.synchronizeServices( cid, con ) ; | sidman.synchronizeServices( cid, con ) ; | ||
+ | |||
} | } | ||
Строка 63: | Строка 72: | ||
{ | { | ||
_DEBUG = debug ; | _DEBUG = debug ; | ||
+ | } | ||
+ | //Не синхронизировать список услуг. через запятую. | ||
+ | public void notSynchronizeServices( String sids ) | ||
+ | { | ||
+ | noSynchroList = sids ; | ||
} | } | ||
public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять | public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять | ||
Строка 155: | Строка 169: | ||
cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
SQLdel = "DELETE FROM contract_service WHERE id=?" ; | SQLdel = "DELETE FROM contract_service WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vSidsData) ; | ||
+ | if ( sidslist == "" ) { sidslist = "-1" ;} | ||
SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + | SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + | ||
- | + | sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; | |
} | } | ||
else{ | else{ | ||
Строка 166: | Строка 182: | ||
cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; | SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; | ||
- | SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + | + | String sidslist = getServiceList(vNpaySidsData) ; |
+ | if ( sidslist == "" ) { | ||
+ | sidslist = "-1" ; | ||
+ | } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости | ||
+ | SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQLtmp ); | ||
+ | rs = ps.executeQuery() ; | ||
+ | if( !rs.next() ) | ||
+ | { | ||
+ | SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; | ||
+ | ps = con.prepareStatement( SQLtmp ); | ||
+ | ps.executeUpdate() ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; | ||
} | } | ||
Строка 311: | Строка 342: | ||
{ | { | ||
break ; | break ; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | date2 = sd.vDate2.get(j) ; | ||
} | } | ||
} | } | ||
Строка 316: | Строка 351: | ||
vDate2.add(date2) ; | vDate2.add(date2) ; | ||
} | } | ||
- | + | ||
- | + | ||
- | + | ||
sd.vDate1.clear() ; | sd.vDate1.clear() ; | ||
sd.vDate2.clear() ; | sd.vDate2.clear() ; | ||
Строка 348: | Строка 381: | ||
private void addSid( int sid, Date date1, Date date2, int npayService ) | private void addSid( int sid, Date date1, Date date2, int npayService ) | ||
{ | { | ||
+ | String[] noSids = noSynchroList.split(",") ; | ||
+ | for ( int i = 0 ; i<noSids.length; i++ ) | ||
+ | { | ||
+ | if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} | ||
+ | } | ||
//Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно | //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно | ||
if ( date1 == null ) { | if ( date1 == null ) { | ||
Строка 425: | Строка 463: | ||
sid = Integer.parseInt( data ) ; | sid = Integer.parseInt( data ) ; | ||
addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | |||
//print ( "sid=" + sid ) ; | //print ( "sid=" + sid ) ; | ||
} | } | ||
Строка 473: | Строка 512: | ||
} | } | ||
+ | |||
//внутренниц класс для хранения услуги и множества дат date1 и date2 | //внутренниц класс для хранения услуги и множества дат date1 и date2 | ||
private class SidsData{ | private class SidsData{ | ||
Строка 519: | Строка 559: | ||
private Vector vSidsData ; | private Vector vSidsData ; | ||
private Vector vNpaySidsData ; | private Vector vNpaySidsData ; | ||
+ | private String noSynchroList = "1000000" ;//не синхронизировать услуги. | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | == Версия 5.1 == | ||
+ | {{Актуальность Версии|версия=5.1}} | ||
+ | |||
+ | Пофиксино для версии 5.1 | ||
+ | <source lang="java"> | ||
+ | import java.sql.*; | ||
+ | import java.util.*; | ||
+ | import java.math.* ; | ||
+ | import bitel.billing.server.contract.bean.*; | ||
+ | import bitel.billing.server.tariff.*; | ||
+ | import bitel.billing.server.util.*; | ||
+ | import bitel.billing.common.KernelConst; | ||
+ | import bitel.billing.server.npay.bean.*; | ||
+ | import bitel.billing.server.script.bean.event.*; | ||
+ | import bitel.billing.server.npay.*; | ||
+ | |||
+ | |||
+ | public void onEvent( event, setup, con, conSlave ) | ||
+ | { | ||
+ | //print( event ) ; | ||
+ | int NPAY_MID = 4 ; | ||
+ | SidsSynchroManager sidman = new SidsSynchroManager() ; | ||
+ | int cid = event.getContractId() ; | ||
+ | //sidman.setDebugMode(0) ; | ||
+ | sidman.setDeleteNonNeeded(1) ; | ||
+ | sidman.setNpayMid(NPAY_MID) ; | ||
+ | sidman.notSynchronizeServices("9,7,11"); | ||
+ | sidman.synchronizeServices( cid, con ) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | //Класс синхронизации услуг | ||
+ | public class SidsSynchroManager { | ||
+ | |||
+ | public SidsSynchroManager() | ||
+ | { | ||
+ | vSidsData = new Vector() ; | ||
+ | vNpaySidsData = new Vector() ; | ||
+ | GregorianCalendar cal = new GregorianCalendar() ; | ||
+ | cal.set(1970, 0, 1 ) ; | ||
+ | _DATE1_NULL = cal.getTime() ; | ||
+ | cal.set(2020, 0, 1 ) ; | ||
+ | _DATE2_NULL = cal.getTime() ; | ||
+ | } | ||
+ | |||
+ | public void setNpayMid( int npayMid) | ||
+ | { | ||
+ | NPAY_MID = npayMid ; | ||
+ | } | ||
+ | public void setDebugMode(int debug) | ||
+ | { | ||
+ | _DEBUG = debug ; | ||
+ | } | ||
+ | //Не синхронизировать список услуг. через запятую. | ||
+ | public void notSynchronizeServices( String sids ) | ||
+ | { | ||
+ | noSynchroList = sids ; | ||
+ | } | ||
+ | public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять | ||
+ | { | ||
+ | deleteNonNeeded = dnn ; | ||
+ | } | ||
+ | //Точка входа. Синхронизирует сервисы договора | ||
+ | public void synchronizeServices( int cid, Connection con ) | ||
+ | { | ||
+ | vSidsData.clear() ; | ||
+ | vNpaySidsData.clear() ; | ||
+ | //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг | ||
+ | String SQL = "SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title," + | ||
+ | "ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid " + | ||
+ | "WHERE ct.cid=" + cid ; | ||
+ | //print(SQL) ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ); | ||
+ | ResultSet rs = ps.executeQuery(); | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int tree_id = rs.getInt("tree_id") ; | ||
+ | String title = rs.getString("title") ; | ||
+ | Date date1 = rs.getDate("ct.date1") ; | ||
+ | Date date2 = rs.getDate("ct.date2") ; | ||
+ | if ( _DEBUG == 1 ) { | ||
+ | print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор | ||
+ | } | ||
+ | //Выбираем персональные тарифы, и запоминаем периоды действия их услуг | ||
+ | SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; | ||
+ | ps = con.prepareStatement( SQL ); | ||
+ | rs = ps.executeQuery(); | ||
+ | if ( _DEBUG == 1 ){ | ||
+ | print("personals") ; | ||
+ | } | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int tree_id = rs.getInt("tree_id") ; | ||
+ | String title = rs.getString("title") ; | ||
+ | Date date1 = rs.getDate("date1") ; | ||
+ | Date date2 = rs.getDate("date2") ; | ||
+ | if( _DEBUG == 1 ) { | ||
+ | print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | findServicesForTariff( tree_id, 0, date1, date2, con ) ; | ||
+ | } | ||
+ | |||
+ | |||
+ | //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды | ||
+ | calcActualServicePeriods( vSidsData ) ; | ||
+ | //Тоже самое для услуг Абонплат. | ||
+ | calcActualServicePeriods( vNpaySidsData ) ; | ||
+ | |||
+ | //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. | ||
+ | print( "Services must be synchronized with folowing date periods") ; | ||
+ | printInternalDataForContract( cid ) ; | ||
+ | |||
+ | //Обновляем услуги договора | ||
+ | updateSynchronizedServices( cid, 0, con ) ; | ||
+ | //Обновляем услуги абонплат договора | ||
+ | updateSynchronizedServices( cid, NPAY_MID, con ) ; | ||
+ | } | ||
+ | |||
+ | public void printInternalDataForContract( int cid ) | ||
+ | { | ||
+ | print("cid="+cid) ; | ||
+ | print("SERVICES:") ; | ||
+ | for( int i = 0; i<vSidsData.size(); i++) | ||
+ | { | ||
+ | vSidsData.get(i).printData() ; | ||
+ | } | ||
+ | print("NPAY SERVICES:") ; | ||
+ | for( int i = 0; i<vNpaySidsData.size(); i++) | ||
+ | { | ||
+ | vNpaySidsData.get(i).printData() ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) | ||
+ | { | ||
+ | String SQLdelNonNeeded = "" ; | ||
+ | String SQLsel = "" ; | ||
+ | String SQLupd = "" ; | ||
+ | String SQLins = "" ; | ||
+ | String SQLdel = "" ; | ||
+ | Vector vSids = vSidsData ; | ||
+ | String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; | ||
+ | if ( nPayMid == 0 ){ | ||
+ | SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; | ||
+ | SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + | ||
+ | dateNow + ")' WHERE id=?" ; | ||
+ | SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + | ||
+ | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
+ | SQLdel = "DELETE FROM contract_service WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vSidsData) ; | ||
+ | if ( sidslist == "" ) { sidslist = "-1" ;} | ||
+ | SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + | ||
+ | sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; | ||
+ | } | ||
+ | else{ | ||
+ | vSids = vNpaySidsData ; | ||
+ | SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; | ||
+ | SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + | ||
+ | dateNow + ")' WHERE id=?" ; | ||
+ | SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + | ||
+ | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
+ | SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vNpaySidsData) ; | ||
+ | if ( sidslist == "" ) { | ||
+ | sidslist = "-1" ; | ||
+ | } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости | ||
+ | SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQLtmp ); | ||
+ | rs = ps.executeQuery() ; | ||
+ | if( !rs.next() ) | ||
+ | { | ||
+ | SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; | ||
+ | ps = con.prepareStatement( SQLtmp ); | ||
+ | ps.executeUpdate() ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | if ( deleteNonNeeded == 1 ) | ||
+ | { | ||
+ | |||
+ | print( SQLdelNonNeeded ) ; | ||
+ | PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; | ||
+ | psDelOther.executeUpdate( SQLdelNonNeeded ) ; | ||
+ | } | ||
+ | PreparedStatement ps = con.prepareStatement( SQLsel ); | ||
+ | PreparedStatement psUpd = con.prepareStatement( SQLupd ); | ||
+ | PreparedStatement psIns = con.prepareStatement( SQLins ); | ||
+ | PreparedStatement psDel = con.prepareStatement( SQLdel ); | ||
+ | |||
+ | ResultSet rs ; | ||
+ | SidsData sd ; | ||
+ | Date date1, date2 ; | ||
+ | for( int i = 0; i<vSids.size(); i++) | ||
+ | { | ||
+ | sd = vSids.get(i) ; | ||
+ | int sid = sd.sid ; | ||
+ | ps.setInt(1, sid) ; | ||
+ | rs = ps.executeQuery() ; | ||
+ | j = 0 ; | ||
+ | while( rs.next() ) | ||
+ | { | ||
+ | int id = rs.getInt("id") ; | ||
+ | date1 = rs.getDate("date1") ; | ||
+ | date2 = rs.getDate("date2") ; | ||
+ | //Чтобы при сравнении дат equals не давал exeption, подменяем значения null | ||
+ | //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | if ( date1 == null ){ | ||
+ | date1 = _DATE1_NULL.clone() ; | ||
+ | } | ||
+ | if ( date2 == null ){ | ||
+ | date2 = _DATE2_NULL.clone() ; | ||
+ | } | ||
+ | //Лишняя услуга, удаляем | ||
+ | if ( j >= sd.vDate1.size() ) | ||
+ | { | ||
+ | psDel.setInt( 1, id ) ; | ||
+ | psDel.executeUpdate() ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Delete service with id=" + id + " for service="+sid + | ||
+ | " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psDel=" + psDel ) ; | ||
+ | } | ||
+ | continue ; | ||
+ | } | ||
+ | |||
+ | |||
+ | if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) | ||
+ | { | ||
+ | //Возвращаем значения null при необходимости для обновления инфы в БД | ||
+ | if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ | ||
+ | sd.vDate1.set( j, null ) ; | ||
+ | } | ||
+ | if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ | ||
+ | sd.vDate2.set( j, null ) ; | ||
+ | } | ||
+ | psUpd.setInt( 3, id ) ; | ||
+ | psUpd.setDate( 1, sd.vDate1.get(j) ) ; | ||
+ | psUpd.setDate( 2, sd.vDate2.get(j) ) ; | ||
+ | psUpd.executeUpdate() ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Update service with id=" + id + " for service="+sid + " previous date1=" + | ||
+ | TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psUpd=" + psUpd ) ; | ||
+ | } | ||
+ | } | ||
+ | j++ ; | ||
+ | }//end while | ||
+ | |||
+ | for( ; j < sd.vDate1.size(); j++) | ||
+ | { | ||
+ | if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ | ||
+ | sd.vDate1.set( j, null ) ; | ||
+ | } | ||
+ | if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ | ||
+ | sd.vDate2.set( j, null ) ; | ||
+ | } | ||
+ | psIns.setInt(1, sid ) ; | ||
+ | psIns.setDate( 2, sd.vDate1.get(j) ) ; | ||
+ | psIns.setDate( 3, sd.vDate2.get(j) ) ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Insert new service="+sid + " date1=" + | ||
+ | TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psIns" + psIns ) ; | ||
+ | } | ||
+ | psIns.executeUpdate() ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private String getServiceList(Vector vSids) | ||
+ | { | ||
+ | String sids = ""; | ||
+ | int i ; | ||
+ | for( i = 0; i<vSids.size()-1; i++) | ||
+ | { | ||
+ | sids += "" + vSids.get(i).sid + "," ; | ||
+ | } | ||
+ | if ( i < vSids.size()) { | ||
+ | sids += "" + vSids.get(i).sid ; | ||
+ | } | ||
+ | return sids ; | ||
+ | } | ||
+ | |||
+ | private calcActualServicePeriods( Vector vSids ) | ||
+ | { | ||
+ | prepareInternalData() ; | ||
+ | SidsData sd ; | ||
+ | Vector vDate1 = new Vector() ; | ||
+ | Vector vDate2 = new Vector() ; | ||
+ | Date date1 ; | ||
+ | Date date2 ; | ||
+ | GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день | ||
+ | k = 0 ; | ||
+ | for( int i = 0; i<vSids.size(); i++) | ||
+ | { | ||
+ | sd = vSids.get(i) ; | ||
+ | vDate1.clear() ; | ||
+ | vDate2.clear() ; | ||
+ | for ( j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды | ||
+ | { | ||
+ | date1 = sd.vDate1.get(j) ; | ||
+ | date2 = sd.vDate2.get(j) ; | ||
+ | if ( date1.compareTo( date2) > 0 ) | ||
+ | { | ||
+ | print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | print("Services was not synchronized...") ; | ||
+ | return ; | ||
+ | } | ||
+ | for( j++ ; j<sd.vDate1.size(); j++) | ||
+ | { | ||
+ | date1cal.setTime( sd.vDate1.get(j) ) ; | ||
+ | date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; | ||
+ | if ( date2.compareTo(date1cal.getTime()) < 0 ) // Нашли нужный date2 для date1 ; | ||
+ | { | ||
+ | break ; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | date2 = sd.vDate2.get(j) ; | ||
+ | } | ||
+ | } | ||
+ | vDate1.add(date1) ; | ||
+ | vDate2.add(date2) ; | ||
+ | } | ||
+ | |||
+ | sd.vDate1.clear() ; | ||
+ | sd.vDate2.clear() ; | ||
+ | sd.vDate1 = vDate1.clone() ; | ||
+ | sd.vDate2 = vDate2.clone() ; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг | ||
+ | { | ||
+ | SidsData sd ; | ||
+ | for( int i = 0; i<vSidsData.size(); i++) | ||
+ | { | ||
+ | sd = vSidsData.get(i) ; | ||
+ | Collections.sort(sd.vDate1 ) ; | ||
+ | Collections.sort(sd.vDate2 ) ; | ||
+ | } | ||
+ | for( int i = 0; i<vNpaySidsData.size(); i++) | ||
+ | { | ||
+ | sd = vNpaySidsData.get(i) ; | ||
+ | Collections.sort(sd.vDate1 ) ; | ||
+ | Collections.sort(sd.vDate2 ) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private void addSid( int sid, Date date1, Date date2, int npayService ) | ||
+ | { | ||
+ | String[] noSids = noSynchroList.split(",") ; | ||
+ | for ( int i = 0 ; i<noSids.length; i++ ) | ||
+ | { | ||
+ | if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} | ||
+ | } | ||
+ | //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно | ||
+ | if ( date1 == null ) { | ||
+ | date1 = _DATE1_NULL.clone() ; | ||
+ | } | ||
+ | if ( date2 == null ) { | ||
+ | date2 = _DATE2_NULL.clone() ; | ||
+ | } | ||
+ | |||
+ | Vector vSids = vSidsData; | ||
+ | if ( npayService != 0 ) | ||
+ | { | ||
+ | vSids = vNpaySidsData ; | ||
+ | } | ||
+ | int f = 0 ; | ||
+ | SidsData sd ; | ||
+ | for ( int i=0; i < vSids.size(); i++ ) | ||
+ | { | ||
+ | sd = vSids.get(i) ; | ||
+ | if (sd.sid == sid) | ||
+ | { | ||
+ | sd.vDate1.add(date1) ; | ||
+ | sd.vDate2.add(date2) ; | ||
+ | f = 1 ; break ; | ||
+ | } | ||
+ | } | ||
+ | if ( f == 0 ) | ||
+ | { | ||
+ | sd = new SidsData( sid ) ; | ||
+ | sd.vDate1.add(date1) ; | ||
+ | sd.vDate2.add(date2) ; | ||
+ | vSids.add( sd ) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, | ||
+ | Date date1, Date date2, Connection con) | ||
+ | { | ||
+ | String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; | ||
+ | if ( mid != 0 ) | ||
+ | { | ||
+ | SQL += " AND mid=" + mid ; | ||
+ | } | ||
+ | //print(SQL) ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ); | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | |||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int mtreeid = rs.getInt("id") ; | ||
+ | int mid = rs.getInt("mid") ; | ||
+ | int parent_tree = rs.getInt("parent_tree") ; | ||
+ | if (parent_tree != 0 ) | ||
+ | { | ||
+ | findServicesForTariff( parent_tree, mid, date1, date2, con ) ; | ||
+ | continue ; | ||
+ | } | ||
+ | findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) | ||
+ | { | ||
+ | SQL = "SELECT type, data " + | ||
+ | "FROM mtree_node " + | ||
+ | "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ) ; | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | int sid = 0; | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | String type = rs.getString("type") ; | ||
+ | String data = rs.getString("data") ; | ||
+ | //print ( "type=" + type + " data=" + data) ; | ||
+ | if (type.equals("service") ) | ||
+ | { | ||
+ | sid = Integer.parseInt( data ) ; | ||
+ | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | |||
+ | //print ( "sid=" + sid ) ; | ||
+ | } | ||
+ | else if( type.equals("multi_service") ) | ||
+ | { | ||
+ | String[] ss = data.split("&") ; | ||
+ | String[] sids = ss[1].split(",") ; | ||
+ | //print ( "sids=" + ss[1] ) ; | ||
+ | for ( int i=0; i < sids.length; i++ ) | ||
+ | { | ||
+ | sid=Integer.parseInt(sids[i]) ; | ||
+ | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | //print( "sid = " + sid ) ; | ||
+ | } | ||
+ | } | ||
+ | else if( type.equals("month_mode") ) | ||
+ | { | ||
+ | String[] ss = data.split("%") ; | ||
+ | for ( int i = 0; i < ss.length ; i++ ) | ||
+ | { | ||
+ | String[] sids=ss[i].split("&") ; | ||
+ | if ( sids[0].equals("sid") ) | ||
+ | { | ||
+ | sid = Integer.parseInt(sids[1]) ; | ||
+ | addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | break ; | ||
+ | } | ||
+ | } | ||
+ | //print( "month_mode sid = " + sid ) ; | ||
+ | } | ||
+ | else if( type.equals("day_mode") ) | ||
+ | { | ||
+ | String[] ss = data.split("%") ; | ||
+ | for ( int i = 0; i < ss.length ; i++ ) | ||
+ | { | ||
+ | String[] sids=ss[i].split("&") ; | ||
+ | if ( sids[0].equals("sid") ) | ||
+ | { | ||
+ | sid = Integer.parseInt(sids[1]) ; | ||
+ | addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | break ; | ||
+ | } | ||
+ | } | ||
+ | //print( "day_mode sid = " + sid ) ; | ||
+ | } | ||
+ | |||
+ | }//end while | ||
+ | } | ||
+ | |||
+ | |||
+ | //внутренниц класс для хранения услуги и множества дат date1 и date2 | ||
+ | private class SidsData{ | ||
+ | public int sid ; | ||
+ | public Vector vDate1 ; | ||
+ | public Vector vDate2 ; | ||
+ | |||
+ | public SidsData() | ||
+ | { | ||
+ | sid = 0 ; | ||
+ | vDate1 = new Vector() ; | ||
+ | vDate2 = new Vector() ; | ||
+ | } | ||
+ | |||
+ | public SidsData( int s ) | ||
+ | { | ||
+ | sid=s ; | ||
+ | vDate1 = new Vector() ; | ||
+ | vDate2 = new Vector() ; | ||
+ | } | ||
+ | public printData() | ||
+ | { | ||
+ | print ("sid=" + sid) ; | ||
+ | for( i=0; i<vDate1.size(); i++ ) | ||
+ | { | ||
+ | Date date1 = vDate1.get(i) ; | ||
+ | Date date2 = vDate2.get(i) ; | ||
+ | if ( date1.equals( _DATE1_NULL) ){ | ||
+ | date1 = null ; | ||
+ | } | ||
+ | if ( date2.equals( _DATE2_NULL) ){ | ||
+ | date2 = null ; | ||
+ | } | ||
+ | |||
+ | print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private int NPAY_MID=4 ; | ||
+ | private int _DEBUG=0 ; | ||
+ | private int deleteNonNeeded = 0 ; | ||
+ | static private Date _DATE1_NULL ; | ||
+ | static private Date _DATE2_NULL ; | ||
+ | private Vector vSidsData ; | ||
+ | private Vector vNpaySidsData ; | ||
+ | private String noSynchroList = "1000000" ;//не синхронизировать услуги. | ||
+ | } | ||
+ | </source> | ||
+ | +sid + | ||
+ | |||
+ | == Версия 5.2 == | ||
+ | {{Актуальность Версии|версия=5.2}} | ||
+ | |||
+ | Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC) | ||
+ | |||
+ | Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012 | ||
+ | |||
+ | <source lang="java"> | ||
+ | import java.sql.*; | ||
+ | import java.util.*; | ||
+ | import java.math.* ; | ||
+ | import bitel.billing.server.contract.bean.*; | ||
+ | import bitel.billing.server.tariff.*; | ||
+ | import bitel.billing.server.util.*; | ||
+ | import bitel.billing.common.KernelConst; | ||
+ | import bitel.billing.server.npay.bean.*; | ||
+ | import bitel.billing.server.script.bean.event.*; | ||
+ | import bitel.billing.server.npay.*; | ||
+ | import bitel.billing.server.task.bean.*; | ||
+ | |||
+ | public void onEvent( event, setup, con, conSlave ) | ||
+ | { | ||
+ | //print( event ) ; | ||
+ | int NPAY_MID = 4 ; | ||
+ | SidsSynchroManager sidman = new SidsSynchroManager() ; | ||
+ | int cid = event.getContractId() ; | ||
+ | //sidman.setDebugMode(0) ; | ||
+ | sidman.setDeleteNonNeeded(1) ; | ||
+ | sidman.setNpayMid(NPAY_MID) ; | ||
+ | sidman.notSynchronizeServices("9,7,11"); | ||
+ | sidman.synchronizeServices( cid, con ) ; | ||
+ | |||
+ | //Кусок отвечающий за перерасчет абонплаты | ||
+ | // месяц за который идёт перерасчёт | ||
+ | dateTask = new GregorianCalendar(); | ||
+ | // набор услуг, 0- все услуги | ||
+ | serviceSet = 0; | ||
+ | //Комментарий задачи | ||
+ | comment = ""; | ||
+ | email = "null"; | ||
+ | |||
+ | new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) ); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | //Класс синхронизации услуг | ||
+ | public class SidsSynchroManager { | ||
+ | |||
+ | public SidsSynchroManager() | ||
+ | { | ||
+ | vSidsData = new Vector() ; | ||
+ | vNpaySidsData = new Vector() ; | ||
+ | GregorianCalendar cal = new GregorianCalendar() ; | ||
+ | cal.set(1970, 0, 1 ) ; | ||
+ | _DATE1_NULL = cal.getTime() ; | ||
+ | cal.set(2020, 0, 1 ) ; | ||
+ | _DATE2_NULL = cal.getTime() ; | ||
+ | } | ||
+ | |||
+ | public void setNpayMid( int npayMid) | ||
+ | { | ||
+ | NPAY_MID = npayMid ; | ||
+ | } | ||
+ | public void setDebugMode(int debug) | ||
+ | { | ||
+ | _DEBUG = debug ; | ||
+ | } | ||
+ | //Не синхронизировать список услуг. через запятую. | ||
+ | public void notSynchronizeServices( String sids ) | ||
+ | { | ||
+ | noSynchroList = sids ; | ||
+ | } | ||
+ | public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять | ||
+ | { | ||
+ | deleteNonNeeded = dnn ; | ||
+ | } | ||
+ | //Точка входа. Синхронизирует сервисы договора | ||
+ | public void synchronizeServices( int cid, Connection con ) | ||
+ | { | ||
+ | vSidsData.clear() ; | ||
+ | vNpaySidsData.clear() ; | ||
+ | //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг | ||
+ | String SQL = "SELECT tree_id, t.title, ct.date1, ct.date2 " + | ||
+ | "FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id " + | ||
+ | "WHERE ct.cid=" + cid ; | ||
+ | //print(SQL) ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ); | ||
+ | ResultSet rs = ps.executeQuery(); | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int tree_id = rs.getInt("tree_id") ; | ||
+ | String title = rs.getString("title") ; | ||
+ | Date date1 = rs.getDate("ct.date1") ; | ||
+ | Date date2 = rs.getDate("ct.date2") ; | ||
+ | if ( _DEBUG == 1 ) { | ||
+ | print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор | ||
+ | } | ||
+ | //Выбираем персональные тарифы, и запоминаем периоды действия их услуг | ||
+ | SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; | ||
+ | ps = con.prepareStatement( SQL ); | ||
+ | rs = ps.executeQuery(); | ||
+ | if ( _DEBUG == 1 ){ | ||
+ | print("personals") ; | ||
+ | } | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int tree_id = rs.getInt("tree_id") ; | ||
+ | String title = rs.getString("title") ; | ||
+ | Date date1 = rs.getDate("date1") ; | ||
+ | Date date2 = rs.getDate("date2") ; | ||
+ | if( _DEBUG == 1 ) { | ||
+ | print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | findServicesForTariff( tree_id, 0, date1, date2, con ) ; | ||
+ | } | ||
+ | |||
+ | |||
+ | //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды | ||
+ | calcActualServicePeriods( vSidsData ) ; | ||
+ | //Тоже самое для услуг Абонплат. | ||
+ | calcActualServicePeriods( vNpaySidsData ) ; | ||
+ | |||
+ | //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. | ||
+ | print( "Services must be synchronized with folowing date periods") ; | ||
+ | printInternalDataForContract( cid ) ; | ||
+ | |||
+ | //Обновляем услуги договора | ||
+ | updateSynchronizedServices( cid, 0, con ) ; | ||
+ | //Обновляем услуги абонплат договора | ||
+ | updateSynchronizedServices( cid, NPAY_MID, con ) ; | ||
+ | } | ||
+ | |||
+ | public void printInternalDataForContract( int cid ) | ||
+ | { | ||
+ | print("cid="+cid) ; | ||
+ | print("SERVICES:") ; | ||
+ | for( int i = 0; i<vSidsData.size(); i++) | ||
+ | { | ||
+ | vSidsData.get(i).printData() ; | ||
+ | } | ||
+ | print("NPAY SERVICES:") ; | ||
+ | for( int i = 0; i<vNpaySidsData.size(); i++) | ||
+ | { | ||
+ | vNpaySidsData.get(i).printData() ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) | ||
+ | { | ||
+ | String SQLdelNonNeeded = "" ; | ||
+ | String SQLsel = "" ; | ||
+ | String SQLupd = "" ; | ||
+ | String SQLins = "" ; | ||
+ | String SQLdel = "" ; | ||
+ | Vector vSids = vSidsData ; | ||
+ | String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; | ||
+ | if ( nPayMid == 0 ){ | ||
+ | SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; | ||
+ | SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + | ||
+ | dateNow + ")' WHERE id=?" ; | ||
+ | SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + | ||
+ | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
+ | SQLdel = "DELETE FROM contract_service WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vSidsData) ; | ||
+ | if ( sidslist == "" ) { sidslist = "-1" ;} | ||
+ | SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + | ||
+ | sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; | ||
+ | } | ||
+ | else{ | ||
+ | vSids = vNpaySidsData ; | ||
+ | SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; | ||
+ | SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + | ||
+ | dateNow + ")' WHERE id=?" ; | ||
+ | SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + | ||
+ | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
+ | SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vNpaySidsData) ; | ||
+ | if ( sidslist == "" ) { | ||
+ | sidslist = "-1" ; | ||
+ | } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости | ||
+ | SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQLtmp ); | ||
+ | rs = ps.executeQuery() ; | ||
+ | if( !rs.next() ) | ||
+ | { | ||
+ | SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; | ||
+ | ps = con.prepareStatement( SQLtmp ); | ||
+ | ps.executeUpdate() ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | if ( deleteNonNeeded == 1 ) | ||
+ | { | ||
+ | |||
+ | print( SQLdelNonNeeded ) ; | ||
+ | PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; | ||
+ | psDelOther.executeUpdate( SQLdelNonNeeded ) ; | ||
+ | } | ||
+ | PreparedStatement ps = con.prepareStatement( SQLsel ); | ||
+ | PreparedStatement psUpd = con.prepareStatement( SQLupd ); | ||
+ | PreparedStatement psIns = con.prepareStatement( SQLins ); | ||
+ | PreparedStatement psDel = con.prepareStatement( SQLdel ); | ||
+ | |||
+ | ResultSet rs ; | ||
+ | SidsData sd ; | ||
+ | Date date1, date2 ; | ||
+ | for( int i = 0; i<vSids.size(); i++) | ||
+ | { | ||
+ | sd = vSids.get(i) ; | ||
+ | int sid = sd.sid ; | ||
+ | ps.setInt(1, sid) ; | ||
+ | rs = ps.executeQuery() ; | ||
+ | j = 0 ; | ||
+ | while( rs.next() ) | ||
+ | { | ||
+ | int id = rs.getInt("id") ; | ||
+ | date1 = rs.getDate("date1") ; | ||
+ | date2 = rs.getDate("date2") ; | ||
+ | //Чтобы при сравнении дат equals не давал exeption, подменяем значения null | ||
+ | //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | if ( date1 == null ){ | ||
+ | date1 = _DATE1_NULL.clone() ; | ||
+ | } | ||
+ | if ( date2 == null ){ | ||
+ | date2 = _DATE2_NULL.clone() ; | ||
+ | } | ||
+ | //Лишняя услуга, удаляем | ||
+ | if ( j >= sd.vDate1.size() ) | ||
+ | { | ||
+ | psDel.setInt( 1, id ) ; | ||
+ | psDel.executeUpdate() ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Delete service with id=" + id + " for service="+sid + | ||
+ | " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psDel=" + psDel ) ; | ||
+ | } | ||
+ | continue ; | ||
+ | } | ||
+ | |||
+ | |||
+ | if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) | ||
+ | { | ||
+ | //Возвращаем значения null при необходимости для обновления инфы в БД | ||
+ | if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ | ||
+ | sd.vDate1.set( j, null ) ; | ||
+ | } | ||
+ | if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ | ||
+ | sd.vDate2.set( j, null ) ; | ||
+ | } | ||
+ | psUpd.setInt( 3, id ) ; | ||
+ | psUpd.setDate( 1, sd.vDate1.get(j) ) ; | ||
+ | psUpd.setDate( 2, sd.vDate2.get(j) ) ; | ||
+ | psUpd.executeUpdate() ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Update service with id=" + id + " for service="+sid + " previous date1=" + | ||
+ | TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psUpd=" + psUpd ) ; | ||
+ | } | ||
+ | } | ||
+ | j++ ; | ||
+ | }//end while | ||
+ | |||
+ | for( ; j < sd.vDate1.size(); j++) | ||
+ | { | ||
+ | if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ | ||
+ | sd.vDate1.set( j, null ) ; | ||
+ | } | ||
+ | if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ | ||
+ | sd.vDate2.set( j, null ) ; | ||
+ | } | ||
+ | psIns.setInt(1, sid ) ; | ||
+ | psIns.setDate( 2, sd.vDate1.get(j) ) ; | ||
+ | psIns.setDate( 3, sd.vDate2.get(j) ) ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Insert new service="+sid + " date1=" + | ||
+ | TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psIns" + psIns ) ; | ||
+ | } | ||
+ | psIns.executeUpdate() ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private String getServiceList(Vector vSids) | ||
+ | { | ||
+ | String sids = ""; | ||
+ | int i ; | ||
+ | for( i = 0; i<vSids.size()-1; i++) | ||
+ | { | ||
+ | sids += "" + vSids.get(i).sid + "," ; | ||
+ | } | ||
+ | if ( i < vSids.size()) { | ||
+ | sids += "" + vSids.get(i).sid ; | ||
+ | } | ||
+ | return sids ; | ||
+ | } | ||
+ | |||
+ | private calcActualServicePeriods( Vector vSids ) | ||
+ | { | ||
+ | prepareInternalData() ; | ||
+ | SidsData sd ; | ||
+ | Vector vDate1 = new Vector() ; | ||
+ | Vector vDate2 = new Vector() ; | ||
+ | Date date1 ; | ||
+ | Date date2 ; | ||
+ | GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день | ||
+ | k = 0 ; | ||
+ | for( int i = 0; i<vSids.size(); i++) | ||
+ | { | ||
+ | sd = vSids.get(i) ; | ||
+ | vDate1.clear() ; | ||
+ | vDate2.clear() ; | ||
+ | for ( j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды | ||
+ | { | ||
+ | date1 = sd.vDate1.get(j) ; | ||
+ | date2 = sd.vDate2.get(j) ; | ||
+ | if ( date1.compareTo( date2) > 0 ) | ||
+ | { | ||
+ | print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | print("Services was not synchronized...") ; | ||
+ | return ; | ||
+ | } | ||
+ | for( j++ ; j<sd.vDate1.size(); j++) | ||
+ | { | ||
+ | date1cal.setTime( sd.vDate1.get(j) ) ; | ||
+ | date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; | ||
+ | if ( date2.compareTo(date1cal.getTime()) < 0 ) // Нашли нужный date2 для date1 ; | ||
+ | { | ||
+ | break ; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | date2 = sd.vDate2.get(j) ; | ||
+ | } | ||
+ | } | ||
+ | vDate1.add(date1) ; | ||
+ | vDate2.add(date2) ; | ||
+ | } | ||
+ | |||
+ | sd.vDate1.clear() ; | ||
+ | sd.vDate2.clear() ; | ||
+ | sd.vDate1 = vDate1.clone() ; | ||
+ | sd.vDate2 = vDate2.clone() ; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг | ||
+ | { | ||
+ | SidsData sd ; | ||
+ | for( int i = 0; i<vSidsData.size(); i++) | ||
+ | { | ||
+ | sd = vSidsData.get(i) ; | ||
+ | Collections.sort(sd.vDate1 ) ; | ||
+ | Collections.sort(sd.vDate2 ) ; | ||
+ | } | ||
+ | for( int i = 0; i<vNpaySidsData.size(); i++) | ||
+ | { | ||
+ | sd = vNpaySidsData.get(i) ; | ||
+ | Collections.sort(sd.vDate1 ) ; | ||
+ | Collections.sort(sd.vDate2 ) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private void addSid( int sid, Date date1, Date date2, int npayService ) | ||
+ | { | ||
+ | String[] noSids = noSynchroList.split(",") ; | ||
+ | for ( int i = 0 ; i<noSids.length; i++ ) | ||
+ | { | ||
+ | if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} | ||
+ | } | ||
+ | //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно | ||
+ | if ( date1 == null ) { | ||
+ | date1 = _DATE1_NULL.clone() ; | ||
+ | } | ||
+ | if ( date2 == null ) { | ||
+ | date2 = _DATE2_NULL.clone() ; | ||
+ | } | ||
+ | |||
+ | Vector vSids = vSidsData; | ||
+ | if ( npayService != 0 ) | ||
+ | { | ||
+ | vSids = vNpaySidsData ; | ||
+ | } | ||
+ | int f = 0 ; | ||
+ | SidsData sd ; | ||
+ | for ( int i=0; i < vSids.size(); i++ ) | ||
+ | { | ||
+ | sd = vSids.get(i) ; | ||
+ | if (sd.sid == sid) | ||
+ | { | ||
+ | sd.vDate1.add(date1) ; | ||
+ | sd.vDate2.add(date2) ; | ||
+ | f = 1 ; break ; | ||
+ | } | ||
+ | } | ||
+ | if ( f == 0 ) | ||
+ | { | ||
+ | sd = new SidsData( sid ) ; | ||
+ | sd.vDate1.add(date1) ; | ||
+ | sd.vDate2.add(date2) ; | ||
+ | vSids.add( sd ) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, | ||
+ | Date date1, Date date2, Connection con) | ||
+ | { | ||
+ | String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; | ||
+ | if ( mid != 0 ) | ||
+ | { | ||
+ | SQL += " AND mid=" + mid ; | ||
+ | } | ||
+ | //print(SQL) ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ); | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | |||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int mtreeid = rs.getInt("id") ; | ||
+ | int mid = rs.getInt("mid") ; | ||
+ | int parent_tree = rs.getInt("parent_tree") ; | ||
+ | if (parent_tree != 0 ) | ||
+ | { | ||
+ | findServicesForTariff( parent_tree, mid, date1, date2, con ) ; | ||
+ | continue ; | ||
+ | } | ||
+ | findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) | ||
+ | { | ||
+ | SQL = "SELECT type, data " + | ||
+ | "FROM mtree_node " + | ||
+ | "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ) ; | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | int sid = 0; | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | String type = rs.getString("type") ; | ||
+ | String data = rs.getString("data") ; | ||
+ | //print ( "type=" + type + " data=" + data) ; | ||
+ | if (type.equals("service") ) | ||
+ | { | ||
+ | sid = Integer.parseInt( data ) ; | ||
+ | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | |||
+ | //print ( "sid=" + sid ) ; | ||
+ | } | ||
+ | else if( type.equals("multi_service") ) | ||
+ | { | ||
+ | String[] ss = data.split("&") ; | ||
+ | String[] sids = ss[1].split(",") ; | ||
+ | //print ( "sids=" + ss[1] ) ; | ||
+ | for ( int i=0; i < sids.length; i++ ) | ||
+ | { | ||
+ | sid=Integer.parseInt(sids[i]) ; | ||
+ | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | //print( "sid = " + sid ) ; | ||
+ | } | ||
+ | } | ||
+ | else if( type.equals("month_mode") ) | ||
+ | { | ||
+ | String[] ss = data.split("%") ; | ||
+ | for ( int i = 0; i < ss.length ; i++ ) | ||
+ | { | ||
+ | String[] sids=ss[i].split("&") ; | ||
+ | if ( sids[0].equals("sid") ) | ||
+ | { | ||
+ | sid = Integer.parseInt(sids[1]) ; | ||
+ | addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | break ; | ||
+ | } | ||
+ | } | ||
+ | //print( "month_mode sid = " + sid ) ; | ||
+ | } | ||
+ | else if( type.equals("day_mode") ) | ||
+ | { | ||
+ | String[] ss = data.split("%") ; | ||
+ | for ( int i = 0; i < ss.length ; i++ ) | ||
+ | { | ||
+ | String[] sids=ss[i].split("&") ; | ||
+ | if ( sids[0].equals("sid") ) | ||
+ | { | ||
+ | sid = Integer.parseInt(sids[1]) ; | ||
+ | addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | break ; | ||
+ | } | ||
+ | } | ||
+ | //print( "day_mode sid = " + sid ) ; | ||
+ | } | ||
+ | |||
+ | }//end while | ||
+ | } | ||
+ | |||
+ | |||
+ | //внутренниц класс для хранения услуги и множества дат date1 и date2 | ||
+ | private class SidsData{ | ||
+ | public int sid ; | ||
+ | public Vector vDate1 ; | ||
+ | public Vector vDate2 ; | ||
+ | |||
+ | public SidsData() | ||
+ | { | ||
+ | sid = 0 ; | ||
+ | vDate1 = new Vector() ; | ||
+ | vDate2 = new Vector() ; | ||
+ | } | ||
+ | |||
+ | public SidsData( int s ) | ||
+ | { | ||
+ | sid=s ; | ||
+ | vDate1 = new Vector() ; | ||
+ | vDate2 = new Vector() ; | ||
+ | } | ||
+ | public printData() | ||
+ | { | ||
+ | print ("sid=" + sid) ; | ||
+ | for( i=0; i<vDate1.size(); i++ ) | ||
+ | { | ||
+ | Date date1 = vDate1.get(i) ; | ||
+ | Date date2 = vDate2.get(i) ; | ||
+ | if ( date1.equals( _DATE1_NULL) ){ | ||
+ | date1 = null ; | ||
+ | } | ||
+ | if ( date2.equals( _DATE2_NULL) ){ | ||
+ | date2 = null ; | ||
+ | } | ||
+ | |||
+ | print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private int NPAY_MID=4 ; | ||
+ | private int _DEBUG=0 ; | ||
+ | private int deleteNonNeeded = 0 ; | ||
+ | static private Date _DATE1_NULL ; | ||
+ | static private Date _DATE2_NULL ; | ||
+ | private Vector vSidsData ; | ||
+ | private Vector vNpaySidsData ; | ||
+ | private String noSynchroList = "1000000" ;//не синхронизировать услуги. | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | == Версия 6.0 == | ||
+ | {{Актуальность Версии|версия=6.0}} | ||
+ | Дин код | ||
+ | <source lang="java"> | ||
+ | package ru.ellcom.bgbilling.scripts.tariff; | ||
+ | |||
+ | import ru.bitel.bgbilling.kernel.event.Event; | ||
+ | import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase; | ||
+ | import ru.bitel.bgbilling.server.util.Setup; | ||
+ | import ru.bitel.common.sql.ConnectionSet; | ||
+ | |||
+ | |||
+ | import java.sql.Connection; | ||
+ | import java.sql.Date; | ||
+ | import java.sql.PreparedStatement; | ||
+ | import java.sql.ResultSet; | ||
+ | import java.util.Calendar; | ||
+ | import java.util.Collections; | ||
+ | import java.util.GregorianCalendar; | ||
+ | import java.util.Vector; | ||
+ | |||
+ | |||
+ | import bitel.billing.common.TimeUtils; | ||
+ | import bitel.billing.server.npay.Recalculator; | ||
+ | import bitel.billing.server.task.bean.RunTaskDataManager; | ||
+ | |||
+ | public class SyncService | ||
+ | extends EventScriptBase | ||
+ | { | ||
+ | @Override | ||
+ | public void onEvent( Event event, Setup setup, ConnectionSet connectionSet ) | ||
+ | throws Exception | ||
+ | { | ||
+ | int cid = event.getContractId() ; | ||
+ | int NPAY_MID = 6 ; | ||
+ | Connection con = connectionSet.getConnection() ; | ||
+ | //SidsSynchroManager sidman = new SidsSynchroManager() ; | ||
+ | initSynchroManager() ; | ||
+ | //sidman.setDebugMode(0) ; | ||
+ | setDeleteNonNeeded(1) ; | ||
+ | setNpayMid(NPAY_MID) ; | ||
+ | notSynchronizeServices("1000000"); | ||
+ | synchronizeServices( cid, con ) ; | ||
+ | |||
+ | Calendar dateTask = new GregorianCalendar(); | ||
+ | // набор услуг, 0- все услуги | ||
+ | int serviceSet = 0; | ||
+ | //Комментарий задачи | ||
+ | String comment = ""; | ||
+ | String email = "null"; | ||
+ | |||
+ | new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) ); | ||
+ | |||
+ | } | ||
+ | |||
+ | //код класса синхронизации | ||
+ | public void initSynchroManager() | ||
+ | { | ||
+ | vSidsData = new Vector() ; | ||
+ | vNpaySidsData = new Vector() ; | ||
+ | GregorianCalendar cal = new GregorianCalendar() ; | ||
+ | cal.set(1970, 0, 1 ) ; | ||
+ | _DATE1_NULL = new java.sql.Date(cal.getTime().getTime()) ; | ||
+ | cal.set(2020, 0, 1 ) ; | ||
+ | _DATE2_NULL = new java.sql.Date(cal.getTime().getTime()) ; | ||
+ | } | ||
+ | |||
+ | public void setNpayMid( int npayMid) | ||
+ | { | ||
+ | NPAY_MID = npayMid ; | ||
+ | } | ||
+ | public void setDebugMode(int debug) | ||
+ | { | ||
+ | _DEBUG = debug ; | ||
+ | } | ||
+ | //Не синхронизировать список услуг. через запятую. | ||
+ | public void notSynchronizeServices( String sids ) | ||
+ | { | ||
+ | noSynchroList = sids ; | ||
+ | } | ||
+ | public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять | ||
+ | { | ||
+ | deleteNonNeeded = dnn ; | ||
+ | } | ||
+ | //Точка входа. Синхронизирует сервисы договора | ||
+ | public void synchronizeServices( int cid, Connection con ) | ||
+ | throws Exception | ||
+ | { | ||
+ | vSidsData.clear() ; | ||
+ | vNpaySidsData.clear() ; | ||
+ | //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг | ||
+ | String SQL = "SELECT tree_id, t.title, ct.date1, ct.date2 " + | ||
+ | "FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id " + | ||
+ | "WHERE ct.cid=" + cid ; | ||
+ | //print(SQL) ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ); | ||
+ | ResultSet rs = ps.executeQuery(); | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int tree_id = rs.getInt("tree_id") ; | ||
+ | String title = rs.getString("title") ; | ||
+ | Date date1 = rs.getDate("ct.date1") ; | ||
+ | Date date2 = rs.getDate("ct.date2") ; | ||
+ | if ( _DEBUG == 1 ) { | ||
+ | print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор | ||
+ | } | ||
+ | //Выбираем персональные тарифы, и запоминаем периоды действия их услуг | ||
+ | SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; | ||
+ | ps = con.prepareStatement( SQL ); | ||
+ | rs = ps.executeQuery(); | ||
+ | if ( _DEBUG == 1 ){ | ||
+ | print("personals") ; | ||
+ | } | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int tree_id = rs.getInt("tree_id") ; | ||
+ | String title = rs.getString("title") ; | ||
+ | Date date1 = rs.getDate("date1") ; | ||
+ | Date date2 = rs.getDate("date2") ; | ||
+ | if( _DEBUG == 1 ) { | ||
+ | print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | findServicesForTariff( tree_id, 0, date1, date2, con ) ; | ||
+ | } | ||
+ | |||
+ | |||
+ | //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды | ||
+ | calcActualServicePeriods( vSidsData ) ; | ||
+ | //Тоже самое для услуг Абонплат. | ||
+ | calcActualServicePeriods( vNpaySidsData ) ; | ||
+ | |||
+ | //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. | ||
+ | print( "Services must be synchronized with folowing date periods") ; | ||
+ | printInternalDataForContract( cid ) ; | ||
+ | |||
+ | //Обновляем услуги договора | ||
+ | updateSynchronizedServices( cid, 0, con ) ; | ||
+ | //Обновляем услуги абонплат договора | ||
+ | updateSynchronizedServices( cid, NPAY_MID, con ) ; | ||
+ | } | ||
+ | |||
+ | public void printInternalDataForContract( int cid ) | ||
+ | { | ||
+ | print("cid="+cid) ; | ||
+ | print("SERVICES:") ; | ||
+ | for( int i = 0; i<vSidsData.size(); i++) | ||
+ | { | ||
+ | ((SidsData)vSidsData.get(i)).printData() ; | ||
+ | } | ||
+ | print("NPAY SERVICES:") ; | ||
+ | for( int i = 0; i<vNpaySidsData.size(); i++) | ||
+ | { | ||
+ | ((SidsData)vNpaySidsData.get(i)).printData() ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) | ||
+ | throws Exception | ||
+ | { | ||
+ | String SQLdelNonNeeded = "" ; | ||
+ | String SQLsel = "" ; | ||
+ | String SQLupd = "" ; | ||
+ | String SQLins = "" ; | ||
+ | String SQLdel = "" ; | ||
+ | Vector vSids = vSidsData ; | ||
+ | String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; | ||
+ | if ( nPayMid == 0 ){ | ||
+ | SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; | ||
+ | SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + | ||
+ | dateNow + ")' WHERE id=?" ; | ||
+ | SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + | ||
+ | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
+ | SQLdel = "DELETE FROM contract_service WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vSidsData) ; | ||
+ | if ( sidslist == "" ) { sidslist = "-1" ;} | ||
+ | SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + | ||
+ | sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; | ||
+ | } | ||
+ | else{ | ||
+ | vSids = vNpaySidsData ; | ||
+ | SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; | ||
+ | SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + | ||
+ | dateNow + ")' WHERE id=?" ; | ||
+ | SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + | ||
+ | cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; | ||
+ | SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; | ||
+ | String sidslist = getServiceList(vNpaySidsData) ; | ||
+ | if ( sidslist == "" ) { | ||
+ | sidslist = "-1" ; | ||
+ | } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости | ||
+ | String SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQLtmp ); | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | if( !rs.next() ) | ||
+ | { | ||
+ | SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; | ||
+ | ps = con.prepareStatement( SQLtmp ); | ||
+ | ps.executeUpdate() ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | if ( deleteNonNeeded == 1 ) | ||
+ | { | ||
+ | |||
+ | print( SQLdelNonNeeded ) ; | ||
+ | PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; | ||
+ | psDelOther.executeUpdate( SQLdelNonNeeded ) ; | ||
+ | } | ||
+ | PreparedStatement ps = con.prepareStatement( SQLsel ); | ||
+ | PreparedStatement psUpd = con.prepareStatement( SQLupd ); | ||
+ | PreparedStatement psIns = con.prepareStatement( SQLins ); | ||
+ | PreparedStatement psDel = con.prepareStatement( SQLdel ); | ||
+ | |||
+ | ResultSet rs ; | ||
+ | SidsData sd ; | ||
+ | Date date1=null, date2=null ; | ||
+ | for( int i = 0; i<vSids.size(); i++) | ||
+ | { | ||
+ | sd = (SidsData)vSids.get(i) ; | ||
+ | int sid = sd.sid ; | ||
+ | ps.setInt(1, sid) ; | ||
+ | rs = ps.executeQuery() ; | ||
+ | int j = 0 ; | ||
+ | while( rs.next() ) | ||
+ | { | ||
+ | int id = rs.getInt("id") ; | ||
+ | date1 = rs.getDate("date1") ; | ||
+ | date2 = rs.getDate("date2") ; | ||
+ | //Чтобы при сравнении дат equals не давал exeption, подменяем значения null | ||
+ | //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | if ( date1 == null ){ | ||
+ | date1 = (Date)_DATE1_NULL.clone() ; | ||
+ | } | ||
+ | if ( date2 == null ){ | ||
+ | date2 = (Date)_DATE2_NULL.clone() ; | ||
+ | } | ||
+ | //Лишняя услуга, удаляем | ||
+ | if ( j >= sd.vDate1.size() ) | ||
+ | { | ||
+ | psDel.setInt( 1, id ) ; | ||
+ | psDel.executeUpdate() ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Delete service with id=" + id + " for service="+sid + | ||
+ | " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psDel=" + psDel ) ; | ||
+ | } | ||
+ | continue ; | ||
+ | } | ||
+ | |||
+ | |||
+ | if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) | ||
+ | { | ||
+ | //Возвращаем значения null при необходимости для обновления инфы в БД | ||
+ | if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ | ||
+ | sd.vDate1.set( j, null ) ; | ||
+ | } | ||
+ | if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ | ||
+ | sd.vDate2.set( j, null ) ; | ||
+ | } | ||
+ | psUpd.setInt( 3, id ) ; | ||
+ | psUpd.setDate( 1, (Date)sd.vDate1.get(j) ) ; | ||
+ | psUpd.setDate( 2, (Date)sd.vDate2.get(j) ) ; | ||
+ | psUpd.executeUpdate() ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Update service with id=" + id + " for service="+sid + " previous date1=" + | ||
+ | TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psUpd=" + psUpd ) ; | ||
+ | } | ||
+ | } | ||
+ | j++ ; | ||
+ | }//end while | ||
+ | |||
+ | for( ; j < sd.vDate1.size(); j++) | ||
+ | { | ||
+ | if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ | ||
+ | sd.vDate1.set( j, null ) ; | ||
+ | } | ||
+ | if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ | ||
+ | sd.vDate2.set( j, null ) ; | ||
+ | } | ||
+ | psIns.setInt(1, sid ) ; | ||
+ | psIns.setDate( 2, (Date)sd.vDate1.get(j) ) ; | ||
+ | psIns.setDate( 3, (Date)sd.vDate2.get(j) ) ; | ||
+ | if (_DEBUG==1){ | ||
+ | print( "Insert new service="+sid + " date1=" + | ||
+ | TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; | ||
+ | print( "psIns" + psIns ) ; | ||
+ | } | ||
+ | psIns.executeUpdate() ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private String getServiceList(Vector vSids) | ||
+ | { | ||
+ | String sids = ""; | ||
+ | int i ; | ||
+ | for( i = 0; i<vSids.size()-1; i++) | ||
+ | { | ||
+ | sids += "" + ((SidsData)vSids.get(i)).sid + "," ; | ||
+ | } | ||
+ | if ( i < vSids.size()) { | ||
+ | sids += "" + ((SidsData)vSids.get(i)).sid ; | ||
+ | } | ||
+ | return sids ; | ||
+ | } | ||
+ | |||
+ | private void calcActualServicePeriods( Vector vSids ) | ||
+ | { | ||
+ | prepareInternalData() ; | ||
+ | SidsData sd ; | ||
+ | Vector vDate1 = new Vector() ; | ||
+ | Vector vDate2 = new Vector() ; | ||
+ | Date date1 ; | ||
+ | Date date2 ; | ||
+ | GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день | ||
+ | int k = 0 ; | ||
+ | for( int i = 0; i<vSids.size(); i++) | ||
+ | { | ||
+ | sd = (SidsData)vSids.get(i) ; | ||
+ | vDate1.clear() ; | ||
+ | vDate2.clear() ; | ||
+ | for ( int j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды | ||
+ | { | ||
+ | date1 = (Date)sd.vDate1.get(j) ; | ||
+ | date2 = (Date)sd.vDate2.get(j) ; | ||
+ | if ( date1.compareTo( date2) > 0 ) | ||
+ | { | ||
+ | print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | print("Services was not synchronized...") ; | ||
+ | return ; | ||
+ | } | ||
+ | for( j++ ; j<sd.vDate1.size(); j++) | ||
+ | { | ||
+ | date1cal.setTime( new java.util.Date(((Date)sd.vDate1.get(j)).getTime()) ) ; | ||
+ | date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; | ||
+ | if ( date2.compareTo(new java.sql.Date(date1cal.getTime().getTime())) < 0 ) // Нашли нужный date2 для date1 ; | ||
+ | { | ||
+ | break ; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | date2 = (Date)sd.vDate2.get(j) ; | ||
+ | } | ||
+ | } | ||
+ | vDate1.add(date1) ; | ||
+ | vDate2.add(date2) ; | ||
+ | } | ||
+ | |||
+ | sd.vDate1.clear() ; | ||
+ | sd.vDate2.clear() ; | ||
+ | sd.vDate1 = (Vector)vDate1.clone() ; | ||
+ | sd.vDate2 = (Vector)vDate2.clone() ; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | private void prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг | ||
+ | { | ||
+ | SidsData sd ; | ||
+ | for( int i = 0; i<vSidsData.size(); i++) | ||
+ | { | ||
+ | sd = (SidsData)vSidsData.get(i) ; | ||
+ | Collections.sort(sd.vDate1 ) ; | ||
+ | Collections.sort(sd.vDate2 ) ; | ||
+ | } | ||
+ | for( int i = 0; i<vNpaySidsData.size(); i++) | ||
+ | { | ||
+ | sd = (SidsData)vNpaySidsData.get(i) ; | ||
+ | Collections.sort(sd.vDate1 ) ; | ||
+ | Collections.sort(sd.vDate2 ) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | private void addSid( int sid, Date date1, Date date2, int npayService ) | ||
+ | { | ||
+ | String[] noSids = noSynchroList.split(",") ; | ||
+ | for ( int i = 0 ; i<noSids.length; i++ ) | ||
+ | { | ||
+ | if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} | ||
+ | } | ||
+ | //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно | ||
+ | if ( date1 == null ) { | ||
+ | date1 = (Date)_DATE1_NULL.clone() ; | ||
+ | } | ||
+ | if ( date2 == null ) { | ||
+ | date2 = (Date)_DATE2_NULL.clone() ; | ||
+ | } | ||
+ | |||
+ | Vector vSids = vSidsData; | ||
+ | if ( npayService != 0 ) | ||
+ | { | ||
+ | vSids = vNpaySidsData ; | ||
+ | } | ||
+ | int f = 0 ; | ||
+ | SidsData sd ; | ||
+ | for ( int i=0; i < vSids.size(); i++ ) | ||
+ | { | ||
+ | sd = (SidsData)vSids.get(i) ; | ||
+ | if (sd.sid == sid) | ||
+ | { | ||
+ | sd.vDate1.add(date1) ; | ||
+ | sd.vDate2.add(date2) ; | ||
+ | f = 1 ; break ; | ||
+ | } | ||
+ | } | ||
+ | if ( f == 0 ) | ||
+ | { | ||
+ | sd = new SidsData( sid ) ; | ||
+ | sd.vDate1.add(date1) ; | ||
+ | sd.vDate2.add(date2) ; | ||
+ | vSids.add( sd ) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, | ||
+ | Date date1, Date date2, Connection con) | ||
+ | throws Exception | ||
+ | { | ||
+ | String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; | ||
+ | if ( mid != 0 ) | ||
+ | { | ||
+ | SQL += " AND mid=" + mid ; | ||
+ | } | ||
+ | //print(SQL) ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ); | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | |||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | int mtreeid = rs.getInt("id") ; | ||
+ | mid = rs.getInt("mid") ; | ||
+ | int parent_tree = rs.getInt("parent_tree") ; | ||
+ | if (parent_tree != 0 ) | ||
+ | { | ||
+ | findServicesForTariff( parent_tree, mid, date1, date2, con ) ; | ||
+ | continue ; | ||
+ | } | ||
+ | findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) | ||
+ | throws Exception | ||
+ | { | ||
+ | String SQL = "SELECT type, data " + | ||
+ | "FROM mtree_node " + | ||
+ | "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; | ||
+ | PreparedStatement ps = con.prepareStatement( SQL ) ; | ||
+ | ResultSet rs = ps.executeQuery() ; | ||
+ | int sid = 0; | ||
+ | while ( rs.next() ) | ||
+ | { | ||
+ | String type = rs.getString("type") ; | ||
+ | String data = rs.getString("data") ; | ||
+ | //print ( "type=" + type + " data=" + data) ; | ||
+ | if (type.equals("service") ) | ||
+ | { | ||
+ | sid = Integer.parseInt( data ) ; | ||
+ | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | |||
+ | //print ( "sid=" + sid ) ; | ||
+ | } | ||
+ | else if( type.equals("multi_service") ) | ||
+ | { | ||
+ | String[] ss = data.split("&") ; | ||
+ | String[] sids = ss[1].split(",") ; | ||
+ | //print ( "sids=" + ss[1] ) ; | ||
+ | for ( int i=0; i < sids.length; i++ ) | ||
+ | { | ||
+ | sid=Integer.parseInt(sids[i]) ; | ||
+ | addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | //print( "sid = " + sid ) ; | ||
+ | } | ||
+ | } | ||
+ | else if( type.equals("month_mode") ) | ||
+ | { | ||
+ | String[] ss = data.split("%") ; | ||
+ | for ( int i = 0; i < ss.length ; i++ ) | ||
+ | { | ||
+ | String[] sids=ss[i].split("&") ; | ||
+ | if ( sids[0].equals("sid") ) | ||
+ | { | ||
+ | sid = Integer.parseInt(sids[1]) ; | ||
+ | addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | break ; | ||
+ | } | ||
+ | } | ||
+ | //print( "month_mode sid = " + sid ) ; | ||
+ | } | ||
+ | else if( type.equals("day_mode") ) | ||
+ | { | ||
+ | String[] ss = data.split("%") ; | ||
+ | for ( int i = 0; i < ss.length ; i++ ) | ||
+ | { | ||
+ | String[] sids=ss[i].split("&") ; | ||
+ | if ( sids[0].equals("sid") ) | ||
+ | { | ||
+ | sid = Integer.parseInt(sids[1]) ; | ||
+ | addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг | ||
+ | break ; | ||
+ | } | ||
+ | } | ||
+ | //print( "day_mode sid = " + sid ) ; | ||
+ | } | ||
+ | |||
+ | }//end while | ||
+ | } | ||
+ | |||
+ | |||
+ | //внутренниц класс для хранения услуги и множества дат date1 и date2 | ||
+ | private class SidsData{ | ||
+ | public int sid ; | ||
+ | public Vector vDate1 ; | ||
+ | public Vector vDate2 ; | ||
+ | |||
+ | public SidsData() | ||
+ | { | ||
+ | sid = 0 ; | ||
+ | vDate1 = new Vector() ; | ||
+ | vDate2 = new Vector() ; | ||
+ | } | ||
+ | |||
+ | public SidsData( int s ) | ||
+ | { | ||
+ | sid=s ; | ||
+ | vDate1 = new Vector() ; | ||
+ | vDate2 = new Vector() ; | ||
+ | } | ||
+ | public void printData() | ||
+ | { | ||
+ | print ("sid=" + sid) ; | ||
+ | for( int i=0; i<vDate1.size(); i++ ) | ||
+ | { | ||
+ | Date date1 = (Date)vDate1.get(i) ; | ||
+ | Date date2 = (Date)vDate2.get(i) ; | ||
+ | if ( date1.equals( _DATE1_NULL) ){ | ||
+ | date1 = null ; | ||
+ | } | ||
+ | if ( date2.equals( _DATE2_NULL) ){ | ||
+ | date2 = null ; | ||
+ | } | ||
+ | |||
+ | print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" | ||
+ | + TimeUtils.format(date2, "yyyy-MM-dd") ) ; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private int NPAY_MID=6; | ||
+ | private int _DEBUG=0 ; | ||
+ | private int deleteNonNeeded = 0 ; | ||
+ | static private Date _DATE1_NULL ; | ||
+ | static private Date _DATE2_NULL ; | ||
+ | private Vector vSidsData ; | ||
+ | private Vector vNpaySidsData ; | ||
+ | private String noSynchroList = "1000000" ;//не синхронизировать услуги. | ||
} | } | ||
</source> | </source> |
Текущая версия на 22:29, 24 августа 2014
Содержание |
Описание скрипта
Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. Алгоритм коротко таков: Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы
sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1 ... date1_tariffN_with_sid1 date2_tariffN_with_sid1 ... sidN date1_tariff1_with_sidN date2_tariff_with_sidN ... date1_tariffN_with_sidN date2_tariffN_with_sidN
из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!
upd 14.04.2010 Добавлен метод notSynchronizeServices(sids) ; в котором указывается список услуг, через запятую, которую не надо синхронизровать. Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.
Версия 5.0
Внимание! Данное решение/метод/статья относится к версии 5.0 и для других версий может быть неактуальна! Вам нужно самостоятельно поправить решение под свои нужды или воспользоваться помощью на форуме. Будем признательны, если внизу страницы или отдельной статьёй вы разместите исправленное решение для другой версии или подсказки что надо исправить.
import java.sql.*; import java.util.*; import java.math.* ; import bitel.billing.server.contract.bean.*; import bitel.billing.server.tariff.*; import bitel.billing.server.util.*; import bitel.billing.common.KernelConst; import bitel.billing.server.npay.bean.*; import bitel.billing.server.script.bean.event.*; import bitel.billing.server.npay.*; public void onEvent( event, setup, con, conSlave ) { //print( event ) ; int NPAY_MID = 8 ; SidsSynchroManager sidman = new SidsSynchroManager() ; int cid = event.getContractID() ; //sidman.setDebugMode(0) ; sidman.notSynchronizeServices("11,21,41,42,44");//Указываем список сервисов, которые не хотим, чтобы синхронизировались sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем. sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат sidman.synchronizeServices( cid, con ) ; } //Класс синхронизации услуг public class SidsSynchroManager { public SidsSynchroManager() { vSidsData = new Vector() ; vNpaySidsData = new Vector() ; GregorianCalendar cal = new GregorianCalendar() ; cal.set(1970, 0, 1 ) ; _DATE1_NULL = cal.getTime() ; cal.set(2020, 0, 1 ) ; _DATE2_NULL = cal.getTime() ; } public void setNpayMid( int npayMid) { NPAY_MID = npayMid ; } public void setDebugMode(int debug) { _DEBUG = debug ; } //Не синхронизировать список услуг. через запятую. public void notSynchronizeServices( String sids ) { noSynchroList = sids ; } public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять { deleteNonNeeded = dnn ; } //Точка входа. Синхронизирует сервисы договора public void synchronizeServices( int cid, Connection con ) { vSidsData.clear() ; vNpaySidsData.clear() ; //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг String SQL = "SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title," + "ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid " + "WHERE ct.cid=" + cid ; //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery(); while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("ct.date1") ; Date date2 = rs.getDate("ct.date2") ; if ( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор } //Выбираем персональные тарифы, и запоминаем периоды действия их услуг SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; ps = con.prepareStatement( SQL ); rs = ps.executeQuery(); if ( _DEBUG == 1 ){ print("personals") ; } while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("date1") ; Date date2 = rs.getDate("date2") ; if( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con ) ; } //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды calcActualServicePeriods( vSidsData ) ; //Тоже самое для услуг Абонплат. calcActualServicePeriods( vNpaySidsData ) ; //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. print( "Services must be synchronized with folowing date periods") ; printInternalDataForContract( cid ) ; //Обновляем услуги договора updateSynchronizedServices( cid, 0, con ) ; //Обновляем услуги абонплат договора updateSynchronizedServices( cid, NPAY_MID, con ) ; } public void printInternalDataForContract( int cid ) { print("cid="+cid) ; print("SERVICES:") ; for( int i = 0; i<vSidsData.size(); i++) { vSidsData.get(i).printData() ; } print("NPAY SERVICES:") ; for( int i = 0; i<vNpaySidsData.size(); i++) { vNpaySidsData.get(i).printData() ; } } private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) { Vector vSids = vSidsData ; String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; if ( nPayMid == 0 ){ SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM contract_service WHERE id=?" ; String sidslist = getServiceList(vSidsData) ; if ( sidslist == "" ) { sidslist = "-1" ;} SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; } else{ vSids = vNpaySidsData ; SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; String sidslist = getServiceList(vNpaySidsData) ; if ( sidslist == "" ) { sidslist = "-1" ; } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; PreparedStatement ps = con.prepareStatement( SQLtmp ); rs = ps.executeQuery() ; if( !rs.next() ) { SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; ps = con.prepareStatement( SQLtmp ); ps.executeUpdate() ; } } SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; } if ( deleteNonNeeded == 1 ) { print( SQLdelNonNeeded ) ; PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; psDelOther.executeUpdate( SQLdelNonNeeded ) ; } PreparedStatement ps = con.prepareStatement( SQLsel ); PreparedStatement psUpd = con.prepareStatement( SQLupd ); PreparedStatement psIns = con.prepareStatement( SQLins ); PreparedStatement psDel = con.prepareStatement( SQLdel ); ResultSet rs ; SidsData sd ; Date date1, date2 ; for( int i = 0; i<vSids.size(); i++) { sd = vSids.get(i) ; int sid = sd.sid ; ps.setInt(1, sid) ; rs = ps.executeQuery() ; j = 0 ; while( rs.next() ) { int id = rs.getInt("id") ; date1 = rs.getDate("date1") ; date2 = rs.getDate("date2") ; //Чтобы при сравнении дат equals не давал exeption, подменяем значения null //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; if ( date1 == null ){ date1 = _DATE1_NULL.clone() ; } if ( date2 == null ){ date2 = _DATE2_NULL.clone() ; } //Лишняя услуга, удаляем if ( j >= sd.vDate1.size() ) { psDel.setInt( 1, id ) ; psDel.executeUpdate() ; if (_DEBUG==1){ print( "Delete service with id=" + id + " for service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psDel=" + psDel ) ; } continue ; } if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) { //Возвращаем значения null при необходимости для обновления инфы в БД if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psUpd.setInt( 3, id ) ; psUpd.setDate( 1, sd.vDate1.get(j) ) ; psUpd.setDate( 2, sd.vDate2.get(j) ) ; psUpd.executeUpdate() ; if (_DEBUG==1){ print( "Update service with id=" + id + " for service="+sid + " previous date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psUpd=" + psUpd ) ; } } j++ ; }//end while for( ; j < sd.vDate1.size(); j++) { if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psIns.setInt(1, sid ) ; psIns.setDate( 2, sd.vDate1.get(j) ) ; psIns.setDate( 3, sd.vDate2.get(j) ) ; if (_DEBUG==1){ print( "Insert new service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psIns" + psIns ) ; } psIns.executeUpdate() ; } } } private String getServiceList(Vector vSids) { String sids = ""; int i ; for( i = 0; i<vSids.size()-1; i++) { sids += "" + vSids.get(i).sid + "," ; } if ( i < vSids.size()) { sids += "" + vSids.get(i).sid ; } return sids ; } private calcActualServicePeriods( Vector vSids ) { prepareInternalData() ; SidsData sd ; Vector vDate1 = new Vector() ; Vector vDate2 = new Vector() ; Date date1 ; Date date2 ; GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день k = 0 ; for( int i = 0; i<vSids.size(); i++) { sd = vSids.get(i) ; vDate1.clear() ; vDate2.clear() ; for ( j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды { date1 = sd.vDate1.get(j) ; date2 = sd.vDate2.get(j) ; if ( date1.compareTo( date2) > 0 ) { print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; print("Services was not synchronized...") ; return ; } for( j++ ; j<sd.vDate1.size(); j++) { date1cal.setTime( sd.vDate1.get(j) ) ; date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; if ( date2.compareTo(date1cal.getTime()) < 0 ) // Нашли нужный date2 для date1 ; { break ; } else { date2 = sd.vDate2.get(j) ; } } vDate1.add(date1) ; vDate2.add(date2) ; } sd.vDate1.clear() ; sd.vDate2.clear() ; sd.vDate1 = vDate1.clone() ; sd.vDate2 = vDate2.clone() ; } } private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг { SidsData sd ; for( int i = 0; i<vSidsData.size(); i++) { sd = vSidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } for( int i = 0; i<vNpaySidsData.size(); i++) { sd = vNpaySidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } } private void addSid( int sid, Date date1, Date date2, int npayService ) { String[] noSids = noSynchroList.split(",") ; for ( int i = 0 ; i<noSids.length; i++ ) { if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} } //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно if ( date1 == null ) { date1 = _DATE1_NULL.clone() ; } if ( date2 == null ) { date2 = _DATE2_NULL.clone() ; } Vector vSids = vSidsData; if ( npayService != 0 ) { vSids = vNpaySidsData ; } int f = 0 ; SidsData sd ; for ( int i=0; i < vSids.size(); i++ ) { sd = vSids.get(i) ; if (sd.sid == sid) { sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; f = 1 ; break ; } } if ( f == 0 ) { sd = new SidsData( sid ) ; sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; vSids.add( sd ) ; } } private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, Date date1, Date date2, Connection con) { String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; if ( mid != 0 ) { SQL += " AND mid=" + mid ; } //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery() ; while ( rs.next() ) { int mtreeid = rs.getInt("id") ; int mid = rs.getInt("mid") ; int parent_tree = rs.getInt("parent_tree") ; if (parent_tree != 0 ) { findServicesForTariff( parent_tree, mid, date1, date2, con ) ; continue ; } findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; } } private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) { SQL = "SELECT type, data " + "FROM mtree_node " + "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; PreparedStatement ps = con.prepareStatement( SQL ) ; ResultSet rs = ps.executeQuery() ; int sid = 0; while ( rs.next() ) { String type = rs.getString("type") ; String data = rs.getString("data") ; //print ( "type=" + type + " data=" + data) ; if (type.equals("service") ) { sid = Integer.parseInt( data ) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print ( "sid=" + sid ) ; } else if( type.equals("multi_service") ) { String[] ss = data.split("&") ; String[] sids = ss[1].split(",") ; //print ( "sids=" + ss[1] ) ; for ( int i=0; i < sids.length; i++ ) { sid=Integer.parseInt(sids[i]) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print( "sid = " + sid ) ; } } else if( type.equals("month_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "month_mode sid = " + sid ) ; } else if( type.equals("day_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "day_mode sid = " + sid ) ; } }//end while } //внутренниц класс для хранения услуги и множества дат date1 и date2 private class SidsData{ public int sid ; public Vector vDate1 ; public Vector vDate2 ; public SidsData() { sid = 0 ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public SidsData( int s ) { sid=s ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public printData() { print ("sid=" + sid) ; for( i=0; i<vDate1.size(); i++ ) { Date date1 = vDate1.get(i) ; Date date2 = vDate2.get(i) ; if ( date1.equals( _DATE1_NULL) ){ date1 = null ; } if ( date2.equals( _DATE2_NULL) ){ date2 = null ; } print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } } } private int NPAY_MID=8 ; private int _DEBUG=0 ; private int deleteNonNeeded = 0 ; static private Date _DATE1_NULL ; static private Date _DATE2_NULL ; private Vector vSidsData ; private Vector vNpaySidsData ; private String noSynchroList = "1000000" ;//не синхронизировать услуги. }
Версия 5.1
Внимание! Данное решение/метод/статья относится к версии 5.1 и для других версий может быть неактуальна! Вам нужно самостоятельно поправить решение под свои нужды или воспользоваться помощью на форуме. Будем признательны, если внизу страницы или отдельной статьёй вы разместите исправленное решение для другой версии или подсказки что надо исправить.
Пофиксино для версии 5.1
import java.sql.*; import java.util.*; import java.math.* ; import bitel.billing.server.contract.bean.*; import bitel.billing.server.tariff.*; import bitel.billing.server.util.*; import bitel.billing.common.KernelConst; import bitel.billing.server.npay.bean.*; import bitel.billing.server.script.bean.event.*; import bitel.billing.server.npay.*; public void onEvent( event, setup, con, conSlave ) { //print( event ) ; int NPAY_MID = 4 ; SidsSynchroManager sidman = new SidsSynchroManager() ; int cid = event.getContractId() ; //sidman.setDebugMode(0) ; sidman.setDeleteNonNeeded(1) ; sidman.setNpayMid(NPAY_MID) ; sidman.notSynchronizeServices("9,7,11"); sidman.synchronizeServices( cid, con ) ; } //Класс синхронизации услуг public class SidsSynchroManager { public SidsSynchroManager() { vSidsData = new Vector() ; vNpaySidsData = new Vector() ; GregorianCalendar cal = new GregorianCalendar() ; cal.set(1970, 0, 1 ) ; _DATE1_NULL = cal.getTime() ; cal.set(2020, 0, 1 ) ; _DATE2_NULL = cal.getTime() ; } public void setNpayMid( int npayMid) { NPAY_MID = npayMid ; } public void setDebugMode(int debug) { _DEBUG = debug ; } //Не синхронизировать список услуг. через запятую. public void notSynchronizeServices( String sids ) { noSynchroList = sids ; } public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять { deleteNonNeeded = dnn ; } //Точка входа. Синхронизирует сервисы договора public void synchronizeServices( int cid, Connection con ) { vSidsData.clear() ; vNpaySidsData.clear() ; //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг String SQL = "SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title," + "ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid " + "WHERE ct.cid=" + cid ; //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery(); while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("ct.date1") ; Date date2 = rs.getDate("ct.date2") ; if ( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор } //Выбираем персональные тарифы, и запоминаем периоды действия их услуг SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; ps = con.prepareStatement( SQL ); rs = ps.executeQuery(); if ( _DEBUG == 1 ){ print("personals") ; } while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("date1") ; Date date2 = rs.getDate("date2") ; if( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con ) ; } //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды calcActualServicePeriods( vSidsData ) ; //Тоже самое для услуг Абонплат. calcActualServicePeriods( vNpaySidsData ) ; //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. print( "Services must be synchronized with folowing date periods") ; printInternalDataForContract( cid ) ; //Обновляем услуги договора updateSynchronizedServices( cid, 0, con ) ; //Обновляем услуги абонплат договора updateSynchronizedServices( cid, NPAY_MID, con ) ; } public void printInternalDataForContract( int cid ) { print("cid="+cid) ; print("SERVICES:") ; for( int i = 0; i<vSidsData.size(); i++) { vSidsData.get(i).printData() ; } print("NPAY SERVICES:") ; for( int i = 0; i<vNpaySidsData.size(); i++) { vNpaySidsData.get(i).printData() ; } } private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) { String SQLdelNonNeeded = "" ; String SQLsel = "" ; String SQLupd = "" ; String SQLins = "" ; String SQLdel = "" ; Vector vSids = vSidsData ; String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; if ( nPayMid == 0 ){ SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM contract_service WHERE id=?" ; String sidslist = getServiceList(vSidsData) ; if ( sidslist == "" ) { sidslist = "-1" ;} SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; } else{ vSids = vNpaySidsData ; SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; String sidslist = getServiceList(vNpaySidsData) ; if ( sidslist == "" ) { sidslist = "-1" ; } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; PreparedStatement ps = con.prepareStatement( SQLtmp ); rs = ps.executeQuery() ; if( !rs.next() ) { SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; ps = con.prepareStatement( SQLtmp ); ps.executeUpdate() ; } } SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; } if ( deleteNonNeeded == 1 ) { print( SQLdelNonNeeded ) ; PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; psDelOther.executeUpdate( SQLdelNonNeeded ) ; } PreparedStatement ps = con.prepareStatement( SQLsel ); PreparedStatement psUpd = con.prepareStatement( SQLupd ); PreparedStatement psIns = con.prepareStatement( SQLins ); PreparedStatement psDel = con.prepareStatement( SQLdel ); ResultSet rs ; SidsData sd ; Date date1, date2 ; for( int i = 0; i<vSids.size(); i++) { sd = vSids.get(i) ; int sid = sd.sid ; ps.setInt(1, sid) ; rs = ps.executeQuery() ; j = 0 ; while( rs.next() ) { int id = rs.getInt("id") ; date1 = rs.getDate("date1") ; date2 = rs.getDate("date2") ; //Чтобы при сравнении дат equals не давал exeption, подменяем значения null //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; if ( date1 == null ){ date1 = _DATE1_NULL.clone() ; } if ( date2 == null ){ date2 = _DATE2_NULL.clone() ; } //Лишняя услуга, удаляем if ( j >= sd.vDate1.size() ) { psDel.setInt( 1, id ) ; psDel.executeUpdate() ; if (_DEBUG==1){ print( "Delete service with id=" + id + " for service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psDel=" + psDel ) ; } continue ; } if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) { //Возвращаем значения null при необходимости для обновления инфы в БД if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psUpd.setInt( 3, id ) ; psUpd.setDate( 1, sd.vDate1.get(j) ) ; psUpd.setDate( 2, sd.vDate2.get(j) ) ; psUpd.executeUpdate() ; if (_DEBUG==1){ print( "Update service with id=" + id + " for service="+sid + " previous date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psUpd=" + psUpd ) ; } } j++ ; }//end while for( ; j < sd.vDate1.size(); j++) { if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psIns.setInt(1, sid ) ; psIns.setDate( 2, sd.vDate1.get(j) ) ; psIns.setDate( 3, sd.vDate2.get(j) ) ; if (_DEBUG==1){ print( "Insert new service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psIns" + psIns ) ; } psIns.executeUpdate() ; } } } private String getServiceList(Vector vSids) { String sids = ""; int i ; for( i = 0; i<vSids.size()-1; i++) { sids += "" + vSids.get(i).sid + "," ; } if ( i < vSids.size()) { sids += "" + vSids.get(i).sid ; } return sids ; } private calcActualServicePeriods( Vector vSids ) { prepareInternalData() ; SidsData sd ; Vector vDate1 = new Vector() ; Vector vDate2 = new Vector() ; Date date1 ; Date date2 ; GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день k = 0 ; for( int i = 0; i<vSids.size(); i++) { sd = vSids.get(i) ; vDate1.clear() ; vDate2.clear() ; for ( j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды { date1 = sd.vDate1.get(j) ; date2 = sd.vDate2.get(j) ; if ( date1.compareTo( date2) > 0 ) { print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; print("Services was not synchronized...") ; return ; } for( j++ ; j<sd.vDate1.size(); j++) { date1cal.setTime( sd.vDate1.get(j) ) ; date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; if ( date2.compareTo(date1cal.getTime()) < 0 ) // Нашли нужный date2 для date1 ; { break ; } else { date2 = sd.vDate2.get(j) ; } } vDate1.add(date1) ; vDate2.add(date2) ; } sd.vDate1.clear() ; sd.vDate2.clear() ; sd.vDate1 = vDate1.clone() ; sd.vDate2 = vDate2.clone() ; } } private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг { SidsData sd ; for( int i = 0; i<vSidsData.size(); i++) { sd = vSidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } for( int i = 0; i<vNpaySidsData.size(); i++) { sd = vNpaySidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } } private void addSid( int sid, Date date1, Date date2, int npayService ) { String[] noSids = noSynchroList.split(",") ; for ( int i = 0 ; i<noSids.length; i++ ) { if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} } //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно if ( date1 == null ) { date1 = _DATE1_NULL.clone() ; } if ( date2 == null ) { date2 = _DATE2_NULL.clone() ; } Vector vSids = vSidsData; if ( npayService != 0 ) { vSids = vNpaySidsData ; } int f = 0 ; SidsData sd ; for ( int i=0; i < vSids.size(); i++ ) { sd = vSids.get(i) ; if (sd.sid == sid) { sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; f = 1 ; break ; } } if ( f == 0 ) { sd = new SidsData( sid ) ; sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; vSids.add( sd ) ; } } private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, Date date1, Date date2, Connection con) { String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; if ( mid != 0 ) { SQL += " AND mid=" + mid ; } //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery() ; while ( rs.next() ) { int mtreeid = rs.getInt("id") ; int mid = rs.getInt("mid") ; int parent_tree = rs.getInt("parent_tree") ; if (parent_tree != 0 ) { findServicesForTariff( parent_tree, mid, date1, date2, con ) ; continue ; } findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; } } private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) { SQL = "SELECT type, data " + "FROM mtree_node " + "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; PreparedStatement ps = con.prepareStatement( SQL ) ; ResultSet rs = ps.executeQuery() ; int sid = 0; while ( rs.next() ) { String type = rs.getString("type") ; String data = rs.getString("data") ; //print ( "type=" + type + " data=" + data) ; if (type.equals("service") ) { sid = Integer.parseInt( data ) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print ( "sid=" + sid ) ; } else if( type.equals("multi_service") ) { String[] ss = data.split("&") ; String[] sids = ss[1].split(",") ; //print ( "sids=" + ss[1] ) ; for ( int i=0; i < sids.length; i++ ) { sid=Integer.parseInt(sids[i]) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print( "sid = " + sid ) ; } } else if( type.equals("month_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "month_mode sid = " + sid ) ; } else if( type.equals("day_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "day_mode sid = " + sid ) ; } }//end while } //внутренниц класс для хранения услуги и множества дат date1 и date2 private class SidsData{ public int sid ; public Vector vDate1 ; public Vector vDate2 ; public SidsData() { sid = 0 ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public SidsData( int s ) { sid=s ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public printData() { print ("sid=" + sid) ; for( i=0; i<vDate1.size(); i++ ) { Date date1 = vDate1.get(i) ; Date date2 = vDate2.get(i) ; if ( date1.equals( _DATE1_NULL) ){ date1 = null ; } if ( date2.equals( _DATE2_NULL) ){ date2 = null ; } print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } } } private int NPAY_MID=4 ; private int _DEBUG=0 ; private int deleteNonNeeded = 0 ; static private Date _DATE1_NULL ; static private Date _DATE2_NULL ; private Vector vSidsData ; private Vector vNpaySidsData ; private String noSynchroList = "1000000" ;//не синхронизировать услуги. }
+sid +
Версия 5.2
Внимание! Данное решение/метод/статья относится к версии 5.2 и для других версий может быть неактуальна! Вам нужно самостоятельно поправить решение под свои нужды или воспользоваться помощью на форуме. Будем признательны, если внизу страницы или отдельной статьёй вы разместите исправленное решение для другой версии или подсказки что надо исправить.
Пофиксено для 5.2 --Skyb 06:01, 14 февраля 2012 (UTC)
Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --SinTeZWh1te 10:03, 19 апреля 2012
import java.sql.*; import java.util.*; import java.math.* ; import bitel.billing.server.contract.bean.*; import bitel.billing.server.tariff.*; import bitel.billing.server.util.*; import bitel.billing.common.KernelConst; import bitel.billing.server.npay.bean.*; import bitel.billing.server.script.bean.event.*; import bitel.billing.server.npay.*; import bitel.billing.server.task.bean.*; public void onEvent( event, setup, con, conSlave ) { //print( event ) ; int NPAY_MID = 4 ; SidsSynchroManager sidman = new SidsSynchroManager() ; int cid = event.getContractId() ; //sidman.setDebugMode(0) ; sidman.setDeleteNonNeeded(1) ; sidman.setNpayMid(NPAY_MID) ; sidman.notSynchronizeServices("9,7,11"); sidman.synchronizeServices( cid, con ) ; //Кусок отвечающий за перерасчет абонплаты // месяц за который идёт перерасчёт dateTask = new GregorianCalendar(); // набор услуг, 0- все услуги serviceSet = 0; //Комментарий задачи comment = ""; email = "null"; new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) ); } //Класс синхронизации услуг public class SidsSynchroManager { public SidsSynchroManager() { vSidsData = new Vector() ; vNpaySidsData = new Vector() ; GregorianCalendar cal = new GregorianCalendar() ; cal.set(1970, 0, 1 ) ; _DATE1_NULL = cal.getTime() ; cal.set(2020, 0, 1 ) ; _DATE2_NULL = cal.getTime() ; } public void setNpayMid( int npayMid) { NPAY_MID = npayMid ; } public void setDebugMode(int debug) { _DEBUG = debug ; } //Не синхронизировать список услуг. через запятую. public void notSynchronizeServices( String sids ) { noSynchroList = sids ; } public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять { deleteNonNeeded = dnn ; } //Точка входа. Синхронизирует сервисы договора public void synchronizeServices( int cid, Connection con ) { vSidsData.clear() ; vNpaySidsData.clear() ; //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг String SQL = "SELECT tree_id, t.title, ct.date1, ct.date2 " + "FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id " + "WHERE ct.cid=" + cid ; //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery(); while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("ct.date1") ; Date date2 = rs.getDate("ct.date2") ; if ( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор } //Выбираем персональные тарифы, и запоминаем периоды действия их услуг SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; ps = con.prepareStatement( SQL ); rs = ps.executeQuery(); if ( _DEBUG == 1 ){ print("personals") ; } while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("date1") ; Date date2 = rs.getDate("date2") ; if( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con ) ; } //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды calcActualServicePeriods( vSidsData ) ; //Тоже самое для услуг Абонплат. calcActualServicePeriods( vNpaySidsData ) ; //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. print( "Services must be synchronized with folowing date periods") ; printInternalDataForContract( cid ) ; //Обновляем услуги договора updateSynchronizedServices( cid, 0, con ) ; //Обновляем услуги абонплат договора updateSynchronizedServices( cid, NPAY_MID, con ) ; } public void printInternalDataForContract( int cid ) { print("cid="+cid) ; print("SERVICES:") ; for( int i = 0; i<vSidsData.size(); i++) { vSidsData.get(i).printData() ; } print("NPAY SERVICES:") ; for( int i = 0; i<vNpaySidsData.size(); i++) { vNpaySidsData.get(i).printData() ; } } private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) { String SQLdelNonNeeded = "" ; String SQLsel = "" ; String SQLupd = "" ; String SQLins = "" ; String SQLdel = "" ; Vector vSids = vSidsData ; String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; if ( nPayMid == 0 ){ SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM contract_service WHERE id=?" ; String sidslist = getServiceList(vSidsData) ; if ( sidslist == "" ) { sidslist = "-1" ;} SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; } else{ vSids = vNpaySidsData ; SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; String sidslist = getServiceList(vNpaySidsData) ; if ( sidslist == "" ) { sidslist = "-1" ; } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; PreparedStatement ps = con.prepareStatement( SQLtmp ); rs = ps.executeQuery() ; if( !rs.next() ) { SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; ps = con.prepareStatement( SQLtmp ); ps.executeUpdate() ; } } SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; } if ( deleteNonNeeded == 1 ) { print( SQLdelNonNeeded ) ; PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; psDelOther.executeUpdate( SQLdelNonNeeded ) ; } PreparedStatement ps = con.prepareStatement( SQLsel ); PreparedStatement psUpd = con.prepareStatement( SQLupd ); PreparedStatement psIns = con.prepareStatement( SQLins ); PreparedStatement psDel = con.prepareStatement( SQLdel ); ResultSet rs ; SidsData sd ; Date date1, date2 ; for( int i = 0; i<vSids.size(); i++) { sd = vSids.get(i) ; int sid = sd.sid ; ps.setInt(1, sid) ; rs = ps.executeQuery() ; j = 0 ; while( rs.next() ) { int id = rs.getInt("id") ; date1 = rs.getDate("date1") ; date2 = rs.getDate("date2") ; //Чтобы при сравнении дат equals не давал exeption, подменяем значения null //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; if ( date1 == null ){ date1 = _DATE1_NULL.clone() ; } if ( date2 == null ){ date2 = _DATE2_NULL.clone() ; } //Лишняя услуга, удаляем if ( j >= sd.vDate1.size() ) { psDel.setInt( 1, id ) ; psDel.executeUpdate() ; if (_DEBUG==1){ print( "Delete service with id=" + id + " for service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psDel=" + psDel ) ; } continue ; } if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) { //Возвращаем значения null при необходимости для обновления инфы в БД if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psUpd.setInt( 3, id ) ; psUpd.setDate( 1, sd.vDate1.get(j) ) ; psUpd.setDate( 2, sd.vDate2.get(j) ) ; psUpd.executeUpdate() ; if (_DEBUG==1){ print( "Update service with id=" + id + " for service="+sid + " previous date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psUpd=" + psUpd ) ; } } j++ ; }//end while for( ; j < sd.vDate1.size(); j++) { if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psIns.setInt(1, sid ) ; psIns.setDate( 2, sd.vDate1.get(j) ) ; psIns.setDate( 3, sd.vDate2.get(j) ) ; if (_DEBUG==1){ print( "Insert new service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psIns" + psIns ) ; } psIns.executeUpdate() ; } } } private String getServiceList(Vector vSids) { String sids = ""; int i ; for( i = 0; i<vSids.size()-1; i++) { sids += "" + vSids.get(i).sid + "," ; } if ( i < vSids.size()) { sids += "" + vSids.get(i).sid ; } return sids ; } private calcActualServicePeriods( Vector vSids ) { prepareInternalData() ; SidsData sd ; Vector vDate1 = new Vector() ; Vector vDate2 = new Vector() ; Date date1 ; Date date2 ; GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день k = 0 ; for( int i = 0; i<vSids.size(); i++) { sd = vSids.get(i) ; vDate1.clear() ; vDate2.clear() ; for ( j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды { date1 = sd.vDate1.get(j) ; date2 = sd.vDate2.get(j) ; if ( date1.compareTo( date2) > 0 ) { print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; print("Services was not synchronized...") ; return ; } for( j++ ; j<sd.vDate1.size(); j++) { date1cal.setTime( sd.vDate1.get(j) ) ; date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; if ( date2.compareTo(date1cal.getTime()) < 0 ) // Нашли нужный date2 для date1 ; { break ; } else { date2 = sd.vDate2.get(j) ; } } vDate1.add(date1) ; vDate2.add(date2) ; } sd.vDate1.clear() ; sd.vDate2.clear() ; sd.vDate1 = vDate1.clone() ; sd.vDate2 = vDate2.clone() ; } } private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг { SidsData sd ; for( int i = 0; i<vSidsData.size(); i++) { sd = vSidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } for( int i = 0; i<vNpaySidsData.size(); i++) { sd = vNpaySidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } } private void addSid( int sid, Date date1, Date date2, int npayService ) { String[] noSids = noSynchroList.split(",") ; for ( int i = 0 ; i<noSids.length; i++ ) { if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} } //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно if ( date1 == null ) { date1 = _DATE1_NULL.clone() ; } if ( date2 == null ) { date2 = _DATE2_NULL.clone() ; } Vector vSids = vSidsData; if ( npayService != 0 ) { vSids = vNpaySidsData ; } int f = 0 ; SidsData sd ; for ( int i=0; i < vSids.size(); i++ ) { sd = vSids.get(i) ; if (sd.sid == sid) { sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; f = 1 ; break ; } } if ( f == 0 ) { sd = new SidsData( sid ) ; sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; vSids.add( sd ) ; } } private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, Date date1, Date date2, Connection con) { String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; if ( mid != 0 ) { SQL += " AND mid=" + mid ; } //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery() ; while ( rs.next() ) { int mtreeid = rs.getInt("id") ; int mid = rs.getInt("mid") ; int parent_tree = rs.getInt("parent_tree") ; if (parent_tree != 0 ) { findServicesForTariff( parent_tree, mid, date1, date2, con ) ; continue ; } findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; } } private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) { SQL = "SELECT type, data " + "FROM mtree_node " + "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; PreparedStatement ps = con.prepareStatement( SQL ) ; ResultSet rs = ps.executeQuery() ; int sid = 0; while ( rs.next() ) { String type = rs.getString("type") ; String data = rs.getString("data") ; //print ( "type=" + type + " data=" + data) ; if (type.equals("service") ) { sid = Integer.parseInt( data ) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print ( "sid=" + sid ) ; } else if( type.equals("multi_service") ) { String[] ss = data.split("&") ; String[] sids = ss[1].split(",") ; //print ( "sids=" + ss[1] ) ; for ( int i=0; i < sids.length; i++ ) { sid=Integer.parseInt(sids[i]) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print( "sid = " + sid ) ; } } else if( type.equals("month_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "month_mode sid = " + sid ) ; } else if( type.equals("day_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "day_mode sid = " + sid ) ; } }//end while } //внутренниц класс для хранения услуги и множества дат date1 и date2 private class SidsData{ public int sid ; public Vector vDate1 ; public Vector vDate2 ; public SidsData() { sid = 0 ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public SidsData( int s ) { sid=s ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public printData() { print ("sid=" + sid) ; for( i=0; i<vDate1.size(); i++ ) { Date date1 = vDate1.get(i) ; Date date2 = vDate2.get(i) ; if ( date1.equals( _DATE1_NULL) ){ date1 = null ; } if ( date2.equals( _DATE2_NULL) ){ date2 = null ; } print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } } } private int NPAY_MID=4 ; private int _DEBUG=0 ; private int deleteNonNeeded = 0 ; static private Date _DATE1_NULL ; static private Date _DATE2_NULL ; private Vector vSidsData ; private Vector vNpaySidsData ; private String noSynchroList = "1000000" ;//не синхронизировать услуги. }
Версия 6.0
Внимание! Данное решение/метод/статья относится к версии 6.0 и для других версий может быть неактуальна! Вам нужно самостоятельно поправить решение под свои нужды или воспользоваться помощью на форуме. Будем признательны, если внизу страницы или отдельной статьёй вы разместите исправленное решение для другой версии или подсказки что надо исправить.
Дин код
package ru.ellcom.bgbilling.scripts.tariff; import ru.bitel.bgbilling.kernel.event.Event; import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.sql.ConnectionSet; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Calendar; import java.util.Collections; import java.util.GregorianCalendar; import java.util.Vector; import bitel.billing.common.TimeUtils; import bitel.billing.server.npay.Recalculator; import bitel.billing.server.task.bean.RunTaskDataManager; public class SyncService extends EventScriptBase { @Override public void onEvent( Event event, Setup setup, ConnectionSet connectionSet ) throws Exception { int cid = event.getContractId() ; int NPAY_MID = 6 ; Connection con = connectionSet.getConnection() ; //SidsSynchroManager sidman = new SidsSynchroManager() ; initSynchroManager() ; //sidman.setDebugMode(0) ; setDeleteNonNeeded(1) ; setNpayMid(NPAY_MID) ; notSynchronizeServices("1000000"); synchronizeServices( cid, con ) ; Calendar dateTask = new GregorianCalendar(); // набор услуг, 0- все услуги int serviceSet = 0; //Комментарий задачи String comment = ""; String email = "null"; new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) ); } //код класса синхронизации public void initSynchroManager() { vSidsData = new Vector() ; vNpaySidsData = new Vector() ; GregorianCalendar cal = new GregorianCalendar() ; cal.set(1970, 0, 1 ) ; _DATE1_NULL = new java.sql.Date(cal.getTime().getTime()) ; cal.set(2020, 0, 1 ) ; _DATE2_NULL = new java.sql.Date(cal.getTime().getTime()) ; } public void setNpayMid( int npayMid) { NPAY_MID = npayMid ; } public void setDebugMode(int debug) { _DEBUG = debug ; } //Не синхронизировать список услуг. через запятую. public void notSynchronizeServices( String sids ) { noSynchroList = sids ; } public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять { deleteNonNeeded = dnn ; } //Точка входа. Синхронизирует сервисы договора public void synchronizeServices( int cid, Connection con ) throws Exception { vSidsData.clear() ; vNpaySidsData.clear() ; //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг String SQL = "SELECT tree_id, t.title, ct.date1, ct.date2 " + "FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id " + "WHERE ct.cid=" + cid ; //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery(); while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("ct.date1") ; Date date2 = rs.getDate("ct.date2") ; if ( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор } //Выбираем персональные тарифы, и запоминаем периоды действия их услуг SQL = "SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=" + cid ; ps = con.prepareStatement( SQL ); rs = ps.executeQuery(); if ( _DEBUG == 1 ){ print("personals") ; } while ( rs.next() ) { int tree_id = rs.getInt("tree_id") ; String title = rs.getString("title") ; Date date1 = rs.getDate("date1") ; Date date2 = rs.getDate("date2") ; if( _DEBUG == 1 ) { print ("tree_id=" + tree_id + " title=" + title + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } findServicesForTariff( tree_id, 0, date1, date2, con ) ; } //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды calcActualServicePeriods( vSidsData ) ; //Тоже самое для услуг Абонплат. calcActualServicePeriods( vNpaySidsData ) ; //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги. print( "Services must be synchronized with folowing date periods") ; printInternalDataForContract( cid ) ; //Обновляем услуги договора updateSynchronizedServices( cid, 0, con ) ; //Обновляем услуги абонплат договора updateSynchronizedServices( cid, NPAY_MID, con ) ; } public void printInternalDataForContract( int cid ) { print("cid="+cid) ; print("SERVICES:") ; for( int i = 0; i<vSidsData.size(); i++) { ((SidsData)vSidsData.get(i)).printData() ; } print("NPAY SERVICES:") ; for( int i = 0; i<vNpaySidsData.size(); i++) { ((SidsData)vNpaySidsData.get(i)).printData() ; } } private void updateSynchronizedServices( int cid, int nPayMid, Connection con ) throws Exception { String SQLdelNonNeeded = "" ; String SQLsel = "" ; String SQLupd = "" ; String SQLins = "" ; String SQLdel = "" ; Vector vSids = vSidsData ; String dateNow = TimeUtils.format(new GregorianCalendar(), "yyyy-MM-dd hh:mm:ss") ; if ( nPayMid == 0 ){ SQLsel = "SELECT id, date1, date2 FROM contract_service WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM contract_service WHERE id=?" ; String sidslist = getServiceList(vSidsData) ; if ( sidslist == "" ) { sidslist = "-1" ;} SQLdelNonNeeded = "DELETE FROM contract_service WHERE cid=" + cid + " AND sid NOT IN (" + sidslist +") AND sid NOT IN (" + noSynchroList + ")" ; } else{ vSids = vNpaySidsData ; SQLsel = "SELECT id, date1, date2 FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid=? ORDER BY date1, date2" ; SQLupd = "UPDATE npay_service_object_" + nPayMid + " SET date1=?, date2=?, comment='Service synchronize(update from " + dateNow + ")' WHERE id=?" ; SQLins = "INSERT INTO npay_service_object_" + nPayMid + " (cid, sid, date1, date2, comment ) VALUES ( " + cid + ", ? , ? , ?, 'Service synchronize(insert from " + dateNow + ")')" ; SQLdel = "DELETE FROM npay_service_object_" + nPayMid + " WHERE id=?" ; String sidslist = getServiceList(vNpaySidsData) ; if ( sidslist == "" ) { sidslist = "-1" ; } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости String SQLtmp = "SELECT mid FROM contract_module WHERE cid=" + cid + " AND mid=" + NPAY_MID ; PreparedStatement ps = con.prepareStatement( SQLtmp ); ResultSet rs = ps.executeQuery() ; if( !rs.next() ) { SQLtmp = "INSERT INTO contract_module (cid,mid) VALUES (" + cid + "," + NPAY_MID + ")" ; ps = con.prepareStatement( SQLtmp ); ps.executeUpdate() ; } } SQLdelNonNeeded = "DELETE FROM npay_service_object_" + nPayMid + " WHERE cid=" + cid + " AND sid NOT IN (" + sidslist + ") AND sid NOT IN (" + noSynchroList + ")" ; } if ( deleteNonNeeded == 1 ) { print( SQLdelNonNeeded ) ; PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ; psDelOther.executeUpdate( SQLdelNonNeeded ) ; } PreparedStatement ps = con.prepareStatement( SQLsel ); PreparedStatement psUpd = con.prepareStatement( SQLupd ); PreparedStatement psIns = con.prepareStatement( SQLins ); PreparedStatement psDel = con.prepareStatement( SQLdel ); ResultSet rs ; SidsData sd ; Date date1=null, date2=null ; for( int i = 0; i<vSids.size(); i++) { sd = (SidsData)vSids.get(i) ; int sid = sd.sid ; ps.setInt(1, sid) ; rs = ps.executeQuery() ; int j = 0 ; while( rs.next() ) { int id = rs.getInt("id") ; date1 = rs.getDate("date1") ; date2 = rs.getDate("date2") ; //Чтобы при сравнении дат equals не давал exeption, подменяем значения null //print( "date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; if ( date1 == null ){ date1 = (Date)_DATE1_NULL.clone() ; } if ( date2 == null ){ date2 = (Date)_DATE2_NULL.clone() ; } //Лишняя услуга, удаляем if ( j >= sd.vDate1.size() ) { psDel.setInt( 1, id ) ; psDel.executeUpdate() ; if (_DEBUG==1){ print( "Delete service with id=" + id + " for service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psDel=" + psDel ) ; } continue ; } if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) ) { //Возвращаем значения null при необходимости для обновления инфы в БД if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psUpd.setInt( 3, id ) ; psUpd.setDate( 1, (Date)sd.vDate1.get(j) ) ; psUpd.setDate( 2, (Date)sd.vDate2.get(j) ) ; psUpd.executeUpdate() ; if (_DEBUG==1){ print( "Update service with id=" + id + " for service="+sid + " previous date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psUpd=" + psUpd ) ; } } j++ ; }//end while for( ; j < sd.vDate1.size(); j++) { if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){ sd.vDate1.set( j, null ) ; } if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){ sd.vDate2.set( j, null ) ; } psIns.setInt(1, sid ) ; psIns.setDate( 2, (Date)sd.vDate1.get(j) ) ; psIns.setDate( 3, (Date)sd.vDate2.get(j) ) ; if (_DEBUG==1){ print( "Insert new service="+sid + " date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd")) ; print( "psIns" + psIns ) ; } psIns.executeUpdate() ; } } } private String getServiceList(Vector vSids) { String sids = ""; int i ; for( i = 0; i<vSids.size()-1; i++) { sids += "" + ((SidsData)vSids.get(i)).sid + "," ; } if ( i < vSids.size()) { sids += "" + ((SidsData)vSids.get(i)).sid ; } return sids ; } private void calcActualServicePeriods( Vector vSids ) { prepareInternalData() ; SidsData sd ; Vector vDate1 = new Vector() ; Vector vDate2 = new Vector() ; Date date1 ; Date date2 ; GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день int k = 0 ; for( int i = 0; i<vSids.size(); i++) { sd = (SidsData)vSids.get(i) ; vDate1.clear() ; vDate2.clear() ; for ( int j = 0 ; j < sd.vDate1.size() ; )//Отсеиваем ненужные периоды { date1 = (Date)sd.vDate1.get(j) ; date2 = (Date)sd.vDate2.get(j) ; if ( date1.compareTo( date2) > 0 ) { print("Fatal error, date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " > date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; print("Services was not synchronized...") ; return ; } for( j++ ; j<sd.vDate1.size(); j++) { date1cal.setTime( new java.util.Date(((Date)sd.vDate1.get(j)).getTime()) ) ; date1cal.roll(Calendar.DAY_OF_YEAR,-1) ; if ( date2.compareTo(new java.sql.Date(date1cal.getTime().getTime())) < 0 ) // Нашли нужный date2 для date1 ; { break ; } else { date2 = (Date)sd.vDate2.get(j) ; } } vDate1.add(date1) ; vDate2.add(date2) ; } sd.vDate1.clear() ; sd.vDate2.clear() ; sd.vDate1 = (Vector)vDate1.clone() ; sd.vDate2 = (Vector)vDate2.clone() ; } } private void prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг { SidsData sd ; for( int i = 0; i<vSidsData.size(); i++) { sd = (SidsData)vSidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } for( int i = 0; i<vNpaySidsData.size(); i++) { sd = (SidsData)vNpaySidsData.get(i) ; Collections.sort(sd.vDate1 ) ; Collections.sort(sd.vDate2 ) ; } } private void addSid( int sid, Date date1, Date date2, int npayService ) { String[] noSids = noSynchroList.split(",") ; for ( int i = 0 ; i<noSids.length; i++ ) { if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;} } //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно if ( date1 == null ) { date1 = (Date)_DATE1_NULL.clone() ; } if ( date2 == null ) { date2 = (Date)_DATE2_NULL.clone() ; } Vector vSids = vSidsData; if ( npayService != 0 ) { vSids = vNpaySidsData ; } int f = 0 ; SidsData sd ; for ( int i=0; i < vSids.size(); i++ ) { sd = (SidsData)vSids.get(i) ; if (sd.sid == sid) { sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; f = 1 ; break ; } } if ( f == 0 ) { sd = new SidsData( sid ) ; sd.vDate1.add(date1) ; sd.vDate2.add(date2) ; vSids.add( sd ) ; } } private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, Date date1, Date date2, Connection con) throws Exception { String SQL = "SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=" + tree_id ; if ( mid != 0 ) { SQL += " AND mid=" + mid ; } //print(SQL) ; PreparedStatement ps = con.prepareStatement( SQL ); ResultSet rs = ps.executeQuery() ; while ( rs.next() ) { int mtreeid = rs.getInt("id") ; mid = rs.getInt("mid") ; int parent_tree = rs.getInt("parent_tree") ; if (parent_tree != 0 ) { findServicesForTariff( parent_tree, mid, date1, date2, con ) ; continue ; } findServicesForTariff2( mtreeid, mid, date1, date2, con ) ; } } private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con ) throws Exception { String SQL = "SELECT type, data " + "FROM mtree_node " + "WHERE mtree_id=" + mtreeid + " AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')" ; PreparedStatement ps = con.prepareStatement( SQL ) ; ResultSet rs = ps.executeQuery() ; int sid = 0; while ( rs.next() ) { String type = rs.getString("type") ; String data = rs.getString("data") ; //print ( "type=" + type + " data=" + data) ; if (type.equals("service") ) { sid = Integer.parseInt( data ) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print ( "sid=" + sid ) ; } else if( type.equals("multi_service") ) { String[] ss = data.split("&") ; String[] sids = ss[1].split(",") ; //print ( "sids=" + ss[1] ) ; for ( int i=0; i < sids.length; i++ ) { sid=Integer.parseInt(sids[i]) ; addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг //print( "sid = " + sid ) ; } } else if( type.equals("month_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "month_mode sid = " + sid ) ; } else if( type.equals("day_mode") ) { String[] ss = data.split("%") ; for ( int i = 0; i < ss.length ; i++ ) { String[] sids=ss[i].split("&") ; if ( sids[0].equals("sid") ) { sid = Integer.parseInt(sids[1]) ; addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг break ; } } //print( "day_mode sid = " + sid ) ; } }//end while } //внутренниц класс для хранения услуги и множества дат date1 и date2 private class SidsData{ public int sid ; public Vector vDate1 ; public Vector vDate2 ; public SidsData() { sid = 0 ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public SidsData( int s ) { sid=s ; vDate1 = new Vector() ; vDate2 = new Vector() ; } public void printData() { print ("sid=" + sid) ; for( int i=0; i<vDate1.size(); i++ ) { Date date1 = (Date)vDate1.get(i) ; Date date2 = (Date)vDate2.get(i) ; if ( date1.equals( _DATE1_NULL) ){ date1 = null ; } if ( date2.equals( _DATE2_NULL) ){ date2 = null ; } print (" date1=" + TimeUtils.format(date1, "yyyy-MM-dd") + " date2=" + TimeUtils.format(date2, "yyyy-MM-dd") ) ; } } } private int NPAY_MID=6; private int _DEBUG=0 ; private int deleteNonNeeded = 0 ; static private Date _DATE1_NULL ; static private Date _DATE2_NULL ; private Vector vSidsData ; private Vector vNpaySidsData ; private String noSynchroList = "1000000" ;//не синхронизировать услуги. }