OWL ITS + 탐지시스템(인터넷 진흥원)
박지현
2022-03-07 398a4927e195755bd6a46be99337efd8dacc3dc2
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java
@@ -4,6 +4,7 @@
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.constant.ElasticSearchConstants;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.data.CheckIssueData;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.domain.enumType.CustomFieldType;
import kr.wisestone.owl.domain.enumType.IssueHistoryType;
@@ -13,8 +14,9 @@
import kr.wisestone.owl.service.*;
import kr.wisestone.owl.util.*;
import kr.wisestone.owl.vo.IssueHistoryVo;
import kr.wisestone.owl.vo.IssueVo;
import kr.wisestone.owl.web.condition.IssueHistoryCondition;
import kr.wisestone.owl.web.form.IssueForm;
import kr.wisestone.owl.web.form.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,6 +41,9 @@
    private UserService userService;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private IssueHistoryMapper issueHistoryMapper;
    @Autowired
@@ -59,13 +64,22 @@
    @Override
    @Transactional
    public void addIssueHistory(Issue issue, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        User user = this.webAppUtil.getLoginUserObject();
        addIssueHistory(issue, user, issueHistoryType, issueChangeDescription);
    }
    //  이력 생성
    @Override
    @Transactional
    public void addIssueHistory(Issue issue, User user, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        IssueHistory issueHistory = new IssueHistory();
        issueHistory.setIssue(issue);
        issueHistory.setProject(issue.getProject());
        issueHistory.setIssueHistoryType(issueHistoryType);
        StringBuilder description = new StringBuilder();
        //  이력 정보를 만들어 낸다.
        this.makeDescription(description, issueHistoryType, issueChangeDescription);
        this.makeDescription(user, description, issueHistoryType, issueChangeDescription);
        issueHistory.setDescription(description.toString());
        this.issueHistoryRepository.saveAndFlush(issueHistory);
@@ -77,6 +91,13 @@
    //  이력 정보를 만들어 낸다.
    @Override
    public void makeDescription(StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        User user = this.webAppUtil.getLoginUserObject();
        makeDescription(user, description, issueHistoryType, issueChangeDescription);
    }
    //  이력 정보를 만들어 낸다.
    @Override
    public void makeDescription(User user, StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        description.append("<div class=\"activity-text\">");
        //  생성, 수정, 삭제에 대해 기록을 남긴다.
@@ -86,9 +107,9 @@
                description.append("<span class='activity-timestamp'>");
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                description.append(this.webAppUtil.getLoginUser().getName());
                description.append(user.getName());
                description.append(" - ");
                description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount()));
                description.append(CommonUtil.decryptAES128(user.getAccount()));
                description.append(")");
                description.append("</span></h6>");
                break;
@@ -99,10 +120,10 @@
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                if (this.webAppUtil.getLoginUser() != null) {
                    description.append(this.webAppUtil.getLoginUser().getName());
                if (user != null) {
                    description.append(user.getName());
                    description.append(" - ");
                    description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount()));
                    description.append(CommonUtil.decryptAES128(user.getAccount()));
                }
                else {
                    description.append("OWL-ITS-SYSTEM");
@@ -120,11 +141,33 @@
                description.append("<span class=\"activity-timestamp\">");
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                description.append(this.webAppUtil.getLoginUser().getName());
                description.append(user.getName());
                description.append(" - ");
                description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount()));
                description.append(CommonUtil.decryptAES128(user.getAccount()));
                description.append(")");
                description.append("</span></h6>");
                break;
            case SEND:
                description.append("<h6 class=\"creat\"><span class=\"dot\"></span><span translate=\"common.sendMailIssue\">이슈 메일 전송</span>");
                description.append("<span class=\"activity-timestamp\">");
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                if (user != null) {
                    description.append(user.getName());
                    description.append(" - ");
                    description.append(CommonUtil.decryptAES128(user.getAccount()));
                }
                else {
                    description.append("OWL-ITS-SYSTEM");
                    description.append(" - ");
                    description.append(this.systemEmail);
                }
                description.append(")");
                description.append("</span></h6>");
                description.append(issueChangeDescription);
                break;
        }
@@ -268,13 +311,25 @@
    //  이슈 아이디에 해당하는 기록 정보를 가져온다.
    @Override
    @Transactional(readOnly = true)
    public List<IssueHistoryVo> findIssueHistory(Long issueId) {
        return this.issueHistoryRepository.findByIssueId(issueId);
    public List<IssueHistoryVo> findIssueHistory(Issue issue) {
        List<IssueHistoryVo> issueHistoryVos = this.issueHistoryRepository.findByIssueId(issue.getId());
        if (issueHistoryVos != null && issueHistoryVos.size() > 0) {
            for (IssueHistoryVo issueHistoryVo : issueHistoryVos) {
                issueHistoryVo.setTitle(issue.getTitle());
            }
        }
        return issueHistoryVos;
    }
    //  이슈 변경 내역을 추출한다.
    @Override
    public StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List<MultipartFile> files) {
    public StringBuilder detectIssueChange(IssueForm issueForm, CheckIssueData data, List<MultipartFile> files) {
        return this.detectIssueChange(data.getIssue(), issueForm, data.getProject(), data.getOldIssueStatus(), data.getNewIssueStatus(), data.getIssueType(), data.getPriority(), data.getSeverity(), files);
    }
    //  이슈 변경 내역을 추출한다.
    @Override
    public StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus oldIssueStatus, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List<MultipartFile> files) {
        StringBuilder description = new StringBuilder();
        //  이슈 프로젝트 변경 정보를 기록한다.
@@ -284,7 +339,7 @@
        //  이슈 우선순위 변경 정보를 기록한다.
        this.detectIssuePriority(issue, issueForm, description, priority);
        //  이슈 상태 변경 정보를 기록한다.
        this.detectIssueStatus(issue, issueForm, description, issueStatus);
        this.detectIssueStatus(issue, issueForm, description, oldIssueStatus, issueStatus);
        //  이슈 타입 변경 정보를 기록한다.
        this.detectIssueType(issue, issueForm, description, issueType);
        //  이슈에 첨부된 파일에 대해 변경 정보를 기록한다.
@@ -292,7 +347,12 @@
        //  이슈 기간 변경 정보를 기록한다.
        this.detectIssuePeriod(issue, issueForm, description);
        //  담당자 변경 정보를 기록한다.
        //this.detectIssueManager(issue, issueForm, description);
        this.detectIssueManager(issue, issueForm, description);
        if (issueForm.getIsApi().equals(Issue.IS_API_NO)) { //api로 변경 시 담당부서 변경 불가
            //  담당부서 변경 정보를 기록한다.
            this.detectIssueDepartment(issue, issueForm, description);
        }
        //  사용자 정의 필드 변경 정보를 기록한다.
        this.detectCustomField(issue, issueForm, description);
@@ -363,11 +423,12 @@
    //  이슈 상태 변경 정보를 기록한다.
    @Override
    public void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus issueStatus) {
        if (!issue.getIssueStatus().getId().equals(issueForm.getIssueStatusId())) {
    @Transactional
    public void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus oldIssueStatus, IssueStatus issueStatus) {
        if (!oldIssueStatus.getId().equals(issueForm.getIssueStatusId())) {
            String title = "<span translate=\"common.updateHasStatus\">상태가 변경되었습니다.</span>";
            //  이력 정보를 html 태그로 만들어 준다.
            this.makeIssueHistoryHtml(description, title, issue.getIssueStatus().getName(), issueStatus.getName());
            this.makeIssueHistoryHtml(description, title, oldIssueStatus.getName(), issueStatus.getName());
            //  이슈 위험 관리에 상태 변경 정보를 업데이트한다. - 담당자 변경
            this.issueRiskService.modifyIssueRisk(issue, true, false, issueForm.getIssueStatusId());
@@ -391,7 +452,7 @@
    public void recordRemoveWorkflowToIssueStatus(String oldIssueStatusName, String newIssueStatusName, StringBuilder description) {
        description.append("<ul class=\"activity-list\">");
        String title = "<span translate=\"common.upddetectReservationIssueStatusateWorkflowNotExist\">변경된 워크플로우에서 상태가 존재하지 않아 이슈의 상태가 변경되었습니다.</span>";
        String title = "<span translate=\"common.updateWorkflowNotExist\">변경된 워크플로우에서 상태가 존재하지 않아 이슈의 상태가 변경되었습니다.</span>";
        //  이력 정보를 html 태그로 만들어 준다.
        this.makeIssueHistoryHtml(description, title, oldIssueStatusName, newIssueStatusName);
@@ -447,10 +508,8 @@
        else {
            recodeIssuePeriod.append("<span translate=\"common.unspecified\">미지정</span>");
        }
        return recodeIssuePeriod.toString();
    }
    // 연관 일감 변경 정보를 기록한다.
    @Override
@@ -462,6 +521,272 @@
           description.append("<span translate=\"issue.relationIssueRemoveHistory\">연관 일감이 삭제되었습니다. " + issueRelation.getRelationIssue().getTitle() + "</span>");
           description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueRelation.getRelationIssue().getTitle() + "</span>");
       }
    }
    // 하위 일감 변경 정보를 기록한다.
    @Override
    public void detectDownIssues(IssueHistoryType type, Issue issue, StringBuilder description) {
        if (type == IssueHistoryType.ADD) {
            description.append("<span translate=\"issue.downIssueAddHistory\">하위 일감이 추가되었습니다. </span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issue.getTitle() + "</span>");
        }else {
            description.append("<span translate=\"issue.downIssueRemoveHistory\">하위 일감이 삭제되었습니다. </span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issue.getTitle() + "</span>");
        }
    }
    // 이슈 메일 전송 정보를 기록한다.
    @Override
    public void detectSendIssueMail(IssueHistoryType type, IssueForm issueForm, StringBuilder description) {
        this.detectSendIssueMail(type, issueForm.getSendEmails(), description);
    }
    // 이슈 메일 전송 정보를 기록한다.
    @Override
    public void detectSendIssueMail(IssueHistoryType type, List<String> sendMails, StringBuilder description) {
        if (type == IssueHistoryType.SEND) {
            description.append("<span translate=\"issue.sendIssueMailHistory\">이슈 메일 전송을 완료했습니다. </span>");
            if(sendMails != null && sendMails.size() > 0){
                for (String sendEmail : sendMails){
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + CommonUtil.decryptAES128(sendEmail) + "</span>");
                }
            }
        }
    }
    // 업체 정보 변경 정보를 기록한다.
    @Override
    @Transactional
    public void detectIssueCompany(IssueHistoryType type, Map<String, Object> param, CompanyFieldForm companyFieldForm, IssueCompany issueCompany, StringBuilder description) {
        Long companyFieldId = 0L;
        Long id = 0L;
        String name = "";
        String manager = "";
        String tel = "";
        String email = "";
        String memo = "";
        Long companyTypeId = 0L;
        Long parentSectorId = 0L;
        Long childSectorId = 0L;
        Long regionId = 0L;
        Long statusId = 0L;
        String companyTypeName = "";
        String parentSectorName = "";
        String childSectorName = "";
        String regionName = "";
        String statusName = "";
        if (param != null) {
            id = MapUtil.getLong(param, "companyId");
            name = MapUtil.getString(param, "name");
            manager = MapUtil.getString(param, "manager");
            tel = MapUtil.getString(param, "tel");
            email = MapUtil.getString(param, "email");
            memo = MapUtil.getString(param, "memo");
            companyTypeId = MapUtil.getLong(param, "companyTypeId");
            parentSectorId = MapUtil.getLong(param, "parentSectorId");
            childSectorId = MapUtil.getLong(param, "childSectorId");
            regionId = MapUtil.getLong(param, "regionId");
            statusId = MapUtil.getLong(param, "statusId");
            companyTypeName = MapUtil.getString(param, "companyTypeName");
            parentSectorName = MapUtil.getString(param, "parentSectorName");
            childSectorName = MapUtil.getString(param, "childSectorName");
            regionName = MapUtil.getString(param, "regionName");
            statusName = MapUtil.getString(param, "statusName");
        }else if(companyFieldForm != null) {
            id = companyFieldForm.getId();
            name = companyFieldForm.getName();
            manager = companyFieldForm.getManager();
            tel = companyFieldForm.getTel();
            email = companyFieldForm.getEmail();
            memo = companyFieldForm.getMemo();
            companyTypeId = companyFieldForm.getCompanyTypeId();
            parentSectorId = companyFieldForm.getParentSectorId();
            childSectorId = companyFieldForm.getChildSectorId();
            regionId = companyFieldForm.getRegionId();
            statusId = companyFieldForm.getStatusId();
            companyTypeName = companyFieldForm.getCompanyTypeName();
            parentSectorName = companyFieldForm.getParentSectorName();
            childSectorName = companyFieldForm.getChildSectorName();
            regionName = companyFieldForm.getRegionName();
            statusName = companyFieldForm.getStatusName();
        }
        if (issueCompany.getCompanyField() != null && issueCompany.getCompanyField().getId() != null) {
            companyFieldId = issueCompany.getCompanyField().getId();
        }
        if (type == IssueHistoryType.ADD && issueCompany.getCompanyField() != null) { //추가 할 경우
            description.append("<span translate=\"issue.issueCompanyAddHistory\">업체 정보가 추가되었습니다. </span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueCompany.getCompanyField().getName() + "</span>");
        } else if (type == IssueHistoryType.MODIFY) { //수정 할 경우
            if (id != null && !companyFieldId.equals(id)) {
                description.append("<span translate=\"issue.issueCompanyModifyHistory\">업체 정보가 변경되었습니다. </span>");
                description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + name + "</span>");
            } else {
                if (companyFieldId.equals(id) && manager != null && (issueCompany.getManager() == null || !issueCompany.getManager().equals(manager))) {
                    description.append("<span translate=\"issue.issueCompanyModifyManagerHistory\">&nbsp;>&nbsp;업체 정보의 담당자가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + manager + "</span>");
                }
                if (companyFieldId.equals(id) && tel != null && (issueCompany.getTel() == null || !issueCompany.getTel().equals(tel))) {
                    description.append("<span translate=\"issue.issueCompanyModifyTelHistory\">&nbsp;>&nbsp;업체 정보의 전화번호가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + tel + "</span>");
                }
                if (companyFieldId.equals(id) && email != null && (issueCompany.getEmail() == null || !issueCompany.getEmail().equals(email))) {
                    description.append("<span translate=\"issue.issueCompanyModifyEmailHistory\">&nbsp;>&nbsp;업체 정보의 이메일이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + email + "</span>");
                }
                if (companyFieldId.equals(id) && memo != null && (issueCompany.getMemo() == null || !issueCompany.getMemo().equals(memo))) {
                    description.append("<span translate=\"issue.issueCompanyModifyMemoHistory\">&nbsp;>&nbsp;업체 정보의 비고가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + memo + "</span>");
                }
                if (companyFieldId.equals(id) && companyTypeName != null && (issueCompany.getCompanyTypeId() == null || !issueCompany.getCompanyTypeId().equals(companyTypeId))) {
                    description.append("<span translate=\"issue.issueCompanyModifyCompanyTypeHistory\">&nbsp;>&nbsp;업체 정보의 기업구분이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + companyTypeName + "</span>");
                }
                if (companyFieldId.equals(id) && parentSectorName != null && (issueCompany.getParentSectorId() == null || !issueCompany.getParentSectorId().equals(parentSectorId))) {
                    description.append("<span translate=\"issue.issueCompanyModifyParentSectorHistory\">&nbsp;>&nbsp;업체 정보의 업종(대분류)이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + parentSectorName + "</span>");
                }
                if (companyFieldId.equals(id) && childSectorName != null && (issueCompany.getChildSectorId() == null || !issueCompany.getChildSectorId().equals(childSectorId))) {
                    description.append("<span translate=\"issue.issueCompanyModifyChildSectorHistory\">&nbsp;>&nbsp;업체 정보의 업종(중분류)이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + childSectorName + "</span>");
                }
                if (companyFieldId.equals(id) && statusName != null && (issueCompany.getStatusId() == null || !issueCompany.getStatusId().equals(statusId))) {
                    description.append("<span translate=\"issue.issueCompanyModifyStatusHistory\">&nbsp;>&nbsp;업체 정보의 상태가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + statusName + "</span>");
                }
                if (companyFieldId.equals(id) && regionName != null && (issueCompany.getRegionId() == null || !issueCompany.getRegionId().equals(regionId))) {
                    description.append("<span translate=\"issue.issueCompanyModifyRegionHistory\">&nbsp;>&nbsp;업체 정보의 지역이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + regionName + "</span>");
                }
            }
        } else {
            description.append("<span translate=\"issue.issueCompanyRemoveHistory\">업체 정보가 삭제되었습니다. " + issueCompany.getCompanyField().getName() + "</span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueCompany.getCompanyField().getName() + "</span>");
        }
    }
    // ISP 정보 변경 정보를 기록한다.
    @Override
    public void detectIssueIsp(IssueHistoryType type, Map<String, Object> param, IspFieldForm ispFieldForm, IssueIsp issueIsp, StringBuilder description) {
        Long ispFieldId = 0L;
        Long id = 0L;
        String name = "";
        String manager = "";
        String tel = "";
        String email = "";
        String memo = "";
        if (param != null) {
            id = MapUtil.getLong(param, "ispId");
            name = MapUtil.getString(param, "name");
            manager = MapUtil.getString(param, "manager");
            tel = MapUtil.getString(param, "tel");
            email = MapUtil.getString(param, "email");
            memo = MapUtil.getString(param, "memo");
        }else if(ispFieldForm != null) {
            id = ispFieldForm.getId();
            name = ispFieldForm.getName();
            manager = ispFieldForm.getManager();
            tel = ispFieldForm.getTel();
            email = ispFieldForm.getEmail();
            memo = ispFieldForm.getMemo();
        }
        if (issueIsp.getIspField() != null && issueIsp.getIspField().getId() != null) {
            ispFieldId = issueIsp.getIspField().getId();
        }
        if (type == IssueHistoryType.ADD) {
            description.append("<span translate=\"issue.issueIspAddHistory\">ISP 정보가 추가되었습니다. </span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueIsp.getIspField().getName() + "</span>");
        } else if (type == IssueHistoryType.MODIFY) {
            if (id != null && !ispFieldId.equals(id)) { //수정 할 경우
                description.append("<span translate=\"issue.issueIspModifyHistory\">ISP 정보가 변경되었습니다. </span>");
                description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + name + "</span>");
            } else {
                if (ispFieldId.equals(id) && manager != null && (issueIsp.getManager() == null || !issueIsp.getManager().equals(manager))) {
                    description.append("<span translate=\"issue.issueIspModifyManagerHistory\">ISP 정보의 담당자가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + manager + "</span>");
                }
                if (ispFieldId.equals(id) && tel != null && (issueIsp.getTel() == null || !issueIsp.getTel().equals(tel))) {
                    description.append("<span translate=\"issue.issueIspModifyTelHistory\">ISP 정보의 전화번호가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + tel + "</span>");
                }
                if (ispFieldId.equals(id) && email != null && (issueIsp.getEmail() == null || !issueIsp.getEmail().equals(email))) {
                    description.append("<span translate=\"issue.issueIspModifyEmailHistory\">ISP 정보의 이메일이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + email + "</span>");
                }
                if (ispFieldId.equals(id) && memo != null && (issueIsp.getMemo() == null || !issueIsp.getMemo().equals(memo))) {
                    description.append("<span translate=\"issue.issueIspModifyMemoHistory\">ISP 정보의 비고가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + memo + "</span>");
                }
            }
        } else {
            description.append("<span translate=\"issue.issueIspRemoveHistory\">ISP 정보가 삭제되었습니다. " + issueIsp.getIspField().getName() + "</span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueIsp.getIspField().getName() + "</span>");
        }
    }
    // 호스팅 정보 변경 정보를 기록한다.
    @Override
    public void detectIssueHosting(IssueHistoryType type, Map<String, Object> param, HostingFieldForm hostingFieldForm, IssueHosting issueHosting, StringBuilder description) {
        Long hostingFieldId = 0L;
        Long id = 0L;
        String name = "";
        String manager = "";
        String tel = "";
        String email = "";
        String memo = "";
        if (param != null) {
            id = MapUtil.getLong(param, "hostingId");
            name = MapUtil.getString(param, "name");
            manager = MapUtil.getString(param, "manager");
            tel = MapUtil.getString(param, "tel");
            email = MapUtil.getString(param, "email");
            memo = MapUtil.getString(param, "memo");
        }else if(hostingFieldForm != null) {
            id = hostingFieldForm.getId();
            name = hostingFieldForm.getName();
            manager = hostingFieldForm.getManager();
            tel = hostingFieldForm.getTel();
            email = hostingFieldForm.getEmail();
            memo = hostingFieldForm.getMemo();
        }
        if (issueHosting.getHostingField() != null && issueHosting.getHostingField().getId() != null) {
            hostingFieldId = issueHosting.getHostingField().getId();
        }
        if (type == IssueHistoryType.ADD) {
            description.append("<span translate=\"issue.issueHostingAddHistory\">호스팅 정보가 추가되었습니다. </span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueHosting.getHostingField().getName() + "</span>");
        }else if(type == IssueHistoryType.MODIFY){
            if(id != null && !hostingFieldId.equals(id)){ //수정 할 경우
                description.append("<span translate=\"issue.issueHostingModifyHistory\">호스팅 정보가 변경되었습니다. </span>");
                description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + name + "</span>");
            } else {
                if(hostingFieldId.equals(id) && manager != null && (issueHosting.getManager() == null || !issueHosting.getManager().equals(manager))){
                    description.append("<span translate=\"issue.issueHostingModifyManagerHistory\">호스팅 정보의 담당자가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + manager + "</span>");
                }
                if(hostingFieldId.equals(id) && tel != null && (issueHosting.getTel() == null || !issueHosting.getTel().equals(tel))){
                    description.append("<span translate=\"issue.issueHostingModifyTelHistory\">호스팅 정보의 전화번호가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + tel + "</span>");
                }
                if(hostingFieldId.equals(id) && email != null && (issueHosting.getEmail() == null || !issueHosting.getEmail().equals(email))){
                    description.append("<span translate=\"issue.issueHostingModifyEmailHistory\">호스팅 정보의 이메일이 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + email + "</span>");
                }
                if(hostingFieldId.equals(id) && memo != null && (issueHosting.getMemo() == null || !issueHosting.getMemo().equals(memo))){
                    description.append("<span translate=\"issue.issueHostingModifyMemoHistory\">호스팅 정보의 비고가 변경되었습니다. </span>");
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + memo + "</span>");
                }
            }
        } else {
            description.append("<span translate=\"issue.issueHostingRemoveHistory\">호스팅 정보가 삭제되었습니다. " + issueHosting.getHostingField().getName() + "</span>");
            description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + issueHosting.getHostingField().getName() + "</span>");
        }
    }
    //  담당자 변경 정보를 기록한다.
@@ -537,6 +862,75 @@
        this.makeIssueHistoryHtml(description, title, beforeUser.toString(), afterUser.toString());
    }
    //  담당부서 변경 정보를 기록한다.
    @Override
    public void detectIssueDepartment(Issue issue, IssueForm issueForm, StringBuilder description) {
        boolean saveIssueRisk = false;  //  이슈 위험 관리에 이중 저장되는 것을 방지하기 위한 구분 값
        //  담당부서 수가 달라졌을 경우
        if(issue.getIssueDepartments().size() != issueForm.getDepartmentIds().size()){
            this.recodeIssueDepartment(issue, issueForm, description);
            // 이슈 위험 관리에 담당부서 변경 정보를 업데이트 한다. - 담당부서 변경
            this.issueRiskService.modifyIssueRisk(issue, false, true, null);
            saveIssueRisk = true;
        }else if (issue.getIssueDepartments().size() > 0 && issueForm.getDepartmentIds().size() > 0) {//  담당부서 수는 같으나 담당부서가 달라졌을 경우
            //  이전 담당자 표시
            for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
                boolean change = true;
                Department department = issueDepartment.getDepartment();
                for (Long departmentId : issueForm.getDepartmentIds()) {
                    if (department.getId().equals(departmentId)) {
                        change = false;
                        break;
                    }
                }
                if (change) {
                    //  담당부서 변경 정보 기록
                    this.recodeIssueDepartment(issue, issueForm, description);
                    //  담당부서 수가 달라졌을 경우에 저장되지 않았다면 여기서 이슈 위험 관리 저장을 한다.
                    if (!saveIssueRisk) {
                        //  이슈 위험 관리에 담당부서 변경 정보를 업데이트한다. - 담당부서 변경
                        this.issueRiskService.modifyIssueRisk(issue, false, true, null);
                    }
                    break;
                }
            }
        }
    }
    //  담당부서 변경 정보 기록
    private void recodeIssueDepartment(Issue issue, IssueForm issueForm, StringBuilder description) {
        String title = "<span translate=\"common.updateDepartment\">담당부서가 변경되었습니다.</span>";
        StringBuilder beforeDepartment = new StringBuilder();
        //  이전 담당부서 표시
        for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
            beforeDepartment.append(issueDepartment.getDepartment().getDepartmentName());
            beforeDepartment.append(", ");
        }
        //  담당부서가 없었으면 없음으로 표시
        if (issue.getIssueDepartments().size() < 1) {
            beforeDepartment.append("<span translate=\"common.none\">없음</span>");
        }
        StringBuilder afterDepartment = new StringBuilder();
        for (Long departmentId : issueForm.getDepartmentIds()) {
            Department department = this.departmentService.getDepartment(departmentId);
            afterDepartment.append(department.getDepartmentName());
            afterDepartment.append(", ");
        }
        //  담당부서가 없었으면 없음으로 표시
        if (issueForm.getDepartmentIds().size() < 1) {
            afterDepartment.append("<span translate=\"common.none\">없음</span>");
        }
        //  이력 정보를 html 태그로 만들어 준다.
        this.makeIssueHistoryHtml(description, title, beforeDepartment.toString(), afterDepartment.toString());
    }
    //  이슈에 첨부된 파일에 대해 변경 정보를 기록한다.
    @Override
    public void detectAttachedFile(IssueForm issueForm, StringBuilder description, List<MultipartFile> files) {
@@ -569,6 +963,12 @@
            switch (customField.getCustomFieldType()) {
                case INPUT :
                case SINGLE_SELECT :
                case NUMBER :
                case DATETIME :
                case IP_ADDRESS :
                case EMAIL :
                case SITE :
                case TEL :
                    boolean existIssueCustomFieldValue = false;
                    for (IssueCustomFieldValue savedIssueCustomFieldValue : issue.getIssueCustomFieldValues()) {
@@ -730,6 +1130,12 @@
        if (StringUtils.isEmpty(value)) {
            switch(customFieldType) {
                case INPUT:
                case NUMBER:
                case DATETIME:
                case IP_ADDRESS:
                case EMAIL:
                case SITE:
                case TEL:
                    result = "<span translate=\"common.noValueEntered\">입력한 값이 없습니다.</span>";
                    break;
                case SINGLE_SELECT: