From 4110a9f2f18eed8bb8fce21a6475649ab29c3986 Mon Sep 17 00:00:00 2001 From: Hyojin Ahn Date: Wed, 24 Jun 2026 10:03:41 -0400 Subject: [PATCH] =?UTF-8?q?=EA=B3=A0=EA=B0=9D=20=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EC=9D=B4=EC=97=90=20+-=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/dto/CustomerActiveTrendPointDto.java | 8 ++++- .../erp/repository/CustomerRepository.java | 31 +++++++++++-------- .../com/goi/erp/service/CustomerService.java | 4 +++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/goi/erp/dto/CustomerActiveTrendPointDto.java b/src/main/java/com/goi/erp/dto/CustomerActiveTrendPointDto.java index 54e83e4..707ea93 100644 --- a/src/main/java/com/goi/erp/dto/CustomerActiveTrendPointDto.java +++ b/src/main/java/com/goi/erp/dto/CustomerActiveTrendPointDto.java @@ -19,6 +19,12 @@ public class CustomerActiveTrendPointDto { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private LocalDate date; - // 그 날짜에 활성( cus_contract_date <= date AND (terminated IS NULL OR terminated > date) )인 고객 수 + // 그 날짜의 활성 고객 수 (cus_status='A' 기준, 날짜로 과거 재구성) private long count; + + // 그 날짜에 계약 시작한 고객 수 (cus_contract_date = date) + private long added; + + // 그 날짜에 해지된 고객 수 (cus_terminated_date = date) + private long removed; } \ No newline at end of file diff --git a/src/main/java/com/goi/erp/repository/CustomerRepository.java b/src/main/java/com/goi/erp/repository/CustomerRepository.java index ba9b26d..6d2b9e0 100644 --- a/src/main/java/com/goi/erp/repository/CustomerRepository.java +++ b/src/main/java/com/goi/erp/repository/CustomerRepository.java @@ -30,24 +30,29 @@ public interface CustomerRepository extends JpaRepository { // 오늘 추가된 고객 수: cus_contract_date = 오늘 long countByCusContractDate(LocalDate cusContractDate); - // 날짜별 활성 고객 수 (선그래프용). - // - 활성 기준 = cus_status='A' (현재 활성 플래그가 진짜 기준) - // - 그 위에 날짜로 과거 시점 재구성: cus_contract_date <= D AND (cus_terminated_date IS NULL OR cus_terminated_date > D) - // - 즉 "지금 활성('A')이면서 그 날짜에 계약기간 안에 있던" 고객 수 → 오늘 값은 전체(활성) 고객 수와 일치 - // - generate_series 로 [startDate, endDate] 각 날짜를 만들고 LEFT JOIN 으로 카운트 → 빈 날도 0으로 채워짐 - // - return: [0]=날짜(date), [1]=활성 고객 수(bigint) + // 날짜별 활성 고객 수 + 신규/해지 (선그래프·막대그래프용). + // - active_count = cus_status='A' 이고 그 날짜에 계약기간 안에 있던 고객 수 (날짜로 과거 재구성) + // - added_count = 그 날짜에 계약 시작 (cus_contract_date = D) + // - removed_count = 그 날짜에 해지 (cus_terminated_date = D) + // - generate_series 로 [startDate, endDate] 각 날짜 생성 → 빈 날도 0 + // - return: [0]=날짜(date), [1]=active(bigint), [2]=added(bigint), [3]=removed(bigint) @Query(value = """ SELECT CAST(series.day AS date) AS day, - COUNT(c.cus_id) AS active_count + (SELECT COUNT(*) FROM crm.customer c + WHERE c.cus_status = 'A' + AND c.cus_contract_date IS NOT NULL + AND c.cus_contract_date <= CAST(series.day AS date) + AND (c.cus_terminated_date IS NULL OR c.cus_terminated_date > CAST(series.day AS date)) + ) AS active_count, + (SELECT COUNT(*) FROM crm.customer a + WHERE a.cus_contract_date = CAST(series.day AS date) + ) AS added_count, + (SELECT COUNT(*) FROM crm.customer r + WHERE r.cus_terminated_date = CAST(series.day AS date) + ) AS removed_count FROM generate_series(CAST(:startDate AS timestamp), CAST(:endDate AS timestamp), INTERVAL '1 day') AS series(day) - LEFT JOIN crm.customer c - ON c.cus_status = 'A' - AND c.cus_contract_date IS NOT NULL - AND c.cus_contract_date <= CAST(series.day AS date) - AND (c.cus_terminated_date IS NULL OR c.cus_terminated_date > CAST(series.day AS date)) - GROUP BY series.day ORDER BY series.day """, nativeQuery = true) List findActiveCustomerTrend(@Param("startDate") LocalDate startDate, diff --git a/src/main/java/com/goi/erp/service/CustomerService.java b/src/main/java/com/goi/erp/service/CustomerService.java index 585bb5b..abb835c 100644 --- a/src/main/java/com/goi/erp/service/CustomerService.java +++ b/src/main/java/com/goi/erp/service/CustomerService.java @@ -124,10 +124,14 @@ public class CustomerService { day = LocalDate.parse(row[0].toString()); } long count = ((Number) row[1]).longValue(); + long added = ((Number) row[2]).longValue(); + long removed = ((Number) row[3]).longValue(); result.add(CustomerActiveTrendPointDto.builder() .date(day) .count(count) + .added(added) + .removed(removed) .build()); } return result;