/*
* Aipo is a groupware program developed by TOWN, Inc.
* Copyright (C) 2004-2015 TOWN, Inc.
* http://www.aipo.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aimluck.eip.workflow;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;
import com.aimluck.commons.field.ALNumberField;
import com.aimluck.commons.field.ALStringField;
import com.aimluck.eip.cayenne.om.portlet.EipTWorkflowRequest;
import com.aimluck.eip.cayenne.om.portlet.EipTWorkflowRequestMap;
import com.aimluck.eip.common.ALAbstractFormData;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.common.ALPageNotFoundException;
import com.aimluck.eip.modules.actions.common.ALAction;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.services.accessctl.ALAccessControlConstants;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.util.ALLocalizationUtils;
import com.aimluck.eip.workflow.util.WorkflowUtils;
import com.aimluck.eip.workflow.util.WorkflowUtils.Type;
/**
* ワークフローの承認/否認のフォームデータを管理するクラスです。 <BR>
*
*/
public class WorkflowConfirmFormData extends ALAbstractFormData {
/** logger */
private static final JetspeedLogger logger = JetspeedLogFactoryService
.getLogger(WorkflowConfirmFormData.class.getName());
/** コメント */
private ALStringField comment;
/** 承認フラグ(承認:true、否認:false) */
private boolean accept_flg;
/** 差し戻し先の順位 */
private ALNumberField passback_order;
/**
*
* @param action
* @param rundata
* @param context
*
*
*/
@Override
public void init(ALAction action, RunData rundata, Context context)
throws ALPageNotFoundException, ALDBErrorException {
super.init(action, rundata, context);
}
/**
* 各フィールドを初期化します。 <BR>
*
*
*/
@Override
public void initField() {
// コメント
comment = new ALStringField();
comment.setFieldName(ALLocalizationUtils.getl10n("WORKFLOW_COMMENT"));
comment.setTrim(true);
// 承認フラグ
accept_flg = false;
// 差し戻し先の順位
passback_order = new ALNumberField();
}
/**
* リクエストの各フィールドに対する制約条件を設定します。 <BR>
*
*
*/
@Override
protected void setValidator() {
// コメントの文字数制限
comment.limitMaxLength(1000);
if (!accept_flg) {
passback_order.setNotNull(true);
passback_order.limitMinValue(0);
}
}
/**
* リクエストのフォームに入力されたデータの妥当性検証を行います。 <BR>
*
* @param msgList
* @return TRUE 成功 FALSE 失敗
*
*/
@Override
protected boolean validate(List<String> msgList) {
// コメント
comment.validate(msgList);
if (!accept_flg) {
// 差し戻し先の順位
passback_order.validate(msgList);
}
return (msgList.size() == 0);
}
/**
* リクエストをデータベースから読み出します。 <BR>
*
* @param rundata
* @param context
* @param msgList
* @return TRUE 成功 FALSE 失敗
*/
@Override
protected boolean loadFormData(RunData rundata, Context context,
List<String> msgList) {
return false;
}
/**
* リクエストをデータベースから削除します。 <BR>
*
* @param rundata
* @param context
* @param msgList
* @return TRUE 成功 FALSE 失敗
*/
@Override
protected boolean deleteFormData(RunData rundata, Context context,
List<String> msgList) {
return false;
}
/**
* リクエストをデータベースに格納します。 <BR>
*
* @param rundata
* @param context
* @param msgList
* @return TRUE 成功 FALSE 失敗
*/
@Override
protected boolean insertFormData(RunData rundata, Context context,
List<String> msgList) {
return false;
}
/**
* データベースに格納されているリクエストを更新します。 <BR>
*
* @param rundata
* @param context
* @param msgList
* @return TRUE 成功 FALSE 失敗
*/
@Override
protected boolean updateFormData(RunData rundata, Context context,
List<String> msgList) {
try {
int login_user_id = ALEipUtils.getUserId(rundata);
// get object model
EipTWorkflowRequest request =
WorkflowUtils.getEipTWorkflowRequest(rundata, context, true);
if (request == null) {
return false;
}
List<EipTWorkflowRequestMap> maps =
WorkflowUtils.getEipTWorkflowRequestMap(request);
WorkflowRequestMapHandler mapHandler =
new WorkflowRequestMapHandler(maps);
EipTWorkflowRequestMap currentMap = mapHandler.getCurrentMap();
Date now = Calendar.getInstance().getTime();
if (currentMap.getUserId() != login_user_id) {
return false;
}
if (accept_flg) {
// accept case
currentMap.setStatus(WorkflowUtils.DB_STATUS_ACCEPT);
currentMap.setNote(comment.getValue());
currentMap.setUpdateDate(now);
mapHandler.changeStatusForNextUser();
if (mapHandler.isApprovalForAll()) {
// all accept case
request.setProgress(WorkflowUtils.DB_PROGRESS_ACCEPT);
mapHandler.setFlowStatus(Type.ACCEPT);
List<Integer> excludeUserList = new ArrayList<Integer>();
excludeUserList.add(login_user_id);
// mail,activity to all users except last approver
mapHandler.setSendMailMapsForAll(excludeUserList);
mapHandler.setRecipientsForAll(excludeUserList);
} else {
mapHandler.setFlowStatus(Type.REQUEST);
// mail,activity to next user
EipTWorkflowRequestMap nextRequestMap =
maps.get(mapHandler.getLatestOrderIndex());
mapHandler.addSendMailMaps(nextRequestMap);
mapHandler.addRecipients(nextRequestMap);
}
} else {
// pass back case
currentMap.setStatus(WorkflowUtils.DB_STATUS_DENIAL);
currentMap.setNote(comment.getValue());
currentMap.setUpdateDate(now);
int passback_user_order = (int) passback_order.getValue();
// pass back user is applicant user case
if (mapHandler.isApplicantUser(passback_user_order)
&& !WorkflowUtils.isDisabledOrDeleted(mapHandler
.getApplicantUserMap()
.getUserId())) {
request.setProgress(WorkflowUtils.DB_PROGRESS_DENAIL);
mapHandler.setFlowStatus(Type.DENAIL);
// mail to applicant user and approver
mapHandler.addSendMailMapsForApplicantAndApprover(login_user_id);
// activity to applicant user only
mapHandler.addRecipientsApplicantOnly();
} else {
// pass back user is approver or unable user
boolean result =
mapHandler.passbackToApprover(passback_user_order, login_user_id);
if (!result) {
// passback user and next users all unable case
// all accept
request.setProgress(WorkflowUtils.DB_PROGRESS_ACCEPT);
mapHandler.setFlowStatus(Type.ACCEPT);
List<Integer> noList = new ArrayList<Integer>();
// mail, activity to all user
mapHandler.setSendMailMapsForAll(noList);
mapHandler.setRecipientsForAll(noList);
}
}
}
request.setUpdateDate(now);
Database.commit();
// save to eventlog
ALEventlogFactoryService.getInstance().getEventlogHandler().log(
request.getRequestId(),
ALEventlogConstants.PORTLET_TYPE_WORKFLOW,
request.getEipTWorkflowCategory().getCategoryName()
+ " "
+ request.getRequestName());
// activity
if (mapHandler.isRecipientsNotEmpty()) {
ALEipUser user = ALEipUtils.getALEipUser(login_user_id);
WorkflowUtils.createWorkflowRequestActivity(request, user
.getName()
.getValue(), mapHandler.getRecipients(), mapHandler.getFlowStatus());
}
// send mail
WorkflowUtils.sendMailForUpdate(
rundata,
mapHandler.getSendMailMaps(),
request,
comment.getValue(),
mapHandler.getFlowStatus());
} catch (ALPageNotFoundException ex) {
Database.rollback();
msgList.add(ALLocalizationUtils
.getl10n("WORKFLOW_WORKFLOW_ALREADY_DELETED"));
logger.error("[WorkflowConfirmFormData]", ex);
return false;
} catch (Exception ex) {
Database.rollback();
logger.error("workflow", ex);
return false;
}
return true;
}
public void setAcceptFlg(boolean bool) {
accept_flg = bool;
}
/**
* アクセス権限チェック用メソッド。<br />
* アクセス権限の機能名を返します。
*
* @return
*/
@Override
public String getAclPortletFeature() {
return ALAccessControlConstants.POERTLET_FEATURE_WORKFLOW_REQUEST_SELF;
}
private static class WorkflowRequestMapHandler {
EipTWorkflowRequestMap currentMap;
int orderIndex;
int latestOrderIndex;
List<EipTWorkflowRequestMap> requestMaps;
List<EipTWorkflowRequestMap> sendMailMaps;
int requestMapSize;
Type flowStatus;
List<String> recipients;
public WorkflowRequestMapHandler(List<EipTWorkflowRequestMap> requestMaps) {
this.requestMaps = requestMaps;
this.currentMap = null;
this.orderIndex = 0;
this.sendMailMaps = new ArrayList<EipTWorkflowRequestMap>();
this.requestMapSize = requestMaps.size();
this.flowStatus = null;
this.recipients = new ArrayList<String>();
this.init();
}
public void init() {
for (int i = 0; i < requestMapSize; i++) {
currentMap = requestMaps.get(i);
if (WorkflowUtils.DB_STATUS_CONFIRM.equals(currentMap.getStatus())) {
orderIndex = i;
break;
}
}
this.latestOrderIndex = orderIndex;
}
public EipTWorkflowRequestMap getCurrentMap() {
return currentMap;
}
@SuppressWarnings("unused")
public int getOrderInex() {
return orderIndex;
}
public List<EipTWorkflowRequestMap> getSendMailMaps() {
return sendMailMaps;
}
@SuppressWarnings("unused")
public int getRequestMapSize() {
return requestMapSize;
}
public int getLatestOrderIndex() {
return latestOrderIndex;
}
public Type getFlowStatus() {
return flowStatus;
}
public void setFlowStatus(Type str) {
this.flowStatus = str;
}
public List<String> getRecipients() {
return recipients;
}
public void changeStatusForNextUser() {
EipTWorkflowRequestMap nextRequestMap;
latestOrderIndex++;
while (latestOrderIndex < requestMapSize) {
// まだ申請先が残っている場合、次の申請先を指定
nextRequestMap = requestMaps.get(latestOrderIndex);
// 次のユーザーが削除済みだった場合は自動的に承認させる
if (WorkflowUtils.isDisabledOrDeleted(nextRequestMap.getUserId())) {
// 自動承認
nextRequestMap.setStatus(WorkflowUtils.DB_STATUS_THROUGH);
latestOrderIndex++;
} else {
nextRequestMap.setStatus(WorkflowUtils.DB_STATUS_CONFIRM);
break;
}
}
}
public boolean isApprovalForAll() {
return getLatestOrderIndex() == requestMapSize;
}
public void setSendMailMapsForAll(List<Integer> excludeUserList) {
for (EipTWorkflowRequestMap requestMap : requestMaps) {
int userId = requestMap.getUserId();
boolean isExclude = false;
for (Integer excluedUserId : excludeUserList) {
if (userId == excluedUserId) {
isExclude = true;
break;
}
}
if (!isExclude) {
sendMailMaps.add(requestMap);
}
}
}
public void addSendMailMaps(EipTWorkflowRequestMap requestMap) {
sendMailMaps.add(requestMap);
}
public boolean isApplicantUser(int request_order) {
return request_order == 0;
}
public EipTWorkflowRequestMap getApplicantUserMap() {
return requestMaps.get(0);
}
public void addSendMailMapsForApplicantAndApprover(int loginUserId) {
for (EipTWorkflowRequestMap requestMap : requestMaps) {
if (requestMap.getUserId() == loginUserId) {
break;
} else {
this.addSendMailMaps(requestMap);
}
}
}
public void addSendMailMapsForApprover(int passbackUserId, int loginUserId) {
boolean isStart = false;
for (EipTWorkflowRequestMap requestMap : requestMaps) {
int userId = requestMap.getUserId();
if (userId == passbackUserId) {
isStart = true;
}
if (userId == loginUserId) {
break;
} else {
if (isStart) {
this.addSendMailMaps(requestMap);
}
}
}
}
public boolean passbackToApprover(int passbackUserOrderIndex,
int loginUserId) {
EipTWorkflowRequestMap passbackMap =
getRequestMapByOrderIndex(passbackUserOrderIndex);
if (null == passbackMap) {
return false;
}
int passbackUserId = passbackMap.getUserId();
// bass back user equals myself
if (passbackUserId == loginUserId) {
// status change to C and process done .
currentMap.setStatus(WorkflowUtils.DB_STATUS_CONFIRM);
setFlowStatus(Type.DENAIL);
// mail,activity to myself
addSendMailMaps(passbackMap);
addRecipients(passbackMap);
return true;
}
if (WorkflowUtils.isDisabledOrDeleted(passbackUserId)) {
// pass back user is unable
// auto approve and process to next user
passbackMap.setStatus(WorkflowUtils.DB_STATUS_THROUGH);
return passbackToApprover(passbackUserOrderIndex + 1, loginUserId);
} else {
// status change to C and process done .
passbackMap.setStatus(WorkflowUtils.DB_STATUS_CONFIRM);
setFlowStatus(Type.DENAIL);
// mail to passback user and approver
addSendMailMapsForApprover(passbackUserId, loginUserId);
// activity to passback user only
addRecipients(passbackMap);
return true;
}
}
public EipTWorkflowRequestMap getRequestMapByOrderIndex(int orderIndex) {
for (EipTWorkflowRequestMap requestMap : requestMaps) {
if (requestMap.getOrderIndex() == orderIndex) {
return requestMap;
}
}
return null;
}
@SuppressWarnings("unused")
public boolean isSendMailMapsNotEmpty() {
return (null != sendMailMaps) && (sendMailMaps.size() > 0);
}
public void setRecipientsForAll(List<Integer> excludeUserList) {
for (EipTWorkflowRequestMap requestMap : requestMaps) {
int userId = requestMap.getUserId();
boolean isExclude = false;
for (Integer excluedUserId : excludeUserList) {
if (userId == excluedUserId) {
isExclude = true;
break;
}
}
if (!isExclude) {
try {
ALEipUser user = ALEipUtils.getALEipUser(requestMap.getUserId());
recipients.add(user.getName().getValue());
} catch (ALDBErrorException e) {
logger.error("[WorkflowConfirmFormData]", e);
}
}
}
}
public void addRecipients(EipTWorkflowRequestMap requestMap) {
try {
ALEipUser user = ALEipUtils.getALEipUser(requestMap.getUserId());
recipients.add(user.getName().getValue());
} catch (ALDBErrorException e) {
logger.error("[WorkflowConfirmFormData]", e);
}
}
public void addRecipientsApplicantOnly() {
addRecipients(requestMaps.get(0));
}
public boolean isRecipientsNotEmpty() {
return (null != recipients) && (recipients.size() > 0);
}
}
}