Commit d0a3ff8f authored by doc@bgerp.org's avatar doc@bgerp.org

p12059 Extract process messaged to linked processes. Close control on linked...

p12059 Extract process messaged to linked processes. Close control on linked proceses. Fix red border in queue editor. Cleanup, refactoring.
parent 2371b732
A: Moving messages to newly created and linked copy of current process, https://bgerp.ru/doc/3.0/manual/kernel/message.html#process
A: Localization for BGMessageException, https://bgerp.ru/doc/3.0/manual/project.html#localization
A: Checking on the process closing being closed all the 'processMade' links, https://bgerp.ru/doc/3.0/manual/kernel/process/index.html#linked-process
F: Left red border on saving configuration of process queue.
C: Rename configuration key 'processDependCloseCheckDirection' to 'process.close.check.processDepend', default value 'up'.
C: Refactoring, cleanup of unused files.
Time Build (generated automatically)
N(A) - NEW, C - CHANGE, F - FIX
A - ADD NEW, C - CHANGE, F - FIX
28.02.2020 10:16:03 1347
N: Plugin Report: enhanced UI, Java classes for data retrieving, https://bgerp.ru/doc/3.0/manual/plugin/report/index.html
N: Plugin Report: report "Processes", https://bgerp.ru/doc/3.0/manual/plugin/report/index.html
N: JSP tags "shell:title", "shell:state", "ui:user-link", "ui:page-control" instead of includes.
A: Plugin Report: enhanced UI, Java classes for data retrieving, https://bgerp.ru/doc/3.0/manual/plugin/report/index.html
A: Plugin Report: report "Processes", https://bgerp.ru/doc/3.0/manual/plugin/report/index.html
A: JSP tags "shell:title", "shell:state", "ui:user-link", "ui:page-control" instead of includes.
C: Rewrite of deprecated code in JS and JSP.
C: CSS "width: 100%" for table classes "data" and "hdata".
F: Exception on refresh the table of linked processed.
......
......@@ -345,8 +345,8 @@
<b>allowedTypeIds</b> - id типов сообщений через запятую, разрешённых к просмотру<br/>
</item>
<item action="ru.bgcrm.struts.action.MessageAction:newMessageLoad" title="Загрузка нового сообщения"/>
<item action="ru.bgcrm.struts.action.MessageAction:messageUpdateProcess" title="Изменение процесса сообщения"/>
<item action="ru.bgcrm.struts.action.MessageAction:messageUpdateTags" title="Изменение тегов сообщения"/>
<item action="ru.bgcrm.struts.action.MessageAction:messageUpdateProcess" title="Изменение процесса сообщения"/>
<item action="ru.bgcrm.struts.action.MessageAction:messageUpdateProcessToCopy" title="Изменение процесса сообщения на копию текущего"/>
<item action="ru.bgcrm.struts.action.MessageAction:messageUpdate" title="Создание/редактирование сообщения"/>
<item action="ru.bgcrm.struts.action.MessageAction:processMessageList" title="Просмотр списка сообщений процесса"/>
......
......@@ -3,6 +3,7 @@
<!--
<p><ru></ru><en></en></p>
-->
<p><ru>Перенесено из процесса #%s</ru><en>Moved from process #%s</en></p>
<p><ru>Свойства</ru><en>Properties</en></p>
<p><ru>Сохранить свойства</ru><en>Save properties</en></p>
<p><ru>Пароль</ru><en>Password</en></p>
......
......@@ -16,8 +16,6 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.log4j.Logger;
import ru.bgcrm.dao.EventProcessorLogDAO;
import ru.bgcrm.dynamic.DynamicClassManager;
import ru.bgcrm.event.listener.DynamicEventListener;
......@@ -185,20 +183,12 @@ public class EventProcessor {
listener.notify(event, conSet);
}
} catch (TimeoutException e) {
throw new BGMessageException("Время ожидания выполнения скрипта" + listener.getClass().getName()
+ " истекло! (" + timeout + " мс).");
throw new BGMessageException("Время ожидания выполнения скрипта '%s' истекло! (%s мс).", listener.getClass().getName(), timeout);
} catch (InterruptedException | ExecutionException e) {
throw new BGMessageException("При выполнении скрипта " + listener.getClass().getName()
+ " возникло исключение " + e.getMessage());
throw new BGMessageException("При выполнении скрипта '%s' возникло исключение '%s'", listener.getClass().getName(), e.getMessage());
}
resultStatus = "Successful";
} catch (BGMessageException e) {
resultStatus = e.getMessage();
throw new BGMessageException(e.getMessage());
} catch (BGException e) {
resultStatus = e.getMessage();
throw new BGException(e);
} finally {
long timeEnd = Calendar.getInstance().getTimeInMillis();
......
......@@ -24,21 +24,26 @@ public class ProcessClosingListener {
Process process = e.getProcess();
if (process.getCloseTime() != null) {
ProcessType type = ProcessTypeCache.getProcessType(process.getTypeId());
String checkDirection = type.getProperties().getConfigMap().get("processDependCloseCheckDirection", DIRECTION_DOWN);
List<Process> result = null;
if (DIRECTION_DOWN.equals(checkDirection)) {
result = new ProcessLinkDAO(connectionSet.getConnection(), e.getUser()).getLinkProcessList(process.getId(), Process.LINK_TYPE_DEPEND, false, null);
for (Process link : result)
if (link.getCloseTime() == null)
throw new BGMessageException("Есть незакрытые зависящие процессы");
} else if (DIRECTION_UP.equals(checkDirection)) {
result = new ProcessLinkDAO(connectionSet.getConnection(), e.getUser()).getLinkedProcessList(process.getId(), Process.LINK_TYPE_DEPEND, false, null);
for (Process linked : result)
if (linked.getCloseTime() == null)
throw new BGMessageException("Есть незакрытые процессы, от которых зависит данный");
}
checkLinkedProcesses(connectionSet, process, Process.LINK_TYPE_DEPEND, DIRECTION_UP);
checkLinkedProcesses(connectionSet, process, Process.LINK_TYPE_MADE, DIRECTION_DOWN);
}
}
private void checkLinkedProcesses(ConnectionSet connectionSet, Process process, String linkType, String defaultDirection) throws Exception {
ProcessType type = ProcessTypeCache.getProcessType(process.getTypeId());
String checkDirection = type.getProperties().getConfigMap().get("process.close.check." + linkType, defaultDirection);
List<Process> result = null;
if (DIRECTION_DOWN.equals(checkDirection)) {
result = new ProcessLinkDAO(connectionSet.getConnection()).getLinkProcessList(process.getId(), linkType, false, null);
for (Process link : result)
if (link.getCloseTime() == null)
throw new BGMessageException("Есть незакрытые привязанные процессы типа: %s", linkType);
} else if (DIRECTION_UP.equals(checkDirection)) {
result = new ProcessLinkDAO(connectionSet.getConnection()).getLinkedProcessList(process.getId(), linkType, false, null);
for (Process linked : result)
if (linked.getCloseTime() == null)
throw new BGMessageException("Есть незакрытые процессы, к которым привязан данный с типом: %s", linkType);
}
}
}
......@@ -3,16 +3,15 @@ package ru.bgcrm.model;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import ru.bgcrm.util.SerialUtils;
import ru.bgerp.util.Log;
/**
* Map для хранения параметров форм, в т.ч. типа checkbox,
* когда приходит несколько значений под одним именем.
*/
public class ArrayHashMap extends HashMap<String, Object> {
private static final Logger log = Logger.getLogger(ArrayHashMap.class);
private static final Log log = Log.getLog();
private static final long serialVersionUID = SerialUtils.generateSerialVersionUID(ArrayHashMap.class);
......
package ru.bgcrm.model;
public class BGException
extends Exception
{
public BGException()
{}
public class BGException extends Exception {
public BGException() {}
public BGException( String message )
{
super( message );
}
public BGException(String message) {
super(message);
}
public BGException( Throwable cause )
{
super( cause );
}
public BGException(Throwable cause) {
super(cause);
}
public BGException( String message, Throwable cause )
{
super( message, cause );
}
/**
* Для вызова в JEXL скриптах.
* @param message
* @throws BGException
*/
public static void throwNew( String message )
throws BGException
{
throw new BGException( message );
}
public BGException(String message, Throwable cause) {
super(message, cause);
}
/**
* Для вызова в JEXL скриптах.
* @param message
* @throws BGException
*/
public static void throwNew(String message) throws BGException {
throw new BGException(message);
}
}
package ru.bgcrm.model;
/**
* Исключение, сообщение которого необходимо показать пользователю и не надо писать в лог.
* Localized message, not written in log.
*/
public class BGMessageException
extends BGException
{
// код с ошибкой для автоматической обработки, например, класс исключения при вызове Web сервиса
private final String exception;
public BGMessageException( String exception, String message )
{
super( message );
this.exception = exception;
}
public BGMessageException( String message )
{
this( null, message );
}
public class BGMessageException extends BGException {
private final Object[] args;
public String getException()
{
return exception;
}
public BGMessageException(String message, Object... args) {
super(message);
this.args = args;
}
public Object[] getArgs() {
return args;
}
}
package ru.bgcrm.model;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Page {
public static final int DEFAULT_PAGE_SIZE = 25;
......@@ -77,7 +78,7 @@ public class Page {
this.recordCount = recordCount;
if (recordCount > 0 && pageSize > 0) {
BigDecimal a = new BigDecimal(recordCount);
BigDecimal b = a.divide(new BigDecimal(pageSize), BigDecimal.ROUND_UP);
BigDecimal b = a.divide(new BigDecimal(pageSize), RoundingMode.UP);
pageCount = b.intValue();
if (pageIndex > pageCount) {
pageIndex = pageCount;
......
package ru.bgcrm.model.customer;
/*
import ru.bgcrm.util.Config;
import ru.bgcrm.util.ParameterMap;
public class KeyParamsConfig
extends Config
{
public KeyParamsConfig( ParameterMap setup )
{
super( setup );
}
}
*/
package ru.bgcrm.model.customer;
/*
import java.util.Set;
import ru.bgcrm.model.IdTitle;
public class SearchMode
extends IdTitle
{
private Set<Integer> parameterGroupsIds;
public SearchMode( int id, String title, Set<Integer> parameterGroupIds )
{
super( id, title );
this.parameterGroupsIds = parameterGroupIds;
}
public Set<Integer> getParameterGroupsIds()
{
return parameterGroupsIds;
}
}
*/
\ No newline at end of file
package ru.bgcrm.model.customer;
/*
import java.util.Collection;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import ru.bgcrm.util.Config;
import ru.bgcrm.util.ParameterMap;
import ru.bgcrm.util.Utils;
public class SearchModeConfig
extends Config
{
private SortedMap<Integer, SearchMode> modeMap = new TreeMap<Integer, SearchMode>();
public SearchModeConfig( ParameterMap setup )
{
super( setup );
for( Map.Entry<Integer, ParameterMap> me : setup.subIndexed( "customer.searchMode." ).entrySet() )
{
int id = me.getKey();
ParameterMap params = me.getValue();
SearchMode searchMode = new SearchMode( id, params.get( "title" ), Utils.toIntegerSet( params.get( "parameterGroupIds" ) ) );
if( searchMode.getId() > 0 && Utils.notBlankString( searchMode.getTitle() ) )
{
modeMap.put( searchMode.getId(), searchMode );
}
else
{
log.error( "Error load customer search mode " + id );
}
}
}
public Collection<SearchMode> getModes()
{
return modeMap.values();
}
}
*/
\ No newline at end of file
package ru.bgcrm.model.timer;
import java.util.Date;
import ru.bgcrm.util.TimeUtils;
/**
* Отложенный таймер, запускающийся в определенное время.
*/
public class Timer
{
public static final int ENTITY_PROCESS = 1;
// код таймера
private int id;
// тип сущности, к которой привязан таймер
private int entityType = ENTITY_PROCESS;
// код сущности, к которой привязан таймер
private int entityId;
// имя таймера
private String name;
// время отрабатывания
private Date time;
// имя скрипта, которому передастся событие таймера
private String scriptName;
// конфигурация таймера
private String data;
public int getId()
{
return id;
}
public void setId( int id )
{
this.id = id;
}
public int getEntityType()
{
return entityType;
}
public void setEntityType( int entityType )
{
this.entityType = entityType;
}
public Date getTime()
{
return time;
}
public void setTime( Date time )
{
this.time = time;
}
public String getData()
{
return data;
}
public void setData( String data )
{
this.data = data;
}
public int getEntityId()
{
return entityId;
}
public void setEntityId( int entityId )
{
this.entityId = entityId;
}
public String getName()
{
return name;
}
public void setName( String name )
{
this.name = name;
}
public String getScriptName()
{
return scriptName;
}
public void setScriptName( String scriptName )
{
this.scriptName = scriptName;
}
@Override
public String toString()
{
StringBuilder result = new StringBuilder();
result.append( "id=" );
result.append( id );
result.append( "; entityType=" );
result.append( entityType );
result.append( "; entityId=" );
result.append( entityId );
result.append( "; name=" );
result.append( name );
result.append( "; time=" );
result.append( TimeUtils.format( time, "dd.MM.yyyy HH:mm:ss" ) );
result.append( "; data=" );
result.append( data );
return result.toString();
}
}
\ No newline at end of file
package ru.bgcrm.model.timer;
/*
import java.io.Serializable;
public interface TimerProcessor
extends Serializable
{
public void processTimer( Timer timer );
}
*/
\ No newline at end of file
......@@ -605,7 +605,7 @@ public class TransferData {
+ dbInfo.getId() + " вернул ошибку: " + rootNode.path("message").textValue();
if (exceptionType != null && exceptionType.equals("ru.bitel.bgbilling.common.BGMessageException")) {
throw new BGMessageException(exceptionType, text);
throw new BGMessageException(text);
} else {
throw new BGException(text);
}
......
......@@ -22,7 +22,7 @@ public class ReportAction extends BaseAction {
public ActionForward get(ActionMapping mapping, DynActionForm form, ConnectionSet conSet) throws Exception {
Report report = setup.getConfig(Config.class).getReportMap().get(form.get("reportId"));
if (report == null)
throw new BGMessageException(l.l("Report not found"));
throw new BGMessageException("Отчёт не найден.");
if (StringUtils.isNotBlank(report.getDaoClass())) {
log.debug("Creating Java DAO class: %s", report.getDaoClass());
......
......@@ -286,11 +286,12 @@ public class BaseAction extends DispatchAction {
resultStatus = "Successful";
} catch (BGMessageException ex) {
resultStatus = ex.getMessage();
return sendError(form, ex.getMessage());
resultStatus = l.l(ex.getMessage(), ex.getArgs());
return sendError(form, resultStatus);
} catch (Throwable ex) {
resultStatus = ex.getMessage();
log.error(ex.getMessage(), ex);
log.error(resultStatus, ex);
StringWriter sw = new StringWriter();
ex.printStackTrace(new PrintWriter(sw));
......
......@@ -21,14 +21,14 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import ru.bgcrm.cache.ProcessTypeCache;
import ru.bgcrm.cache.UserNewsCache;
import ru.bgcrm.dao.CommonDAO;
......@@ -42,6 +42,7 @@ import ru.bgcrm.dao.user.UserDAO;
import ru.bgcrm.event.EventProcessor;
import ru.bgcrm.event.MessageRemovedEvent;
import ru.bgcrm.model.BGException;
import ru.bgcrm.model.BGMessageException;
import ru.bgcrm.model.CommonObjectLink;
import ru.bgcrm.model.SearchResult;
import ru.bgcrm.model.config.TagConfig;
......@@ -168,21 +169,20 @@ public class MessageAction extends BaseAction {
return processJsonForward(conSet, form);
}
public ActionForward messageUpdateProcessToCopy(ActionMapping mapping, DynActionForm form, ConnectionSet conSet)
throws Exception {
Connection con = conSet.getConnection();
public ActionForward messageUpdateProcessToCopy(ActionMapping mapping, DynActionForm form, Connection con) throws Exception {
MessageDAO messageDao = new MessageDAO(con);
ProcessDAO processDao = new ProcessDAO(con);
ProcessLinkDAO linkDao = new ProcessLinkDAO(con);
Message message = messageDao.getMessageById(form.getId());
if (message == null)
throw new BGException("Сообщение не найдено.");
throw new BGMessageException("Сообщение не найдено.");
Process process = processDao.getProcess(message.getProcessId());
if (process == null)
throw new BGException("Процесс не найден.");
throw new BGMessageException("Процесс не найден.");
String linkType = form.getParam("linkType");
Process newProcess = new Process();
newProcess.setTypeId(process.getTypeId());
......@@ -194,17 +194,23 @@ public class MessageAction extends BaseAction {
newProcess.setCreateUserId(form.getUserId());
processDao.updateProcess(newProcess);
processDao.updateProcessGroups(process.getProcessGroups(), newProcess.getId());
processDao.updateProcessExecutors(process.getProcessExecutors(), newProcess.getId());
linkDao.copyLinks(process.getId(), newProcess.getId(), null);
if (StringUtils.isBlank(linkType))
linkDao.copyLinks(process.getId(), newProcess.getId(), null);
else
linkDao.addLink(new CommonObjectLink(process.getId(), linkType, newProcess.getId(), ""));
message.setProcessId(newProcess.getId());
messageDao.updateMessageProcess(message);
message.setText(l.l("Перенесено из процесса #%s", process.getId()) + "\n\n" + message.getText());
messageDao.updateMessage(message);
form.setResponseData("process", newProcess);
return processJsonForward(conSet, form);
return processJsonForward(con, form);
}
public ActionForward messageDelete(ActionMapping mapping, DynActionForm form, ConnectionSet conSet)
......
package ru.bgcrm.util;
public class AddressStruct
{
private String index = "";
private String city = "";
private String area = "";
private String quarter = "";
private String street = "";
private String house = "";
private int houseID = 0;
private String frac = "";
private String flat = "";
private String room = "";
private String pod = "";
private String floor = "";
private String comment = "";
private String fullAddress = "";
public String getIndex()
{
return index;
}
public void setIndex( String index )
{
this.index = index;
}
public String getCity()
{
return city;
}
public void setCity( String city )
{
this.city = city;
}
public String getArea()
{
return area;
}
public void setArea( String area )
{
this.area = area;
}
public String getQuarter()
{
return quarter;
}
public void setQuarter( String quarter )
{
this.quarter = quarter;
}
public String getStreet()
{
return street;
}
public void setStreet( String street )
{
this.street = street;
}
public String getHouse()
{
return house;
}
public void setHouse( String house )
{
this.house = house;
}
public String getFrac()
{
return frac;
}
public void setFrac( String frac )
{
this.frac = frac;
}
public String getFlat()
{
return flat;
}
public void setFlat( String flat )
{
this.flat = flat;
}
public String getRoom()
{
return room;
}
public void setRoom( String room )
{
this.room = room;
}
public String getPod()
{
return pod;
}
public void setPod( String pod )