From bdb1efdc604fce543e21152b4263a9362f64389f Mon Sep 17 00:00:00 2001
From: minhee <alsdldlfrl@gmail.com>
Date: 목, 10 3월 2022 15:35:19 +0900
Subject: [PATCH] - api 이슈 추가 시 입력한 ip에 속해있는 업체정보를 가진 이슈의 하위로 입력되도록 수정 - issue_company 테이블에 ip 컬럼 추가 및 이슈 추가/수정 시 ip 대역대 항목 추가

---
 src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java | 1616 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 1,250 insertions(+), 366 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 f5641ed..11bdddd 100644
--- a/src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
+++ b/src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -11,13 +11,14 @@
 import kr.wisestone.owl.domain.enumType.EmailType;
 import kr.wisestone.owl.domain.enumType.IssueHistoryType;
 import kr.wisestone.owl.domain.enumType.IssueStatusType;
+import kr.wisestone.owl.exception.ApiAuthException;
+import kr.wisestone.owl.exception.ApiParameterException;
 import kr.wisestone.owl.exception.OwlRuntimeException;
+import kr.wisestone.owl.mapper.DepartmentMapper;
 import kr.wisestone.owl.mapper.IssueMapper;
+import kr.wisestone.owl.mapper.IssueRelationMapper;
 import kr.wisestone.owl.mapper.ProjectMapper;
-import kr.wisestone.owl.repository.IssueRelationRepository;
-import kr.wisestone.owl.repository.IssueRepository;
-import kr.wisestone.owl.repository.UserDepartmentRepository;
-import kr.wisestone.owl.repository.WorkflowDepartmentRepository;
+import kr.wisestone.owl.repository.*;
 import kr.wisestone.owl.service.*;
 import kr.wisestone.owl.util.*;
 import kr.wisestone.owl.util.DateUtil;
@@ -32,6 +33,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.messaging.simp.SimpMessagingTemplate;
@@ -43,7 +46,10 @@
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
+import java.text.ParseException;
 import java.util.*;
+
+import static kr.wisestone.owl.domain.enumType.CustomFieldType.*;
 
 @Service
 public class IssueServiceImpl extends AbstractServiceImpl<Issue, Long, JpaRepository<Issue, Long>> implements IssueService {
@@ -79,6 +85,18 @@
 
     @Autowired
     private ApiTokenService apiTokenService;
+
+    @Autowired
+    private CompanyFieldService companyFieldService;
+
+    @Autowired
+    private CompanyFieldCategoryService companyFieldCategoryService;
+
+    @Autowired
+    private IspFieldService ispFieldService;
+
+    @Autowired
+    private HostingFieldService hostingFieldService;
 
     @Autowired
     private CommonConfiguration configuration;
@@ -168,16 +186,37 @@
     private IssueMapper issueMapper;
 
     @Autowired
+    private IssueCompanyRepository issueCompanyRepository;
+
+    @Autowired
+    private IssueIspRepository issueIspRepository;
+
+    @Autowired
+    private IssueHostingRepository issueHostingRepository;
+
+    @Autowired
     private ExcelConditionCheck excelConditionCheck;
 
     @Autowired
     private SimpMessagingTemplate simpMessagingTemplate;
 
     @Autowired
+    private UserDepartmentService userDepartmentService;
+
+    @Autowired
     private UserDepartmentRepository userDepartmentRepository;
 
     @Autowired
+    private DepartmentMapper departmentMapper;
+
+    @Autowired
     private WorkflowDepartmentRepository workflowDepartmentRepository;
+
+    @Autowired
+    private IssueRelationMapper issueRelationMapper;
+
+    @Autowired
+    private WorkflowTransitionService workflowTransitionService;
 
     @Override
     protected JpaRepository<Issue, Long> getRepository() {
@@ -195,17 +234,26 @@
         this.issueVersionService.addIssueVersion(issue);
     }
 
+    @Override
+    @Transactional
+    public void addIssueVersion(Long id, Long userId) {
+        Issue issue = this.getIssue(id);
+        User user = this.userService.getUser(userId);
+        //  �씠�뒋 踰꾩쟾 �깮�꽦
+        this.issueVersionService.addIssueVersion(issue, user);
+    }
+
 
     private IssueForm convertToIssueForm(IssueApiForm issueApiForm, User user) {
         if (issueApiForm.getIssueTypeId() == null) {
-            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
+            throw new ApiParameterException(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));
+            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
         }
 
         Workflow workflow = issueType.getWorkflow();
@@ -219,13 +267,16 @@
                 }
             }
         } else if (issueApiForm.getIssueStatusId() == null){
-            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_ISSUE_STATUS_NOT_EXIST));
+            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_ISSUE_STATUS_NOT_EXIST));
+        } else if (!this.workflowTransitionService.contains(issueApiForm.getIssueStatusId(), workflow.getId())) {
+            //�씠�뒋 �긽�깭 �쑀�슚�꽦 �솗�씤
+            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_ISSUE_STATUS_NOT_EXIST_IN_WORKFLOW));
         }
 
         // �봽濡쒖젥�듃 �엯�젰
         Project project = issueType.getProject();
         if (project == null){
-            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR));
+            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR));
         }
         issueForm.setProjectId(project.getId());
 
@@ -258,8 +309,8 @@
                     issueApiForm.addUseIssueCustomFieldId(customFieldApiOverlap.getCustomField().getId());
                 }
 
-                // 以묐났�맂 �씠�뒋寃��깋
-                List<Issue> issues = this.findIssue(issueApiForm, customFieldApiOverlaps, user.getId());
+                // 以묐났�맂 �긽�쐞 �씠�뒋寃��깋
+                List<Issue> issues = this.findIssue(issueApiForm, issueForm, customFieldApiOverlaps, user.getId());
                 int size = issues.size();
                 if (size > 0) {
                     Issue targetIssue = issues.get(0);
@@ -275,6 +326,7 @@
 
             // �궗�슜�옄 �젙�쓽 �븘�뱶 �꽕�젙
             issueForm.setIssueCustomFields(issueApiForm.getCustomFieldValues());
+            //  媛숈� �룄硫붿씤 �뾽泥� 李얘린
 
             // api �엯�젰媛� �쟻�슜
             ConvertUtil.copyProperties(issueApiForm, issueForm);
@@ -282,7 +334,102 @@
             return issueForm;
 
         } else {
-            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR));
+            throw new ApiAuthException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR));
+        }
+    }
+
+    /**
+     * �룄硫붿씤�씠 �룞�씪�븳 �뾽泥� 李얘린
+     * @param issueForm IssueForm
+     * @return IssueForm
+     */
+    private IssueForm findCompanyField(IssueForm issueForm) {
+        if(issueForm.getIssueCustomFields() != null && issueForm.getIssueCustomFields().size() > 0) {
+            CompanyFieldCondition condition = new CompanyFieldCondition();
+            List<Map<String, Object>> companyFields = Lists.newArrayList();
+            List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
+            List<Map<String, Object>> issueIspFields = Lists.newArrayList();
+            List<Map<String, Object>> issueHostingFields = Lists.newArrayList();
+
+            for (Map<String, Object> issueCustomField : issueForm.getIssueCustomFields()) {
+                Long customFieldId = MapUtil.getLong(issueCustomField, "customFieldId");
+                CustomField customField = this.customFieldService.getCustomField(customFieldId);
+                if(customField != null && customField.getCustomFieldType().equals(SITE) && customField.getName().equals("�룄硫붿씤")) {
+                    String useValue = issueCustomField.get("useValue").toString();
+                    String[] urlArr = null;
+                    List<String> urls = Lists.newArrayList();
+                    if (useValue.contains(",")) {
+                        urlArr = useValue.split(",");
+                        urls.addAll(Arrays.asList(urlArr));
+                    } else {
+                        urls.add(useValue);
+                    }
+                    condition.setUrl(urls);
+                    companyFields = this.companyFieldService.find(condition);
+
+                    if(companyFields != null && companyFields.size() > 0) {
+                        for (Map<String, Object> companyField : companyFields) {
+                            CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
+                            companyField.put("companyId", companyField.get("id"));
+                            issueCompanyFields.add(companyField);
+                            if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
+                                Map<String, Object> ispField = this.ispFieldService.find(companyFieldVo.getIspId());
+                                if (ispField != null) {
+                                    ispField.put("ispId", ispField.get("id"));
+                                    issueIspFields.add(ispField);
+                                }
+                            }
+                            if(companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) {
+                                Map<String, Object> hostingField = this.hostingFieldService.find(companyFieldVo.getHostingId());
+                                if (hostingField != null) {
+                                    hostingField.put("hostingId", hostingField.get("id"));
+                                    issueHostingFields.add(hostingField);
+                                }
+                            }
+                        }
+                    }
+                }
+                issueForm.setIssueCompanyFields(issueCompanyFields);
+                issueForm.setIssueIspFields(issueIspFields);
+                issueForm.setIssueHostingFields(issueHostingFields);
+            }
+        }
+
+        return issueForm;
+    }
+
+    /**
+     * 議곌굔�뿉 留욌뒗 �뙆�듃�꼫 �젙蹂� 李얘린
+     * @param condition CompanyFieldCondition
+     * @param issueCompanyFields List<Map<String, Object>>
+     * @param issueIspFields List<Map<String, Object>>
+     * @param issueHostingFields List<Map<String, Object>>
+     */
+    private void findPartner(CompanyFieldCondition condition, List<Map<String, Object>> issueCompanyFields
+            , List<Map<String, Object>> issueIspFields, List<Map<String, Object>> issueHostingFields) {
+
+        List<Map<String, Object>> companyFields = this.companyFieldService.find(condition);
+
+        if(companyFields != null && companyFields.size() > 0) {
+            for (Map<String, Object> companyField : companyFields) {
+                CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
+                companyField.put("companyId", companyField.get("id"));
+                issueCompanyFields.add(companyField);
+                if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
+                    Map<String, Object> ispField = this.ispFieldService.find(companyFieldVo.getIspId());
+                    if (ispField != null) {
+                        ispField.put("ispId", ispField.get("id"));
+                        issueIspFields.add(ispField);
+                    }
+                }
+                if(companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) {
+                    Map<String, Object> hostingField = this.hostingFieldService.find(companyFieldVo.getHostingId());
+                    if (hostingField != null) {
+                        hostingField.put("hostingId", hostingField.get("id"));
+                        issueHostingFields.add(hostingField);
+                    }
+                }
+            }
         }
     }
 
@@ -303,12 +450,22 @@
         IssueForm issueForm = this.convertToIssueForm(issueApiForm, user);
 
         List<Issue> issues = Lists.newArrayList();
-        if (issueForm.getParentIssueId() != null) {
+        if (issueForm.getParentIssueId() != null    // 湲곗〈 異붽��맂 �긽�쐞 �씪媛먯씠 �뾾嫄곕굹 �꽕�젙�맂 以묐났 �씠�뒋 id媛� �뾾�쓣�븣
+                || issueApiForm.getUseIssueCustomFieldIds().size() == 0) {
             issues.add(addIssue(user, issueForm, issueApiForm.getMultipartFiles()));
         } else {
-            // �긽�쐞 �씠�뒋 異붽�
+            // 媛��긽 �긽�쐞 �씠�뒋 異붽�
             IssueForm parentIssueForm = issueForm.clone();
+            // 媛��긽 �긽�쐞 �씠�뒋 異붽�
             parentIssueForm.setUseIssueCustomFields(issueApiForm.getUseIssueCustomFieldIds());
+            //  媛숈� �룄硫붿씤 �뾽泥� 李얘린
+            if (parentIssueForm.getIssueCompanyFields() == null) {
+                IssueForm partners = this.findCompanyField(parentIssueForm);
+                parentIssueForm.setIssueCompanyFields(partners.getIssueCompanyFields());
+                parentIssueForm.setIssueIspFields(partners.getIssueIspFields());
+                parentIssueForm.setIssueHostingFields(partners.getIssueHostingFields());
+            }
+
             Issue issue = addIssue(user, parentIssueForm, null);
             issues.add(issue);
             // �븯�쐞 �씠�뒋 異붽�
@@ -329,21 +486,62 @@
     }
 
     // 以묐났�맂 �긽�쐞 �씠�뒋 寃��깋
-    private List<Issue> findIssue(IssueApiForm issueApiform, List<CustomFieldApiOverlap> customFieldApiOverlaps, Long userId) {
+    private List<Issue> findIssue(IssueApiForm issueApiform, IssueForm issueForm, List<CustomFieldApiOverlap> customFieldApiOverlaps, Long userId) {
         List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
         List<Issue> resultIssueVos = Lists.newArrayList();
         String comma = ",";
 
         if (issueCustomFieldValueForms.size() > 0) {
             String concatUseValue = "";
+            String customFieldType = "";
             int useIdx = 0;
+            int cntIp = 0;
+            int cntSite = 0;
 
             IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator();
             Collections.sort(issueCustomFieldValueForms, comp);
 
+            List<String> userValues = Lists.newArrayList();
+            CompanyFieldCondition condition = new CompanyFieldCondition();
+            List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
+            List<Map<String, Object>> issueIspFields = Lists.newArrayList();
+            List<Map<String, Object>> issueHostingFields = Lists.newArrayList();
+
             for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
+                userValues.add(issueCustomFieldValueForm.getUseValue());
+
                 for(CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                     if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) {
+
+                        String useValue = issueCustomFieldValueForm.getUseValue();
+                        if (useValue.contains(" ")) {
+                            useValue = useValue.replace(" ","");
+                        }
+
+                        if (customFieldApiOverlap.getCustomField().getCustomFieldType().equals(IP_ADDRESS)) {
+                            long ip = ConvertUtil.ipToLong(useValue);
+                            customFieldType = IP_ADDRESS.toString();
+                            if (cntIp == 0){
+                                condition.setIp(ip);
+                            }
+                            cntIp ++;
+                        }
+
+                        if(customFieldApiOverlap.getCustomField().getCustomFieldType().equals(SITE)) {
+                            String[] urlArr = null;
+                            List<String> urls = Lists.newArrayList();
+                            if (useValue.contains(",")) {
+                                urlArr = useValue.split(",");
+                                urls.addAll(Arrays.asList(urlArr));
+                            } else {
+                                urls.add(useValue);
+                            }
+                            if (cntSite == 0) {
+                                condition.setUrl(urls);
+                            }
+                            cntSite ++;
+                        }
+
                         if (useIdx > 0) {
                             concatUseValue = concatUseValue.concat(comma);
                         }
@@ -353,10 +551,29 @@
                 }
             }
 
+            // 異붽� �븷 url or ip�뿉 �룷�븿�릺�뼱�엳�뒗 �뙆�듃�꼫 李얘린
+            this.findPartner(condition, issueCompanyFields, issueIspFields, issueHostingFields);
+
+            issueForm.setIssueCompanyFields(issueCompanyFields);
+            issueForm.setIssueIspFields(issueIspFields);
+            issueForm.setIssueHostingFields(issueHostingFields);
+
             IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
             issueCustomFieldValueCondition.setUseValue(concatUseValue);
+            issueCustomFieldValueCondition.setUseValues(userValues);
             issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId());
-            List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
+            issueCustomFieldValueCondition.setCustomFieldType(customFieldType);
+//            issueCustomFieldValueCondition.setIssueStatusType("CLOSE");
+            List<Map<String, Object>> results = Lists.newArrayList();
+            if (customFieldType.equals(IP_ADDRESS.toString()) && issueForm.getIssueCompanyFields() != null && issueForm.getIssueCompanyFields().size() > 0) {
+                long ipValue = ConvertUtil.ipToLong(concatUseValue);
+                issueCustomFieldValueCondition.setUseValue(String.valueOf(ipValue));
+                //  �븯�쐞�씠�뒋議곌굔�쓽 ���엯�씠 IP�씪 寃쎌슦 媛숈� �뾽泥댁젙蹂댁씤 �씠�뒋 李얘린
+                results = this.issueMapper.findByCustomFieldValueOfIp(issueCustomFieldValueCondition);
+            } else {
+                results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
+            }
+
             if (results != null && results.size() > 0) {
                 for (Map<String, Object> result : results) {
                     resultIssueVos.add(this.getIssue(MapUtil.getLong(result, "id")));
@@ -378,6 +595,8 @@
     @Override
     @Transactional
     public Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) {
+        StringBuilder detectIssueChange = new StringBuilder();
+
         //  �궗�슜�븯怨� �엳�뒗 �뾽臾� 怨듦컙�씠 �솢�꽦 �긽�깭�씤吏� �솗�씤�븳�떎. �궗�슜 怨듦컙�뿉�꽌 濡쒓렇�씤�븳 �궗�슜�옄媛� 鍮꾪솢�꽦�씤吏� �솗�씤�븳�떎.
         Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId());
         //  �봽濡쒖젥�듃 �쑀�슚�꽦 泥댄겕
@@ -408,6 +627,12 @@
         if (issueForm.getParentIssueId() != null){
             Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
             issue.setParentIssue(parentIssue);
+
+            // �긽�쐞 �씠�뒋媛� 醫낅즺�씪寃쎌슦 ��湲곕줈 蹂�寃�
+            IssueStatus parentIssueStatus = parentIssue.getIssueStatus();
+            if (parentIssueStatus.getIssueStatusType().equals(IssueStatusType.CLOSE)) {
+                parentIssue.setIssueStatus(issueStatus);
+            }
         }
 
         issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project));    //  媛� �봽濡쒖젥�듃�쓽 怨좎쑀 �씠�뒋 踰덊샇 �깮�꽦
@@ -415,17 +640,26 @@
         issue = this.issueRepository.saveAndFlush(issue);
 
         issue.setReverseIndex(issue.getId() * -1);  //  荑쇰━ �냽�룄 媛쒖꽑�쓣 �쐞�빐 由щ쾭�뒪 �씤�뜳�뒪 �깮�꽦
+
+        if (issueForm.getParentIssueId() != null){
+            Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
+            if (issueForm.getIsApi().equals(Issue.IS_API_YES)
+                    || (issueForm.getInheritYn() != null && issueForm.getInheritYn())) {
+                //  �븯�쐞�씠�뒋�뿉 �긽�쐞�씠�뒋�쓽 �뙆�듃�꼫 �젙蹂� �쟻�슜
+                this.inheritPartners(issue, parentIssue);
+            }
+        }
+
         //  �떞�떦�옄 吏��젙
         //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
         //  �떞�떦遺��꽌 吏��젙
         this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds());
         //  �뾽泥� �젙蹂� ���옣
-        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
+        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange);
         //  ISP �젙蹂� ���옣
-        this.issueIspService.modifyIssueIspField(issue, issueForm.getIssueIspFields());
+        this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange);
         //  HOSTING �젙蹂� ���옣
-        this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields());
-
+        this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange);
 
         //  泥⑤� �뙆�씪 ���옣
         //  multipartFile �쓣 file Map List 媛앹껜濡� 蹂�寃쏀븳�떎.
@@ -460,10 +694,20 @@
         return addRelIssue(user, issueForm, multipartFiles);
     }
 
-    //  �뿰愿��씠�뒋瑜� �깮�꽦�븳�떎.
+    //  �븯�쐞�씠�뒋瑜� �깮�꽦�븳�떎.
     @Override
     @Transactional
-    public Issue addRelIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) {
+    public Issue addDownIssue(Map<String, Object> resJsonData, IssueForm issueForm, List<MultipartFile> multipartFiles) {
+        User user = this.webAppUtil.getLoginUserObject();
+        return addDownIssue(resJsonData, user, issueForm, multipartFiles);
+    }
+
+    //  �븯�쐞�씠�뒋瑜� �깮�꽦�븳�떎.
+    @Override
+    @Transactional
+    public Issue addDownIssue(Map<String, Object> resJsonData, User user, IssueForm issueForm, List<MultipartFile> multipartFiles) {
+        StringBuilder detectIssueChange = new StringBuilder();
+
         //  �궗�슜�븯怨� �엳�뒗 �뾽臾� 怨듦컙�씠 �솢�꽦 �긽�깭�씤吏� �솗�씤�븳�떎. �궗�슜 怨듦컙�뿉�꽌 濡쒓렇�씤�븳 �궗�슜�옄媛� 鍮꾪솢�꽦�씤吏� �솗�씤�븳�떎.
         Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId());
         //  �봽濡쒖젥�듃 �쑀�슚�꽦 泥댄겕
@@ -506,11 +750,105 @@
         //  �떞�떦遺��꽌 吏��젙
         this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds());
         //  �뾽泥� �젙蹂� ���옣
-        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
+        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange);
         //  ISP �젙蹂� ���옣
-        this.issueIspService.modifyIssueIspField(issue, issueForm.getIssueIspFields());
+        this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange);
         //  HOSTING �젙蹂� ���옣
-        this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields());
+        this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange);
+
+        //  泥⑤� �뙆�씪 ���옣
+        //  multipartFile �쓣 file Map List 媛앹껜濡� 蹂�寃쏀븳�떎.
+        List<Map<String, Object>> convertFileMaps = this.convertMultipartFileToFile(multipartFiles);
+        this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount());
+
+        //  �뀓�뒪�듃 �뿉�뵒�꽣�뿉 泥⑤��븳 �뙆�씪�쓣 �씠�뒋�� �뿰寃�
+        this.checkNotHaveIssueIdAttachedFile(issue, issueForm);
+        //  �궗�슜�옄 �젙�쓽 �븘�뱶 ���옣
+        this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields());
+        //  �씠�뒋 �씠�젰 �깮�꽦
+        this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null);
+        //  �씠�뒋 �쐞�뿕 愿�由� �깮�꽦
+        this.issueRiskService.addIssueRisk(issue, project.getWorkspace());
+
+        //  �쁺�냽�꽦 而⑦뀓�뒪�듃 鍮꾩슦湲�
+        this.clear();
+        //  �씠�뒋 �깮�꽦, �궘�젣�떆 �삁�빟 �씠硫붿씪�뿉 �벑濡앺빐�넃�뒗�떎.
+        this.reservationIssueEmail(issue, EmailType.ISSUE_ADD);
+        //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
+
+        UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class);
+        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD));
+
+        IssueVo issueVo = this.convertToIssueVo(issue);
+        resJsonData.put(Constants.RES_KEY_CONTENTS, issueVo);
+
+        return issue;
+    }
+
+    /**
+     * Issue瑜� IssueVo濡� 蹂��솚(�븯�쐞�씠�뒋�쓽 �뙆�듃�꼫 �젙蹂� �긽�냽 �떆 �븘�슂)
+     * @param issue Issue
+     * @return IssueVo
+     */
+    private IssueVo convertToIssueVo(Issue issue) {
+        IssueVo issueVo = ConvertUtil.copyProperties(issue, IssueVo.class);
+        issueVo.setInheritPartners(issue.getIssueType().getInheritPartners());
+        issueVo.setUsePartner(issue.getIssueType().getUsePartner());
+        return issueVo;
+    }
+
+    //  �뿰愿��씠�뒋瑜� �깮�꽦�븳�떎.
+    @Override
+    @Transactional
+    public Issue addRelIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) {
+        StringBuilder detectIssueChange = new StringBuilder();
+        //  �궗�슜�븯怨� �엳�뒗 �뾽臾� 怨듦컙�씠 �솢�꽦 �긽�깭�씤吏� �솗�씤�븳�떎. �궗�슜 怨듦컙�뿉�꽌 濡쒓렇�씤�븳 �궗�슜�옄媛� 鍮꾪솢�꽦�씤吏� �솗�씤�븳�떎.
+        Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId());
+        //  �봽濡쒖젥�듃 �쑀�슚�꽦 泥댄겕
+        Project project = this.projectService.getProject(issueForm.getProjectId());
+        //  �씠�뒋 �쑀�삎 �쑀�슚�꽦 泥댄겕
+        IssueType issueType = this.issueTypeService.getIssueType(issueForm.getIssueTypeId());
+        //  �슦�꽑�닚�쐞 �쑀�슚�꽦 泥댄겕
+        Priority priority = this.priorityService.getPriority(issueForm.getPriorityId());
+        //  以묒슂�룄 �쑀�슚�꽦 泥댄겕
+        Severity severity = this.severityService.getSeverity(issueForm.getSeverityId());
+
+        //  �젣紐� �쑀�슚�꽦 泥댄겕
+        this.verifyTitle(issueForm.getTitle());
+        //  �궇吏� �쑀�슚�꽦 泥댄겕
+        this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate());
+        //  �떞�떦 遺��꽌 �쑀�슚�꽦 泥댄겕
+        //this.verifyIssueDepartment(project, issueForm);
+
+        //  �씠�뒋 �긽�깭 �쑀�삎�씠 '��湲�' �씤 �씠�뒋 �긽�깭 媛��졇�삤湲�
+        IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow());
+
+        Issue issue = ConvertUtil.copyProperties(issueForm, Issue.class);
+        issue.setProject(project);
+        issue.setIssueStatus(issueStatus);
+        issue.setIssueType(issueType);
+        issue.setPriority(priority);
+        issue.setSeverity(severity);
+        if (issueForm.getParentIssueId() != null){
+            Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
+            issue.setParentIssue(parentIssue);
+        }
+
+        issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project));    //  媛� �봽濡쒖젥�듃�쓽 怨좎쑀 �씠�뒋 踰덊샇 �깮�꽦
+
+        issue = this.issueRepository.saveAndFlush(issue);
+
+        issue.setReverseIndex(issue.getId() * -1);  //  荑쇰━ �냽�룄 媛쒖꽑�쓣 �쐞�빐 由щ쾭�뒪 �씤�뜳�뒪 �깮�꽦
+        //  �떞�떦�옄 吏��젙
+        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
+        //  �떞�떦遺��꽌 吏��젙
+        this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds());
+        //  �뾽泥� �젙蹂� ���옣
+        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange);
+        //  ISP �젙蹂� ���옣
+        this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange);
+        //  HOSTING �젙蹂� ���옣
+        this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange);
 
         //  泥⑤� �뙆�씪 ���옣
         //  multipartFile �쓣 file Map List 媛앹껜濡� 蹂�寃쏀븳�떎.
@@ -558,7 +896,7 @@
     }
 
     //  �씠�뒋 �젙蹂대�� �씠硫붿씪 �쟾�넚�뿉 �궗�슜�븯湲� �쐞�빐 Map �삎�깭濡� 蹂��솚�븳�떎.
-    private void makeIssueMapToIssue(Issue issue, Map<String, Object> issueMap) {
+    public void makeIssueMapToIssue(Issue issue, Map<String, Object> issueMap) {
         issueMap.put("title", issue.getTitle());
         issueMap.put("issueNumber", issue.getIssueNumber());
         issueMap.put("issueTypeName", issue.getIssueType().getName());
@@ -612,7 +950,7 @@
                 useValues.add(issueCustomFieldValueVo.getUseValue());
                 customField.put(issueCustomFieldValueVo.getCustomFieldVo().getName(), useValues);
             } else {
-                if (issueCustomFieldValueVo.getCustomFieldVo().getCustomFieldType().equals(CustomFieldType.INPUT.toString())) {
+                if (issueCustomFieldValueVo.getCustomFieldVo().getCustomFieldType().equals(INPUT.toString())) {
                     customField.put(issueCustomFieldValueVo.getCustomFieldVo().getName(), issueCustomFieldValueVo.getUseValue());
                 } else {
                     customField.put(issueCustomFieldValueVo.getCustomFieldVo().getName(), Lists.newArrayList(issueCustomFieldValueVo.getUseValue()));
@@ -666,15 +1004,28 @@
         }
     }
 
-    //  �궇吏� �쑀�슚�꽦 泥댄겕
+    /**
+     * �궇吏� �쑀�슚�꽦 泥댄겕
+     * @param startDate �떆�옉 �씪�옄(臾몄옄)
+     * @param completeDate 醫낅즺 �씪�옄(臾몄옄)
+     */
     private void checkStartCompleteDate(String startDate, String completeDate) {
         if (!StringUtils.isEmpty(startDate) && !StringUtils.isEmpty(completeDate)) {
             Date start = DateUtil.convertStrToDate(startDate, "yy-MM-dd");
             Date end = DateUtil.convertStrToDate(completeDate, "yy-MM-dd");
-            if (start.getTime() > end.getTime()) {
-                throw new OwlRuntimeException(
-                        this.messageAccessor.getMessage(MsgConstants.DATE_PICKER_NOT_AVAILABLE));
-            }
+            checkStartCompleteDate(start, end);
+        }
+    }
+
+    /**
+     * �궇吏� �쑀�슚�꽦 泥댄겕
+     * @param start �떆�옉 �씪�옄
+     * @param end 醫낅즺 �씪�옄
+     */
+    private void checkStartCompleteDate(Date start, Date end) {
+        if (start.getTime() > end.getTime()) {
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.DATE_PICKER_NOT_AVAILABLE));
         }
     }
 
@@ -694,8 +1045,22 @@
             for(UserDepartment myDepartment : myDepartments){
                 myDepartmentIds.add(myDepartment.getDepartmentId());
             }
+        } else {
+            myDepartmentIds.add(-1L);
         }
         issueCondition.setMyDepartmentIds(myDepartmentIds);
+    }
+
+    void SetAllDepartmentId(IssueCondition issueCondition){
+        List<Long> departmentIds = Lists.newArrayList();
+        List<Map<String, Object>> departmentList = this.departmentMapper.find(null);
+
+        if(departmentList != null && departmentList.size() > 0){
+            for(Map<String, Object> department : departmentList){
+                departmentIds.add((Long) department.get("id"));
+            }
+        }
+        issueCondition.setMyDepartmentIds(departmentIds);
     }
 
     void SetWorkflowDepartment(List<IssueVo> issueVos){
@@ -720,7 +1085,6 @@
     @Override
     @Transactional(readOnly = true)
     public List<IssueVo> findIssue(Map<String, Object> resJsonData, IssueCondition issueCondition, Pageable pageable) {
-
         //  寃��깋 議곌굔�쓣 留뚮뱺�떎
         if (!this.makeIssueSearchCondition(issueCondition, Lists.newArrayList("01", "02", "03"), pageable)) {
             //  �씠�뒋 紐⑸줉�쓣 李얠� 紐삵븷 寃쎌슦 湲곕낯 �젙蹂대줈 由ы꽩�븳�떎.
@@ -737,42 +1101,40 @@
             return Lists.newArrayList();
         }
 
-        //  �뒠�떇 �쟾 - 1.3 / 1.2 / 1.1
-        //  �뒠�떇 �썑 (�떒�씪/�떎以� 寃��깋 議곌굔 3媛� 湲곗�) - 0.49 / 0.41 / 0.47 / 0.41
-
         List<IssueVo> issueVos = Lists.newArrayList();  //  �씠�뒋 紐⑸줉 �뜲�씠�꽣 ���옣 而щ젆�뀡
         //  �궗�슜�옄 �젙�쓽 �븘�뱶濡� 寃��깋�븳 �씠�뒋 �븘�씠�뵒 媛�
         List<String> issueKeys = Lists.newArrayList(issueIds);
         issueCondition.setIssueIds(issueKeys);
-
-        issueCondition.setLoginUserId(this.webAppUtil.getLoginId());
-        issueCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
         User user = this.webAppUtil.getLoginUserObject();
+
+        issueCondition.setLoginUserId(user.getId());
+        issueCondition.setWorkspaceId(user.getLastWorkspaceId());
 
 
         List<Map<String, Object>> results = Lists.newArrayList();
         Long totalCount = 0L;
-        UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId());
+//        UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId());
 
-//        if (this.userWorkspaceService.checkWorkspaceManager(user)
-//                || MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE_PROJECT_ALL)) {
-            results = this.issueMapper.find(issueCondition);
-            totalCount = this.issueMapper.count(issueCondition);
-//        }
-//        } else{
+//        if (!this.userWorkspaceService.checkWorkspaceManager(user)
+//                && !MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE)) { //理쒓퀬愿�由ъ옄 & �봽濡쒖젥�듃,�씠�뒋 愿�由ъ옄 �씪 寃쎌슦 紐⑤뱺 �씠�뒋 蹂닿린
 //            this.SetMyDepartmentId(issueCondition);
+        //this.SetAllDepartmentId(issueCondition);
+//        } /*else{
 //            results = this.issueMapper.findByDepartment(issueCondition);
 //            totalCount = this.issueMapper.countByDepartment(issueCondition);
-//        }
+//        }*/
+//        StopWatch serviceStart = new StopWatch();
+//        serviceStart.start();
+        results = this.issueMapper.find(issueCondition);
+//         serviceStart.stop();
+//        log.error("result : " + serviceStart.toString());
 
+//        serviceStart = new StopWatch();
+//        serviceStart.start();
+        totalCount = this.issueMapper.count(issueCondition);
 
-        //  �뒠�떇 �쟾 - 0.8, 0.9, 0.9, 0.9, 0.9
-        /*StopWatch serviceStart = new StopWatch();
-        serviceStart.start();*/
-        //  �뒠�떇 �쟾 - 1.1, 1.1, 1.3, 1.2
-
-        /*serviceStart.stop();
-        log.debug("serviceENd1 : " + serviceStart.getTime());*/
+//        serviceStart.stop();
+//        log.error("totalCount : " + serviceStart.toString());
 
         int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1;
         //  �씠�뒋 �븘�씠�뵒 珥덇린�솕
@@ -784,11 +1146,12 @@
         this.setMapToIssueVo(results, issueVos, issueCondition, user);
 
         if (issueCondition.getTree()) {
+            this.setParentIssue(issueVos);
             this.setDownIssues(user, issueVos);
             this.setRelationIssues(issueVos);
         }
-        this.setCountDownIssues(issueVos);
 
+        this.setCountDownIssues(issueVos);
         this.SetWorkflowDepartment(issueVos); //�썙�겕�뵆濡쒖슦�뿉 �꽕�젙�븳 �떞�떦遺��꽌 媛��졇�삤湲�
 
         resJsonData.put(Constants.RES_KEY_CONTENTS, issueVos);
@@ -813,9 +1176,9 @@
                 IssueVo addIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class);
                 addIssueVo.setIssueTypeId(downIssue.getIssueType().getId());
                 downIssueVos.add(addIssueVo);
-
             }
             issueVo.setIssueDownVos(downIssueVos);
+
             if (downIssueVos.size() > 0) {
                 this.setDownIssues(user, downIssueVos);
             }
@@ -825,11 +1188,10 @@
             this.setIssueDepartmentList(issueVos, issueCondition, user);
             //  �벑濡앹옄 �젙蹂� 異붽�
             this.setRegister(issueVos);  //  �떞�떦�옄 �젙蹂� �뀑�똿
-
             //  �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂� 異붽�
             this.setIssueCustomFieldValue(issueVos, issueCondition);
-
-            this.SetWorkflowDepartment(issueVos); //�썙�겕�뵆濡쒖슦�뿉 �꽕�젙�븳 �떞�떦遺��꽌 媛��졇�삤湲�
+            //�썙�겕�뵆濡쒖슦�뿉 �꽕�젙�븳 �떞�떦遺��꽌 媛��졇�삤湲�
+            this.SetWorkflowDepartment(issueVos);
         }
     }
 
@@ -839,6 +1201,20 @@
             List<IssueVo> relationIssues = this.issueRelationService.findRelationIssue(issueVo.getId());
             for(IssueVo relationIssue : relationIssues){
                 issueVo.addRelationIssueVo(ConvertUtil.copyProperties(relationIssue, IssueVo.class));
+            }
+        }
+    }
+
+    // �긽�쐞 �씠�뒋 泥댄겕
+    private void setParentIssue(List<IssueVo> issueVos) {
+        for(IssueVo issueVo : issueVos) {
+            if(issueVo.getParentIssueId() != null) {
+                Issue parentIssue = this.getIssue(issueVo.getParentIssueId());
+                //issueVo.setParentIssueVo(ConvertUtil.copyProperties(parentIssue, IssueVo.class));
+                if(parentIssue.getIssueCustomFieldValues() == null || parentIssue.getIssueCustomFieldValues().size() == 0){
+                    issueVo.setIssueCustomFieldValueVos(null);
+                }
+                ConvertUtil.copyProperties(parentIssue, issueVo);
             }
         }
     }
@@ -880,15 +1256,19 @@
     public void findApiIssue(ApiMonitorCondition apiMonitorCondition, Map<String, Object> resJsonData) {
 
         IssueTypeCondition issueTypeCondition = new IssueTypeCondition();
+        issueTypeCondition.setIsApi(Issue.IS_API_YES);
         List<IssueTypeVo> issueTypes = this.issueTypeService.findIssueType(issueTypeCondition);
 
-        // 媛믪씠 �뾾�쓣 寃쎌슦 珥덇린媛� �엯�젰
-        if (StringUtils.isEmpty(apiMonitorCondition.getSearchPeriod())) {
-            apiMonitorCondition.setSearchPeriod(DateUtil.LAST_SEVEN_DAYS);
-        }
-
         //  寃��깋 �씪�옄瑜� 援ы븳�떎.
-        List<Date> searchDates = CommonUtil.findSearchPeriod(apiMonitorCondition.getSearchPeriod());
+        List<Date> searchDates = Lists.newArrayList();
+        if (apiMonitorCondition.getSearchPeriod().equals(DateUtil.CUSTOM_INPUT)) {
+            Date startDate = DateUtil.convertStrToDate(apiMonitorCondition.getSearchStartDate(), "yyyy-MM-dd");
+            Date endDate = DateUtil.addDays(DateUtil.convertStrToDate(apiMonitorCondition.getSearchEndDate(), "yyyy-MM-dd"), 1);
+
+            searchDates = CommonUtil.findSearchPeriod(startDate, endDate);
+        } else {
+            searchDates = CommonUtil.findSearchPeriod(apiMonitorCondition.getSearchPeriod());
+        }
 
         //  �궇吏쒓� 寃��깋�릺吏� �븡�븯�쑝硫� �삤瑜�
         if (searchDates.size() < 1) {
@@ -1026,6 +1406,9 @@
     private void setMapToIssueVo(List<Map<String, Object>> results, List<IssueVo> issueVos, IssueCondition issueCondition, User user) {
         for (Map<String, Object> result : results) {
             IssueVo issueVo = ConvertUtil.convertMapToClass(result, IssueVo.class);
+            if (MapUtil.getString(result, "inheritPartners") != null && MapUtil.getString(result, "inheritPartners").equals("1")) {
+                issueVo.setInheritPartners(true);
+            }
             issueVos.add(issueVo);
             issueCondition.addIssueIds(String.valueOf(issueVo.getId()));
         }
@@ -1050,6 +1433,9 @@
         condition.setLoginUserId(this.webAppUtil.getLoginId());
         condition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
 
+        User user = this.webAppUtil.getLoginUserObject();
+        UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId());
+
         //  �봽濡쒖젥�듃 �궎媛� 議댁옱�븷 寃쎌슦 �봽濡쒖젥�듃 �궎�뿉 �빐�떦�븯�뒗 �봽濡쒖젥�듃瑜� 議고쉶�븯怨� 寃��깋 議곌굔�뿉 �뀑�똿�븳�떎.
         if (!this.getProjectByProjectKey(condition.getProjectKey(), condition)) {
             return false;
@@ -1057,9 +1443,17 @@
 
         //  �봽濡쒖젥�듃瑜� �꽑�깮�븯吏� �븡�븯�쑝硫� �빐�떦 �뾽臾� 怨듦컙�뿉�꽌 李몄뿬�븯怨� �엳�뒗 �봽濡쒖젥�듃瑜� 李얜뒗�떎.
         if (condition.getProjectIds().size() < 1) {
-            List<Map<String, Object>> projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectStatues, condition.getProjectType());
-            List<Long> projectIds = Lists.newArrayList();
+            List<Map<String, Object>> projects = Lists.newArrayList();
+            if (this.userWorkspaceService.checkWorkspaceManager(user) || MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT)){
+                return true;
+            }/*else if (MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE)){
+                projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectStatues, condition.getProjectType());
+            }*/
+            else {
+                projects = this.projectService.findByWorkspaceIdAndIncludeProject(projectStatues, condition.getProjectType());
+            }
 
+            List<Long> projectIds = Lists.newArrayList();
             for (Map<String, Object> result : projects) {
                 Long projectId = MapUtil.getLong(result, "id");
 
@@ -1097,7 +1491,10 @@
         //  �봽濡쒖젥�듃瑜� �꽑�깮�븯吏� �븡�븯�쑝硫� �빐�떦 �뾽臾� 怨듦컙�뿉�꽌 李몄뿬�븯怨� �엳�뒗 �봽濡쒖젥�듃瑜� 李얜뒗�떎.
         if (condition.getProjectIds().size() < 1) {
             List<Map<String, Object>> projects = null;
-            if (this.userWorkspaceService.checkWorkspaceManager(user)) {
+            UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId());
+            if (this.userWorkspaceService.checkWorkspaceManager(user)
+                    || (MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT) &&
+                    MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE))) {
                 projects = this.projectMapper.findByWorkspaceManagerAll(projectCondition);
             } else  {
                 projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectCondition);
@@ -1206,7 +1603,7 @@
             }
 
             //  �씠�뒋 �닔�젙 沅뚰븳�쓣 媛뽮퀬 �엳�뒗吏� �솗�씤
-            if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user)) {
+            if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user, null)) {
                 issueVo.setModifyPermissionCheck(Boolean.TRUE);
             }
         }
@@ -1243,7 +1640,7 @@
             }
 
             //  �씠�뒋 �닔�젙 沅뚰븳�쓣 媛뽮퀬 �엳�뒗吏� �솗�씤
-            if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user)) {
+            if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user, issueVo.getDepartmentVos())) {
                 issueVo.setModifyPermissionCheck(Boolean.TRUE);
             }
         }
@@ -1254,10 +1651,24 @@
     @Transactional(readOnly = true)
     public void detailIssue(Map<String, Object> resJsonData, IssueCondition issueCondition) {
         IssueVo issueVo = new IssueVo();
+        Pageable relPageable = issueCondition.getRelPageable();
+        Pageable downPageable = issueCondition.getDownPageable();
 
         if (issueCondition.getId() != null) {
             Issue issue = this.getIssue(issueCondition.getId());
             issueVo = ConvertUtil.copyProperties(issue, IssueVo.class);
+            User user = this.webAppUtil.getLoginUserObject();
+
+            if (relPageable != null) {
+                issueVo.setRelPageNumber(relPageable.getPageNumber());
+                issueVo.setRelPageSize(relPageable.getPageSize());
+                issueVo.setRelPage(relPageable.getPageNumber() * relPageable.getPageSize());
+            }
+            if (downPageable != null) {
+                issueVo.setDownPageNumber(downPageable.getPageNumber());
+                issueVo.setDownPage(downPageable.getPageNumber() * downPageable.getPageSize());
+                issueVo.setDownPageSize(downPageable.getPageSize());
+            }
 
             switch (issueCondition.getDeep()) {
                 case "01": //  �봽濡쒖젥�듃, �씠�뒋 �쑀�삎, �씠�뒋 �긽�깭,  �슦�꽑�닚�쐞, 以묒슂�룄, �떞�떦遺��꽌, 泥⑤��뙆�씪, �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� �뀑�똿�븳�떎.
@@ -1274,17 +1685,15 @@
                     this.setIssueCustomFields(issue, issueVo);  //  �궗�슜�옄 �젙�쓽 �븘�뱶 媛� �젙蹂� �뀑�똿
                     this.setRelationIssue(issue, issueVo);        //�뿰愿� �씪媛� �뀑�똿
                     this.setDownIssues(issue, issueVo); //�븯�쐞 �씠�뒋 �꽭�똿
-
                     break;
 
                 case "02": //  �봽濡쒖젥�듃, �씠�뒋 �쑀�삎, �씠�뒋 �긽�깭,  �슦�꽑�닚�쐞, 以묒슂�룄, �떞�떦�옄, 泥⑤��뙆�씪, �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂�, �뙎湲�, 湲곕줉�쓣 �뀑�똿�븳�떎.
-                    this.setIssueDetail(issueVo, issue);    //  �씠�뒋 �긽�꽭 �젙蹂대�� �뀑�똿�븳�떎.
-                    this.setIssueTableConfigs(issue, issueVo);
+                    this.setIssueDetail(issueVo, issue, user);    //  �씠�뒋 �긽�꽭 �젙蹂대�� �뀑�똿�븳�떎.
+                    this.setIssueTableConfigs(issue, issueVo, issueCondition);
                     issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class));
                     break;
             }
         }
-
         //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
         log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_DETAIL));
 
@@ -1292,8 +1701,9 @@
     }
 
     // �뀒�씠釉� �꽕�젙 �뀑�똿
-    private void setIssueTableConfigs(Issue issue, IssueVo issueVo) {
-        Long IssueTypeId = issue.getIssueType().getId();
+    private void setIssueTableConfigs(Issue issue, IssueVo issueVo, IssueCondition issueCondition) {
+        //Long IssueTypeId = issue.getIssueType().getId();
+        Long IssueTypeId = issueCondition.getIssueTypeId();
 
         for (int tableConfigType : IssueTableConfig.IssueTableTypes) {
             if (tableConfigType != IssueTableConfig.ISSUE_TABLE_TYPE_MAIN) {
@@ -1313,8 +1723,21 @@
 
     // �븯�쐞 �씠�뒋 �젙蹂대�� �뀑�똿�븳�떎
     private void setDownIssues(Issue issue, IssueVo issueVo) {
-        List<Issue> downIssues = this.issueRepository.findByParentIssueId(issue.getId());
-        if(downIssues != null && downIssues.size()>0){
+        Page<Issue> downIssues = null;
+
+        List<Issue> downIssueList = this.issueRepository.findByParentIssueId(issue.getId());
+        if(downIssueList != null && downIssueList.size() > 0) {
+            int startPage = 0;
+            if (issueVo.getDownPage() != 0) {
+                startPage = (int) Math.floor(issueVo.getDownPage()/issueVo.getDownPageSize());
+            }
+            Pageable pageable = PageRequest.of(startPage, issueVo.getDownPageSize());
+            downIssues = this.issueRepository.findByParentIssueId(issue.getId(), pageable);
+        }
+        if(downIssues != null){
+            issueVo.setDownTotalPage(downIssues.getTotalPages());
+            issueVo.setDownTotalCount(downIssues.getTotalElements());
+
             List<IssueVo> resultList = new ArrayList<>();
             for(Issue downIssue : downIssues){
                 IssueVo downIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class);
@@ -1329,6 +1752,13 @@
                 this.setRegister(downIssue, downIssueVo); // �벑濡앹옄
                 this.setIssueDepartment(downIssue, downIssueVo);  //  �떞�떦遺��꽌 �젙蹂� �뀑�똿
                 this.setIssueCustomFields(downIssue, downIssueVo);   // �궗�슜�옄�젙�쓽�븘�뱶 �젙蹂� �꽭�똿
+                this.setIssueHistory(downIssue, downIssueVo);   //  �씠�뒋 湲곕줉 �젙蹂� �뀑�똿
+                this.setIssueComments(downIssue, downIssueVo);  //  �뙎湲� �젙蹂� �뀑�똿
+                this.setIssueCompanyField(downIssue, downIssueVo);  //�뾽泥� �젙蹂� �꽭�똿
+                this.setIssueIspField(downIssue, downIssueVo);  //ISP �젙蹂� �꽭�똿
+                this.setIssueHostingField(downIssue, downIssueVo);  //HOSTING �젙蹂� �꽭�똿
+
+                downIssueVo.setModifyPermissionCheck(issueVo.getModifyPermissionCheck());
 
                 resultList.add(downIssueVo);
             }
@@ -1339,7 +1769,12 @@
     //  �씠�뒋 �긽�꽭 �젙蹂대�� �뀑�똿�븳�떎.
     @Override
     @Transactional(readOnly = true)
-    public void setIssueDetail(IssueVo issueVo, Issue issue) {
+    public void setIssueDetail(IssueVo issueVo, Issue issue, User user) {
+        //  �씠�뒋 �닔�젙 沅뚰븳�쓣 媛뽮퀬 �엳�뒗吏� �솗�씤
+        if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user, issueVo.getDepartmentVos())) {
+            issueVo.setModifyPermissionCheck(Boolean.TRUE);
+        }
+
         issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class));
         issueVo.setIssueTypeVo(ConvertUtil.copyProperties(issue.getIssueType(), IssueTypeVo.class));
         IssueStatusVo issueStatusVo = ConvertUtil.copyProperties(issue.getIssueStatus(), IssueStatusVo.class, "issueStatusType");
@@ -1352,10 +1787,10 @@
         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); //�븯�쐞 �씪媛� �꽭�똿
+        this.setIssueComments(issue, issueVo);  //  �뙎湲� �젙蹂� �뀑�똿
+        this.setIssueHistory(issue, issueVo);   //  �씠�뒋 湲곕줉 �젙蹂� �뀑�똿
 
         IssueType issueType = this.issueTypeService.getIssueType(issueVo.getIssueTypeVo().getId()); // �씠�뒋�쓽 �씠�뒋�쑀�삎 媛앹껜
         Integer using = issueType.getUsePartner() != null ? issueType.getUsePartner().intValue() : 0; // �씠�뒋�쑀�삎蹂꾨줈 �궗�슜以묒씤 �뾽泥�/ISP/�샇�뒪�똿 媛�
@@ -1374,7 +1809,6 @@
         this.setIssueCompanyField(issue, issueVo);  //�뾽泥� �젙蹂� �꽭�똿
         this.setIssueIspField(issue, issueVo);  //ISP �젙蹂� �꽭�똿
         this.setIssueHostingField(issue, issueVo);  //HOSTING �젙蹂� �꽭�똿
-
         this.setParentIssue(issue,issueVo); //�긽�쐞 �씠�뒋 �젙蹂� �꽭�똿
     }
 
@@ -1406,13 +1840,18 @@
 
     // �뿰愿� �씠�뒋 �젙蹂대�� �뀑�똿�븳�떎
     private void setRelationIssue(Issue issue, IssueVo issueVo) {
-        Set<IssueRelation> issueRelations = issue.getIssueRelations();
-        if (issue != null && issueVo != null && issueRelations.size() > 0) {
-            for (IssueRelation issueRelation : issueRelations) {
-                IssueRelationVo issueRelationVo = ConvertUtil.copyProperties(issueRelation, IssueRelationVo.class);
+        //Set<IssueRelation> issueRelations = issue.getIssueRelations();
 
-                Issue relationIssue = issueRelation.getRelationIssue();
+        List<Map<String, Object>> results = this.issueRelationMapper.findByIssueId(issueVo);
+        Long totalCount = this.issueRelationMapper.count(issueVo);
 
+        if (issue != null && issueVo != null && results.size() > 0) {
+            int totalPage = (int) Math.ceil((totalCount - 1) / issueVo.getRelPageSize()) + 1;
+            issueVo.setRelTotalPage(totalPage);
+            issueVo.setRelTotalCount(totalCount);
+            for (Map<String, Object> result : results) {
+                IssueRelationVo issueRelationVo = ConvertUtil.convertMapToClass(result, IssueRelationVo.class);
+                Issue relationIssue = this.findOne(MapUtil.getLong(result, "relationIssueId"));
                 IssueVo relIssueVo = ConvertUtil.copyProperties(relationIssue, IssueVo.class);
                 Project project = this.projectService.getProject(relationIssue.getProject().getId());
                 relIssueVo.setProjectId(project.getId());
@@ -1429,9 +1868,30 @@
                 issueStatusVo.setIssueStatusType(relationIssue.getIssueStatus().getIssueStatusType().toString());
                 issueRelationVo.setIssueStatusVo(issueStatusVo);
 
+                issueRelationVo.setModifyPermissionCheck(issueVo.getModifyPermissionCheck());
+
                 this.setRegister(relationIssue, relIssueVo); // �벑濡앹옄
                 this.setIssueDepartment(relationIssue, relIssueVo);  //  �떞�떦遺��꽌 �젙蹂� �뀑�똿
                 this.setIssueCustomFields(relationIssue, relIssueVo);   // �궗�슜�옄�젙�쓽�븘�뱶 �젙蹂� �꽭�똿
+
+                Set<IssueCompany> issueCompanies = relationIssue.getIssueCompanies();
+                Iterator<IssueCompany> itrCompany = issueCompanies.iterator();
+                while (itrCompany.hasNext()) {
+                    issueRelationVo.addIssueCompanyVo(ConvertUtil.copyProperties(itrCompany.next(), IssueCompanyVo.class));
+                }
+
+                Set<IssueIsp> issueIsps = relationIssue.getIssueIspFields();
+                Iterator<IssueIsp> itrIsp = issueIsps.iterator();
+                while (itrIsp.hasNext()) {
+                    issueRelationVo.addIssueIspVo(ConvertUtil.copyProperties(itrIsp.next(), IssueIspVo.class));
+                }
+
+                Set<IssueHosting> issueHostings = relationIssue.getIssueHostingFields();
+                Iterator<IssueHosting> itrHosting = issueHostings.iterator();
+                while (itrHosting.hasNext()) {
+                    issueRelationVo.addIssueHostingVo(ConvertUtil.copyProperties(itrHosting.next(), IssueHostingVo.class));
+                }
+
                 issueVo.addIssueRelationVo(issueRelationVo);
             }
         } else {
@@ -1483,6 +1943,15 @@
             DepartmentVo departmentVo = ConvertUtil.copyProperties(issueDepartment.getDepartment(), DepartmentVo.class);
             departmentVo.setByName(departmentVo.getDepartmentName());
             departmentVos.add(departmentVo);
+
+            List<UserDepartment> userDepartments = this.userDepartmentRepository.findByDepartmentId(departmentVo.getId());
+            if (userDepartments != null && userDepartments.size() > 0) {
+                for (UserDepartment userDepartment : userDepartments) {
+                    if (userDepartment.getUserId().equals(this.webAppUtil.getLoginId())){
+                        issueVo.setModifyPermissionCheck(Boolean.TRUE);
+                    }
+                }
+            }
         }
         issueVo.setDepartmentVos(departmentVos);
     }
@@ -1524,7 +1993,7 @@
 
     //  �씠�뒋 湲곕줉 �젙蹂대�� �뀑�똿�븳�떎.
     private void setIssueHistory(Issue issue, IssueVo issueVo) {
-        issueVo.setIssueHistoryVos(this.issueHistoryService.findIssueHistory(issue.getId()));
+        issueVo.setIssueHistoryVos(this.issueHistoryService.findIssueHistory(issue));
     }
 
     // �궗�슜�옄 �젙�쓽 �븘�뱶 媛믪씠 媛숈� �씠�뒋 李얘린
@@ -1536,10 +2005,15 @@
         List<Issue> resultIssueVos = Lists.newArrayList();
         String comma = ",";
 
+        List<String> userValues = Lists.newArrayList();
         if (issueCustomFieldValueForms.size() > 0) {
+            IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator();
+            Collections.sort(issueCustomFieldValueForms, comp);
+
             String concatUseValue = "";
             for (int i = 0; i < issueCustomFieldValueForms.size(); i++) {
                 IssueCustomFieldValueForm issueCustomFieldValueForm = issueCustomFieldValueForms.get(i);
+                userValues.add(issueCustomFieldValueForm.getUseValue());
                 if (i > 0) {
                     concatUseValue = concatUseValue.concat(comma);
                 }
@@ -1548,7 +2022,9 @@
 
             IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
             issueCustomFieldValueCondition.setUseValue(concatUseValue);
+            issueCustomFieldValueCondition.setUseValues(userValues);
             issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId());
+            issueCustomFieldValueCondition.setIssueStatusType("CLOSE");
             List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
             if (results != null && results.size() > 0) {
                 for (Map<String, Object> result : results) {
@@ -1583,21 +2059,28 @@
             List<Issue> issues = Lists.newArrayList();
             for (Issue issueVo : issue) {
                 issueForm.setId(issueVo.getId());
+                issueForm.setTitle(issueVo.getTitle());
 
                 // �옄�룞 醫낅즺 �긽�깭 �꽕�젙�씠 �릺�뼱 �엳吏� �븡�쑝硫� �삤瑜섎컻�깮
                 Issue modifyIssue = this.modifyIssueForApi(user, issueForm, files);
                 Issue parentIssue = modifyIssue.getParentIssue();
                 IssueType issueType = modifyIssue.getIssueType();
-                IssueStatus issueStatus = issueType.getIssueStatus();
+
+                Set<IssueTypeApiEndStatus> issueTypeApiEndStatuses = issueType.getIssueTypeApiEndStatuses();
+                IssueTypeApiEndStatus issueStatus = null;
+                if (issueTypeApiEndStatuses != null && issueTypeApiEndStatuses.size() > 0) {
+                    issueStatus = issueTypeApiEndStatuses.iterator().next();
+                } else {
+                    throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_COMPLETE_ISSUE_STATUS_NOT_EXIST));
+                }
+
                 if (parentIssue != null) {
-                    if (issueStatus == null) {
-                        throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_COMPLETE_ISSUE_STATUS_NOT_EXIST));
-                    }
+
                     IssueCondition issueCondition = new IssueCondition(issueVo.getId(), parentIssue.getId());
                     List<Map<String, Object>> results = this.issueMapper.findNotCompleteByParentIssueId(issueCondition);
                     // �븯�쐞 �씪媛먯씠 紐⑤몢 醫낅즺 �긽�깭�씪�븣 �긽�쐞 �씪媛먮룄 醫낅즺 泥섎━
                     if (results == null || results.size() == 0) {
-                        parentIssue.setIssueStatus(issueType.getIssueStatus());
+                        parentIssue.setIssueStatus(issueStatus.getIssueStatus());
                         this.issueRepository.saveAndFlush(parentIssue);
                     }
                 }
@@ -1664,6 +2147,13 @@
     // �씠�뒋 �닔�젙(API�슜)
     private Issue modifyIssueForApi(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) {
         CheckIssueData checkIssueData = this.checkIssue(user, issueForm);
+
+        if (issueForm.getComment() != null && !issueForm.getComment().equals("")) { //�뙎湲� 異붽�
+            IssueCommentForm issueCommentForm = new IssueCommentForm();
+            issueCommentForm.setDescription(issueForm.getComment());
+            issueCommentForm.setIssueId(issueForm.getId());
+            this.issueCommentService.addIssueComment(issueCommentForm, user);
+        }
 
         // �씠�뒋 �씠�젰 �궓湲곌린
         this.addIssueHistoryModify(user, issueForm, checkIssueData, multipartFiles);
@@ -1759,20 +2249,30 @@
         this.checkNotHaveIssueIdAttachedFile(issue, issueForm);
         //  �궗�슜�옄 �젙�쓽 �븘�뱶 ���옣
         this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields());
-        //  �씠�뒋 �씠�젰 �벑濡�
-        if (!StringUtils.isEmpty(detectIssueChange.toString())) {
-            this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString());
-        }
         //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
         UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class);
         log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_MODIFY));
 
         //  �뾽泥� �젙蹂� ���옣
-        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
+        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange);
         //  ISP �젙蹂� ���옣
-        this.issueIspService.modifyIssueIspField(issue, issueForm.getIssueIspFields());
+        this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange);
         //  HOSTING �젙蹂� ���옣
-        this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields());
+        this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange);
+
+        //  �뙆�듃�꼫�젙蹂� �븯�쐞�씠�뒋 �긽�냽
+        List<Issue> downIssues = this.issueRepository.findByParentIssueId(issue.getId());
+        if (issueForm.getInheritYn() != null && issueForm.getInheritYn()
+                && downIssues != null && downIssues.size() > 0) {
+            for (Issue downIssue : downIssues) {
+                this.inheritPartners(downIssue, issue);
+            }
+        }
+
+        //  �씠�뒋 �씠�젰 �벑濡�
+        if (!StringUtils.isEmpty(detectIssueChange.toString())) {
+            this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString());
+        }
 
         return issue;
     }
@@ -1889,7 +2389,7 @@
     //  �씠�뒋 �닔�젙 沅뚰븳 泥댄겕
     private void verifyIssueModifyPermission(Issue issue, User user) {
         //  �씠�뒋 �닔�젙 沅뚰븳�쓣 媛뽮퀬 �엳�뒗吏� �솗�씤
-        if (!this.checkHasPermission(ConvertUtil.copyProperties(issue, IssueVo.class), this.getIssueUserVos(issue), user)) {
+        if (!this.checkHasPermission(ConvertUtil.copyProperties(issue, IssueVo.class), this.getIssueUserVos(issue), user, this.getIssueDepartmentVos(issue))) {
             throw new OwlRuntimeException(
                     this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_MODIFY_PERMISSION));
         }
@@ -1914,18 +2414,41 @@
         return userVos;
     }
 
+    //  �씠�뒋�뿉�꽌 �떞�떦�옄 �젙蹂대�� 異붿텧�븳�떎.
+    private List<DepartmentVo> getIssueDepartmentVos(Issue issue) {
+        List<DepartmentVo> departmentVos = Lists.newArrayList();
+
+        Set<IssueDepartment> issueDepartments = issue.getIssueDepartments();
+
+        try {
+            for (IssueDepartment issueDepartment : issueDepartments) {
+                Department department = issueDepartment.getDepartment();
+                DepartmentVo departmentVo = ConvertUtil.copyProperties(department, DepartmentVo.class);
+                departmentVos.add(departmentVo);
+            }
+        } catch (Exception ex) {
+
+        }
+
+        return departmentVos;
+    }
+
     //  �씠�뒋 �닔�젙 沅뚰븳�쓣 媛뽮퀬 �엳�뒗吏� �솗�씤
-    private boolean checkHasPermission(IssueVo issueVo, List<UserVo> issueUserVos, User user) {
+    private boolean checkHasPermission(IssueVo issueVo, List<UserVo> issueUserVos, User user, List<DepartmentVo> departmentVos) {
         boolean hasPermission = false;
 
         //  �뾽臾� 怨듦컙 愿�由ъ옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
         hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.WORKSPACE_MANAGER, issueVo, null, null, user);
         //  �봽濡쒖젥�듃 愿�由ъ옄�씪 寃쎌슦 �빐�떦 �봽濡쒖젥�듃�뿉 �벑濡앸맂 �씠�뒋�뒗 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
         hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.PROJECT_MANAGER, issueVo, null, null, user);
+        //  �씠�뒋 愿�由ъ옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
+        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ISSUE_MANAGER, issueVo, null, null, user);
         //   �씠�뒋 �벑濡앹옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
         hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.REGISTER, issueVo, null, null, user);
-        //  �씠�뒋 �떞�떦�옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎. => �떞�떦遺��꽌濡� �닔�젙 - 泥댄겕
+        //  �씠�뒋 �떞�떦�옄�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
         //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ASSIGNEE, issueVo, issueUserVos);
+        //  �씠�뒋 �떞�떦遺��꽌�씪 寃쎌슦 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
+        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.DEPARTMENT, issueVo, null, departmentVos, user);
         //  �떞�떦�옄媛� �뾾�쑝硫� 紐⑤뱺 �궗�슜�옄媛� �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
 
         //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ALL_ISSUE_MANAGER, issueVo, null, null, user);
@@ -1935,7 +2458,7 @@
     }
 
     //  �씠�뒋 �닔�젙 沅뚰븳�쓣 �솗�씤�븳�떎.
-    private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List<UserVo> issueUserVos, List<DepartmentVo> issueDepartmentVos, User user) {
+    private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List<UserVo> issueUserVos, List<DepartmentVo> departmentVos, User user) {
         if (!hasPermission) {
             switch (checkType) {
                 case Issue.WORKSPACE_MANAGER:  //  �뾽臾� 怨듦컙 愿�由ъ옄
@@ -1947,6 +2470,11 @@
                     Issue issue = this.getIssue(issueVo.getId());
                     //  �봽濡쒖젥�듃 愿�由ъ옄�씪 寃쎌슦 �빐�떦 �봽濡쒖젥�듃�뿉 �벑濡앸맂 �씠�뒋�뒗 �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
                     hasPermission = this.projectRoleUserService.checkProjectManager(issue.getProject(), user);
+                    break;
+
+                case Issue.ISSUE_MANAGER:    //  �씠�뒋 愿�由ъ옄
+                    UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId());
+                    hasPermission = MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE);
                     break;
 
                 case Issue.REGISTER:   //  �씠�뒋 �벑濡앹옄
@@ -1970,17 +2498,22 @@
 
                 case Issue.DEPARTMENT:
                     //  �떞�떦遺��꽌媛� �뾾�쑝硫� 紐⑤뱺 �궗�슜�옄媛� �닔�젙 沅뚰븳�쓣 媛뽯뒗�떎.
-                    if (issueDepartmentVos.size() < 1) {
+                    /*if (userDepartmentVos.size() < 1) {
                         hasPermission = true;
                         break;
-                    }
-                    //   �씠�뒋 �떞�떦遺��꽌 �뿬遺� �솗�씤
-                    /*for (DepartmentVo issueDepartmentVo : issueDepartmentVos) {
-                        if (issueDepartmentVo.getId().equals()) {
-                            hasPermission = true;
-                            break;
-                        }
                     }*/
+                    //   �씠�뒋 �떞�떦遺��꽌 �뿬遺� �솗�씤
+                    for (DepartmentVo departmentVo : departmentVos) {
+                        List<UserDepartment> userDepartments = this.userDepartmentService.findByDepartmentId(departmentVo.getId());
+                        if(userDepartments != null && userDepartments.size() > 0) {
+                            for (UserDepartment userDepartment : userDepartments) {
+                                if (userDepartment.getUserId().equals(user.getId())){
+                                    hasPermission = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
                     break;
             }
         }
@@ -2003,6 +2536,19 @@
         this.verifyIssueModifyPermission(issue, user);
 
         IssueStatus issueStatus = this.issueStatusService.getIssueStatus(issueForm.getIssueStatusId());
+
+        if (issueStatus.getIssueStatusType().toString().equals("CLOSE")) {
+            List<String> downIssuesStatus = issueForm.getDownIssuesStatus();
+            if (downIssuesStatus != null && downIssuesStatus.size() > 0) {
+                for (String downIssueStatus : downIssuesStatus) {
+                    if (!downIssueStatus.equals("CLOSE")) {
+                        throw new OwlRuntimeException(
+                                this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_MODIFY_STATUS));
+                    }
+                }
+            }
+        }
+
         //  �씠�뒋 �긽�깭瑜� 蹂�寃쏀븷 �븣 �꽑�깮�븳 �씠�뒋 �긽�깭濡� 蹂�寃쏀븷 �닔 �엳�뒗吏� �솗�씤�븳�떎.
         this.issueStatusService.checkNextIssueStatus(issue, issueStatus);
         //  蹂�寃� �씠�젰 �젙蹂� 異붿텧
@@ -2162,21 +2708,24 @@
                     this.messageAccessor.getMessage(MsgConstants.ISSUE_REMOVE_NOT_SELECT));
         }
 
-        List<Issue> removeIssues = Lists.newArrayList();
+        Set<Long> removeIds = new HashSet<>();
 
         for (Long issueId : issueForm.getRemoveIds()) {
+            removeIds.add(issueId);
             //�븯�쐞�씠�뒋 泥댄겕
             List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueId);
             if(downIssues != null && downIssues.size() > 0){
                 for(Issue downIssue : downIssues){
                     Long downIssueId = downIssue.getId();
-                    downIssue = this.issueRemoves(downIssueId, user);
-                    removeIssues.add(downIssue);
+                    removeIds.add(downIssueId);
                 }
             }
-            Issue issue = this.issueRemoves(issueId, user);
-            removeIssues.add(issue);
         }
+
+        for (Long removeId : removeIds) {
+            this.issueRemoves(removeId, user);
+        }
+
         //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
         log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_REMOVE));
     }
@@ -2371,6 +2920,9 @@
         excelInfo.addAttrInfos(new ExportExcelAttrVo("register", this.messageAccessor.message("common.register"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �벑濡앹옄
         excelInfo.addAttrInfos(new ExportExcelAttrVo("period", this.messageAccessor.message("common.period"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 湲곌컙
         excelInfo.addAttrInfos(new ExportExcelAttrVo("modifyDate", this.messageAccessor.message("common.modifyDate"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 理쒖쥌 蹂�寃쎌씪
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("companyName", this.messageAccessor.message("common.company"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �뾽泥�
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("ispName", this.messageAccessor.message("common.isp"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // ISP
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("hostingName", this.messageAccessor.message("common.hosting"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �샇�뒪�똿
 
 
         //  �궗�슜�옄 �젙�쓽 �븘�뱶瑜� �궗�슜�븳 �씠�뒋瑜� 李얜뒗�떎. 留뚯빟 �씠�뒋媛� �뾾�떎硫� �뿬湲곗꽌 �씠�뒋 議고쉶媛� �걹�궃�떎.
@@ -2431,8 +2983,16 @@
 
         for (IssueVo issueVo : issueVos) {
             for (Map<String, Object> issueCustomFieldValue : issueCustomFieldValues) {
+                int count = 0;
+                Map<String, Object> useValues = new HashMap<>();
+
                 if (issueVo.getId().equals(MapUtil.getLong(issueCustomFieldValue, "issueId"))) {
                     IssueCustomFieldValueVo issueCustomFieldValueVo = new IssueCustomFieldValueVo();
+
+                    useValues.put("useValue"+count, MapUtil.getString(issueCustomFieldValue, "useValue"));
+                    useValues.put("customFieldId", MapUtil.getLong(issueCustomFieldValue, "customFieldId"));
+                    issueCustomFieldValueVo.setUseValues(useValues);
+
                     issueCustomFieldValueVo.setUseValue(MapUtil.getString(issueCustomFieldValue, "useValue"));
 
                     CustomFieldVo customFieldVo = new CustomFieldVo();
@@ -2454,6 +3014,30 @@
             CompanyField companyField = issueCompany.getCompanyField();
             if (companyField != null) {
                 issueCompanyVo.setCompanyId(issueCompany.getCompanyField().getId());
+                if (issueCompany.getCompanyTypeId() != null && issueCompany.getCompanyTypeId() != -1) {
+                    CompanyFieldCategory companyType = this.companyFieldCategoryService.find(issueCompany.getCompanyTypeId());
+                    issueCompanyVo.setCompanyTypeName(companyType.getUseValue());
+                }
+                if (issueCompany.getParentSectorId() != null && issueCompany.getParentSectorId() != -1) {
+                    CompanyFieldCategory parentSector = this.companyFieldCategoryService.find(issueCompany.getParentSectorId());
+                    issueCompanyVo.setParentSectorName(parentSector.getUseValue());
+                }
+                if (issueCompany.getChildSectorId() != null && issueCompany.getChildSectorId() != -1) {
+                    CompanyFieldCategory childSector = this.companyFieldCategoryService.find(issueCompany.getChildSectorId());
+                    issueCompanyVo.setChildSectorName(childSector.getUseValue());
+                }
+                if (issueCompany.getRegionId() != null && issueCompany.getRegionId() != -1) {
+                    CompanyFieldCategory region = this.companyFieldCategoryService.find(issueCompany.getRegionId());
+                    issueCompanyVo.setRegionName(region.getUseValue());
+                }
+                if (issueCompany.getStatusId() != null && issueCompany.getStatusId() != -1) {
+                    if (issueCompany.getStatusName() != null && !issueCompany.getStatusName().equals("")) {
+                        issueCompanyVo.setStatusName(issueCompany.getStatusName());
+                    } else {
+                        CompanyFieldCategory status = this.companyFieldCategoryService.find(issueCompany.getStatusId());
+                        issueCompanyVo.setStatusName(status.getUseValue());
+                    }
+                }
             }
             issueCompanyVos.add(issueCompanyVo);
         }
@@ -2523,6 +3107,9 @@
                 result.put("departments", CommonUtil.convertDepartmentVosToString(issueVo.getDepartmentVos()));
                 result.put("priorityName", issueVo.getPriorityName());
                 result.put("severityName", issueVo.getSeverityName());
+                result.put("companyName", issueVo.getCompanyName());
+                result.put("ispName", issueVo.getIspName());
+                result.put("hostingName", issueVo.getHostingName());
 
                 UserVo register = this.userService.removeSensitiveUser(issueVo.getRegisterId());
                 //  �벑濡앹옄
@@ -2596,13 +3183,13 @@
         excelInfo.setFileName(this.messageAccessor.message("common.registerExcelIssue")); // �뿊��濡� �씠�뒋 �벑濡앺븯湲�
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.title"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // �젣紐�
         excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.content"), 40, ExportExcelAttrVo.ALIGN_CENTER)); // �궡�슜
-        excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.projectKey"), 10, ExportExcelAttrVo.ALIGN_LEFT)); // �봽濡쒖젥�듃 �궎
-        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.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)); // 醫낅즺�씪
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.company"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �뾽泥�
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.isp"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // ISP
+        excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.hosting"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // �샇�뒪�똿
         //  �봽濡쒖젥�듃�뿉 �뿰寃곕맂 �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� 異붿텧�븯�뿬 �뿊�� download �뀥�뵆由우쓣 留뚮뱺�떎.
         this.makeIssueExcelTemplateCustomFields(excelInfo, conditions);
         //  �뿊���뿉 �꽔�쓣 �뜲�씠�꽣 - IssueVos �뜲�씠�꽣瑜� �뿊���뿉�꽌 �몴�떆�븷 �닔 �엳�뒗 �뜲�씠�꽣濡� 蹂�寃쏀븳�떎.
@@ -2624,7 +3211,7 @@
     //  �뿊�� import 濡� �씠�뒋瑜� �벑濡앺븳�떎.
     @Override
     @Transactional
-    public void importExcel(MultipartFile multipartFile) throws Exception {
+    public void importExcel(IssueForm issueForm, MultipartFile multipartFile) throws Exception {
         /*StopWatch serviceStart = new StopWatch();
         serviceStart.start();*/
 
@@ -2635,25 +3222,30 @@
             //  �뾽濡쒕뱶 �뙆�씪 �솗�옣�옄 泥댄겕
             this.verifyMultipartFileExtension(multipartFile);
 
-            Map<String, Project> projectMaps = new HashMap<>(); //  �봽濡쒖젥�듃 紐⑥쓬
-            Map<String, IssueType> issueTypeMaps = new HashMap<>(); //  �씠�뒋 ���엯 紐⑥쓬
             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, DepartmentVo> 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<>(); //  �씠�뒋 ���엯 + �궗�슜�옄 �젙�쓽 �븘�뱶 �뿰寃� �젙蹂�
+
+            Map<String, CompanyField> companyFieldMaps = new HashMap<>();   //�뾽泥� 紐⑥쓬
+            Map<String, IspField> ispFieldMaps = new HashMap<>();   //isp 紐⑥쓬
+            Map<String, HostingField> hostingFieldMaps = new HashMap<>();   //�샇�뒪�똿 紐⑥쓬
+
             Workspace workspace = this.workspaceService.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());  //  �씠�뒋瑜� �꽔�쑝�젮�뒗 �뾽臾� 怨듦컙
             //  �씠�뒋�쓽 二쇱슂 �냽�꽦�쓣 map �뿉 ���옣�븯�뿬 �뿊�� import �뿉�꽌 吏��젙�븳 ���긽(�씠�뒋 �냽�꽦)�쓣 鍮좊Ⅴ寃� 李얠쓣 �닔 �엳寃� �븳�떎.
-            this.IssueAttributeMapToList(projectMaps, issueTypeMaps, priorityMaps, severityMaps, userMaps, departmentMaps, customFieldMaps, issueNumberMaps, issueTypeCustomFieldMaps, issueStatusReadyMaps);
+            this.IssueAttributeMapToList(issueForm, priorityMaps, severityMaps, departmentMaps, customFieldMaps,
+                    issueTypeCustomFieldMaps, companyFieldMaps, ispFieldMaps, hostingFieldMaps);
             //  0.237 - 0.230
 
             List<IssueForm> issueForms = Lists.newArrayList();
             List<String> headers = Lists.newArrayList();
 
             Workbook workbook;
+
+            IssueType issueType = new IssueType();
+            Workflow workflow = new Workflow();
 
             workbook = WorkbookFactory.create(multipartFile.getInputStream());
             Sheet sheet = workbook.getSheetAt(0);
@@ -2690,7 +3282,20 @@
                 //  1踰� �뿤�뜑遺��꽣 �뜲�씠�꽣 �쁺�뿭
                 if (rowIndex > 1) {
                     //  �씠�뒋濡� �벑濡앺븯湲� �쐞�빐 IssueForm �뿉 �뜲�씠�꽣瑜� �뀑�똿�븳�떎.
-                    issueForms.add(this.setIssueFormToExcelField(row, (rowIndex + 1), issueStatusReadyMaps, projectMaps, issueTypeMaps, priorityMaps, severityMaps, userMaps, customFieldMaps, issueNumberMaps, headers));
+                    IssueForm newIssueForm = this.setIssueFormToExcelField(row, (rowIndex + 1), priorityMaps, severityMaps, customFieldMaps,
+                            companyFieldMaps, ispFieldMaps, hostingFieldMaps, headers);
+                    ConvertUtil.copyProperties(issueForm, newIssueForm);
+
+                    Project project = this.projectService.getProject(newIssueForm.getProjectId());
+                    Long issueNumber = this.issueNumberGeneratorService.generateIssueNumber(project);
+                    newIssueForm.setIssueNumber(issueNumber);
+
+                    issueType = this.issueTypeService.getIssueType(newIssueForm.getIssueTypeId());
+                    workflow = issueType.getWorkflow();
+                    IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(workflow);
+
+                    newIssueForm.setIssueStatusId(issueStatus.getId());
+                    issueForms.add(newIssueForm);
                 }
             }
 
@@ -2699,9 +3304,29 @@
             }
             //  1.176
 
-
             //  �씠�뒋 �벑濡�
             this.issueMapper.insertBatch(issueForms);
+
+            for (IssueForm saveIssueForm : issueForms) {
+                Issue issue = new Issue();
+                ConvertUtil.copyProperties(saveIssueForm, issue);
+
+                if (issueForm.getInheritYn() != null && issueForm.getInheritYn() && issueForm.getParentIssueId() != null) {
+                    Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
+                    //  �긽�쐞�씠�뒋�쓽 �뙆�듃�꼫 �젙蹂� �긽�냽
+                    this.inheritPartners(issue, parentIssue);
+                }
+
+                saveIssueForm.setId(issue.getId());
+
+                //  �썙�겕�뵆濡쒖슦 ��湲� �긽�깭�쓽 遺��꽌 異붽�
+                List<Long> departmentsIds = this.workflowDepartmentService.findFirstDepartmentIds(workflow);
+                if (departmentsIds != null && departmentsIds.size() > 0) {
+                    this.issueDepartmentService.add(departmentsIds, workspace, issue);
+                }
+                this.setIssuePartners(saveIssueForm, issue);
+            }
+
             //  0.416 - 0.439
 
             //  1.373 ~ 1.394
@@ -2720,8 +3345,6 @@
             this.bulkInsertIssueCustomFieldValue(issueForms, issueTypeCustomFieldMaps);
             //  3.628 - 3.445
 
-            // �뾽泥�,ISP,�샇�뒪�똿 異붽�
-
             /*serviceStart.stop();
             log.debug("2李� ���옣 �떆媛� : " + serviceStart.getTime());*/
 
@@ -2731,7 +3354,68 @@
             //  reverse index �뾽�뜲�씠�듃
             this.issueMapper.updateBatch(issueForms);
             //  利앷��맂 �씠�뒋 踰덊샇瑜� �뾽�뜲�씠�듃 �븳�떎.
-            this.issueNumberGeneratorService.updateIssueNumber(issueNumberMaps);
+//            issueNumberMaps.put(issueForm.getProjectId(), issueForm.getProjectId());
+//            this.issueNumberGeneratorService.updateIssueNumber(issueNumberMaps);
+        }
+    }
+
+    /**
+     * �뿊��濡� �엯�젰�븳 �뙆�듃�꼫 �젙蹂� ���옣
+     * @param issueForm IssueForm
+     */
+    private void setIssuePartners(IssueForm issueForm, Issue issue) {
+        //issueCompany �벑濡�
+        if (issueForm.getIssueCompanyFields() != null && issueForm.getIssueCompanyFields().size() > 0) {
+            for (Map<String, Object> issueCompanyMap : issueForm.getIssueCompanyFields()) {
+                CompanyField companyField =  ConvertUtil.convertMapToClass(issueCompanyMap, CompanyField.class);
+                IssueCompany issueCompany = ConvertUtil.convertMapToClass(issueCompanyMap, IssueCompany.class, "id", "registerDate", "modifyDate");
+                issueCompany.setCompanyField(companyField);
+                issueCompany.setIssue(issue);
+                this.issueCompanyRepository.saveAndFlush(issueCompany);
+
+                //  �궗�슜�옄媛� ISP瑜� 吏곸젒 �엯�젰�븯吏� �븡�븯�쓣 寃쎌슦 �뾽泥댁뿉 �벑濡앸릺�뼱�엳�뒗 ISP �꽕�젙
+                if (issueForm.getIssueIspFields() == null || issueForm.getIssueIspFields().size() < 1) {
+                    //  �뾽泥댁쓽 ISP媛� �엳�뒗 寃쎌슦 issueISP �벑濡�
+                    if (companyField.getIspId() != null && companyField.getIspId() != -1) {
+                        IspField ispField = this.ispFieldService.getIsp(companyField.getIspId());
+                        IssueIsp issueIsp = ConvertUtil.copyProperties(ispField, IssueIsp.class, "id", "registerDate", "modifyDate");
+                        issueIsp.setIspField(ispField);
+                        issueIsp.setIssue(issue);
+                        this.issueIspRepository.saveAndFlush(issueIsp);
+                    }
+                }
+                //  �궗�슜�옄媛� �샇�뒪�똿�쓣 吏곸젒 �엯�젰�븯吏� �븡�븯�쓣 寃쎌슦 �뾽泥댁뿉 �벑濡앸릺�뼱�엳�뒗 �샇�뒪�똿 �꽕�젙
+                if (issueForm.getIssueHostingFields() == null || issueForm.getIssueHostingFields().size() < 1) {
+                    //  �뾽泥댁쓽 �샇�뒪�똿�씠 �엳�뒗 寃쎌슦 issueHosting �벑濡�
+                    if (companyField.getHostingId() != null && companyField.getHostingId() != -1) {
+                        HostingField hostingField = this.hostingFieldService.getHosting(companyField.getHostingId());
+                        IssueHosting issueHosting = ConvertUtil.copyProperties(hostingField, IssueHosting.class, "id", "registerDate", "modifyDate");
+                        issueHosting.setHostingField(hostingField);
+                        issueHosting.setIssue(issue);
+                        this.issueHostingRepository.saveAndFlush(issueHosting);
+                    }
+                }
+            }
+        }
+        //issueIsp �벑濡�
+        if (issueForm.getIssueIspFields() != null && issueForm.getIssueIspFields().size() > 0) {
+            for (Map<String, Object> issueIspMap : issueForm.getIssueIspFields()) {
+                IssueIsp issueIsp = ConvertUtil.convertMapToClass(issueIspMap, IssueIsp.class, "id", "registerDate", "modifyDate");
+                IspField ispField = ConvertUtil.convertMapToClass(issueIspMap, IspField.class);
+                issueIsp.setIspField(ispField);
+                issueIsp.setIssue(issue);
+                this.issueIspRepository.saveAndFlush(issueIsp);
+            }
+        }
+        //issueHosting �벑濡�
+        if (issueForm.getIssueHostingFields() != null && issueForm.getIssueHostingFields().size() > 0) {
+            for (Map<String, Object> issueHostingMap : issueForm.getIssueHostingFields()) {
+                IssueHosting issueHosting = ConvertUtil.convertMapToClass(issueHostingMap, IssueHosting.class, "id", "registerDate", "modifyDate");
+                HostingField hostingField = ConvertUtil.convertMapToClass(issueHostingMap, HostingField.class);
+                issueHosting.setHostingField(hostingField);
+                issueHosting.setIssue(issue);
+                this.issueHostingRepository.saveAndFlush(issueHosting);
+            }
         }
     }
 
@@ -2832,6 +3516,9 @@
                 issueCustomField.put("registerId", this.webAppUtil.getLoginId());
                 issueCustomFieldValueMaps.add(issueCustomField);
             }
+
+            //  �뿊���뿉 �뾽泥대챸�쓣 �엯�젰�븯吏� �븡�븯�쓣 寃쎌슦 媛숈� �룄硫붿씤 �뾽泥� 李얘린
+            this.findPartnerByDomain(issueForm);
         }
 
         if (issueCustomFieldValueMaps.size() > 0) {
@@ -2839,51 +3526,57 @@
         }
     }
 
-    //  �씠�뒋�쓽 二쇱슂 �냽�꽦�쓣 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, 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();
+    /**
+     * �뿊���뿉 �뾽泥대챸�쓣 �엯�젰�븯吏� �븡�븯�쓣 寃쎌슦 媛숈� �룄硫붿씤 �뾽泥� 李얘린
+     * @param issueForm IssueForm
+     */
+    private void findPartnerByDomain(IssueForm issueForm) {
+        if (issueForm.getIssueCompanyFields() == null || issueForm.getIssueCompanyFields().size() < 1) {
+            // 媛숈� �룄硫붿씤 �뾽泥� 李얘린
+            IssueForm partners = this.findCompanyField(issueForm);
+            Issue issue = this.findOne(issueForm.getId());
+            if (partners.getIssueCompanyFields() != null && partners.getIssueCompanyFields().size() > 0) {
+                for (Map<String, Object> company : partners.getIssueCompanyFields()) {
+                    IssueCompany issueCompany = ConvertUtil.convertMapToClass(company, IssueCompany.class);
+                    CompanyField companyField = ConvertUtil.convertMapToClass(company, CompanyField.class);
+                    issueCompany.setCompanyField(companyField);
+                    issueCompany.setIssue(issue);
 
-        for (Project project : projects) {
-            projectIds.add(project.getId());
-            //  �빐�떦 �봽濡쒖젥�듃�뿉�꽌 �깮�꽦�릺�뒗 �떎�쓬 �씠�뒋 踰덊샇瑜� �깮�꽦�빐�삩�떎.
-            issueNumberMaps.put(project.getId(), this.issueNumberGeneratorService.generateIssueNumber(project));
-            projectMaps.put(project.getProjectKey(), project);
-
-            for (IssueTypeCustomField issueTypeCustomField : project.getIssueTypeCustomFields()) {
-                //  鍮좊Ⅴ寃� 李얘린 �쐞�빐 �씠�뒋 ���엯 �븘�씠�뵒 + �궗�슜�옄 �젙�쓽 �븘�뱶 �븘�씠�뵒瑜� �궎濡� �븳�떎.
-                String makeKey = issueTypeCustomField.getIssueType().getId().toString() + issueTypeCustomField.getCustomField().getId().toString();
-                issueTypeCustomFieldMaps.put(makeKey, issueTypeCustomField.getId());
+                    this.issueCompanyRepository.saveAndFlush(issueCompany);
+                }
             }
-
-            //  �봽濡쒖젥�듃�뿉 李몄뿬�븯�뒗 �궗�슜�옄 �젙蹂�
-            List<Map<String, Object>> users = this.userService.findProjectMember(project);
-            Map<String, Object> userMap = new HashMap<>();
-            //  �궗�슜�옄 �젙蹂대�� Map �뿉 ���옣
-            for (Map<String, Object> user : users) {
-                userMap.put(CommonUtil.decryptAES128(MapUtil.getString(user, "account")), MapUtil.getLong(user, "userId"));
+            if (partners.getIssueIspFields() != null && partners.getIssueIspFields().size() > 0) {
+                for (Map<String, Object> isp : partners.getIssueIspFields()) {
+                    IssueIsp issueIsp = ConvertUtil.convertMapToClass(isp, IssueIsp.class);
+                    IspField ispField = ConvertUtil.convertMapToClass(isp, IspField.class);
+                    issueIsp.setIspField(ispField);
+                    issueIsp.setIssue(issue);
+                    this.issueIspRepository.saveAndFlush(issueIsp);
+                }
             }
-
-            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"));
+            if (partners.getIssueHostingFields() != null && partners.getIssueHostingFields().size() > 0) {
+                for (Map<String, Object> hosting : partners.getIssueHostingFields()) {
+                    IssueHosting issueHosting = ConvertUtil.convertMapToClass(hosting, IssueHosting.class);
+                    HostingField hostingField = ConvertUtil.convertMapToClass(hosting, HostingField.class);
+                    issueHosting.setHostingField(hostingField);
+                    issueHosting.setIssue(issue);
+                    this.issueHostingRepository.saveAndFlush(issueHosting);
+                }
             }
         }
+    }
 
-        //  �씠�뒋 �쑀�삎�쓣 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
-        List<IssueType> issueTypes = this.issueTypeService.findByWorkspaceId();
-        for (IssueType issueType : issueTypes) {
-            issueTypeMaps.put(issueType.getName(), issueType);
+    //  �씠�뒋�쓽 二쇱슂 �냽�꽦�쓣 map �뿉 ���옣�븯�뿬 �뿊�� import �뿉�꽌 吏��젙�븳 ���긽(�씠�뒋 �냽�꽦)�쓣 鍮좊Ⅴ寃� 李얠쓣 �닔 �엳寃� �븳�떎.
+    private void IssueAttributeMapToList(IssueForm issueForm, Map<String, Priority> priorityMaps, Map<String, Severity> severityMaps,
+                                         Map<String, DepartmentVo> departmentMaps, Map<String, CustomField> customFieldMaps,Map<String, Long> issueTypeCustomFieldMaps,
+                                         Map<String, CompanyField> companyFieldMaps, Map<String, IspField> ispFieldMaps, Map<String, HostingField> hostingFieldMaps) {
 
-            IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow());
-            issueStatusReadyMaps.put(issueType.getId().toString(), issueStatus);
+        Project project = this.projectService.getProject(issueForm.getProjectId());
+
+        for (IssueTypeCustomField issueTypeCustomField : project.getIssueTypeCustomFields()) {
+            //  鍮좊Ⅴ寃� 李얘린 �쐞�빐 �씠�뒋 ���엯 �븘�씠�뵒 + �궗�슜�옄 �젙�쓽 �븘�뱶 �븘�씠�뵒瑜� �궎濡� �븳�떎.
+            String makeKey = issueTypeCustomField.getIssueType().getId().toString() + issueTypeCustomField.getCustomField().getId().toString();
+            issueTypeCustomFieldMaps.put(makeKey, issueTypeCustomField.getId());
         }
 
         //  �슦�꽑�닚�쐞瑜� 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
@@ -2903,98 +3596,190 @@
         for (CustomField customField : customFields) {
             customFieldMaps.put(customField.getName(), customField);
         }
+
+        //  �뾽泥� �젙蹂대�� 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
+        List<CompanyField> companyFields = this.companyFieldService.findAll();
+        for (CompanyField companyField : companyFields) {
+            companyFieldMaps.put(companyField.getName(), companyField);
+        }
+        //  ISP �젙蹂대�� 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
+        List<IspField> ispFields = this.ispFieldService.findAll();
+        for (IspField ispField : ispFields) {
+            ispFieldMaps.put(ispField.getName(), ispField);
+        }
+        //  �샇�뒪�똿 �젙蹂대�� 諛붾줈 李얠쓣 �닔 �엳寃� 以�鍮�
+        List<HostingField> hostingFields = this.hostingFieldService.findAll();
+        for (HostingField hostingField : hostingFields) {
+            hostingFieldMaps.put(hostingField.getName(), hostingField);
+        }
+    }
+
+    /**
+     * cell String�쑝濡� 蹂��솚 �븿�닔
+     * @param cell Cell
+     * @param isNull boolean
+     * @return String
+     */
+    private String stringToCell (Cell cell, boolean isNull) {
+        String cellStr = "";
+        if (!isNull) {
+            cellStr = CommonUtil.convertExcelStringToCell(cell);
+            //  怨듬갚 �젣嫄�
+            cell.setCellValue(cellStr.trim());
+        } else {
+            cell.setCellValue(cellStr);
+        }
+        return cellStr;
+    }
+
+    /**
+     * cell NULL 泥댄겕 �븿�닔
+     * 鍮� 媛믪씠 �븘�땶 cell 泥댄겕
+     * @param cell Cell
+     * @return boolean
+     */
+    private Boolean cellNullCheck (Cell cell) {
+        int cellType = cell.getCellType();
+        if (cellType < Cell.CELL_TYPE_BLANK) {
+            if (cellType == Cell.CELL_TYPE_STRING) {
+                if (cell.getStringCellValue() != null && !cell.getStringCellValue().equals("")) {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        }
+        return true;
     }
 
     //  �뿊�� �븘�뱶�뿉 �엳�뒗 �젙蹂대�� �씠�뒋 form �쑝濡� �삷湲대떎.
-    private IssueForm setIssueFormToExcelField(Row row, int rowIndex, Map<String, IssueStatus> issueStatusReadyMaps, 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, List<String> headers) {
+    private IssueForm setIssueFormToExcelField(Row row, int rowIndex, Map<String, Priority> priorityMaps,
+                                               Map<String, Severity> severityMaps, Map<String, CustomField> customFieldMaps,
+                                               Map<String, CompanyField> companyFieldMaps, Map<String, IspField> ispFieldMaps, Map<String, HostingField> hostingFieldMaps,
+                                               List<String> headers) throws ParseException {
         IssueForm issueForm = new IssueForm();
         issueForm.setRegisterId(this.webAppUtil.getLoginId());
-        Project project = null;
 
         //  �젣紐�, �궡�슜, �봽濡쒖젥�듃 �궎, �씠�뒋 ���엯, �슦�꽑�닚�쐞, 以묒슂�룄, �떞�떦�옄, �떆�옉�씪, 醫낅즺�씪, �궗�슜�옄 �젙�쓽 �븘�뱶
         for (int cellIndex = 0; cellIndex < headers.size(); cellIndex++) {
             Cell cell = row.getCell(cellIndex);
+
+            String cellStr = "";
+            boolean isNull = true;
+
+            if (cell != null) {
+                isNull = cellNullCheck(cell);
+                cellStr = stringToCell(cell, isNull); //cell�쓣 String�쑝濡� 蹂��솚
+            }
+
             switch (cellIndex) {
                 case 0:
                     //  �씠�뒋 �젣紐⑹쓣 IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormTitle(cell, issueForm, rowIndex);
+                    if (isNull) {
+                        throw new OwlRuntimeException(
+                                this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISSUE_TITLE_IS_NULL, rowIndex));
+                    }
+                    this.setIssueFormTitle(cellStr, issueForm, rowIndex);
                     break;
 
                 case 1:    //  �궡�슜
-                    if (cell != null) {
-                        issueForm.setDescription(CommonUtil.convertExcelStringToCell(cell));
-                    } else {
-                        //  null �엯�젰 諛⑹�
-                        issueForm.setDescription("");
-                    }
-
+                    issueForm.setDescription(cellStr);
                     break;
 
-                case 2:    //  �봽濡쒖젥�듃 �궎�� �씠�뒋 踰덊샇
-                    project = this.setIssueFormProjectKeyAndIssueNumber(cell, issueForm, projectMaps, issueNumberMaps, rowIndex);
+                case 2:
+                    //  �슦�꽑�닚�쐞瑜� IssueForm �뿉 ���옣�븳�떎.
+                    if (isNull) {
+                        throw new OwlRuntimeException(
+                                this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PRIORITY_IS_NULL, rowIndex));
+                    }
+                    this.setIssueFormPriority(cellStr, priorityMaps, issueForm, rowIndex);
                     break;
 
                 case 3:
-                    //  �씠�뒋 ���엯�쓣 IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormIssueType(cell, issueTypeMaps, issueForm, rowIndex);
-                    //  �씠�뒋 ���엯�뿉 �뿰寃곕맂 �썙�겕�뵆濡쒖슦�쓽 �긽�깭 �냽�꽦 '��湲�' �씤 �긽�깭瑜� issueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormIssueStatus(issueStatusReadyMaps, issueForm, rowIndex);
-                    break;
-
-                case 4:
-                    //  �슦�꽑�닚�쐞瑜� IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormPriority(cell, priorityMaps, issueForm, rowIndex);
-                    break;
-
-                case 5:
                     //  以묒슂�룄瑜� IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormSeverity(cell, severityMaps, issueForm, rowIndex);
+                    if (isNull) {
+                        throw new OwlRuntimeException(
+                                this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_SEVERITY_IS_NULL, rowIndex));
+                    }
+                    this.setIssueFormSeverity(cellStr, severityMaps, issueForm, rowIndex);
+                    break;
+                /*case 6:
+                    //  �떞�떦�옄瑜� IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormAssignee(cell, userMaps, issueForm, project);
+                    break;*/
+                case 4:
+                    //  �떆�옉�씪�쓣 IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormPeriod(cellStr, issueForm, true, rowIndex, isNull);
+                    break;
+                case 5:
+                    //  醫낅즺�씪�쓣 IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormPeriod(cellStr, issueForm, false, rowIndex, isNull);
                     break;
                 case 6:
-                    //  �떞�떦遺��꽌瑜� IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormAssignee(cell, userMaps, issueForm, project);
+                    //  �뾽泥대�� IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormCompanyField(cellStr, companyFieldMaps, issueForm, rowIndex);
                     break;
                 case 7:
-                    //  �떆�옉�씪�쓣 IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormPeriod(cell, issueForm, true, rowIndex);
+                    //  ISP瑜� IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormIspField(cellStr, ispFieldMaps, issueForm, rowIndex);
                     break;
                 case 8:
-                    //  醫낅즺�씪�쓣 IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormPeriod(cell, issueForm, false, rowIndex);
+                    //  �샇�뒪�똿�쓣 IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormHostingField(cellStr, hostingFieldMaps, issueForm, rowIndex);
                     break;
                 default:
-                    //  8踰� �씠�긽遺��꽣�뒗 �궗�슜�옄 �젙�쓽 �븘�뱶. �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� IssueForm �뿉 ���옣�븳�떎.
-                    this.setIssueFormCustomFieldValue(cell, customFieldMaps, issueForm, headers.get(cellIndex), rowIndex);
+                    //  9踰� 遺��꽣�뒗 �궗�슜�옄 �젙�쓽 �븘�뱶. �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� IssueForm �뿉 ���옣�븳�떎.
+                    this.setIssueFormCustomFieldValue(cellStr, customFieldMaps, issueForm, headers.get(cellIndex), rowIndex);
             }
         }
 
         return issueForm;
     }
 
-    //  �씠�뒋 �젣紐⑹쓣 IssueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormTitle(Cell cell, IssueForm issueForm, int rowIndex) {
-        if (cell == null) {
-            throw new OwlRuntimeException(
-                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISSUE_TITLE_IS_NULL, rowIndex));
+    private void setIssueFormHostingField(String cell, Map<String, HostingField> hostingFieldMaps, IssueForm issueForm, int rowIndex) {
+        if (cell.length() > 0) {
+            Map<String, Object> issueHostingFields = new HashMap<>();
+            HostingField hostingFieldMap = hostingFieldMaps.get(cell);
+            if (hostingFieldMap == null) {
+                throw new OwlRuntimeException(
+                        this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_HOSTING_NOT_EXIST, rowIndex));
+            }
+            ConvertUtil.copyProperties(hostingFieldMap, issueHostingFields);
+            issueForm.addIssueHostingField(issueHostingFields);
         }
+    }
 
-        String title = CommonUtil.convertExcelStringToCell(cell);
+    private void setIssueFormIspField(String cell, Map<String, IspField> ispFieldMaps, IssueForm issueForm, int rowIndex) {
+        if (cell.length() > 0) {
+            Map<String, Object> issueIspFields = new HashMap<>();
+            IspField ispFieldMap = ispFieldMaps.get(cell);
+            if (ispFieldMap == null) {
+                throw new OwlRuntimeException(
+                        this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISP_NOT_EXIST, rowIndex));
+            }
+            ConvertUtil.copyProperties(ispFieldMap, issueIspFields);
+            issueForm.addIssueIspField(issueIspFields);
+        }
+    }
 
+    private void setIssueFormCompanyField(String cell, Map<String, CompanyField> companyFieldMaps, IssueForm issueForm, int rowIndex) {
+        if (cell.length() > 0) {
+            Map<String, Object> issueCompanyFields = new HashMap<>();
+            CompanyField companyFieldMap = companyFieldMaps.get(cell);
+            if (companyFieldMap == null) {
+                throw new OwlRuntimeException(
+                        this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_COMPANY_NOT_EXIST, rowIndex));
+            }
+            ConvertUtil.copyProperties(companyFieldMap, issueCompanyFields);
+            issueForm.addissueCompanyField(issueCompanyFields);
+        }
+    }
+
+    //  �씠�뒋 �젣紐⑹쓣 IssueForm �뿉 ���옣�븳�떎.
+    private void setIssueFormTitle(String title, IssueForm issueForm, int rowIndex) {
         //  �젣紐� �쑀�슚�꽦 泥댄겕
         this.verifyTitle(title);
         issueForm.setTitle(title);
-    }
-
-    //  �봽濡쒖젥�듃 �궎, �씠�뒋 怨좎쑀 踰덊샇, �떞�떦�옄瑜� IssueForm �뿉 ���옣�븳�떎.
-    private Project setIssueFormProjectKeyAndIssueNumber(Cell cell, IssueForm issueForm, Map<String, Project> projectMaps, Map<Long, Long> issueNumberMaps, int rowIndex) {
-        //  �봽濡쒖젥�듃 �븘�씠�뵒瑜� IssueForm �뿉 ���옣�븳�떎.
-        Project project = this.setIssueFormProject(cell, projectMaps, issueForm, rowIndex);
-
-        //  �씠�뒋 怨좎쑀 踰덊샇瑜� IssueForm �뿉 ���옣�븳�떎.
-        this.setIssueFormIssueNumber(issueForm, issueNumberMaps, project, rowIndex);
-
-        return project;
     }
 
     //  �봽濡쒖젥�듃 �븘�씠�뵒瑜� IssueForm �뿉 ���옣�븳�떎.
@@ -3030,43 +3815,10 @@
         issueNumberMaps.put(project.getId(), ++issueNumber);  //  �씠�뒋 踰덊샇瑜� 1�뵫 利앷� �떆�궓�떎.
     }
 
-    //  �씠�뒋 ���엯�쓣 IssueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormIssueType(Cell cell, Map<String, IssueType> issueTypeMaps, IssueForm issueForm, int rowIndex) {
-        if (cell == null) {
-            throw new OwlRuntimeException(
-                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISSUE_TYPE_IS_NULL, rowIndex));
-        }
-
-        IssueType issueType = issueTypeMaps.get(CommonUtil.convertExcelStringToCell(cell));
-
-        if (issueType == null) {
-            throw new OwlRuntimeException(
-                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISSUE_TYPE_NOT_EXIST, rowIndex));
-        }
-
-        issueForm.setIssueTypeId(issueType.getId());
-    }
-
-    //  �씠�뒋 ���엯�뿉 �뿰寃곕맂 �썙�겕�뵆濡쒖슦�쓽 �긽�깭 �냽�꽦 '��湲�' �씤 �긽�깭瑜� issueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormIssueStatus(Map<String, IssueStatus> issueStatusReadyMaps, IssueForm issueForm, int rowIndex) {
-        IssueStatus issueStatus = issueStatusReadyMaps.get(issueForm.getIssueTypeId().toString());
-
-        if (issueStatus == null) {
-            throw new OwlRuntimeException(
-                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISSUE_STATUS_READY_NOT_EXIST, rowIndex));
-        }
-
-        issueForm.setIssueStatusId(issueStatus.getId());
-    }
 
     //  �슦�꽑�닚�쐞瑜� IssueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormPriority(Cell cell, Map<String, Priority> priorityMaps, IssueForm issueForm, int rowIndex) {
-        if (cell == null) {
-            throw new OwlRuntimeException(
-                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PRIORITY_IS_NULL, rowIndex));
-        }
-
-        Priority priority = priorityMaps.get(CommonUtil.convertExcelStringToCell(cell));
+    private void setIssueFormPriority(String priorityStr, Map<String, Priority> priorityMaps, IssueForm issueForm, int rowIndex) {
+        Priority priority = priorityMaps.get(priorityStr);
 
         if (priority == null) {
             throw new OwlRuntimeException(
@@ -3077,13 +3829,8 @@
     }
 
     //  以묒슂�룄瑜� IssueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormSeverity(Cell cell, Map<String, Severity> severityMaps, IssueForm issueForm, int rowIndex) {
-        if (cell == null) {
-            throw new OwlRuntimeException(
-                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_SEVERITY_IS_NULL, rowIndex));
-        }
-
-        Severity severity = severityMaps.get(CommonUtil.convertExcelStringToCell(cell));
+    private void setIssueFormSeverity(String strSeverity, Map<String, Severity> severityMaps, IssueForm issueForm, int rowIndex) {
+        Severity severity = severityMaps.get(strSeverity);
 
         if (severity == null) {
             throw new OwlRuntimeException(
@@ -3093,33 +3840,27 @@
         issueForm.setSeverityId(severity.getId());
     }
 
-    //  �떞�떦遺��꽌瑜� 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> departmentIds = Lists.newArrayList();
+            List<Long> userIds = Lists.newArrayList();
 
             for (String account : splitAssignee) {
                 if (MapUtil.getLong(userMap, account) != null) {
-                    departmentIds.add(MapUtil.getLong(userMap, account));
+                    userIds.add(MapUtil.getLong(userMap, account));
                 }
             }
-
-            issueForm.setDepartmentIds(departmentIds);
+            issueForm.setUserIds(userIds);
         }
     }
-
     //  �떆�옉�씪, 醫낅즺�씪�쓣 IssueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormPeriod(Cell cell, IssueForm issueForm, Boolean checkStartDate, int rowIndex) {
-        if (cell != null && !cell.toString().equals("")) {
+    private void setIssueFormPeriod(String periodDate, IssueForm issueForm, Boolean checkStartDate, int rowIndex, boolean isNull) throws ParseException {
+        if (!isNull) {
 
-            Date startDate;
-
-            try {
-                startDate = cell.getDateCellValue();
-            } catch (Exception e) {
+            Date startDate = DateUtil.convertStrToDateOnly(periodDate);
+            if (startDate == null) {
                 throw new OwlRuntimeException(
                         this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALIDITY_EMPTY, rowIndex));
             }
@@ -3129,96 +3870,121 @@
             } else {
                 issueForm.setCompleteDate(DateUtil.convertDateToStr(startDate, "yyyy-MM-dd"));
 
+                //  醫낅즺�씪留� �엯�젰 �뻽�쓣 寃쎌슦
+                if (issueForm.getCompleteDate() != null && issueForm.getStartDate() == null) {
+                    throw new OwlRuntimeException(
+                            this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALIDITY_EMPTY_START, rowIndex));
+                }
+
                 try {
                     //  �궇吏� �쑀�슚�꽦 泥댄겕
                     this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate());
                 } catch (OwlRuntimeException e) {
                     throw new OwlRuntimeException(
-                            this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALIDITY, rowIndex));
+                            this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALID, rowIndex));
                 }
             }
         }
     }
 
-    //  �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� IssueForm �뿉 ���옣�븳�떎.
-    private void setIssueFormCustomFieldValue(Cell cell, Map<String, CustomField> customFieldMaps, IssueForm issueForm, String customFieldName, int rowIndex) {
-        if (cell != null) {
-            String cellValue = CommonUtil.convertExcelStringToCell(cell);
-            Map<String, Object> issueCustomFieldMap = new HashMap<>();
-            CustomField customField = customFieldMaps.get(customFieldName);
+    //  �궗�슜�옄 �젙�쓽 �븘�뱶 �젙蹂대�� IssueForm �뿉 ���옣�븳�떎.-
+    private void setIssueFormCustomFieldValue(String cellValue, Map<String, CustomField> customFieldMaps, IssueForm issueForm, String customFieldName, int rowIndex) {
+        Map<String, Object> issueCustomFieldMap = new HashMap<>();
+        CustomField customField = customFieldMaps.get(customFieldName);
 
-            if (customField == null) {
-                throw new OwlRuntimeException(
-                        this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_HEADER_CUSTOM_FIELD_NOT_EXIST, rowIndex));
-            }
-            //  �궗�슜�옄 �젙�쓽 �븘�뱶 媛믪씠 怨듬갚�씠硫� 以묒�
-            if (StringUtils.isEmpty(cellValue)) {
-                return;
-            }
+        if (customField == null) {
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_HEADER_CUSTOM_FIELD_NOT_EXIST, rowIndex));
+        }
+        //  �궗�슜�옄 �젙�쓽 �븘�뱶 媛믪씠 怨듬갚�씠硫� 以묒�
+        if (StringUtils.isEmpty(cellValue)) {
+            return;
+        }
 
-            boolean validity = false;
+        boolean validity = false;
 
-            switch (customField.getCustomFieldType()) {
-                case INPUT:
-                case NUMBER:
-                case DATETIME:
-                case IP_ADDRESS:
-                case EMAIL:
-                case SITE:
-                case TEL:
-                    if (cellValue.length() > 100) {
+        switch (customField.getCustomFieldType()) {
+            case INPUT:
+            case NUMBER:
+            case DATETIME:
+            case IP_ADDRESS:
+            case EMAIL:
+            case SITE:
+            case TEL:
+                if (customField.getCustomFieldType() != INPUT && cellValue.length() > 100) { //INPUT ���엯�� 100�옄 �젣�븳 �뾾�쓬
+                    throw new OwlRuntimeException(
+                            this.messageAccessor.getMessage(MsgConstants.CUSTOM_FIELD_TEXT_TYPE_MAX_LENGTH_OUT));
+                }
+
+                //DATETIME�씪 寃쎌슦 format 蹂�寃�
+                if (customField.getCustomFieldType() == DATETIME) {
+                    Date date = DateUtil.convertStrToDate(cellValue);
+                    if (date == null) {
                         throw new OwlRuntimeException(
-                                this.messageAccessor.getMessage(MsgConstants.CUSTOM_FIELD_TEXT_TYPE_MAX_LENGTH_OUT));
+                                this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_DATETIME_NOT_DASH, rowIndex));
                     }
+                }
 
-                    issueCustomFieldMap.put("customFieldId", customField.getId());
-                    issueCustomFieldMap.put("useValue", cellValue);
-                    issueForm.addIssueCustomFields(issueCustomFieldMap);
-                    break;
-                case SINGLE_SELECT:
-                    //  媛� �쑀�슚�꽦 泥댄겕
+                //IP_ADDRESS�씪 寃쎌슦 �젙洹쒗몴�쁽�떇 泥댄겕
+                if (customField.getCustomFieldType() == IP_ADDRESS) {
+                    String regExp = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
+                            + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
+                            + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
+                            + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
+
+                    if (!cellValue.matches(regExp)) {
+                        throw new OwlRuntimeException(
+                                this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_IP_ADDRESS_NOT_VALIDITY, rowIndex));
+                    }
+                }
+
+                issueCustomFieldMap.put("customFieldId", customField.getId());
+                issueCustomFieldMap.put("useValue", cellValue);
+                issueForm.addIssueCustomFields(issueCustomFieldMap);
+                break;
+            case SINGLE_SELECT:
+                //  媛� �쑀�슚�꽦 泥댄겕
+                for (CustomFieldValue customFieldValue : customField.getCustomFieldValues()) {
+                    if (customFieldValue.getValue().equals(cellValue)) {
+                        validity = true;
+                        break;
+                    }
+                }
+
+                if (!validity) {
+                    throw new OwlRuntimeException(
+                            this.messageAccessor.getMessage(MsgConstants.EXCEL_CUSTOM_FIELD_VALUE_NOT_VALIDITY, rowIndex));
+                }
+
+                issueCustomFieldMap.put("customFieldId", customField.getId());
+                issueCustomFieldMap.put("useValue", cellValue);
+                issueForm.addIssueCustomFields(issueCustomFieldMap);
+
+                break;
+            case MULTI_SELECT:
+                //  媛� �쑀�슚�꽦 泥댄겕
+                String[] useValues = cellValue.split("#");
+                //  �빐, �떖
+                for (String useValue : useValues) {
                     for (CustomFieldValue customFieldValue : customField.getCustomFieldValues()) {
-                        if (customFieldValue.getValue().equals(cellValue)) {
+
+                        if (customFieldValue.getValue().equals(useValue)) {
                             validity = true;
-                            break;
+                            Map<String, Object> multiValueMap = new HashMap<>();
+                            multiValueMap.put("customFieldId", customField.getId());
+                            multiValueMap.put("useValue", useValue);
+                            issueForm.addIssueCustomFields(multiValueMap);
                         }
+
                     }
+                }
 
-                    if (!validity) {
-                        throw new OwlRuntimeException(
-                                this.messageAccessor.getMessage(MsgConstants.EXCEL_CUSTOM_FIELD_VALUE_NOT_VALIDITY, rowIndex));
-                    }
+                if (!validity) {
+                    throw new OwlRuntimeException(
+                            this.messageAccessor.getMessage(MsgConstants.EXCEL_CUSTOM_FIELD_VALUE_NOT_VALIDITY, rowIndex));
+                }
 
-                    issueCustomFieldMap.put("customFieldId", customField.getId());
-                    issueCustomFieldMap.put("useValue", cellValue);
-                    issueForm.addIssueCustomFields(issueCustomFieldMap);
-
-                    break;
-                case MULTI_SELECT:
-                    //  媛� �쑀�슚�꽦 泥댄겕
-                    String[] useValues = cellValue.split("#");
-                    //  �빐, �떖
-                    for (String useValue : useValues) {
-                        for (CustomFieldValue customFieldValue : customField.getCustomFieldValues()) {
-
-                            if (customFieldValue.getValue().equals(useValue)) {
-                                validity = true;
-                                Map<String, Object> multiValueMap = new HashMap<>();
-                                multiValueMap.put("customFieldId", customField.getId());
-                                multiValueMap.put("useValue", useValue);
-                                issueForm.addIssueCustomFields(multiValueMap);
-                            }
-
-                        }
-                    }
-
-                    if (!validity) {
-                        throw new OwlRuntimeException(
-                                this.messageAccessor.getMessage(MsgConstants.EXCEL_CUSTOM_FIELD_VALUE_NOT_VALIDITY, rowIndex));
-                    }
-
-                    break;
-            }
+                break;
         }
     }
 
@@ -3276,7 +4042,7 @@
     //  �씠�뒋瑜� �뀥�뵆由우뿉 �뵲�씪 �뙆�듃�꼫 �떞�떦�옄�뿉寃� 硫붿씪濡� 諛쒖넚�븳�떎.
     @Override
     @Transactional(readOnly = true)
-    public void sendIssueEmailPartners(EmailTemplateForm emailTemplateForm) {
+    public void sendIssueEmailPartners(EmailTemplateForm emailTemplateForm, List<MultipartFile> multipartFiles) {
         if (emailTemplateForm.getSendEmails().size() < 1) {
             throw new OwlRuntimeException(
                     this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
@@ -3303,10 +4069,43 @@
         for(int i=0; i < sendMails.length; i++) {
             sendMails[i] = CommonUtil.decryptAES128(sendMails[i]);
         }
-        this.systemEmailService.sendEmail(emailTemplateForm.getTitle(), emailTemplateForm.getTemplate(), sendMails, null);
+        this.systemEmailService.sendEmail(emailTemplateForm.getTitle(), emailTemplateForm.getTemplate(), sendMails, null, multipartFiles);
 
         this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, emailTemplateForm.getSendEmails(), sb);
         this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString());
+    }
+
+    @Override
+    public void sendCommonEmail(EmailCommonForm emailCommonForm, List<MultipartFile> multipartFiles) {
+        if (emailCommonForm.getSendEmails().size() < 1) {
+            throw new OwlRuntimeException(
+                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
+        }
+
+        Issue issue = null;
+        if(emailCommonForm.getIssueId() != null) {
+            issue = this.getIssue(emailCommonForm.getIssueId());
+        }
+
+        //  諛쒖떊�옄 �몴�떆
+        User user = this.webAppUtil.getLoginUserObject();
+        UserVo toUser = this.webAppUtil.getLoginUser();
+
+        //  �궗�슜�옄 �떆�뒪�뀥 湲곕뒫 �궗�슜 �젙蹂� �닔吏�
+        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL));
+        StringBuilder sb = new StringBuilder();
+
+        Locale locale = CommonUtil.getUserLanguage(user.getLanguage());
+        String[] sendMails = ConvertUtil.ToArray(emailCommonForm.getSendEmails());
+        for(int i=0; i < sendMails.length; i++) {
+            sendMails[i] = CommonUtil.decryptAES128(sendMails[i]);
+        }
+        this.systemEmailService.sendEmail(emailCommonForm.getTitle(), emailCommonForm.getDescription(), sendMails, null, multipartFiles);
+
+        if (issue != null) {
+            this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, emailCommonForm.getSendEmails(), sb);
+            this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString());
+        }
     }
 
     //  �삁�빟 諛쒖깮 �씠�뒋瑜� �떎�뻾�븳�떎
@@ -3477,43 +4276,128 @@
     @Transactional
     @Override
     public void modifyParentIssue(IssueForm issueDownForm) {
-        Issue issue = this.getIssue(issueDownForm.getId()); //�븯�쐞 �씠�뒋
+        //Issue issue = this.getIssue(issueDownForm.getId()); //�븯�쐞 �씠�뒋
         Long newParentIssueId = issueDownForm.getParentIssueId(); //蹂�寃쏀븷 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋
-
         StringBuilder sb = new StringBuilder();
 
-        Issue parentIssue = issue.getParentIssue(); //蹂�寃� �쟾 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋
-        if(parentIssue != null && parentIssue.getId().equals(newParentIssueId)){ //蹂�寃� �쟾 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋媛� 議댁옱 �븷 寃쎌슦
-            this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
-            this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString());
-        }
+        for (Long downId : issueDownForm.getIds()) {
+            Issue issue = this.getIssue(downId);
 
-        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);
+            Issue parentIssue = issue.getParentIssue(); //蹂�寃� �쟾 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋
+            if(parentIssue != null && parentIssue.getId().equals(newParentIssueId)){ //蹂�寃� �쟾 �븯�쐞�씠�뒋�쓽 �긽�쐞�씠�뒋媛� 議댁옱 �븷 寃쎌슦
+                this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
+                this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString());
+            }
+
+            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);
+            }
+
+            if (issueDownForm.getInheritYn() != null && issueDownForm.getInheritYn() && issue.getParentIssue() != null) {
+                //  �긽�쐞�씠�뒋�쓽 �뙆�듃�꼫 �젙蹂� �긽�냽諛쏄린
+                issue = this.inheritPartners(issue, parentIssue);
+            }
+
+            this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); //parentIssue = myIssue(湲곕줉�� �쁽�옱 �긽�꽭�럹�씠吏��뿉 �빐�빞�븯�땲源�)
+            this.issueRepository.saveAndFlush(issue);
         }
-        this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); //parentIssue = myIssue(湲곕줉�� �쁽�옱 �긽�꽭�럹�씠吏��뿉 �빐�빞�븯�땲源�)
-        this.issueRepository.saveAndFlush(issue);
+    }
+
+    /**
+     * �긽�쐞�씠�뒋�쓽 �뙆�듃�꼫 �젙蹂� �긽�냽諛쏄린
+     * @param issue Issue
+     * @param parentIssue Issue
+     * @return Issue
+     */
+    private Issue inheritPartners(Issue issue, Issue parentIssue) {
+        if (parentIssue != null) {
+            if (parentIssue.getIssueType().getInheritPartners()) {
+                IssueCompany issueCompany = new IssueCompany();
+                IssueIsp issueIsp = new IssueIsp();
+                IssueHosting issueHosting = new IssueHosting();
+
+                if (parentIssue.getIssueCompanies() != null && parentIssue.getIssueCompanies().size() > 0) {
+                    issue.getIssueCompanies().clear();
+                    issue.getIssueCompanies().addAll(parentIssue.getIssueCompanies());
+                    Iterator<IssueCompany> itrCompany = issue.getIssueCompanies().iterator();
+                    ConvertUtil.copyProperties(itrCompany.next(), issueCompany, "id");
+                    issueCompany.setIssue(issue);
+                    issueCompany.setCompanyField(parentIssue.getIssueCompanies().iterator().next().getCompanyField());
+                    this.issueCompanyRepository.saveAndFlush(issueCompany);
+                } else {
+                    this.issueCompanyRepository.deleteByIssueId(issue.getId());
+                    this.issueCompanyRepository.flush();
+                }
+                if (parentIssue.getIssueIspFields() != null && parentIssue.getIssueIspFields().size() > 0) {
+                    issue.getIssueIspFields().clear();
+                    issue.getIssueIspFields().addAll(parentIssue.getIssueIspFields());
+                    Iterator<IssueIsp> itrIsp = issue.getIssueIspFields().iterator();
+                    ConvertUtil.copyProperties(itrIsp.next(), issueIsp, "id");
+                    issueIsp.setIssue(issue);
+                    issueIsp.setIspField(parentIssue.getIssueIspFields().iterator().next().getIspField());
+                    this.issueIspRepository.saveAndFlush(issueIsp);
+                } else {
+                    this.issueIspRepository.deleteByIssueId(issue.getId());
+                    this.issueIspRepository.flush();
+                }
+                if (parentIssue.getIssueHostingFields() != null && parentIssue.getIssueHostingFields().size() > 0) {
+                    issue.getIssueHostingFields().clear();
+                    issue.getIssueHostingFields().addAll(parentIssue.getIssueHostingFields());
+                    Iterator<IssueHosting> itrHosting = issue.getIssueHostingFields().iterator();
+                    ConvertUtil.copyProperties(itrHosting.next(), issueHosting, "id");
+                    issueHosting.setIssue(issue);
+                    issueHosting.setHostingField(parentIssue.getIssueHostingFields().iterator().next().getHostingField());
+                    this.issueHostingRepository.saveAndFlush(issueHosting);
+                } else {
+                    this.issueHostingRepository.deleteByIssueId(issue.getId());
+                    this.issueHostingRepository.flush();
+                }
+            }
+        }
+        return 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();
+        Integer using = 0;
+
+        if (issueTypeId != null) {
+            IssueType issueType = this.issueTypeService.getIssueType(issueTypeId); // �씠�뒋�쓽 �씠�뒋�쑀�삎 媛앹껜
+            using = issueType.getUsePartner() != null ? issueType.getUsePartner().intValue() : 0; // �씠�뒋�쑀�삎蹂꾨줈 �궗�슜以묒씤 �뾽泥�/ISP/�샇�뒪�똿 媛�
+        } else {
+            for (int partner : UsePartner.partners) {
+                using += partner;
+            }
+        }
+
         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);
         }
+
+        resJsonData.put(Constants.RES_KEY_CONTENTS, usePartnerVos);
+    }
+
+    @Override
+    public void findReadyDepartments(Map<String, Object> resJsonData, DepartmentCondition condition, Pageable pageable) {
+        IssueType issueType = this.issueTypeService.getIssueType(condition.getIssueTypeId());
+        if (issueType != null) {
+            //  �씠�뒋 �긽�깭 �쑀�삎�씠 '��湲�' �씤 �씠�뒋 �긽�깭 媛��졇�삤湲�
+            IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow());
+            condition.setIssueStatusId(issueStatus.getId());
+            condition.setWorkflowId(issueType.getWorkflow().getId());
+        }
+        List<Map<String, Object>> departmentVos = this.departmentMapper.findByIssueStatusId(condition);
+        resJsonData.put(Constants.RES_KEY_CONTENTS, departmentVos);
     }
 }
\ No newline at end of file

--
Gitblit v1.8.0