| | |
| | | IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator(); |
| | | Collections.sort(issueCustomFieldValueForms, comp); |
| | | |
| | | List<String> userValues = Lists.newArrayList(); |
| | | for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) { |
| | | userValues.add(issueCustomFieldValueForm.getUseValue()); |
| | | for(CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) { |
| | | if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) { |
| | | if (useIdx > 0) { |
| | |
| | | |
| | | IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition(); |
| | | issueCustomFieldValueCondition.setUseValue(concatUseValue); |
| | | issueCustomFieldValueCondition.setUseValues(userValues); |
| | | issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId()); |
| | | List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); |
| | | if (results != null && results.size() > 0) { |
| | |
| | | this.setIssueHistory(downIssue, downIssueVo); // 이슈 기록 정보 셋팅 |
| | | this.setIssueComments(downIssue, downIssueVo); // 댓글 정보 셋팅 |
| | | |
| | | downIssueVo.setModifyPermissionCheck(issueVo.getModifyPermissionCheck()); |
| | | |
| | | resultList.add(downIssueVo); |
| | | } |
| | | issueVo.setIssueDownVos(resultList); |
| | |
| | | IssueStatusVo issueStatusVo = ConvertUtil.copyProperties(relationIssue.getIssueStatus(), IssueStatusVo.class, "issueStatusType"); |
| | | issueStatusVo.setIssueStatusType(relationIssue.getIssueStatus().getIssueStatusType().toString()); |
| | | issueRelationVo.setIssueStatusVo(issueStatusVo); |
| | | |
| | | issueRelationVo.setModifyPermissionCheck(issueVo.getModifyPermissionCheck()); |
| | | |
| | | this.setRegister(relationIssue, relIssueVo); // 등록자 |
| | | this.setIssueDepartment(relationIssue, relIssueVo); // 담당부서 정보 셋팅 |
| | |
| | | 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); |
| | | } |
| | |
| | | |
| | | IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition(); |
| | | issueCustomFieldValueCondition.setUseValue(concatUseValue); |
| | | issueCustomFieldValueCondition.setUseValues(userValues); |
| | | issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId()); |
| | | List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); |
| | | if (results != null && results.size() > 0) { |
| | |
| | | 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)); // 종료일 |
| | | // 프로젝트에 연결된 사용자 정의 필드 정보를 추출하여 엑셀 download 템플릿을 만든다. |
| | |
| | | // 엑셀 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();*/ |
| | | |
| | |
| | | // 업로드 파일 확장자 체크 |
| | | 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, 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<>(); // 이슈 타입 + 사용자 정의 필드 연결 정보 |
| | | |
| | | 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(priorityMaps, severityMaps, departmentMaps, customFieldMaps, issueTypeCustomFieldMaps); |
| | | // 0.237 - 0.230 |
| | | |
| | | List<IssueForm> issueForms = Lists.newArrayList(); |
| | |
| | | // 1번 헤더부터 데이터 영역 |
| | | if (rowIndex > 1) { |
| | | // 이슈로 등록하기 위해 IssueForm 에 데이터를 셋팅한다. |
| | | issueForms.add(this.setIssueFormToExcelField(row, (rowIndex + 1), issueStatusReadyMaps, projectMaps, issueTypeMaps, priorityMaps, severityMaps, userMaps, departmentMaps, customFieldMaps, issueNumberMaps, headers)); |
| | | IssueForm newIssueForm = this.setIssueFormToExcelField(row, (rowIndex + 1), priorityMaps, severityMaps, departmentMaps, customFieldMaps, headers); |
| | | ConvertUtil.copyProperties(issueForm, newIssueForm); |
| | | |
| | | |
| | | |
| | | issueForms.add(newIssueForm); |
| | | |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | // 이슈 등록 |
| | | this.issueMapper.insertBatch(issueForms); |
| | | // this.issueMapper.insertBatch(issueForms); |
| | | |
| | | for (IssueForm saveIssueForm : issueForms) { |
| | | Issue issue = new Issue(); |
| | | ConvertUtil.copyProperties(saveIssueForm, issue); |
| | | |
| | | IssueType issueType = this.issueTypeService.getIssueType(saveIssueForm.getIssueTypeId()); |
| | | Workflow workflow = issueType.getWorkflow(); |
| | | |
| | | Project project = this.projectService.getProject(saveIssueForm.getProjectId()); |
| | | Long issueNumber = this.issueNumberGeneratorService.generateIssueNumber(project); |
| | | |
| | | IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(workflow); |
| | | |
| | | issue.setPriority(this.priorityService.getPriority(saveIssueForm.getPriorityId())); |
| | | issue.setSeverity(this.severityService.getSeverity(saveIssueForm.getSeverityId())); |
| | | issue.setIssueStatus(issueStatus); |
| | | issue.setIssueType(issueType); |
| | | issue.setProject(project); |
| | | issue.setIssueNumber(issueNumber); |
| | | issue.setParentIssue(this.getIssue(saveIssueForm.getParentIssueId())); |
| | | |
| | | issue = this.issueRepository.saveAndFlush(issue); |
| | | |
| | | saveIssueForm.setId(issue.getId()); |
| | | |
| | | IssueDepartment issueDepartment = new IssueDepartment(); |
| | | issueDepartment.setIssue(issue); |
| | | issueDepartment.setWorkspace(workspace); |
| | | |
| | | List<Long> departmentsIds = this.workflowDepartmentService.findFirstDepartmentIds(workflow); |
| | | for (Long departmentId : departmentsIds) { |
| | | issueDepartment.setDepartment(this.departmentService.getDepartment(departmentId)); |
| | | } |
| | | issue.addIssueDepartment(issueDepartment); |
| | | |
| | | saveIssueForm.setIssueStatusId(issueStatus.getId()); |
| | | } |
| | | |
| | | |
| | | // 0.416 - 0.439 |
| | | |
| | | // 1.373 ~ 1.394 |
| | |
| | | // reverse index 업데이트 |
| | | this.issueMapper.updateBatch(issueForms); |
| | | // 증가된 이슈 번호를 업데이트 한다. |
| | | this.issueNumberGeneratorService.updateIssueNumber(issueNumberMaps); |
| | | // issueNumberMaps.put(issueForm.getProjectId(), issueForm.getProjectId()); |
| | | // this.issueNumberGeneratorService.updateIssueNumber(issueNumberMaps); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // 이슈의 주요 속성을 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, DepartmentVo> 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(); |
| | | |
| | | 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()); |
| | | } |
| | | |
| | | // 프로젝트에 참여하는 사용자 정보 |
| | | 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")); |
| | | } |
| | | userMaps.put(project.getProjectKey(), userMap); |
| | | } |
| | | |
| | | // 이슈 유형을 바로 찾을 수 있게 준비 |
| | | List<IssueType> issueTypes = this.issueTypeService.findByWorkspaceId(); |
| | | for (IssueType issueType : issueTypes) { |
| | | issueTypeMaps.put(issueType.getName(), issueType); |
| | | |
| | | IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow()); |
| | | issueStatusReadyMaps.put(issueType.getId().toString(), issueStatus); |
| | | |
| | | // 워크플로우에 속해있는 부서 정보 |
| | | List<DepartmentVo> departments = this.departmentService.findWorkflowDepartment(issueType.getId()); |
| | | // 부서 정보를 저장 |
| | | for (DepartmentVo department : departments) { |
| | | departmentMaps.put(department.getDepartmentName(), department); |
| | | } |
| | | } |
| | | private void IssueAttributeMapToList(Map<String, Priority> priorityMaps, Map<String, Severity> severityMaps, |
| | | Map<String, DepartmentVo> departmentMaps, Map<String, CustomField> customFieldMaps,Map<String, Long> issueTypeCustomFieldMaps) { |
| | | |
| | | // 우선순위를 바로 찾을 수 있게 준비 |
| | | List<Priority> priorities = this.priorityService.findByWorkspaceId(); |
| | |
| | | } |
| | | |
| | | // 엑셀 필드에 있는 정보를 이슈 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, DepartmentVo> departmentMaps, 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, DepartmentVo> departmentMaps, |
| | | Map<String, CustomField> customFieldMaps, List<String> headers) { |
| | | IssueForm issueForm = new IssueForm(); |
| | | issueForm.setRegisterId(this.webAppUtil.getLoginId()); |
| | | Project project = null; |
| | |
| | | |
| | | break; |
| | | |
| | | case 2: // 프로젝트 키와 이슈 번호 |
| | | project = this.setIssueFormProjectKeyAndIssueNumber(cell, issueForm, projectMaps, issueNumberMaps, rowIndex); |
| | | break; |
| | | |
| | | case 3: |
| | | // 이슈 타입을 IssueForm 에 저장한다. |
| | | this.setIssueFormIssueType(cell, issueTypeMaps, issueForm, rowIndex); |
| | | // 이슈 타입에 연결된 워크플로우의 상태 속성 '대기' 인 상태를 issueForm 에 저장한다. |
| | | this.setIssueFormIssueStatus(issueStatusReadyMaps, issueForm, rowIndex); |
| | | break; |
| | | |
| | | case 4: |
| | | case 2: |
| | | // 우선순위를 IssueForm 에 저장한다. |
| | | this.setIssueFormPriority(cell, priorityMaps, issueForm, rowIndex); |
| | | break; |
| | | |
| | | case 5: |
| | | case 3: |
| | | // 중요도를 IssueForm 에 저장한다. |
| | | this.setIssueFormSeverity(cell, severityMaps, issueForm, rowIndex); |
| | | break; |
| | |
| | | // 담당자를 IssueForm 에 저장한다. |
| | | this.setIssueFormAssignee(cell, userMaps, issueForm, project); |
| | | break;*/ |
| | | case 6: |
| | | // 담당부서를 IssueForm 에 저장한다. |
| | | if (cell != null) { |
| | | this.setIssueFormDepartment(cell, departmentMaps, issueForm, project); |
| | | } |
| | | break; |
| | | case 7: |
| | | case 4: |
| | | // 시작일을 IssueForm 에 저장한다. |
| | | if (cell != null) { |
| | | this.setIssueFormPeriod(cell, issueForm, true, rowIndex); |
| | | } |
| | | break; |
| | | case 8: |
| | | case 5: |
| | | // 종료일을 IssueForm 에 저장한다. |
| | | if (cell != null) { |
| | | this.setIssueFormPeriod(cell, issueForm, false, 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 에 저장한다. |
| | |
| | | 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) { |
| | |
| | | issueForm.setUserIds(userIds); |
| | | } |
| | | } |
| | | |
| | | // 담당부서를 IssueForm 에 저장한다. |
| | | private void setIssueFormDepartment(Cell cell, Map<String, DepartmentVo> departmentMaps, IssueForm issueForm, Project project) { |
| | | if (cell != null) { |
| | | String[] splitDepartment = CommonUtil.convertExcelStringToCell(cell).split("#"); |
| | | |
| | | // 값이 공백이면 중지 |
| | | String cellValue = CommonUtil.convertExcelStringToCell(cell); |
| | | if (StringUtils.isEmpty(cellValue)) { |
| | | return; |
| | | } |
| | | |
| | | List<Long> departmentIds = Lists.newArrayList(); |
| | | |
| | | for (String department : splitDepartment) { |
| | | DepartmentVo departmentVo = departmentMaps.get(department); |
| | | departmentIds.add(departmentVo.getId()); |
| | | } |
| | | issueForm.setDepartmentIds(departmentIds); |
| | | } |
| | | } |
| | | |
| | | // 시작일, 종료일을 IssueForm 에 저장한다. |
| | | private void setIssueFormPeriod(Cell cell, IssueForm issueForm, Boolean checkStartDate, int rowIndex) { |
| | | if (cell != null && !cell.toString().equals("")) { |