From 7476ad22442c349f0751709957fee068d463980a Mon Sep 17 00:00:00 2001
From: wyu <kknd09321@nate.com>
Date: 수, 01 12월 2021 20:44:51 +0900
Subject: [PATCH] 이슈 수정 오류 및 메일 보내기 템플릿 이미지 추가

---
 src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java |  676 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 611 insertions(+), 65 deletions(-)

diff --git a/src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java b/src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
index 8fec89e..14aae02 100644
--- a/src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
+++ b/src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -6,6 +6,7 @@
 import kr.wisestone.owl.constant.Constants;
 import kr.wisestone.owl.constant.ElasticSearchConstants;
 import kr.wisestone.owl.constant.MsgConstants;
+import kr.wisestone.owl.constant.UsePartner;
 import kr.wisestone.owl.domain.*;
 import kr.wisestone.owl.domain.enumType.CustomFieldType;
 import kr.wisestone.owl.domain.enumType.EmailType;
@@ -20,10 +21,10 @@
 import kr.wisestone.owl.util.DateUtil;
 import kr.wisestone.owl.vo.*;
 import kr.wisestone.owl.web.condition.IssueCondition;
+import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition;
 import kr.wisestone.owl.web.condition.IssueTypeCustomFieldCondition;
 import kr.wisestone.owl.web.condition.ProjectCondition;
-import kr.wisestone.owl.web.form.IssueCommentForm;
-import kr.wisestone.owl.web.form.IssueForm;
+import kr.wisestone.owl.web.form.*;
 import kr.wisestone.owl.web.view.ExcelView;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.time.StopWatch;
@@ -44,7 +45,6 @@
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.util.*;
-import java.util.concurrent.locks.Condition;
 
 @Service
 public class IssueServiceImpl extends AbstractServiceImpl<Issue, Long, JpaRepository<Issue, Long>> implements IssueService {
@@ -53,6 +53,9 @@
 
     @Autowired
     private IssueRepository issueRepository;
+
+    @Autowired
+    private IssueTableConfigService issueTableConfigService;
 
     @Autowired
     private ProjectService projectService;
@@ -70,6 +73,24 @@
     private SeverityService severityService;
 
     @Autowired
+    private CustomFieldApiOverlapService customFieldApiOverlapService;
+
+    @Autowired
+    private IssueApiDefaultService issueApiDefaultService;
+
+    @Autowired
+    private ApiTokenService apiTokenService;
+
+    @Autowired
+    private CompanyFieldService companyFieldService;
+
+    @Autowired
+    private IspFieldService ispFieldService;
+
+    @Autowired
+    private HostingFieldService hostingFieldService;
+
+    @Autowired
     private CommonConfiguration configuration;
 
     @Autowired
@@ -82,7 +103,19 @@
     private IssueCustomFieldValueService issueCustomFieldValueService;
 
     @Autowired
+    private IssueCompanyService issueCompanyService;
+
+    @Autowired
+    private IssueIspService issueIspService;
+
+    @Autowired
+    private IssueHostingService issueHostingService;
+
+    @Autowired
     private IssueUserService issueUserService;
+
+    @Autowired
+    private IssueDepartmentService issueDepartmentService;
 
     @Autowired
     private CustomFieldService customFieldService;
@@ -94,6 +127,9 @@
     private UserService userService;
 
     @Autowired
+    private DepartmentService departmentService;
+
+    @Autowired
     private IssueCommentService issueCommentService;
 
     @Autowired
@@ -101,6 +137,9 @@
 
     @Autowired
     private ProjectRoleUserService projectRoleUserService;
+
+    @Autowired
+    private ProjectRoleDepartmentService projectRoleDepartmentService;
 
     @Autowired
     private IssueRiskService issueRiskService;
@@ -152,12 +191,109 @@
     }
 
 
+
+    //  API 瑜� �넻�빐 �씠�뒋 異붽�.
+    @Override
+    @Transactional
+    public Issue addApiIssue(IssueApiForm issueApiForm) {
+        if (issueApiForm.getIssueTypeId() == null) {
+            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
+        }
+
+        IssueForm issueForm = ConvertUtil.copyProperties(issueApiForm, IssueForm.class);
+//        issueForm.setFiles(issueApiForm.getFiles());
+        IssueType issueType = this.issueTypeService.getIssueType(issueApiForm.getIssueTypeId());
+        if (issueType == null){
+            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
+        }
+
+        // �봽濡쒖젥�듃 �엯�젰
+        Project project = issueType.getProject();
+        if (project == null){
+            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR));
+        }
+        issueForm.setProjectId(project.getId());
+
+        // �넗�겙�쑝濡� �쑀�� �젙蹂� 媛��졇�삤湲�
+        String token = issueApiForm.getToken();
+        UserVo userVo = this.apiTokenService.certification(token);
+
+        // �빐�떦 �쑀�� �젙蹂닿� �쁽�옱 db�뿉 �엳�뒗吏� �솗�씤
+        User user = this.userService.getUser(userVo.getId());
+        if (user != null) {
+
+            // 湲곕낯媛� �엯�젰�븯湲�
+            IssueApiDefaultForm issueApiDefaultForm = new IssueApiDefaultForm();
+            issueApiDefaultForm.setUserId(user.getId());
+            issueApiDefaultForm.setIssueTypeId(issueForm.getIssueTypeId());
+            IssueApiDefault issueApiDefault = this.issueApiDefaultService.find(issueApiDefaultForm);
+            if (issueApiDefault != null) {
+                ConvertUtil.copyProperties(issueApiDefault, issueForm);
+                issueForm.setPriorityId(issueApiDefault.getPriority().getId());
+                issueForm.setSeverityId(issueApiDefault.getSeverity().getId());
+            }
+
+            // 以묐났 媛� �븯�쐞 �씠�뒋濡� 泥섎━�븯湲�
+            CustomFieldApiOverlapForm customFieldApiOverlapForm = new CustomFieldApiOverlapForm();
+            customFieldApiOverlapForm.setUserId(user.getId());
+            customFieldApiOverlapForm.setIssueTypeId(issueForm.getIssueTypeId());
+
+            IssueVo issueVo = this.findIssue(issueApiForm, user.getId());
+            if (issueVo != null) {
+                issueForm.setParentIssueId(issueVo.getId());
+            }
+
+            issueForm.setIsApi(Issue.IS_API_YES);
+
+            // �궗�슜�옄 �젙�쓽 �븘�뱶 �꽕�젙
+            issueForm.setIssueCustomFields(issueApiForm.getCustomFieldValues());
+
+            // api �엯�젰媛� �쟻�슜
+            ConvertUtil.copyProperties(issueApiForm, issueForm);
+
+            return addIssue(user, issueForm, issueApiForm.getMultipartFiles());
+        } else {
+            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR));
+        }
+    }
+
+    // 以묐났�맂 �긽�쐞 �씠�뒋 寃��깋
+    private IssueVo findIssue(IssueApiForm issueApiForm, Long userId) {
+        IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
+
+        List<CustomFieldApiOverlap> customFieldApiOverlaps = this.customFieldApiOverlapService.find(userId, issueApiForm.getIssueTypeId());
+        if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) {
+            for (CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
+                for (IssueCustomFieldValueForm issueCustomFieldValue : issueApiForm.getIssueCustomFieldValues()) {
+                    if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValue.getCustomFieldId())) {
+                        issueCustomFieldValueCondition.addUseValues(issueCustomFieldValue.getUseValue());
+                    }
+                }
+            }
+            List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
+            if (results != null && results.size() > 0) {
+                IssueVo issueVo = new IssueVo();
+                ConvertUtil.convertMapToObject(results.get(0), issueVo);
+                return issueVo;
+            }
+        }
+        return null;
+    }
+
     //  �씠�뒋瑜� �깮�꽦�븳�떎.
     @Override
     @Transactional
     public Issue addIssue(IssueForm issueForm, List<MultipartFile> multipartFiles) {
+        User user = this.webAppUtil.getLoginUserObject();
+        return addIssue(user, issueForm, multipartFiles);
+    }
+
+    //  �씠�뒋瑜� �깮�꽦�븳�떎.
+    @Override
+    @Transactional
+    public Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) {
         //  �궗�슜�븯怨� �엳�뒗 �뾽臾� 怨듦컙�씠 �솢�꽦 �긽�깭�씤吏� �솗�씤�븳�떎. �궗�슜 怨듦컙�뿉�꽌 濡쒓렇�씤�븳 �궗�슜�옄媛� 鍮꾪솢�꽦�씤吏� �솗�씤�븳�떎.
-        this.workspaceService.checkUseWorkspace();
+        Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId());
         //  �봽濡쒖젥�듃 �쑀�슚�꽦 泥댄겕
         Project project = this.projectService.getProject(issueForm.getProjectId());
         //  �씠�뒋 �쑀�삎 �쑀�슚�꽦 泥댄겕
@@ -171,6 +307,8 @@
         this.verifyTitle(issueForm.getTitle());
         //  �궇吏� �쑀�슚�꽦 泥댄겕
         this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate());
+        //  �떞�떦 遺��꽌 �쑀�슚�꽦 泥댄겕
+        this.verifyIssueDepartment(project, issueForm);
 
         //  �씠�뒋 �긽�깭 �쑀�삎�씠 '��湲�' �씤 �씠�뒋 �긽�깭 媛��졇�삤湲�
         IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow());
@@ -181,40 +319,51 @@
         issue.setIssueType(issueType);
         issue.setPriority(priority);
         issue.setSeverity(severity);
+
         issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project));    //  媛� �봽濡쒖젥�듃�쓽 怨좎쑀 �씠�뒋 踰덊샇 �깮�꽦
 
-        this.issueRepository.saveAndFlush(issue);
+        issue = this.issueRepository.saveAndFlush(issue);
 
         issue.setReverseIndex(issue.getId() * -1);  //  荑쇰━ �냽�룄 媛쒖꽑�쓣 �쐞�빐 由щ쾭�뒪 �씤�뜳�뒪 �깮�꽦
         //  �떞�떦�옄 吏��젙
-        this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
+        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
+        //  �떞�떦遺��꽌 吏��젙
+        this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
+        //  �뾽泥� �젙蹂� ���옣
+        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
+        //  ISP �젙蹂� ���옣
+        this.issueIspService.modifyIssueIspField(issue, issueForm.getIssueIspFields());
+        //  HOSTING �젙蹂� ���옣
+        this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields());
 
+
+        //  泥⑤� �뙆�씪 ���옣
         //  multipartFile �쓣 file Map List 媛앹껜濡� 蹂�寃쏀븳�떎.
         List<Map<String, Object>> convertFileMaps = this.convertMultipartFileToFile(multipartFiles);
-        //  泥⑤� �뙆�씪 ���옣
-        this.attachedFileService.addAttachedFile(convertFileMaps, issue, this.webAppUtil.getLoginUser().getAccount());
+        this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount());
+
         //  �뀓�뒪�듃 �뿉�뵒�꽣�뿉 泥⑤��븳 �뙆�씪�쓣 �씠�뒋�� �뿰寃�
         this.checkNotHaveIssueIdAttachedFile(issue, issueForm);
         //  �궗�슜�옄 �젙�쓽 �븘�뱶 ���옣
         this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields());
         //  �씠�뒋 �씠�젰 �깮�꽦
-        this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.ADD, null);
+        this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null);
         //  �씠�뒋 �쐞�뿕 愿�由� �깮�꽦
         this.issueRiskService.addIssueRisk(issue, project.getWorkspace());
         //  �쁺�냽�꽦 而⑦뀓�뒪�듃 鍮꾩슦湲�
         this.clear();
         //  �씠�뒋 �깮�꽦, �궘�젣�떆 �삁�빟 �씠硫붿씪�뿉 �벑濡앺빐�넃�뒗�떎.
-        this.reservationIssueEmail(issue.getId(), EmailType.ISSUE_ADD);
+        this.reservationIssueEmail(issue, EmailType.ISSUE_ADD);
         //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
-        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ADD));
+
+        UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class);
+        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD));
 
         return issue;
     }
 
     //  �씠�뒋 �깮�꽦, �궘�젣�떆 �삁�빟 �씠硫붿씪�뿉 �벑濡앺빐�넃�뒗�떎.
-    private void reservationIssueEmail(Long id, EmailType emailType) {
-        Issue issue = this.getIssue(id);
-
+    private void reservationIssueEmail(Issue issue, EmailType emailType) {
         Map<String, Object> issueMap = new HashMap<>();
         //  �씠�뒋 �젙蹂대�� �씠硫붿씪 �쟾�넚�뿉 �궗�슜�븯湲� �쐞�빐 Map �삎�깭濡� 蹂��솚�븳�떎.
         this.makeIssueMapToIssue(issue, issueMap);
@@ -251,8 +400,16 @@
             assigneeBuilder.append(")");
             assigneeBuilder.append("\n");
         }
-
         issueMap.put("assignees", assigneeBuilder.toString());
+
+        //  �떞�떦遺��꽌
+        StringBuilder departsBuilder = new StringBuilder();
+        for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
+            departsBuilder.append(issueDepartment.getDepartment().getDepartmentName());
+            departsBuilder.append("\n");
+        }
+        issueMap.put("departsBuilder", departsBuilder.toString());
+
         //  湲곌컙
         if (!StringUtils.isEmpty(issue.getStartDate())) {
             issueMap.put("period", issue.getStartDate() + " ~ " + issue.getCompleteDate());
@@ -303,6 +460,9 @@
 
         issueMap.put("customFields", customFields);
         issueMap.put("description", issue.getDescription());
+
+        //�뾽泥�,ISP,HOSTING 異붽�
+
 
         StringBuilder attachedFileBuilder = new StringBuilder();
 
@@ -383,14 +543,15 @@
         issueCondition.setIssueIds(issueKeys);
 
         List<Map<String, Object>> results = this.issueMapper.find(issueCondition);
+
         //  �뒠�떇 �쟾 - 0.8, 0.9, 0.9, 0.9, 0.9
-        StopWatch serviceStart = new StopWatch();
-        serviceStart.start();
+        /*StopWatch serviceStart = new StopWatch();
+        serviceStart.start();*/
         Long totalCount = this.issueMapper.count(issueCondition);
         //  �뒠�떇 �쟾 - 1.1, 1.1, 1.3, 1.2
 
-        serviceStart.stop();
-        log.debug("serviceENd1 : " + serviceStart.getTime());
+        /*serviceStart.stop();
+        log.debug("serviceENd1 : " + serviceStart.getTime());*/
 
         int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1;
         //  �씠�뒋 �븘�씠�뵒 珥덇린�솕
@@ -411,7 +572,7 @@
     @Override
     @Transactional(readOnly = true)
     public List<IssueVo> findChartIssue(Map<String, Object> resJsonData,
-                                   IssueCondition issueCondition, Pageable pageable) {
+                                        IssueCondition issueCondition, Pageable pageable) {
 
         //  寃��깋 議곌굔�쓣 留뚮뱺�떎
         if (!this.makeIssueSearchCondition(issueCondition,Lists.newArrayList("01", "02", "03"), pageable)) {
@@ -514,7 +675,8 @@
         }
 
         //  �씠�뒋 �궗�슜�옄 �젙蹂� 異붽�
-        this.setIssueUserList(issueVos, issueCondition);
+        //this.setIssueUserList(issueVos, issueCondition);
+        this.setIssueDepartmentList(issueVos, issueCondition);
         //  �벑濡앹옄 �젙蹂� 異붽�
         this.setRegister(issueVos);  //  �떞�떦�옄 �젙蹂� �뀑�똿
 
@@ -522,7 +684,7 @@
         this.setIssueCustomFieldValue(issueVos, issueCondition);
     }
 
-        //  寃��깋 議곌굔�쓣 留뚮뱺�떎
+    //  寃��깋 議곌굔�쓣 留뚮뱺�떎
     private boolean makeIssueSearchCondition(IssueCondition condition, List<String> projectStatues, Pageable pageable) {
         if (pageable != null) {
             condition.setPage(pageable.getPageNumber() * pageable.getPageSize());
@@ -694,6 +856,43 @@
         }
     }
 
+    //  �씠�뒋 �떞�떦遺��꽌 �젙蹂대�� �뀑�똿�븳�떎.
+    private void setIssueDepartmentList(List<IssueVo> issueVos, IssueCondition issueCondition) {
+        if (issueVos.size() < 1) {
+            return;
+        }
+
+        List<Map<String, Object>> issueDepartments = this.issueMapper.findIssueDepartment(issueCondition);
+        Map<String, Object> issueConverterDepartments = new HashMap<>();
+
+        //  �씠�뒋�뿉 �빐�떦�븯�뒗 �씠�뒋 �떞�떦遺��꽌 �젙蹂� �뀑�똿
+        for (Map<String, Object> issueDepartment : issueDepartments) {
+            String issueId = MapUtil.getString(issueDepartment, "issueId");
+
+            if (MapUtil.getObject(issueConverterDepartments, issueId) != null) {
+                List<DepartmentVo> departments = (List) MapUtil.getObject(issueConverterDepartments, issueId);
+                departments.add(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription")));
+            } else {
+                List<DepartmentVo> departments = Lists.newArrayList(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription")));
+                issueConverterDepartments.put(issueId, departments);
+            }
+        }
+
+        //  �씠�뒋Vo�뿉 �떞�떦遺��꽌 �젙蹂대�� �뀑�똿
+        for (IssueVo issueVo : issueVos) {
+            if (MapUtil.getObject(issueConverterDepartments, String.valueOf(issueVo.getId())) != null) {
+                List<DepartmentVo> departmentVos = (List) MapUtil.getObject(issueConverterDepartments, String.valueOf(issueVo.getId()));
+
+                issueVo.setDepartmentVos(departmentVos);
+            }
+
+            //  �씠�뒋 �닔�젙 沅뚰븳�쓣 媛뽮퀬 �엳�뒗吏� �솗�씤
+            if (this.checkHasPermission(issueVo, issueVo.getUserVos())) {
+                issueVo.setModifyPermissionCheck(Boolean.TRUE);
+            }
+        }
+    }
+
     //  �씠�뒋 �긽�꽭 �젙蹂대�� 議고쉶�븳�떎.
     @Override
     @Transactional(readOnly = true)
@@ -705,7 +904,7 @@
             issueVo = ConvertUtil.copyProperties(issue, IssueVo.class);
 
             switch (issueCondition.getDeep()) {
-                case "01": //  �봽濡쒖젥�듃, �씠�뒋 �쑀�삎, �씠�뒋 �긽�깭,  �슦�꽑�닚�쐞, 以묒슂�룄, �떞�떦�옄, 泥⑤��뙆�씪, �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� �뀑�똿�븳�떎.
+                case "01": //  �봽濡쒖젥�듃, �씠�뒋 �쑀�삎, �씠�뒋 �긽�깭,  �슦�꽑�닚�쐞, 以묒슂�룄, �떞�떦遺��꽌, 泥⑤��뙆�씪, �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� �뀑�똿�븳�떎.
                     issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class));
                     issueVo.setIssueTypeVo(ConvertUtil.copyProperties(issue.getIssueType(), IssueTypeVo.class));
                     issueVo.setIssueStatusVo(ConvertUtil.copyProperties(issue.getIssueStatus(), IssueStatusVo.class));
@@ -713,14 +912,18 @@
                     issueVo.setSeverityVo(ConvertUtil.copyProperties(issue.getSeverity(), SeverityVo.class));
 
                     this.setRegister(issue, issueVo);   //  �벑濡앹옄 �젙蹂� �뀑�똿
-                    this.setIssueUser(issue, issueVo);  //  �떞�떦�옄 �젙蹂� �뀑�똿
+                    //this.setIssueUser(issue, issueVo);  //  �떞�떦�옄 �젙蹂� �뀑�똿
+                    this.setIssueDepartment(issue, issueVo);  //  �떞�떦遺��꽌 �젙蹂� �뀑�똿
                     this.setAttachedFiles(issue, issueVo);  //  泥⑤� �뙆�씪 �젙蹂� �뀑�똿
                     this.setIssueCustomFields(issue, issueVo);  //  �궗�슜�옄 �젙�쓽 �븘�뱶 媛� �젙蹂� �뀑�똿
                     this.setRelationIssue(issue, issueVo);        //�뿰愿� �씪媛� �뀑�똿
+                    this.setDownIssues(issue, issueVo); //�븯�쐞 �씠�뒋 �꽭�똿
+
                     break;
 
                 case "02": //  �봽濡쒖젥�듃, �씠�뒋 �쑀�삎, �씠�뒋 �긽�깭,  �슦�꽑�닚�쐞, 以묒슂�룄, �떞�떦�옄, 泥⑤��뙆�씪, �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂�, �뙎湲�, 湲곕줉�쓣 �뀑�똿�븳�떎.
                     this.setIssueDetail(issueVo, issue);    //  �씠�뒋 �긽�꽭 �젙蹂대�� �뀑�똿�븳�떎.
+                    issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class));
                     break;
             }
         }
@@ -729,6 +932,30 @@
         log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_DETAIL));
 
         resJsonData.put(Constants.RES_KEY_CONTENTS, issueVo);
+    }
+
+    // �븯�쐞 �씠�뒋 �젙蹂대�� �뀑�똿�븳�떎
+    private void setDownIssues(Issue issue, IssueVo issueVo) {
+        List<Issue> downIssues = this.issueRepository.findByParentIssueId(issue.getId());
+        List<IssueVo> downIssueVos = ConvertUtil.convertObjectsToClasses(downIssues, IssueVo.class);
+        List<IssueVo> resultList = new ArrayList<>();
+        if(downIssues != null && downIssueVos.size()>0){
+            for(IssueVo downIssueVo : downIssueVos){
+                for(Issue downIssue : downIssues){
+                    downIssueVo.setTitle(downIssue.getTitle());
+                    downIssueVo.setIssueTypeVo(ConvertUtil.copyProperties(downIssue.getIssueType(), IssueTypeVo.class));
+                    downIssueVo.setPriorityVo(ConvertUtil.copyProperties(downIssue.getPriority(), PriorityVo.class));
+                    downIssueVo.setSeverityVo(ConvertUtil.copyProperties(downIssue.getSeverity(), SeverityVo.class));
+                    this.setRegister(downIssue, downIssueVo); // �벑濡앹옄
+                    this.setIssueDepartment(downIssue, downIssueVo);  //  �떞�떦遺��꽌 �젙蹂� �뀑�똿
+                    this.setIssueCustomFields(downIssue, downIssueVo);   // �궗�슜�옄�젙�쓽�븘�뱶 �젙蹂� �꽭�똿
+                }
+                resultList.add(downIssueVo);
+            }
+            issueVo.setIssueDownVos(resultList); //�봽濡좏듃�뿉�꽌 List�삎�깭濡� 諛쏆븘以섏꽌 由ъ뒪�듃 �삎�떇�쑝濡� 蹂대궡以�
+        }else{
+            issueVo.setIssueDownVos(null);
+        }
     }
 
     //  �씠�뒋 �긽�꽭 �젙蹂대�� �뀑�똿�븳�떎.
@@ -743,12 +970,41 @@
         issueVo.setPriorityVo(ConvertUtil.copyProperties(issue.getPriority(), PriorityVo.class));
         issueVo.setSeverityVo(ConvertUtil.copyProperties(issue.getSeverity(), SeverityVo.class));
         this.setRegister(issue, issueVo);   //  �벑濡앹옄 �젙蹂� �뀑�똿
-        this.setIssueUser(issue, issueVo);  //  �떞�떦�옄 �젙蹂� �뀑�똿
+        //this.setIssueUser(issue, issueVo);  //  �떞�떦�옄 �젙蹂� �뀑�똿
+        this.setIssueDepartment(issue, issueVo);  //  �떞�떦遺��꽌 �젙蹂� �뀑�똿
         this.setAttachedFiles(issue, issueVo);  //  泥⑤� �뙆�씪 �젙蹂� �뀑�똿
         this.setIssueCustomFields(issue, issueVo);  //  �궗�슜�옄 �젙�쓽 �븘�뱶 媛� �젙蹂� �뀑�똿
         this.setIssueComments(issue, issueVo);  //  �뙎湲� �젙蹂� �뀑�똿
         this.setIssueHistory(issue, issueVo);   //  �씠�뒋 湲곕줉 �젙蹂� �뀑�똿
         this.setRelationIssue(issue, issueVo);        //�뿰愿� �씪媛� �뀑�똿
+        this.setDownIssues(issue, issueVo); //�븯�쐞 �씪媛� �꽭�똿
+
+        IssueType issueType = this.issueTypeService.getIssueType(issueVo.getIssueTypeVo().getId()); // �씠�뒋�쓽 �씠�뒋�쑀�삎 媛앹껜
+        Integer using = issueType.getUsePartner() != null ? issueType.getUsePartner().intValue() : 0; // �씠�뒋�쑀�삎蹂꾨줈 �궗�슜以묒씤 �뾽泥�/ISP/�샇�뒪�똿 媛�
+
+        List<UsePartnerVo> usePartnerVos = Lists.newArrayList();
+        for (Integer usePartner : UsePartner.partners) { //1(�뾽泥�), 2(ISP), 4(�샇�뒪�똿)
+            UsePartnerVo usePartnerVo = UsePartner.checkUsePartner(using, usePartner);
+
+            if (usePartnerVo != null) {
+                usePartnerVos.add(usePartnerVo);
+                //useCompanyVo.setValues();
+            }
+            issueVo.setUsePartnerVos(usePartnerVos);
+        }
+
+        this.setIssueCompanyField(issue, issueVo);  //�뾽泥� �젙蹂� �꽭�똿
+        this.setIssueIspField(issue, issueVo);  //ISP �젙蹂� �꽭�똿
+        this.setIssueHostingField(issue, issueVo);  //HOSTING �젙蹂� �꽭�똿
+
+        this.setParentIssue(issue,issueVo); //�긽�쐞 �씠�뒋 �젙蹂� �꽭�똿
+    }
+
+    //  �긽�쐞�씪媛� �젙蹂� 異붽�
+    private void setParentIssue(Issue issue, IssueVo issueVo) {
+        if(issue.getParentIssue() != null){
+            issueVo.setParentIssueVo(ConvertUtil.copyProperties(issue.getParentIssue(), IssueVo.class));
+        }
     }
 
     //  �벑濡앹옄 �젙蹂� 異붽�
@@ -787,6 +1043,12 @@
 
                 issueRelationVo.setIssueRelation(relIssueVo);
                 issueRelationVo.setTitle(relationIssue.getTitle());
+                issueRelationVo.setIssueTypeVo(ConvertUtil.copyProperties(relationIssue.getIssueType(), IssueTypeVo.class));
+                issueRelationVo.setPriorityVo(ConvertUtil.copyProperties(relationIssue.getPriority(), PriorityVo.class));
+                issueRelationVo.setSeverityVo(ConvertUtil.copyProperties(relationIssue.getSeverity(), SeverityVo.class));
+                this.setRegister(relationIssue, relIssueVo); // �벑濡앹옄
+                this.setIssueDepartment(relationIssue, relIssueVo);  //  �떞�떦遺��꽌 �젙蹂� �뀑�똿
+                this.setIssueCustomFields(relationIssue, relIssueVo);   // �궗�슜�옄�젙�쓽�븘�뱶 �젙蹂� �꽭�똿
                 issueVo.addIssueRelationVo(issueRelationVo);
             }
         } else {
@@ -795,7 +1057,7 @@
     }
 
     //  �씠�뒋 �떞�떦�옄 �젙蹂대�� �뀑�똿�븳�떎.
-    private void setIssueUser(Issue issue, IssueVo issueVo) {
+    /*private void setIssueUser(Issue issue, IssueVo issueVo) {
         List<UserVo> userVos = Lists.newArrayList();
 
         for (IssueUser issueUser : issue.getIssueUsers()) {
@@ -828,6 +1090,18 @@
         }
 
         issueVo.setUserVos(userVos);
+    }*/
+
+    //  �씠�뒋 �떞�떦遺��꽌 �젙蹂대�� �뀑�똿�븳�떎.
+    private void setIssueDepartment(Issue issue, IssueVo issueVo) {
+        List<DepartmentVo> departmentVos = Lists.newArrayList();
+
+        for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
+            DepartmentVo departmentVo = ConvertUtil.copyProperties(issueDepartment.getDepartment(), DepartmentVo.class);
+            departmentVo.setByName(departmentVo.getDepartmentName());
+            departmentVos.add(departmentVo);
+        }
+        issueVo.setDepartmentVos(departmentVos);
     }
 
     //  �씠�뒋 泥⑤��뙆�씪 �젙蹂대�� �뀑�똿�븳�떎.
@@ -892,7 +1166,9 @@
         this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate());
 
         //  �떞�떦�옄 �쑀�슚�꽦 泥댄겕
-        this.verifyIssueAssignee(project, issueForm);
+        //this.verifyIssueAssignee(project, issueForm);
+        //  �떞�떦遺��꽌 �쑀�슚�꽦 泥댄겕
+        this.verifyIssueDepartment(project, issueForm);
 
         Issue issue = this.getIssue(issueForm.getId());
 
@@ -920,8 +1196,11 @@
         issue.setCompleteDate(issueForm.getCompleteDate());
 
         this.issueRepository.saveAndFlush(issue);
-        //  �떞�떦�옄 吏��젙
-        this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
+        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
+        //  �떞�떦遺��꽌 吏��젙
+        if(issueForm.getDepartmentIds().size()>0){
+            this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
+        }
 
         //  multipartFile �쓣 file Map List 媛앹껜濡� 蹂�寃쏀븳�떎.
         List<Map<String, Object>> convertFileMaps = this.convertMultipartFileToFile(multipartFiles);
@@ -938,9 +1217,15 @@
         if (!StringUtils.isEmpty(detectIssueChange.toString())) {
             this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, detectIssueChange.toString());
         }
-
         //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
         log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_MODIFY));
+
+        //  �뾽泥� �젙蹂� ���옣
+        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
+        //  ISP �젙蹂� ���옣
+        this.issueIspService.modifyIssueIspField(issue, issueForm.getIssueIspFields());
+        //  HOSTING �젙蹂� ���옣
+        this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields());
 
         return issue;
     }
@@ -949,12 +1234,14 @@
     private List<Map<String, Object>> convertMultipartFileToFile(List<MultipartFile> multipartFiles) {
         List<Map<String, Object>> convertFileMaps = Lists.newArrayList();
 
-        for (MultipartFile multipartFile : multipartFiles) {
-            try {
-                Map<String, Object> fileMap = CommonUtil.makeFileMap(multipartFile);
-                convertFileMaps.add(fileMap);
-            } catch (Exception e) {
-                log.debug("multipartFile -> file 蹂��솚 �삤瑜�" + e.getMessage());
+        if (multipartFiles != null && multipartFiles.size() > 0) {
+            for (MultipartFile multipartFile : multipartFiles) {
+                try {
+                    Map<String, Object> fileMap = CommonUtil.makeFileMap(multipartFile);
+                    convertFileMaps.add(fileMap);
+                } catch (Exception e) {
+                    log.debug("multipartFile -> file 蹂��솚 �삤瑜�" + e.getMessage());
+                }
             }
         }
 
@@ -994,6 +1281,35 @@
         return false;
     }
 
+    //  �씠�뒋 �떞�떦遺��꽌濡� 吏��젙�맆 遺��꽌媛� �빐�떦 �봽濡쒖젥�듃�뿉 李몄뿬 �븯怨� �엳�뒗 遺��꽌�씤吏� �솗�씤
+    private void verifyIssueDepartment(Project project, IssueForm issueForm) {
+        if (issueForm.getDepartmentIds().size() > 0) {
+            List<Long> trustDepartmentIds = Lists.newArrayList(); //  李몄뿬 �솗�씤�맂 遺��꽌
+
+            for (Long departmentId : issueForm.getDepartmentIds()) {
+                boolean includeProject = false;
+
+                for (ProjectRole projectRole : project.getProjectRoles()) {
+                    ProjectRoleDepartment projectRoleDepartment = this.projectRoleDepartmentService.findByProjectRoleIdAndDepartmentId(projectRole.getId(), departmentId);
+
+                    if (projectRoleDepartment != null) {
+                        includeProject = true;
+                        trustDepartmentIds.add(departmentId);
+                        break;
+                    }
+                }
+
+                //  �뜲�씠�꽣 蹂댁젙 �옉�뾽 - �봽濡쒖젥�듃�뿉�꽌 �젣�쇅�맂 �궗�슜�옄�뒗 �떞�떦�옄�뿉�꽌 �젣�쇅 �맆 �닔 �엳�룄濡� 泥섎━
+                if (!includeProject) {
+                    throw new OwlRuntimeException(
+                            this.messageAccessor.getMessage(MsgConstants.PROJECT_NOT_INCLUDE_DEPARTMENT));
+                }
+            }
+            //  李몄뿬 �솗�씤�맂 遺��꽌濡� �떞�떦遺��꽌 蹂�寃�
+            issueForm.setDepartmentIds(trustDepartmentIds);
+        }
+    }
+
     //  �씠�뒋 �떞�떦�옄濡� 吏��젙�맆 �궗�슜�옄媛� �빐�떦 �봽濡쒖젥�듃�뿉 李몄뿬 �븯怨� �엳�뒗 �궗�슜�옄 �씤吏� �솗�씤
     private void verifyIssueAssignee(Project project, IssueForm issueForm) {
         if (issueForm.getUserIds().size() > 0) {
@@ -1013,10 +1329,10 @@
                 }
 
                 //  �뜲�씠�꽣 蹂댁젙 �옉�뾽 - �봽濡쒖젥�듃�뿉�꽌 �젣�쇅�맂 �궗�슜�옄�뒗 �떞�떦�옄�뿉�꽌 �젣�쇅 �맆 �닔 �엳�룄濡� 泥섎━
-                /*if (!includeProject) {
+                if (!includeProject) {
                     throw new OwlRuntimeException(
                             this.messageAccessor.getMessage(MsgConstants.PROJECT_NOT_INCLUDE_USER));
-                }*/
+                }
             }
             //  李몄뿬 �솗�씤�맂 �궗�슜�옄濡� �떞�떦�옄 蹂�寃�
             issueForm.setUserIds(trustUserIds);
@@ -1051,20 +1367,20 @@
         boolean hasPermission = false;
 
         //  �뾽臾� 怨듦컙 愿�由ъ옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
-        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.WORKSPACE_MANAGER, issueVo, null);
+        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.WORKSPACE_MANAGER, issueVo, null, null);
         //  �봽濡쒖젥�듃 愿�由ъ옄�씪 寃쎌슦 �빐�떦 �봽濡쒖젥�듃�뿉 �벑濡앸맂 �씠�뒋�뒗 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
-        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.PROJECT_MANAGER, issueVo, null);
+        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.PROJECT_MANAGER, issueVo, null, null);
         //   �씠�뒋 �벑濡앹옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
-        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.REGISTER, issueVo, null);
-        //  �씠�뒋 �떞�떦�옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
-        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ASSIGNEE, issueVo, issueUserVos);
+        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.REGISTER, issueVo, null, null);
+        //  �씠�뒋 �떞�떦�옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎. => �떞�떦遺��꽌濡� �닔�젙 - 泥댄겕
+        //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ASSIGNEE, issueVo, issueUserVos);
         //  �떞�떦�옄媛� �뾾�쑝硫� 紐⑤뱺 �궗�슜�옄媛� �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
 
         return hasPermission;
     }
 
     //  �씠�뒋 �닔�젙 沅뚰븳�쓣 �솗�씤�븳�떎.
-    private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List<UserVo> issueUserVos) {
+    private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List<UserVo> issueUserVos, List<DepartmentVo> issueDepartmentVos) {
         if (!hasPermission) {
             switch (checkType) {
                 case Issue.WORKSPACE_MANAGER:  //  �뾽臾� 怨듦컙 愿�由ъ옄
@@ -1088,7 +1404,6 @@
                         hasPermission = true;
                         break;
                     }
-
                     //   �씠�뒋 �떞�떦�옄 �뿬遺� �솗�씤
                     for (UserVo issueUserVo : issueUserVos) {
                         if (issueUserVo.getId().equals(this.webAppUtil.getLoginId())) {
@@ -1096,7 +1411,21 @@
                             break;
                         }
                     }
+                    break;
 
+                case Issue.DEPARTMENT:
+                    //  �떞�떦遺��꽌媛� �뾾�쑝硫� 紐⑤뱺 �궗�슜�옄媛� �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
+                    if (issueDepartmentVos.size() < 1) {
+                        hasPermission = true;
+                        break;
+                    }
+                    //   �씠�뒋 �떞�떦遺��꽌 �뿬遺� �솗�씤
+                    /*for (DepartmentVo issueDepartmentVo : issueDepartmentVos) {
+                        if (issueDepartmentVo.getId().equals()) {
+                            hasPermission = true;
+                            break;
+                        }
+                    }*/
                     break;
             }
         }
@@ -1166,7 +1495,43 @@
         //  蹂�寃� �씠�젰 �젙蹂� 異붿텧
         this.issueHistoryService.detectIssueManager(issue, issueForm, detectIssueChange);
 
-        this.issueUserService.modifyIssueUser(issue, issue.getProject().getWorkspace(), issueForm.getUserIds());
+        this.issueUserService.modifyIssueUser(issue, issue.getProject().getWorkspace(), issueForm.getDepartmentIds()); //getUserIds -> getDepartmentIds
+        this.issueRepository.saveAndFlush(issue);
+
+        //  �씠�뒋 �씠�젰 �벑濡�
+        if (!StringUtils.isEmpty(detectIssueChange.toString())) {
+            StringBuilder stringBuilder = new StringBuilder();
+            stringBuilder.append("<ul class=\"activity-list\">");
+            stringBuilder.append(detectIssueChange.toString());
+            stringBuilder.append("</ul>");
+
+            this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, stringBuilder.toString());
+        }
+
+        //  �씠�뒋 踰꾩쟾 �깮�꽦
+        this.issueVersionService.addIssueVersion(issue);
+
+        //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
+        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_USER_CHANGE));
+    }
+
+    @Override
+    @Transactional
+    public void modifyIssueDepartment(IssueForm issueForm) {
+        //  �궗�슜�븯怨� �엳�뒗 �뾽臾� 怨듦컙�씠 �솢�꽦 �긽�깭�씤吏� �솗�씤�븳�떎. �궗�슜 怨듦컙�뿉�꽌 濡쒓렇�씤�븳 �궗�슜�옄媛� 鍮꾪솢�꽦�씤吏� �솗�씤�븳�떎.
+        this.workspaceService.checkUseWorkspace();
+        //  蹂�寃� �씠�젰 �젙蹂� 異붿텧
+        StringBuilder detectIssueChange = new StringBuilder();
+        //  �씠�뒋 �닔�젙 沅뚰븳 泥댄겕
+        this.verifyIssueModifyPermission(issueForm.getId());
+        Issue issue = this.getIssue(issueForm.getId());
+        issue.setProject(this.projectService.getProject(issueForm.getProjectId()));
+
+        //  蹂�寃� �씠�젰 �젙蹂� 異붿텧
+        this.issueHistoryService.detectIssueDepartment(issue, issueForm, detectIssueChange);
+
+        //this.issueUserService.modifyIssueUser(issue, issue.getProject().getWorkspace(), issueForm.getUserIds());
+        this.issueDepartmentService.modifyIssueDepartment(issue, issue.getProject().getWorkspace(), issueForm.getDepartmentIds());
         this.issueRepository.saveAndFlush(issue);
 
         //  �씠�뒋 �씠�젰 �벑濡�
@@ -1230,7 +1595,7 @@
         }
 
         //  �씠�뒋 �깮�꽦, �궘�젣�떆 �삁�빟 �씠硫붿씪�뿉 �벑濡앺빐�넃�뒗�떎.
-        this.reservationIssueEmail(issue.getId(), EmailType.ISSUE_REMOVE);
+        this.reservationIssueEmail(issue, EmailType.ISSUE_REMOVE);
         //  �씠�뒋 �궘�젣
         this.issueRepository.delete(issue);
 
@@ -1353,7 +1718,7 @@
         excelInfo.addAttrInfos(new ExportExcelAttrVo("title", this.messageAccessor.message("common.issueTitle"), 40, ExportExcelAttrVo.ALIGN_LEFT)); // �씠�뒋 �젣紐�
         excelInfo.addAttrInfos(new ExportExcelAttrVo("description", this.messageAccessor.message("common.content"), 60, ExportExcelAttrVo.ALIGN_LEFT)); // �궡�슜
         excelInfo.addAttrInfos(new ExportExcelAttrVo("issueTypeName", this.messageAccessor.message("common.issueType"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �씠�뒋 ���엯
-        excelInfo.addAttrInfos(new ExportExcelAttrVo("assignees", this.messageAccessor.message("common.assignee"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �떞�떦�옄
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("departments", this.messageAccessor.message("common.department"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �떞�떦遺��꽌
         excelInfo.addAttrInfos(new ExportExcelAttrVo("priorityName", this.messageAccessor.message("common.priority"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // �슦�꽑�닚�쐞
         excelInfo.addAttrInfos(new ExportExcelAttrVo("severityName", this.messageAccessor.message("common.importance"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // 以묒슂�룄
         excelInfo.addAttrInfos(new ExportExcelAttrVo("register", this.messageAccessor.message("common.register"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �벑濡앹옄
@@ -1431,6 +1796,55 @@
         }
     }
 
+    //  �뾽泥� �젙蹂� 異붽�
+    private void setIssueCompanyField(Issue issue, IssueVo issueVo) {
+        List<IssueCompanyVo> issueCompanyVos = Lists.newArrayList();
+
+        for(IssueCompany issueCompany : issue.getIssueCompanies()){
+            IssueCompanyVo issueCompanyVo = ConvertUtil.copyProperties(issueCompany, IssueCompanyVo.class);
+            issueCompanyVo.setId(issueCompany.getId());
+            CompanyField companyField = issueCompany.getCompanyField();
+            if (companyField != null) {
+                issueCompanyVo.setCompanyId(issueCompany.getCompanyField().getId());
+            }
+            issueCompanyVos.add(issueCompanyVo);
+        }
+        issueVo.setIssueCompanyVos(issueCompanyVos);
+    }
+
+    //  Isp �젙蹂� 異붽�
+    private void setIssueIspField(Issue issue, IssueVo issueVo) {
+        List<IssueIspVo> issueIspVos = Lists.newArrayList();
+
+        for(IssueIsp issueIsp : issue.getIssueIspFields()){
+            IssueIspVo issueIspVo = ConvertUtil.copyProperties(issueIsp, IssueIspVo.class);
+            issueIspVo.setId(issueIsp.getId());
+            IspField ispField = issueIsp.getIspField();
+            if (ispField != null) {
+                issueIspVo.setIspId(ispField.getId());
+            }
+            issueIspVos.add(issueIspVo);
+        }
+        issueVo.setIssueIspVos(issueIspVos);
+    }
+
+    // Hosting �젙蹂� 異붽�
+    private void setIssueHostingField(Issue issue, IssueVo issueVo) {
+        List<IssueHostingVo> issueHostingVos = Lists.newArrayList();
+
+        for(IssueHosting issueHosting : issue.getIssueHostingFields()){
+            IssueHostingVo issueHostingVo = ConvertUtil.copyProperties(issueHosting, IssueHostingVo.class);
+            issueHostingVo.setId(issueHosting.getId());
+            HostingField hostingField = issueHosting.getHostingField();
+            if (hostingField != null) {
+                issueHostingVo.setHostingId(hostingField.getId());
+            }
+
+            issueHostingVos.add(issueHostingVo);
+        }
+        issueVo.setIssueHostingVos(issueHostingVos);
+    }
+
     //  �뿰愿��씪媛� �젙蹂� 異붽�
     private void setRelationIssue(IssueVo issueVo, Long issueId) {
         List<IssueVo> relationIssues = this.issueRelationService.findRelationIssue(issueId);
@@ -1458,6 +1872,7 @@
                 result.put("description", description);
                 result.put("issueTypeName", issueVo.getIssueTypeName());
                 result.put("assignees", CommonUtil.convertUserVosToString(issueVo.getUserVos()));
+                result.put("departments", CommonUtil.convertDepartmentVosToString(issueVo.getDepartmentVos()));
                 result.put("priorityName", issueVo.getPriorityName());
                 result.put("severityName", issueVo.getSeverityName());
 
@@ -1484,6 +1899,8 @@
                     }
                 }
 
+                //�뾽泥�, ISP, �샇�뒪�똿 異붽�
+
                 results.add(result);
             } catch (Exception e) {
                 log.error("�뿊�� �떎�슫濡쒕뱶 �삤瑜� 諛쒖깮");
@@ -1504,6 +1921,14 @@
             issueForm.setId(issueId);
             //  �씠�뒋 �긽�깭 蹂�寃�
             this.modifyIssueStatus(issueForm);
+        }
+
+        // �떞�떦 遺��꽌 �닔�젙
+        if (issueForm.getDepartmentIds().size() > 0) {
+            Issue issue = this.getIssue(issueForm.getId());
+            Project project = this.projectService.getProject(issueForm.getProjectId());
+
+            this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
         }
     }
 
@@ -1529,7 +1954,7 @@
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.issueType"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �씠�뒋 ���엯
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.priority"), 5, ExportExcelAttrVo.ALIGN_CENTER)); // �슦�꽑�닚�쐞
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.importance"), 5, ExportExcelAttrVo.ALIGN_CENTER)); // 以묒슂�룄
-        excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.assignee"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �떞�떦�옄
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.department"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �떞�떦遺��꽌
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.startDate"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �떆�옉�씪
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.endDate"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // 醫낅즺�씪
         //  �봽濡쒖젥�듃�뿉 �뿰寃곕맂 �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� 異붿텧�븯�뿬 �뿊�� download �뀥�뵆由우쓣 留뚮뱺�떎.
@@ -1569,13 +1994,14 @@
             Map<String, Priority> priorityMaps = new HashMap<>();   //  �슦�꽑 �닚�쐞 紐⑥쓬
             Map<String, Severity> severityMaps = new HashMap<>();   //  以묒슂�룄 紐⑥쓬
             Map<String, Object> userMaps = new HashMap<>(); //  �궗�슜�옄 紐⑥쓬
+            Map<String, Object> departmentMaps = new HashMap<>(); //  遺��꽌 紐⑥쓬
             Map<String, CustomField> customFieldMaps = new HashMap<>();
             Map<String, IssueStatus> issueStatusReadyMaps = new HashMap<>();   //  �긽�깭 �냽�꽦 '��湲�'�씤 �씠�뒋 �긽�깭
             Map<Long, Long> issueNumberMaps = new HashMap<>();  //  �씠�뒋 踰덊샇 紐⑥쓬
             Map<String, Long> issueTypeCustomFieldMaps = new HashMap<>(); //  �씠�뒋 ���엯 + �궗�슜�옄 �젙�쓽 �븘�뱶 �뿰寃� �젙蹂�
             Workspace workspace = this.workspaceService.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());  //  �씠�뒋瑜� �꽔�쑝�젮�뒗 �뾽臾� 怨듦컙
             //  �씠�뒋�쓽 二쇱슂 �냽�꽦�쓣 map �뿉 ���옣�븯�뿬 �뿊�� import �뿉�꽌 吏��젙�븳 ���긽(�씠�뒋 �냽�꽦)�쓣 鍮좊Ⅴ寃� 李얠쓣 �닔 �엳寃� �븳�떎.
-            this.IssueAttributeMapToList(projectMaps, issueTypeMaps, priorityMaps, severityMaps, userMaps, customFieldMaps, issueNumberMaps, issueTypeCustomFieldMaps, issueStatusReadyMaps);
+            this.IssueAttributeMapToList(projectMaps, issueTypeMaps, priorityMaps, severityMaps, userMaps, departmentMaps, customFieldMaps, issueNumberMaps, issueTypeCustomFieldMaps, issueStatusReadyMaps);
             //  0.237 - 0.230
 
             List<IssueForm> issueForms = Lists.newArrayList();
@@ -1648,6 +2074,8 @@
             this.bulkInsertIssueCustomFieldValue(issueForms, issueTypeCustomFieldMaps);
             //  3.628 - 3.445
 
+            // �뾽泥�,ISP,�샇�뒪�똿 異붽�
+
             /*serviceStart.stop();
             log.debug("2李� ���옣 �떆媛� : " + serviceStart.getTime());*/
 
@@ -1701,10 +2129,11 @@
         List<Map<String, Long>> issueAssigneeMaps = Lists.newArrayList();
 
         for (IssueForm issueForm : issueForms) {
-            for (Long userId : issueForm.getUserIds()) {
+            for (Long departmentId : issueForm.getDepartmentIds()) {
                 Map<String, Long> issueAssigneeMap = new HashMap<>();
                 issueAssigneeMap.put("issueId", issueForm.getId());
-                issueAssigneeMap.put("userId", userId);
+                //issueAssigneeMap.put("userId", userId);
+                issueAssigneeMap.put("departmentId", departmentId);
                 issueAssigneeMap.put("workspaceId", workspace.getId());
                 issueAssigneeMap.put("registerId", this.webAppUtil.getLoginId());
                 issueAssigneeMaps.add(issueAssigneeMap);
@@ -1713,7 +2142,8 @@
 
         if (issueAssigneeMaps.size() > 0) {
             //  �씠�뒋 �떞�떦�옄 踰뚰겕 �벑濡�
-            this.issueUserService.insertIssueUser(issueAssigneeMaps);
+            //this.issueUserService.insertIssueUser(issueAssigneeMaps);
+            this.issueDepartmentService.insertIssueDepartment(issueAssigneeMaps);
         }
     }
 
@@ -1724,6 +2154,7 @@
             Map<String, Long> issueRiskMap = new HashMap<>();
             issueRiskMap.put("issueId", issueForm.getId());
             issueRiskMap.put("changeAssigneeCount", 0L);
+            issueRiskMap.put("changeDepartmentCount", 0L);
             issueRiskMap.put("changeIssueStatusCount", 0L);
             issueRiskMap.put("workspaceId", workspace.getId());
             issueRiskMap.put("issueStatusIds", issueForm.getIssueStatusId());
@@ -1764,7 +2195,7 @@
 
     //  �씠�뒋�쓽 二쇱슂 �냽�꽦�쓣 map �뿉 ���옣�븯�뿬 �뿊�� import �뿉�꽌 吏��젙�븳 ���긽(�씠�뒋 �냽�꽦)�쓣 鍮좊Ⅴ寃� 李얠쓣 �닔 �엳寃� �븳�떎.
     private void IssueAttributeMapToList(Map<String, Project> projectMaps, Map<String, IssueType> issueTypeMaps, Map<String, Priority> priorityMaps, Map<String, Severity> severityMaps,
-                                         Map<String, Object> userMaps, Map<String, CustomField> customFieldMaps, Map<Long, Long> issueNumberMaps, Map<String, Long> issueTypeCustomFieldMaps, Map<String, IssueStatus> issueStatusReadyMaps) {
+                                         Map<String, Object> userMaps, Map<String, Object> departmentMaps, Map<String, CustomField> customFieldMaps, Map<Long, Long> issueNumberMaps, Map<String, Long> issueTypeCustomFieldMaps, Map<String, IssueStatus> issueStatusReadyMaps) {
         //  �봽濡쒖젥�듃 �궎濡� 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
         List<Project> projects = this.projectService.findByWorkspaceId();
         List<Long> projectIds = Lists.newArrayList();
@@ -1790,6 +2221,14 @@
             }
 
             userMaps.put(project.getProjectKey(), userMap);
+
+            //  �봽濡쒖젥�듃�뿉 李몄뿬�븯�뒗 遺��꽌 �젙蹂�
+            List<Map<String, Object>> departments = this.departmentService.findProjectDepartment(project);
+            List<Long> departmentList = Lists.newArrayList();
+            //  遺��꽌 �젙蹂대�� ���옣
+            for (Map<String, Object> department : departments) {
+                departmentList.add(MapUtil.getLong(department, "departmentId"));
+            }
         }
 
         //  �씠�뒋 �쑀�삎�쓣 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
@@ -1867,7 +2306,7 @@
                     this.setIssueFormSeverity(cell, severityMaps, issueForm, rowIndex);
                     break;
                 case 6:
-                    //  �떞�떦�옄瑜� IssueForm �뿉 ���옣�븳�떎.
+                    //  �떞�떦遺��꽌瑜� IssueForm �뿉 ���옣�븳�떎.
                     this.setIssueFormAssignee(cell, userMaps, issueForm, project);
                     break;
                 case 7:
@@ -2008,21 +2447,21 @@
         issueForm.setSeverityId(severity.getId());
     }
 
-    //  �떞�떦�옄瑜� IssueForm �뿉 ���옣�븳�떎.
+    //  �떞�떦遺��꽌瑜� IssueForm �뿉 ���옣�븳�떎.
     private void setIssueFormAssignee(Cell cell, Map<String, Object> userMaps, IssueForm issueForm, Project project) {
         if (cell != null) {
             String[] splitAssignee = CommonUtil.convertExcelStringToCell(cell).split("#");
             Map<String, Object> userMap = (Map<String, Object>) MapUtil.getObject(userMaps, project.getProjectKey());
 
-            List<Long> userIds = Lists.newArrayList();
+            List<Long> departmentIds = Lists.newArrayList();
 
             for (String account : splitAssignee) {
                 if (MapUtil.getLong(userMap, account) != null) {
-                    userIds.add(MapUtil.getLong(userMap, account));
+                    departmentIds.add(MapUtil.getLong(userMap, account));
                 }
             }
 
-            issueForm.setUserIds(userIds);
+            issueForm.setDepartmentIds(departmentIds);
         }
     }
 
@@ -2075,6 +2514,12 @@
 
             switch (customField.getCustomFieldType()) {
                 case INPUT:
+                case NUMBER:
+                case DATETIME:
+                case IP_ADDRESS:
+                case EMAIL:
+                case SITE:
+                case TEL:
                     if (cellValue.length() > 100) {
                         throw new OwlRuntimeException(
                                 this.messageAccessor.getMessage(MsgConstants.CUSTOM_FIELD_TEXT_TYPE_MAX_LENGTH_OUT));
@@ -2155,6 +2600,51 @@
         if (issueForm.getSendEmails().size() < 1) {
             throw new OwlRuntimeException(
                     this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
+        }else if (issueForm.getTemplate() != null){
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE));
+        }
+
+        Issue issue = this.getIssue(issueForm.getId());
+
+        Map<String, Object> issueMap = new HashMap<>();
+        //  �씠�뒋 �젙蹂대�� �씠硫붿씪 �쟾�넚�뿉 �궗�슜�븯湲� �쐞�빐 Map �삎�깭濡� 蹂��솚�븳�떎.
+        this.makeIssueMapToIssue(issue, issueMap);
+        //  諛쒖떊�옄 �몴�떆
+        UserVo toUser = this.webAppUtil.getLoginUser();
+        issueMap.put("toUser", toUser.getName() + "(" + CommonUtil.decryptAES128(toUser.getAccount()) + ")");
+
+        // �씠�뒋 留곹겕
+        String projectKey = issue.getProject().getProjectKey();
+        Long IssueNumber = issue.getIssueNumber();
+        String link = this.configuration.getEmailSendUrl() + "/#/issues/issueList?projectKey=" + projectKey + "&issueNumber=" + IssueNumber.toString();
+
+        issueMap.put("issueLink", link);
+        issueMap.put("projectLink", link);
+
+        //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
+        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL));
+        this.systemEmailService.directEmail(issueForm.getSendEmails().toArray(new String[issueForm.getSendEmails().size()]), EmailType.ISSUE_SEND, issueMap, null);
+
+        if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_1.toString())){
+            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_1, issueMap, null);
+        }else if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_2.toString())){
+            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_2, issueMap, null);
+        }else if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_3.toString())){
+            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_3, issueMap, null);
+        }
+    }
+
+    //  �씠�뒋瑜� �뀥�뵆由우뿉 �뵲�씪 �뙆�듃�꼫 �떞�떦�옄�뿉寃� 硫붿씪濡� 諛쒖넚�븳�떎.
+    @Override
+    @Transactional(readOnly = true)
+    public void sendIssueEmailPartners(IssueForm issueForm) {
+        if (issueForm.getSendEmails().size() < 1) {
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
+        }else if (issueForm.getTemplate() == null){
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE));
         }
 
         Issue issue = this.getIssue(issueForm.getId());
@@ -2177,7 +2667,13 @@
         //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
         log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL));
 
-        this.systemEmailService.directEmail(issueForm.getSendEmails().toArray(new String[issueForm.getSendEmails().size()]), EmailType.ISSUE_SEND, issueMap, null);
+        if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_1.toString())){
+            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_1, issueMap, null);
+        }else if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_2.toString())){
+            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_2, issueMap, null);
+        }else if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_3.toString())){
+            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_3, issueMap, null);
+        }
     }
 
     //  �삁�빟 諛쒖깮 �씠�뒋瑜� �떎�뻾�븳�떎
@@ -2285,17 +2781,24 @@
             taskUserSave.put(taskId.toString(), Lists.newArrayList());
         }
 
-        List<Map<String, Object>> taskUsers = Lists.newArrayList();
+        List<Map<String, Object>> taskDepartments = Lists.newArrayList();
         //  task 媛� �븯�굹�룄 �뾾�쓣 寃쎌슦�뿉�뒗 議고쉶瑜� �븯吏� �븡�뒗�떎.
         if (!taskCondition.getIssueIds().isEmpty()) {
-            taskUsers = this.issueMapper.getAllTaskUser(taskCondition);
+            //taskUsers = this.issueMapper.getAllTaskUser(taskCondition);
+            taskDepartments = this.issueMapper.getAllTaskUser(taskCondition);
         }
 
         //  task_id �뿉 留ㅼ묶�릺�뒗 �떞�떦�옄 �젙蹂대�� 以�鍮꾪븳�떎.
-        for (Map<String, Object> taskUser : taskUsers) {
+        /*for (Map<String, Object> taskUser : taskUsers) {
             Long taskId = MapUtil.getLong(taskUser, "taskId");
             List<UserVo> userVos = (List<UserVo>)taskUserSave.get(taskId.toString());
             userVos.add(ConvertUtil.convertMapToClass(taskUser, UserVo.class));
+        }*/
+
+        for (Map<String, Object> taskDepartment : taskDepartments) {
+            Long taskId = MapUtil.getLong(taskDepartment, "taskId");
+            List<DepartmentVo> departmentVos = (List<DepartmentVo>)taskUserSave.get(taskId.toString());
+            departmentVos.add(ConvertUtil.convertMapToClass(taskDepartment, DepartmentVo.class));
         }
 
         for (Map<String, Object> result : results) {
@@ -2320,8 +2823,12 @@
             }
 
             //  �떞�떦�옄 �뀑�똿
-            List<UserVo> userVos =  (List<UserVo>)taskUserSave.get(taskVo.getId().toString());
-            taskVo.setUserVos(userVos);
+            //List<UserVo> userVos =  (List<UserVo>)taskUserSave.get(taskVo.getId().toString());
+            //taskVo.setUserVos(userVos);
+
+            //  �떞�떦遺��꽌 �꽭�똿
+            List<DepartmentVo> departmentVos = (List<DepartmentVo>)taskUserSave.get(taskVo.getId().toString());
+            taskVo.setDepartmentVos(departmentVos);
 
             List<IssueVo> taskVos = (List<IssueVo>)tasks.get(MapUtil.getString(result, "workflowStatusId"));
             taskVos.add(taskVo);
@@ -2333,4 +2840,43 @@
 
         return tasks;
     }
+
+    @Transactional
+    @Override
+    public void modifyParentIssue(IssueForm issueDownForm) {
+        Issue issue = this.getIssue(issueDownForm.getId()); //�븯�쐞 �씠�뒋
+        Issue parentIssue = issue.getParentIssue(); //蹂�寃� �쟾 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋
+
+        Long newParentIssueId = issueDownForm.getParentIssueId(); //蹂�寃쏀븷 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋
+        StringBuilder sb = new StringBuilder();
+
+        if (newParentIssueId != null) { // 異붽� �븷 寃쎌슦
+            parentIssue = this.getIssue(newParentIssueId); //�긽�쐞�씠�뒋(myIssue)
+            issue.setParentIssue(parentIssue); //myIssue瑜� �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋濡� set
+            this.issueHistoryService.detectDownIssues(IssueHistoryType.ADD, issue, sb); //issue = �븯�쐞�씠�뒋
+        } else  {
+            // �궘�젣 �븷 寃쎌슦
+            this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
+            issue.setParentIssue(null);
+        }
+        this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); //parentIssue = myIssue(湲곕줉�� �쁽�옱 �긽�꽭�럹�씠吏��뿉 �빐�빞�븯�땲源�)
+        this.issueRepository.saveAndFlush(issue);
+
+    }
+
+    @Override
+    public void findPartner(Map<String, Object> resJsonData, Map<String, Object> params) {
+        Long issueTypeId = MapUtil.getLong(params, "issueTypeId");
+        IssueType issueType = this.issueTypeService.getIssueType(issueTypeId); // �씠�뒋�쓽 �씠�뒋�쑀�삎 媛앹껜
+        Integer using = issueType.getUsePartner() != null ? issueType.getUsePartner().intValue() : 0; // �씠�뒋�쑀�삎蹂꾨줈 �궗�슜以묒씤 �뾽泥�/ISP/�샇�뒪�똿 媛�
+
+        List<UsePartnerVo> usePartnerVos = Lists.newArrayList();
+        for (Integer usePartner : UsePartner.partners) { //1(�뾽泥�), 2(ISP), 4(�샇�뒪�똿)
+            UsePartnerVo usePartnerVo = UsePartner.checkUsePartner(using, usePartner);
+            if (usePartnerVo != null) {
+                usePartnerVos.add(usePartnerVo);
+            }
+            resJsonData.put(Constants.RES_KEY_CONTENTS, usePartnerVos);
+        }
+    }
 }

--
Gitblit v1.8.0