From 26e58b01d5444165d47eee672beb57d33723f456 Mon Sep 17 00:00:00 2001 From: DanielLee <198891672+sanghyeonhd@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:10:28 +0900 Subject: [PATCH] =?UTF-8?q?=EB=9D=BC=EB=B2=A8=EB=A7=81=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=EC=97=AC=EB=B6=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 63 ++++++++ .../kamcoback/label/dto/WorkerStatsDto.java | 45 +++++- .../label/service/LabelAllocateService.java | 23 +++ .../core/LabelAllocateCoreService.java | 5 + .../entity/MapSheetAnalInferenceEntity.java | 10 ++ .../label/LabelAllocateRepositoryCustom.java | 4 + .../label/LabelAllocateRepositoryImpl.java | 136 +++++++++++++++--- .../label/LabelWorkRepositoryImpl.java | 25 ++-- 8 files changed, 271 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java index 8bd140e9..663ab9e0 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -6,6 +6,7 @@ import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelingStatDto; +import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.UpdateClosedRequest; import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerListResponse; import com.kamco.cd.kamcoback.label.service.LabelAllocateService; import io.swagger.v3.oas.annotations.Operation; @@ -236,4 +237,66 @@ public class LabelAllocateApiController { String uuid) { return ApiResponseDto.ok(labelAllocateService.moveAvailUserList(userId, uuid)); } + + @Operation( + summary = "작업현황 관리 > 라벨링/검수 종료 여부 업데이트", + description = "라벨링/검수 종료 여부를 업데이트합니다. uuid 생략 시 최신 프로젝트 대상") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "업데이트 성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/projectinfo/closed") + public ApiResponseDto updateClosedYn( + @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "종료 여부 업데이트 요청", + required = true, + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = UpdateClosedRequest.class), + examples = { + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "라벨링 종료", + value = """ + {"closedType": "LABELING", "closedYn": "Y"} + """), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "검수 종료", + value = """ + {"closedType": "INSPECTION", "closedYn": "Y"} + """), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "라벨링 재개", + value = """ + {"closedType": "LABELING", "closedYn": "N"} + """), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "검수 재개", + value = """ + {"closedType": "INSPECTION", "closedYn": "N"} + """), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "특정 프로젝트 라벨링 종료", + value = """ + {"uuid": "f97dc186-e6d3-4645-9737-3173dde8dc64", "closedType": "LABELING", "closedYn": "Y"} + """) + })) + @RequestBody + @Valid + UpdateClosedRequest request) { + + labelAllocateService.updateClosedYn( + request.getUuid(), request.getClosedType(), request.getClosedYn()); + + String typeLabel = "LABELING".equals(request.getClosedType()) ? "라벨링" : "검수"; + String statusMessage = + "Y".equals(request.getClosedYn()) + ? typeLabel + "이(가) 종료되었습니다." + : typeLabel + "이(가) 재개되었습니다."; + + return ApiResponseDto.okObject( + new ApiResponseDto.ResponseObj(ApiResponseDto.ApiResponseCode.OK, statusMessage)); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java index e7a3e035..75f09508 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/WorkerStatsDto.java @@ -2,6 +2,8 @@ package com.kamco.cd.kamcoback.label.dto; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import java.time.ZonedDateTime; import lombok.AllArgsConstructor; import lombok.Builder; @@ -35,6 +37,43 @@ public class WorkerStatsDto { @Schema(description = "프로젝트 UUID") private String uuid; + + @Schema(description = "라벨링 종료 여부 (Y: 종료, N: 진행중)") + private String labelingClosedYn; + + @Schema(description = "검수 종료 여부 (Y: 종료, N: 진행중)") + private String inspectionClosedYn; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "프로젝트 종료 여부 업데이트 요청") + public static class UpdateClosedRequest { + + @Schema( + description = "프로젝트 UUID (선택) - 미입력 시 현재 진행중인 최신 프로젝트가 대상", + example = "f97dc186-e6d3-4645-9737-3173dde8dc64") + private String uuid; + + @NotBlank(message = "종료 유형은 필수입니다.") + @Pattern(regexp = "^(LABELING|INSPECTION)$", message = "종료 유형은 LABELING 또는 INSPECTION이어야 합니다.") + @Schema( + description = "종료 유형 (LABELING: 라벨링, INSPECTION: 검수)", + example = "LABELING", + allowableValues = {"LABELING", "INSPECTION"}, + requiredMode = Schema.RequiredMode.REQUIRED) + private String closedType; + + @NotBlank(message = "종료 여부는 필수입니다.") + @Pattern(regexp = "^[YN]$", message = "종료 여부는 Y 또는 N이어야 합니다.") + @Schema( + description = "종료 여부 (Y: 종료, N: 진행중)", + example = "Y", + allowableValues = {"Y", "N"}, + requiredMode = Schema.RequiredMode.REQUIRED) + private String closedYn; } @Getter @@ -144,7 +183,7 @@ public class WorkerStatsDto { @Schema(description = "검수 작업 상태 (진행중/완료)") private String inspectionStatus; - @Schema(description = "검수 전체 대상 건수") + @Schema(description = "검수 대상 건수 (라벨링 대상과 동일)") private Long inspectionTotalCount; @Schema(description = "검수 완료 건수 (DONE)") @@ -179,10 +218,6 @@ public class WorkerStatsDto { @Deprecated @Schema(description = "[Deprecated] inspectionRemainingCount 사용 권장") private Long remainingInspectCount; - - @Deprecated - @Schema(description = "[Deprecated] labelingStatus/inspectionStatus 사용 권장") - private String workStatus; } @Getter diff --git a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java index ac9bd2f3..caa84cfb 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java @@ -195,4 +195,27 @@ public class LabelAllocateService { public MoveInfo moveAvailUserList(String userId, String uuid) { return labelAllocateCoreService.moveAvailUserList(userId, uuid); } + + /** + * 프로젝트 종료 여부 업데이트 + * + * @param uuid 프로젝트 UUID (선택, 미입력 시 최신 프로젝트 대상) + * @param closedType 종료 유형 (LABELING/INSPECTION) + * @param closedYn 종료 여부 (Y/N) + */ + @Transactional + public void updateClosedYn(String uuid, String closedType, String closedYn) { + String targetUuid = uuid; + + // uuid가 없으면 최신 프로젝트 uuid 조회 + if (targetUuid == null || targetUuid.isBlank()) { + var latestProjectInfo = labelAllocateCoreService.findLatestProjectInfo(); + if (latestProjectInfo == null || latestProjectInfo.getUuid() == null) { + throw new IllegalArgumentException("진행중인 프로젝트가 없습니다."); + } + targetUuid = latestProjectInfo.getUuid(); + } + + labelAllocateCoreService.updateClosedYnByUuid(targetUuid, closedType, closedYn); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java index ff7c00ba..2cf1422d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java @@ -133,4 +133,9 @@ public class LabelAllocateCoreService { String uuid, String userId, String paramUserId, Long assignCount) { labelAllocateRepository.assignOwnerReAllocate(uuid, userId, paramUserId, assignCount); } + + + public void updateClosedYnByUuid(String uuid, String closedType, String closedYn) { + labelAllocateRepository.updateClosedYnByUuid(uuid, closedType, closedYn); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java index 195721e1..73e61299 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java @@ -149,4 +149,14 @@ public class MapSheetAnalInferenceEntity { @Column(name = "stage") private Integer stage; + + @Size(max = 1) + @ColumnDefault("'N'") + @Column(name = "labeling_closed_yn", length = 1) + private String labelingClosedYn = "N"; + + @Size(max = 1) + @ColumnDefault("'N'") + @Column(name = "inspection_closed_yn", length = 1) + private String inspectionClosedYn = "N"; } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java index 350b30c2..319a118b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java @@ -77,4 +77,8 @@ public interface LabelAllocateRepositoryCustom { void insertLabelerUser(Long analUid, String userId, int demand); void assignOwnerReAllocate(String uuid, String userId, String paramUserId, Long assignCount); + + + // 프로젝트 종료 여부 업데이트 (uuid 기반) + void updateClosedYnByUuid(String uuid, String closedType, String closedYn); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java index 6d64776a..28b2f625 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java @@ -335,10 +335,50 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public WorkProgressInfo findWorkProgressInfo(Long analUid) { - BooleanExpression analUidCondition = - analUid != null ? labelingAssignmentEntity.analUid.eq(analUid) : null; + // analUid가 null이면 최신 프로젝트의 analUid 조회 + Long effectiveAnalUid = analUid; + if (effectiveAnalUid == null) { + UUID latestUuid = findLastLabelWorkState(); + if (latestUuid != null) { + effectiveAnalUid = + queryFactory + .select(mapSheetAnalInferenceEntity.id) + .from(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.uuid.eq(latestUuid)) + .fetchOne(); + } + } - // 전체 배정 건수 + BooleanExpression analUidCondition = + effectiveAnalUid != null ? labelingAssignmentEntity.analUid.eq(effectiveAnalUid) : null; + + // analUid로 분석 정보(compareYyyy, targetYyyy, stage) 조회 + MapSheetAnalInferenceEntity analEntity = null; + if (effectiveAnalUid != null) { + analEntity = + queryFactory + .selectFrom(mapSheetAnalInferenceEntity) + .where(mapSheetAnalInferenceEntity.id.eq(effectiveAnalUid)) + .fetchOne(); + } + + // 라벨링 대상 건수: tb_map_sheet_anal_data_inference_geom에서 pnu > 0 AND pass_yn = false(부적합)인 건수 + Long labelingTargetCount = 0L; + if (analEntity != null) { + labelingTargetCount = + queryFactory + .select(mapSheetAnalDataInferenceGeomEntity.geoUid.count()) + .from(mapSheetAnalDataInferenceGeomEntity) + .where( + mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(analEntity.getCompareYyyy()), + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(analEntity.getTargetYyyy()), + mapSheetAnalDataInferenceGeomEntity.stage.eq(analEntity.getStage()), + mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L), + mapSheetAnalDataInferenceGeomEntity.passYn.isFalse()) + .fetchOne(); + } + + // 전체 배정 건수 (tb_labeling_assignment 기준) Long totalAssigned = queryFactory .select(labelingAssignmentEntity.count()) @@ -390,47 +430,69 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto .where(analUidCondition, labelingAssignmentEntity.inspectorUid.isNotNull()) .fetchOne(); - // 남은 작업 건수 계산 - long total = totalAssigned != null ? totalAssigned : 0L; + // 라벨링 대상 건수 (pass_yn = false인 부적합 데이터 기준) + long labelingTotal = labelingTargetCount != null ? labelingTargetCount : 0L; + long assignedTotal = totalAssigned != null ? totalAssigned : 0L; long labelCompleted = labelingCompleted != null ? labelingCompleted : 0L; long inspectCompleted = inspectionCompleted != null ? inspectionCompleted : 0L; long skipped = skipCount != null ? skipCount : 0L; - long labelingRemaining = total - labelCompleted - skipped; - long inspectionRemaining = total - inspectCompleted - skipped; + // 라벨링 남은 건수: 라벨링 대상 건수 - 완료 - 스킵 + long labelingRemaining = labelingTotal - labelCompleted - skipped; + if (labelingRemaining < 0) labelingRemaining = 0; - // 진행률 계산 - double labelingRate = total > 0 ? (double) labelCompleted / total * 100 : 0.0; - double inspectionRate = total > 0 ? (double) inspectCompleted / total * 100 : 0.0; + // 검수 대상 건수: 라벨링 대상 건수와 동일 (기획서 기준) + long inspectionTotal = labelingTotal; + // 검수 남은 건수: 검수 대상 건수 - 검수완료(DONE) - 스킵 + long inspectionRemaining = inspectionTotal - inspectCompleted - skipped; + if (inspectionRemaining < 0) inspectionRemaining = 0; - // 상태 판단 - String labelingStatus = labelingRemaining > 0 ? "진행중" : "완료"; - String inspectionStatus = inspectionRemaining > 0 ? "진행중" : "완료"; + // 진행률 계산 (라벨링 대상 건수 기준) + double labelingRate = labelingTotal > 0 ? (double) labelCompleted / labelingTotal * 100 : 0.0; + double inspectionRate = + inspectionTotal > 0 ? (double) inspectCompleted / inspectionTotal * 100 : 0.0; + + // 상태 판단 (각각의 closedYn이 "Y"이면 "종료", 아니면 진행중/완료) + String labelingStatus; + String inspectionStatus; + + // 라벨링 상태 판단 + if (analEntity != null && "Y".equals(analEntity.getLabelingClosedYn())) { + labelingStatus = "종료"; + } else { + labelingStatus = labelingRemaining > 0 ? "진행중" : "완료"; + } + + // 검수 상태 판단 + if (analEntity != null && "Y".equals(analEntity.getInspectionClosedYn())) { + inspectionStatus = "종료"; + } else { + inspectionStatus = inspectionRemaining > 0 ? "진행중" : "완료"; + } return WorkProgressInfo.builder() - // 라벨링 + // 라벨링 (pass_yn = false인 부적합 데이터 기준) .labelingProgressRate(labelingRate) .labelingStatus(labelingStatus) - .labelingTotalCount(total) + .labelingTotalCount(labelingTotal) .labelingCompletedCount(labelCompleted) .labelingSkipCount(skipped) .labelingRemainingCount(labelingRemaining) .labelerCount(labelerCount != null ? labelerCount : 0L) - // 검수 + // 검수 (라벨링 완료 건수 기준) .inspectionProgressRate(inspectionRate) .inspectionStatus(inspectionStatus) - .inspectionTotalCount(total) + .inspectionTotalCount(inspectionTotal) .inspectionCompletedCount(inspectCompleted) .inspectionSkipCount(skipped) .inspectionRemainingCount(inspectionRemaining) .inspectorCount(inspectorCount != null ? inspectorCount : 0L) // 레거시 호환 필드 (Deprecated) .progressRate(labelingRate) - .totalAssignedCount(total) + .totalAssignedCount(labelingTotal) .completedCount(labelCompleted) .remainingLabelCount(labelingRemaining) .remainingInspectCount(inspectionRemaining) - .workStatus(labelingStatus) .build(); } @@ -677,7 +739,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto mapSheetAnalInferenceEntity.stage, mapSheetAnalInferenceEntity.gukyuinApplyDttm, mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid) + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) .from(mapSheetAnalInferenceEntity) .where(mapSheetAnalInferenceEntity.id.eq(analUid)) .fetchOne(); @@ -692,6 +756,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto ZonedDateTime gukyuinApplyDttm = result.get(mapSheetAnalInferenceEntity.gukyuinApplyDttm); ZonedDateTime createdDttm = result.get(mapSheetAnalInferenceEntity.createdDttm); UUID uuid = result.get(mapSheetAnalInferenceEntity.uuid); + String labelingClosedYn = result.get(mapSheetAnalInferenceEntity.labelingClosedYn); + String inspectionClosedYn = result.get(mapSheetAnalInferenceEntity.inspectionClosedYn); // 변화탐지년도 생성 String detectionYear = @@ -706,6 +772,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto .gukyuinApplyDttm(gukyuinApplyDttm) .startDttm(createdDttm) .uuid(uuid != null ? uuid.toString() : null) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) .build(); } @@ -727,7 +795,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto mapSheetAnalInferenceEntity.stage, mapSheetAnalInferenceEntity.gukyuinApplyDttm, mapSheetAnalInferenceEntity.createdDttm, - mapSheetAnalInferenceEntity.uuid) + mapSheetAnalInferenceEntity.uuid, + mapSheetAnalInferenceEntity.labelingClosedYn, + mapSheetAnalInferenceEntity.inspectionClosedYn) .from(mapSheetAnalInferenceEntity) .where(mapSheetAnalInferenceEntity.uuid.eq(uuid)) .fetchOne(); @@ -741,6 +811,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto Integer stage = result.get(mapSheetAnalInferenceEntity.stage); ZonedDateTime gukyuinApplyDttm = result.get(mapSheetAnalInferenceEntity.gukyuinApplyDttm); ZonedDateTime createdDttm = result.get(mapSheetAnalInferenceEntity.createdDttm); + String labelingClosedYn = result.get(mapSheetAnalInferenceEntity.labelingClosedYn); + String inspectionClosedYn = result.get(mapSheetAnalInferenceEntity.inspectionClosedYn); // 변화탐지년도 생성 String detectionYear = @@ -755,6 +827,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto .gukyuinApplyDttm(gukyuinApplyDttm) .startDttm(createdDttm) .uuid(uuid.toString()) + .labelingClosedYn(labelingClosedYn) + .inspectionClosedYn(inspectionClosedYn) .build(); } @@ -1160,4 +1234,24 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto labelingLabelerEntity.workerUid.eq(paramUserId)) .execute(); } + + + @Override + public void updateClosedYnByUuid(String uuid, String closedType, String closedYn) { + var updateQuery = queryFactory.update(mapSheetAnalInferenceEntity); + + if ("LABELING".equals(closedType)) { + updateQuery.set(mapSheetAnalInferenceEntity.labelingClosedYn, closedYn); + } else if ("INSPECTION".equals(closedType)) { + updateQuery.set(mapSheetAnalInferenceEntity.inspectionClosedYn, closedYn); + } + + updateQuery + .set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now()) + .where(mapSheetAnalInferenceEntity.uuid.eq(UUID.fromString(uuid))) + .execute(); + + em.flush(); + em.clear(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java index 10308aed..57f28ff5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelWorkRepositoryImpl.java @@ -267,32 +267,29 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom { whereSubBuilder.and(labelingAssignmentEntity.workerUid.eq(memberEntity.userId)); + // 공통 조건 추출 + BooleanExpression doneStateCondition = + labelingAssignmentEntity.workState.eq(LabelState.DONE.name()); + NumberExpression assignedCnt = labelingAssignmentEntity.workerUid.count(); - NumberExpression doneCnt = - this.caseSumExpression(labelingAssignmentEntity.workState.eq(LabelState.DONE.name())); + NumberExpression doneCnt = this.caseSumExpression(doneStateCondition); NumberExpression skipCnt = this.caseSumExpression(labelingAssignmentEntity.workState.eq(LabelState.SKIP.name())); NumberExpression day3AgoDoneCnt = this.caseSumExpression( - labelingAssignmentEntity - .workState - .eq(LabelState.DONE.name()) - .and(this.fromDateEqExpression(labelingAssignmentEntity.modifiedDate, -3))); + doneStateCondition.and( + this.fromDateEqExpression(labelingAssignmentEntity.modifiedDate, -3))); NumberExpression day2AgoDoneCnt = this.caseSumExpression( - labelingAssignmentEntity - .workState - .eq(LabelState.DONE.name()) - .and(this.fromDateEqExpression(labelingAssignmentEntity.modifiedDate, -2))); + doneStateCondition.and( + this.fromDateEqExpression(labelingAssignmentEntity.modifiedDate, -2))); NumberExpression day1AgoDoneCnt = this.caseSumExpression( - labelingAssignmentEntity - .workState - .eq(LabelState.DONE.name()) - .and(this.fromDateEqExpression(labelingAssignmentEntity.modifiedDate, -1))); + doneStateCondition.and( + this.fromDateEqExpression(labelingAssignmentEntity.modifiedDate, -1))); NumberExpression remainingCnt = assignedCnt.subtract(doneCnt);