-
Kernel
-
Plugins
-
Решения
-
CHANGES
Kernel
Plugins
Решения
CHANGES
При редактировании параметра ИНН если будет найден контрагент с таким же значением параметра, то он будет открыт в системе с выводом сообщения. Также скрипт заполняет значение параметра КПП на основании ИНН. Коды параметров ИНН и КПП заданы в константах. Класс-обработчик указывается для параметра ИНН.
package ru.bgcrm.dyn.ufanet;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.apache.log4j.Logger;
import ru.bgcrm.dao.ParamValueDAO;
import ru.bgcrm.dao.Tables;
import ru.bgcrm.event.Event;
import ru.bgcrm.event.ParamChangingEvent;
import ru.bgcrm.event.client.CustomerOpenEvent;
import ru.bgcrm.event.listener.DynamicEventListener;
import ru.bgcrm.model.param.Parameter;
import ru.bgcrm.model.BGMessageException;
import ru.bgcrm.struts.form.DynActionForm;
import ru.bgcrm.util.Utils;
import ru.bgcrm.util.sql.ConnectionSet;
public class CustomerParameterUpdate
extends DynamicEventListener
{
private static final int INN_PARAMETER_ID = 248;
private static final int KPP_PARAMETER_ID = 249;
private static final Logger log = Logger.getLogger( CustomerParameterUpdate.class );
@Override
public void notify( Event e, ConnectionSet connectionSet )
{
if( !(e instanceof ParamChangingEvent) )
{
return;
}
ParamChangingEvent event = (ParamChangingEvent)e;
DynActionForm form = event.getForm();
Connection con = connectionSet.getConnection();
Parameter parameter = event.getParameter();
int customerId = event.getObjectId();
try
{
if( INN_PARAMETER_ID == parameter.getId() )
{
//проверка дупликата
String sql = " SELECT * FROM " + Tables.TABLE_CUSTOMER + " AS c " +
" INNER JOIN " + Tables.TABLE_PARAM_TEXT + " AS pt ON c.id=pt.id AND pt.param_id=" + INN_PARAMETER_ID +
" WHERE pt.value=? AND c.id<>? ";
PreparedStatement ps = con.prepareStatement( sql );
ps.setString( 1, String.valueOf( event.getValue() ) );
ps.setInt( 2, customerId );
StringBuilder sb = new StringBuilder();
ResultSet rs = ps.executeQuery();
while( rs.next() )
{
int id = rs.getInt( "c.id" );
String title = rs.getString( "c.title" );
sb.append( "(ID: " ).append( id ).append( ") " );
sb.append( title ).append( "\n" );
form.getResponse().addEvent( new CustomerOpenEvent( id ) );
}
if( Utils.notBlankString( sb.toString() ) )
{
throw new BGMessageException( "Сущетвуют контрагенты с похожими данными:\n" + sb.toString() );
}
else
{
//вставка кпп
ParamValueDAO paramDao = new ParamValueDAO( con );
String kppValue = paramDao.getParamText( customerId, KPP_PARAMETER_ID );
if( Utils.isBlankString( kppValue ) )
{
kppValue = String.valueOf( event.getValue() ).substring( 0, 4 ) + "01001";
paramDao.updateParamText( customerId, KPP_PARAMETER_ID, kppValue );
}
}
}
}
catch( Exception ex )
{
log.error( ex.getMessage(), ex );
}
}
}
При редактировании параметров с паспортными данными, датой рождения производится проверка на совпадения. В случае их нахождения - выводится предупреждение и похожие контрагенты открываются.
Класс-обработчик указывается для всех контроллируемых параметров. Коды параметров указываются в константах.
package ru.bgcrm.dyn.ufanet;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import ru.bgcrm.dao.ParamValueDAO;
import ru.bgcrm.dao.Tables;
import ru.bgcrm.event.Event;
import ru.bgcrm.event.ParamChangingEvent;
import ru.bgcrm.event.client.CustomerOpenEvent;
import ru.bgcrm.event.listener.DynamicEventListener;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.BGMessageException;
import ru.bgcrm.struts.form.DynActionForm;
import ru.bgcrm.util.TimeUtils;
import ru.bgcrm.util.sql.ConnectionSet;
/**
* При правке параметров контрагента.
* Если вводят в 74 параметр серию и номер парспорта другого контрагента - кидать ошибку и открывать контрагента у кого уже стоят такие серия и номер.
* Если вводят в ключевые параметры 73, 75, 77 значение идентичное с другим контрагентом с таким же наименованием кидать сообщение, что подозрительное совпадение полей и открывать так же этого контрагента, но при этом сохранять значения.
* @author danion
*
*/
public class DuplicateCustomerCreationBlocker
extends DynamicEventListener
{
private static int CUSTOMER_PASSPORT_NUMBER_PARAM_ID = 74;
private static int CUSTOMER_BIRTHDAY_PARAM_ID = 73;
private static int CUSTOMER_PASSPORT_DATE_PARAM_ID = 75;
private static int CUSTOMER_ADDRESS = 77;
@Override
public void notify( Event e, ConnectionSet connectionSet )
throws BGMessageException, BGException
{
if( !(e instanceof ParamChangingEvent) )
{
return;
}
try
{
ParamChangingEvent event = (ParamChangingEvent)e;
Connection con = connectionSet.getConnection();
ParamValueDAO paramValueDAO = new ParamValueDAO( con );
DynActionForm form = event.getForm();
int paramId = event.getParameter().getId();
int customerId = event.getObjectId();
if( paramId == CUSTOMER_PASSPORT_NUMBER_PARAM_ID )
{
String value = (String)event.getValue();
String sql = " SELECT * FROM " + Tables.TABLE_CUSTOMER + " AS c " +
" INNER JOIN " + Tables.TABLE_PARAM_TEXT + " AS pt ON c.id=pt.id AND pt.param_id=" + CUSTOMER_PASSPORT_NUMBER_PARAM_ID +
" WHERE pt.value=? AND c.id<>? ";
PreparedStatement ps = con.prepareStatement( sql );
ps.setString( 1, value );
ps.setInt( 2, customerId );
ResultSet rs = ps.executeQuery();
StringBuilder duplicateCustomerInformation = new StringBuilder();
while( rs.next() )
{
int id = rs.getInt( "c.id" );
String title = rs.getString( "c.title" );
duplicateCustomerInformation.append( id + " [" + title + "]\n");
form.getResponse().addEvent( new CustomerOpenEvent( id ) );
}
if( duplicateCustomerInformation.length() > 0 )
{
throw new BGMessageException( "Существуют контрагенты с похожими данными:\n" + duplicateCustomerInformation.toString() );
}
}
if( paramId == CUSTOMER_BIRTHDAY_PARAM_ID || paramId == CUSTOMER_PASSPORT_DATE_PARAM_ID || paramId == CUSTOMER_ADDRESS )
{
Date customerBirthDate = paramValueDAO.getParamDate( customerId, CUSTOMER_BIRTHDAY_PARAM_ID );
Date customerPassportDate = paramValueDAO.getParamDate( customerId, CUSTOMER_PASSPORT_DATE_PARAM_ID );
String customerAddressValue = paramValueDAO.getParamText( customerId, CUSTOMER_ADDRESS );
String sql = " SELECT * FROM " + Tables.TABLE_CUSTOMER + " AS c " +
" INNER JOIN " + Tables.TABLE_PARAM_DATE + " AS b ON c.id=b.id AND b.param_id=" + CUSTOMER_BIRTHDAY_PARAM_ID +
" INNER JOIN " + Tables.TABLE_PARAM_DATE + " AS pd ON c.id=pd.id AND pd.param_id=" + CUSTOMER_PASSPORT_DATE_PARAM_ID +
" INNER JOIN " + Tables.TABLE_PARAM_TEXT + " AS pt ON c.id=pt.id AND pt.param_id=" + CUSTOMER_ADDRESS +
" WHERE b.value=? AND pd.value=? AND pt.value=? AND c.id<>? ";
PreparedStatement ps = con.prepareStatement( sql );
ps.setDate( 1, TimeUtils.convertDateToSqlDate( customerBirthDate ) );
ps.setDate( 2, TimeUtils.convertDateToSqlDate( customerPassportDate ) );
ps.setString( 3, customerAddressValue );
ps.setInt( 4, customerId );
StringBuilder sb = new StringBuilder();
ResultSet rs = ps.executeQuery();
while( rs.next() )
{
int id = rs.getInt( "c.id" );
String title = rs.getString( "c.title" );
sb.append( "(ID: " ).append( id ).append( ") " );
sb.append( title ).append( "\n" );
form.getResponse().addEvent( new CustomerOpenEvent( id ) );
}
form.getResponse().setStatus( "message" );
form.getResponse().setMessage( "Сущесвует контрагент с похожими данными!" );
}
}
catch( SQLException ex )
{
throw new BGException( ex );
}
}
}
Класс выбирает процессы, находящиеся в статусе PROCESS_STATUS_PAY_WAIT (ожидание оплаты) у которых прошла дата повторного звонка. Эти процесс вновь становятся открытыми.
Класс может быть запущен планировщиком либо командой консоли crm.sh runclass <className>.
package ru.bgcrm.dyn.sofit;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;
import org.apache.log4j.Logger;
import ru.bgcrm.struts.action.ProcessAction;
import ru.bgcrm.struts.form.DynActionForm;
import ru.bgcrm.util.Setup;
import ru.bgcrm.util.sql.SQLUtils;
import ru.bgcrm.dao.process.ProcessDAO;
import ru.bgcrm.model.process.Process;
import ru.bgcrm.model.process.StatusChange;
import ru.bgcrm.model.user.User;
import static ru.bgcrm.dao.process.Tables.*;
import static ru.bgcrm.dao.Tables.*;
public class KtvDebtWaitRestore
implements Runnable
{
private static final Logger log = Logger.getLogger( KtvDebtWaitRestore.class );
private static final int PROCESS_TYPE_DEBTOR = 4;
private static final int PROCESS_STATUS_OPEN = 2;
private static final int PROCESS_STATUS_PAY_WAIT = 5;
private static final int PROCESS_PARAM_DATE_RECALL = 2;
@Override
public void run()
{
Connection con = null;
try
{
con = Setup.getSetup().getDBConnectionFromPool();
String query =
"SELECT process.* FROM " + TABLE_PROCESS + " AS process " +
"INNER JOIN " + TABLE_PARAM_DATE + " AS pd ON process.id=pd.id AND pd.param_id=? AND pd.value<=CURDATE() " +
"WHERE close_dt IS NULL AND type_id=? AND status_id=?";
PreparedStatement ps = con.prepareStatement( query );
ps.setInt( 1, PROCESS_PARAM_DATE_RECALL );
ps.setInt( 2, PROCESS_TYPE_DEBTOR );
ps.setInt( 2, PROCESS_STATUS_PAY_WAIT );
ResultSet rs = ps.executeQuery();
while( rs.next() )
{
Process process = ProcessDAO.getProcessFromRs( rs );
log.info( "Opening debt process: " + process.getId() );
StatusChange change = new StatusChange();
change.setProcessId( process.getId() );
change.setDate( new Date() );
change.setStatusId( PROCESS_STATUS_OPEN );
change.setUserId( User.USER_SYSTEM_ID );
change.setComment( "Настала дата повторного обзвона" );
ProcessAction.processStatusUpdate( DynActionForm.SERVER_FORM, con, process, change );
con.commit();
}
ps.close();
}
catch( Exception e )
{
log.error( e.getMessage(), e );
}
finally
{
SQLUtils.closeConnection( con );
}
}
}
Повышение приоритета для старых проблем.
Класс может быть запущен планировщиком либо командой консоли crm.sh runclass <className>.
package ru.bgcrm.dyn;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.GregorianCalendar;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.log4j.Logger;
import ru.bgcrm.dao.ParamValueDAO;
import ru.bgcrm.dao.process.ProcessDAO;
import ru.bgcrm.dao.process.ProcessLinkDAO;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.CommonObjectLink;
import ru.bgcrm.model.Pair;
import ru.bgcrm.model.SearchResult;
import ru.bgcrm.model.process.Process;
import ru.bgcrm.model.process.StatusChange;
import ru.bgcrm.util.Setup;
import ru.bgcrm.util.Utils;
import ru.bgcrm.util.sql.ConnectionSet;
import ru.bgcrm.util.sql.PreparedDelay;
import ru.bgcrm.util.sql.SQLUtils;
import ru.bgcrm.util.TimeUtils;
public class setprior
implements Runnable
{
private static final Logger log = Logger.getLogger(setprior.class );
private static AtomicBoolean working = new AtomicBoolean();
@Override
public void run(){
log.info( "Started" );
if( working.get() ){
log.warn( "Already working" );
return;
}
Connection con = Setup.getSetup().getDBConnectionFromPool();
try{
working.set( true );
ProcessDAO processDao = new ProcessDAO( con );
String query =
"SELECT * FROM process " +
"WHERE process.close_dt IS NULL";
PreparedStatement ps = con.prepareStatement( query );
ResultSet rs = ps.executeQuery();
while( rs.next() ){
Process process = ProcessDAO.getProcessFromRs( rs );
int daysdelta =TimeUtils.daysDelta(TimeUtils.convertDateToCalendar(process.getStatusTime()), new GregorianCalendar())+1;
if ((daysdelta<9)&&(process.getPriority()<daysdelta))
process.setPriority(daysdelta);
processDao.updateProcess(process);
con.commit();
}
ps.close();
}catch( Exception e ){
log.error( e.getMessage(), e );
}finally{
SQLUtils.closeConnection( con);
working.set( false );
}
log.info( "Finished" );
}
}
Класс скрипта указывается в типе процесса. Скрипт можно дополнить обработкой других событий процесса.
package ru.bgcrm.dyn.test;
import ru.bgcrm.event.Event;
import ru.bgcrm.event.ParamChangingEvent;
import ru.bgcrm.event.listener.DynamicEventListener;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.BGMessageException;
import ru.bgcrm.util.sql.ConnectionSet;
public class TestProcessor
extends DynamicEventListener
{
@Override
public void notify( Event e, ConnectionSet connectionSet )
throws BGException
{
//Connection con = connectionSet.getConnection();
if( e instanceof ParamChangingEvent )
{
ParamChangingEvent changingEvent = (ParamChangingEvent)e;
int paramId = changingEvent.getParameter().getId();
if( paramId == 1 )
{
// событие, чтобы перечиталась карточка процесса
changingEvent.getForm().getResponse().addEvent( new ru.bgcrm.event.client.ProcessChangedEvent( changingEvent.getObjectId() ) );
throw new BGMessageException( "Этот параметр править нельзя!" );
}
else if( paramId == 2 )
{
changingEvent.getForm().getResponse().setMessage( "Можно править, но приходит сообщение!" );
}
}
}
}
Класс скрипта указывается в типе процесса. Скрипт можно дополнить обработкой других событий процесса.
package ru.bgcrm.dyn.test;
import org.apache.log4j.Logger;
import ru.bgcrm.dao.process.ProcessDAO;
import ru.bgcrm.event.Event;
import ru.bgcrm.event.ParamChangedEvent;
import ru.bgcrm.event.client.ProcessChangedEvent;
import ru.bgcrm.event.listener.DynamicEventListener;
import ru.bgcrm.util.sql.ConnectionSet;
public class ParamChangedEventListener
extends DynamicEventListener
{
private static final Logger log = Logger.getLogger( ParamChangedEventListener.class );
@Override
public void notify( Event e, ConnectionSet connectionSet )
{
if( !(e instanceof ParamChangedEvent) )
{
return;
}
ParamChangedEvent pce = (ParamChangedEvent)e;
try
{
ProcessDAO processDao = new ProcessDAO( connectionSet.getConnection() );
ru.bgcrm.model.process.Process process = processDao.getProcess( pce.getObjectId() );
process.setDescription( "Изменено!!\n" + process.getDescription() );
processDao.updateProcess( process );
// чтобы в браузере обновилась вкладка
pce.getForm().getResponse().addEvent( new ProcessChangedEvent( pce.getObjectId() ) );
}
catch( Exception ex )
{
log.error( ex.getMessage(), ex );
}
}
}
Класс скрипта указывается в типе процесса. Скрипт можно дополнить обработкой других событий процесса.
При изменении статуса:
Оповещает с помощью вспомогательного класса Notificator создателя процесса о переключении его статуса. Перед закрытием процесса:
Проверяет, что в списковом параметре PARAMETER_SOGL_LIST проставлены все исполнители с процесса группой USER_GROUP_SOGL_DPT. Списковый параметр должен быть привязан к таблице user. При закрытии процесса:
Заполняет текстовый параметр PROCESS_PARAM_REAL_EXECUTE_TIME временем выполнения процесса.
package ru.bgcrm.dyn.ufanet.sogl;
import java.sql.Connection;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import ru.bgcrm.cache.ProcessTypeCache;
import ru.bgcrm.dao.ParamValueDAO;
import ru.bgcrm.dao.process.StatusChangeDAO;
import ru.bgcrm.dyn.ufanet.Notificator;
import ru.bgcrm.dyn.ufanet.Notificator.NotificationType;
import ru.bgcrm.dyn.ufanet.Thesaurus;
import ru.bgcrm.event.Event;
import ru.bgcrm.event.ParamChangingEvent;
import ru.bgcrm.event.listener.DynamicEventListener;
import ru.bgcrm.event.process.ProcessChangedEvent;
import ru.bgcrm.event.process.ProcessChangingEvent;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.param.ParameterAddressValue;
import ru.bgcrm.model.process.Process;
import ru.bgcrm.model.process.ProcessExecutor;
import ru.bgcrm.model.process.ProcessType;
import ru.bgcrm.model.process.StatusChange;
import ru.bgcrm.util.sql.ConnectionSet;
public class SoglasEventProcessor
extends DynamicEventListener
{
private static final int PROCESS_ACCEPT_STATUS_ID = 46;
private static final int PARAMETER_SOGL_LIST = 701;
private static final int USER_GROUP_SOGL_DPT = 60;
private static final int PROCESS_STATUS_AGREED = 17;
private static final int PROCESS_PARAM_REAL_EXECUTE_TIME = 804;
private static final Logger log = Logger.getLogger( SoglasEventProcessor.class );
private Connection con;
@Override
public void notify( Event e, ConnectionSet connectionSet )
throws BGException
{
con = connectionSet.getConnection();
if( e instanceof ParamChangingEvent )
{
onParameterChanging( e );
}
else if( e instanceof ProcessChangingEvent )
{
onProcessChanging( (ProcessChangingEvent)e );
}
else if( e instanceof ProcessChangedEvent )
{
onProcessChanged( (ProcessChangedEvent)e );
}
}
private void onProcessChanged( ProcessChangedEvent event )
throws BGException
{
int statusId = event.getProcess().getStatusId();
Process process = event.getProcess();
ProcessType type = ProcessTypeCache.getProcessType( process.getTypeId() );
int processId = process.getId();
if( event.isStatus() )
{
ParamValueDAO paramValueDAO = new ParamValueDAO( con );
ParameterAddressValue address = paramValueDAO.getParamAddress( process.getId(), Thesaurus.Process.PROCESS_PARAMETER_ADDRESS_ID, 1 );
if( address != null )
{
String title = "Изменение статуса процесса " + process.getId();
String text = " Статус процесса " + process.getId() + " по адресу " + address.getValue() + " изменился на " + process.getStatusTitle();
Notificator.notificate( new HashSet<Integer>( Arrays.asList( process.getCreateUserId() ) ), title, text, new HashSet<NotificationType>( Arrays.asList( NotificationType.SMS, NotificationType.NEWS, NotificationType.EMAIL ) ) );
}
}
if( event.isStatus() && type.getProperties().getCloseStatusIds().contains( statusId ) )
{
StatusChangeDAO statusChangeDAO = new StatusChangeDAO( con );
List<StatusChange> statusHistory = statusChangeDAO.getProcessStatus( processId, PROCESS_ACCEPT_STATUS_ID );
if( statusHistory.isEmpty() )
{
return;
}
//вычисление времени решения процесса
long diffInMillis = process.getCloseTime().getTime() - statusHistory.iterator().next().getDate().getTime();
int diffInDays = (int)diffInMillis / 1000 / 86400;
int diffInHours = (int)(diffInMillis / 1000 - 86400 * diffInDays) / 3600;
int diffInMins = (int)(diffInMillis / 1000 - 86400 * diffInDays - 3600 * diffInHours) / 60;
GregorianCalendar cal = new GregorianCalendar( 0, 0, diffInDays, diffInHours, diffInMins, 0 );
String diffTime = String.format( "%d д. %tH:%tM", diffInDays, cal, cal );
new ParamValueDAO( con ).updateParamText( processId, PROCESS_PARAM_REAL_EXECUTE_TIME, diffTime );
}
}
private void onProcessChanging( ProcessChangingEvent event )
throws BGException
{
Process process = event.getProcess();
int processId = process.getId();
if( !event.isStatus() )
{
return;
}
int statusId = event.getStatusChange().getStatusId();
if( statusId != PROCESS_STATUS_AGREED )
{
return;
}
Set<Integer> soglSet = new ParamValueDAO( con ).getParamList( processId, PARAMETER_SOGL_LIST );
for( ProcessExecutor executor : process.getProcessExecutors() )
{
if( executor.getGroupId() == USER_GROUP_SOGL_DPT && !soglSet.contains( executor.getUserId() ) )
{
throw new BGException( "Процесс должен быть согласован всеми согласователями из списка исполнителей перед закрытием" );
}
}
}
private void onParameterChanging( Event e )
throws BGException
{
ParamChangingEvent event = (ParamChangingEvent)e;
if( event.getParameter() == null || event.getParameter().getId() != PARAMETER_SOGL_LIST )
{
return;
}
Set<Integer> newSet = null;
try
{
newSet = (Set<Integer>)event.getValue();
}
catch( Exception ex )
{
log.debug( ex );
}
if( newSet == null )
{
return;
}
checkPermission( event.getUser().getId(), new ParamValueDAO( con ).getParamList( event.getObjectId(), PARAMETER_SOGL_LIST ), newSet );
}
private void checkPermission( int userId, Set<Integer> source, Set<Integer> newSet )
throws BGException
{
List<Integer> disjSet = (List<Integer>)CollectionUtils.disjunction( source, newSet );
if( disjSet.size() > 1 || (disjSet.size() == 1 && !disjSet.contains( userId )) )
{
throw new BGException( "Вы можете проставить согласование только от своего имени" );
}
}
}
Фрагмент кода обработчика событий процесса, генерирует новость по появлению в процессе новых сообщений. В заголовок новости помещается адресный параметр процесса и привязанный контрагент. В тексте сообщения отображается ссылка открытия карточки процесса.
....
private void generateNews( Connection con, Process process, UserEvent event )
throws BGException
{
ProcessLinkDAO linkDao = new ProcessLinkDAO( con );
ParamValueDAO paramDao = new ParamValueDAO( con );
NewsDAO newsDao = new NewsDAO( con );
CommonObjectLink linkCustomer = Utils.getFirst( linkDao.getObjectLinksWithType( process.getId(), Customer.OBJECT_TYPE ) );
ParameterAddressValue address = Utils.getFirst( paramDao.getParamAddress( process.getId(), PROCESS_PARAM_ADDRESS ).values() );
if( address == null )
{
address = Utils.getFirst( paramDao.getParamAddress( process.getId(), PROCESS_PARAM_ADDRESSES ).values() );
}
if( linkCustomer == null || address == null) )
{
return;
}
News news = new News();
news.setCreateDate( new Date() );
news.setLifeTime( 200 );
news.setReadTime( 400 );
news.setUserId( event.getForm().getUserId() );
Set<Integer> userIds = new HashSet<Integer>( process.getExecutorIds() );
// обработка события "сообщение добавлено"
if( event instanceof ProcessMessageAddedEvent )
{
final int typeId = process.getTypeId();
ProcessType type = ProcessTypeCache.getProcessType( typeId );
news.setTitle( type.getTitle() + " " + linkCustomer.getLinkedObjectTitle() + " => новое сообщение" );
// описание и ссылка открытия процесса в теле сообщения
String text =
type.getTitle() + " \"" + linkCustomer.getLinkedObjectTitle() + ", " + address.getValue() + "\" получено новое сообщение.<br/>" +
"<a href='#UNDEF' onClick='openProcess( " + process.getId() + " )'>Перейти к процессу</a>";
news.setDescription( text );
}
// пользователь, добавивший сообщение, новость не получает
userIds.remove( event.getForm().getUserId() );
if( userIds.size() > 0 &&
Utils.notBlankString( news.getTitle() ) )
{
newsDao.updateNewsUsers( news, userIds );
}
}
....