--- src/main/java/kr/itn/itnhub/dashboard/DashboardMapper.java
+++ src/main/java/kr/itn/itnhub/dashboard/DashboardMapper.java
... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 |
* @param doneStatus 권리처리 완료로 셀 상태값. 코드표에서 와야 하는데 SQL이 코드표를 |
| 15 | 15 |
* 참조할 방법이 없어 서비스가 읽어 넘긴다. |
| 16 | 16 |
*/ |
| 17 |
- List<DashboardOrgRow> findOrgRows(@Param("doneStatus") String doneStatus);
|
|
| 17 |
+ List<DashboardOrgProjection> findOrgRows(@Param("doneStatus") String doneStatus);
|
|
| 18 | 18 |
|
| 19 | 19 |
List<DistributionItem> reviewResultDistribution(); |
| 20 | 20 |
List<DistributionItem> reviewSourceKoglDistribution(); |
+++ src/main/java/kr/itn/itnhub/dashboard/DashboardOrgProjection.java
... | ... | @@ -0,0 +1,32 @@ |
| 1 | +package kr.itn.itnhub.dashboard; | |
| 2 | + | |
| 3 | +import kr.itn.itnhub.org.OrgOperationalState; | |
| 4 | + | |
| 5 | +/** DB 집계 결과를 API 응답 모델로 변환하는 내부 조회 모델. */ | |
| 6 | +public record DashboardOrgProjection( | |
| 7 | + Long id, | |
| 8 | + String orgNo, | |
| 9 | + String orgName, | |
| 10 | + Long applicantContactId, | |
| 11 | + String channelIdMj, | |
| 12 | + String channelIdLaw, | |
| 13 | + Integer stage, | |
| 14 | + String lawyerName, | |
| 15 | + String mjName, | |
| 16 | + String lawyerAssignedDate, | |
| 17 | + int reviewTotal, | |
| 18 | + int reviewDone, | |
| 19 | + int processTotal, | |
| 20 | + int processDone, | |
| 21 | + Long stageChangedAt, | |
| 22 | + Long lastChangedAt, | |
| 23 | + int reCount) { | |
| 24 | + | |
| 25 | + DashboardOrgRow toRow() { | |
| 26 | + OrgOperationalState operationalState = OrgOperationalState.from( | |
| 27 | + applicantContactId, channelIdMj, channelIdLaw); | |
| 28 | + return new DashboardOrgRow(id, orgNo, orgName, operationalState.status(), stage, | |
| 29 | + operationalState.hasChannel(), lawyerName, mjName, lawyerAssignedDate, | |
| 30 | + reviewTotal, reviewDone, processTotal, processDone, stageChangedAt, lastChangedAt, reCount); | |
| 31 | + } | |
| 32 | +} |
--- src/main/java/kr/itn/itnhub/dashboard/DashboardService.java
+++ src/main/java/kr/itn/itnhub/dashboard/DashboardService.java
... | ... | @@ -42,7 +42,9 @@ |
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 | 44 |
public DashboardResponse dashboard() {
|
| 45 |
- List<DashboardOrgRow> rows = mapper.findOrgRows(doneStatus()); |
|
| 45 |
+ List<DashboardOrgRow> rows = mapper.findOrgRows(doneStatus()).stream() |
|
| 46 |
+ .map(DashboardOrgProjection::toRow) |
|
| 47 |
+ .toList(); |
|
| 46 | 48 |
RightsDashboardStats rights = new RightsDashboardStats( |
| 47 | 49 |
mapper.reviewResultDistribution(), |
| 48 | 50 |
mapper.reviewSourceKoglDistribution(), |
+++ src/main/java/kr/itn/itnhub/org/OrgOperationalState.java
... | ... | @@ -0,0 +1,30 @@ |
| 1 | +package kr.itn.itnhub.org; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 기관 담당자 및 채널 정보에서 파생되는 운영 상태. | |
| 5 | + * 상태 판정과 채널 보유 여부가 항상 같은 공백 처리 규칙을 사용하도록 한곳에서 계산한다. | |
| 6 | + */ | |
| 7 | +public record OrgOperationalState(OrgStatus status, boolean hasChannel) { | |
| 8 | + | |
| 9 | + public static OrgOperationalState from(Long applicantContactId, String channelIdMj, String channelIdLaw) { | |
| 10 | + boolean mjActive = filled(channelIdMj); | |
| 11 | + boolean lawActive = filled(channelIdLaw); | |
| 12 | + OrgStatus status; | |
| 13 | + | |
| 14 | + if (mjActive && lawActive) { | |
| 15 | + status = OrgStatus.ACTIVE; | |
| 16 | + } else if (mjActive || lawActive) { | |
| 17 | + status = OrgStatus.PARTIAL; | |
| 18 | + } else if (applicantContactId != null) { | |
| 19 | + status = OrgStatus.READY; | |
| 20 | + } else { | |
| 21 | + status = OrgStatus.INFO_PENDING; | |
| 22 | + } | |
| 23 | + | |
| 24 | + return new OrgOperationalState(status, mjActive || lawActive); | |
| 25 | + } | |
| 26 | + | |
| 27 | + private static boolean filled(String value) { | |
| 28 | + return value != null && !value.isBlank(); | |
| 29 | + } | |
| 30 | +} |
--- src/main/java/kr/itn/itnhub/org/Organization.java
+++ src/main/java/kr/itn/itnhub/org/Organization.java
... | ... | @@ -28,25 +28,12 @@ |
| 28 | 28 |
* 저장하면 채널ID와 상태가 어긋나는 순간이 생기고, 그 어긋남을 고칠 방법이 없다. |
| 29 | 29 |
*/ |
| 30 | 30 |
public OrgStatus getStatus() {
|
| 31 |
- boolean mjActive = filled(channelIdMj); |
|
| 32 |
- boolean lawActive = filled(channelIdLaw); |
|
| 33 |
- |
|
| 34 |
- if (mjActive && lawActive) {
|
|
| 35 |
- return OrgStatus.ACTIVE; |
|
| 36 |
- } |
|
| 37 |
- if (mjActive || lawActive) {
|
|
| 38 |
- return OrgStatus.PARTIAL; |
|
| 39 |
- } |
|
| 40 |
- return hasApplicantAssigned() ? OrgStatus.READY : OrgStatus.INFO_PENDING; |
|
| 31 |
+ return OrgOperationalState.from(applicantContactId, channelIdMj, channelIdLaw).status(); |
|
| 41 | 32 |
} |
| 42 | 33 |
|
| 43 | 34 |
/** 신청기관 담당자가 배정되어야 채널을 만들 수 있다(담당자관리에서 등록·배정된 담당자). */ |
| 44 | 35 |
public boolean hasApplicantAssigned() {
|
| 45 | 36 |
return applicantContactId != null; |
| 46 |
- } |
|
| 47 |
- |
|
| 48 |
- private static boolean filled(String value) {
|
|
| 49 |
- return value != null && !value.isBlank(); |
|
| 50 | 37 |
} |
| 51 | 38 |
|
| 52 | 39 |
public Long getId() { return id; }
|
--- src/main/resources/mapper/DashboardMapper.xml
+++ src/main/resources/mapper/DashboardMapper.xml
... | ... | @@ -5,16 +5,17 @@ |
| 5 | 5 |
|
| 6 | 6 |
<!-- |
| 7 | 7 |
record라서 constructor 매핑을 쓴다(ProcessItemMapper의 statsResultMap과 같은 방식). |
| 8 |
- arg 순서는 DashboardOrgRow의 컴포넌트 순서와 반드시 같아야 한다. |
|
| 8 |
+ arg 순서는 DashboardOrgProjection의 컴포넌트 순서와 반드시 같아야 한다. |
|
| 9 | 9 |
--> |
| 10 |
- <resultMap id="orgRowResultMap" type="kr.itn.itnhub.dashboard.DashboardOrgRow"> |
|
| 10 |
+ <resultMap id="orgRowResultMap" type="kr.itn.itnhub.dashboard.DashboardOrgProjection"> |
|
| 11 | 11 |
<constructor> |
| 12 | 12 |
<idArg column="id" javaType="java.lang.Long"/> |
| 13 | 13 |
<arg column="org_no" javaType="java.lang.String"/> |
| 14 | 14 |
<arg column="org_name" javaType="java.lang.String"/> |
| 15 |
- <arg column="org_status" javaType="kr.itn.itnhub.org.OrgStatus"/> |
|
| 15 |
+ <arg column="applicant_contact_id" javaType="java.lang.Long"/> |
|
| 16 |
+ <arg column="channel_id_mj" javaType="java.lang.String"/> |
|
| 17 |
+ <arg column="channel_id_law" javaType="java.lang.String"/> |
|
| 16 | 18 |
<arg column="stage" javaType="java.lang.Integer"/> |
| 17 |
- <arg column="has_channel" javaType="_boolean"/> |
|
| 18 | 19 |
<arg column="lawyer_name" javaType="java.lang.String"/> |
| 19 | 20 |
<arg column="mj_name" javaType="java.lang.String"/> |
| 20 | 21 |
<arg column="lawyer_assigned_date" javaType="java.lang.String"/> |
... | ... | @@ -49,14 +50,10 @@ |
| 49 | 50 |
o.id, |
| 50 | 51 |
o.org_no, |
| 51 | 52 |
o.org_name, |
| 52 |
- case |
|
| 53 |
- when nullif(trim(o.channel_id_mj), '') is not null and nullif(trim(o.channel_id_law), '') is not null then 'ACTIVE' |
|
| 54 |
- when nullif(trim(o.channel_id_mj), '') is not null or nullif(trim(o.channel_id_law), '') is not null then 'PARTIAL' |
|
| 55 |
- when o.applicant_contact_id is not null then 'READY' |
|
| 56 |
- else 'INFO_PENDING' |
|
| 57 |
- end as org_status, |
|
| 53 |
+ o.applicant_contact_id, |
|
| 54 |
+ o.channel_id_mj, |
|
| 55 |
+ o.channel_id_law, |
|
| 58 | 56 |
o.stage, |
| 59 |
- (o.channel_id_mj is not null or o.channel_id_law is not null) as has_channel, |
|
| 60 | 57 |
lc.name as lawyer_name, |
| 61 | 58 |
mc.name as mj_name, |
| 62 | 59 |
o.lawyer_assigned_date, |
--- src/test/java/kr/itn/itnhub/org/OrganizationStatusTest.java
+++ src/test/java/kr/itn/itnhub/org/OrganizationStatusTest.java
... | ... | @@ -74,4 +74,14 @@ |
| 74 | 74 |
org.setApplicantContactId(null); |
| 75 | 75 |
assertThat(org.hasApplicantAssigned()).isFalse(); |
| 76 | 76 |
} |
| 77 |
+ |
|
| 78 |
+ @Test |
|
| 79 |
+ void 공백_채널ID는_등록된_채널로_보지_않는다() {
|
|
| 80 |
+ Organization org = withApplicant(); |
|
| 81 |
+ org.setChannelIdMj(" ");
|
|
| 82 |
+ org.setChannelIdLaw("\t");
|
|
| 83 |
+ |
|
| 84 |
+ assertThat(org.getStatus()).isEqualTo(OrgStatus.READY); |
|
| 85 |
+ assertThat(OrgOperationalState.from(org.getApplicantContactId(), " ", "\t").hasChannel()).isFalse(); |
|
| 86 |
+ } |
|
| 77 | 87 |
} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?