diff --git a/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationNoteGroupResponse.java b/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationNoteGroupResponse.java index 37fb4b5..2079c9c 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationNoteGroupResponse.java +++ b/src/main/java/com/piuda/callcare/domain/medication/dto/response/MedicationNoteGroupResponse.java @@ -5,11 +5,11 @@ import java.time.LocalDate; import java.util.List; -@Schema(description = "약물노트 그룹 카드 — 복용 시작일 + 병원 기준 묶음") +@Schema(description = "약물노트 그룹 카드 — 처방일 + 병원 기준 묶음") public record MedicationNoteGroupResponse( - @Schema(description = "복용 시작일 (그룹 키)") - LocalDate startDate, + @Schema(description = "처방일 (파싱 성공 시 처방일, 실패 시 복용 시작일 fallback — 그룹 키)") + LocalDate prescriptionDate, @Schema(description = "병원명 (없으면 null)") String hospitalName, diff --git a/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java b/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java index 4a96a78..d4802e8 100644 --- a/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java +++ b/src/main/java/com/piuda/callcare/domain/medication/service/query/MedicationQueryService.java @@ -63,16 +63,18 @@ public List searchNotes(Long userId, Long seniorId, private List toNoteGroupResponses(List medications) { Map> grouped = new LinkedHashMap<>(); for (Medication m : medications) { - String key = m.getStartDate() + "|" + m.getHospitalName(); + LocalDate groupDate = m.getPrescriptionDate() != null ? m.getPrescriptionDate() : m.getStartDate(); + String key = groupDate + "|" + m.getHospitalName(); grouped.computeIfAbsent(key, k -> new ArrayList<>()).add(m); } return grouped.values().stream() .map(group -> { Medication first = group.get(0); + LocalDate groupDate = first.getPrescriptionDate() != null ? first.getPrescriptionDate() : first.getStartDate(); List items = group.stream() .map(medicationConverter::toNoteItemResponse) .toList(); - return new MedicationNoteGroupResponse(first.getStartDate(), first.getHospitalName(), items); + return new MedicationNoteGroupResponse(groupDate, first.getHospitalName(), items); }) .toList(); } diff --git a/src/main/java/com/piuda/callcare/domain/ocrresult/converter/OcrResultConverter.java b/src/main/java/com/piuda/callcare/domain/ocrresult/converter/OcrResultConverter.java index 2931c49..b2f53a8 100644 --- a/src/main/java/com/piuda/callcare/domain/ocrresult/converter/OcrResultConverter.java +++ b/src/main/java/com/piuda/callcare/domain/ocrresult/converter/OcrResultConverter.java @@ -5,17 +5,19 @@ import com.piuda.callcare.domain.ocrresult.entity.OcrResult; import org.springframework.stereotype.Component; +import java.time.LocalDate; import java.util.List; @Component public class OcrResultConverter { - // OcrResult + 파싱된 약 목록 → OcrResultResponse - public OcrResultResponse toResponse(OcrResult ocrResult, List parsedDrugs) { + // OcrResult + 파싱된 약 목록 + 처방일 → OcrResultResponse + public OcrResultResponse toResponse(OcrResult ocrResult, List parsedDrugs, LocalDate prescriptionDate) { return new OcrResultResponse( ocrResult.getId(), ocrResult.getRawText(), - parsedDrugs + parsedDrugs, + prescriptionDate ); } } diff --git a/src/main/java/com/piuda/callcare/domain/ocrresult/dto/OcrParseResult.java b/src/main/java/com/piuda/callcare/domain/ocrresult/dto/OcrParseResult.java index ac9150f..3a84a58 100644 --- a/src/main/java/com/piuda/callcare/domain/ocrresult/dto/OcrParseResult.java +++ b/src/main/java/com/piuda/callcare/domain/ocrresult/dto/OcrParseResult.java @@ -1,8 +1,10 @@ package com.piuda.callcare.domain.ocrresult.dto; +import java.time.LocalDate; import java.util.List; public record OcrParseResult( String rawText, - List parsedDrugs + List parsedDrugs, + LocalDate prescriptionDate // 처방일 파싱 성공 시 채워짐, 실패 시 null ) {} diff --git a/src/main/java/com/piuda/callcare/domain/ocrresult/dto/response/OcrResultResponse.java b/src/main/java/com/piuda/callcare/domain/ocrresult/dto/response/OcrResultResponse.java index 9922ded..57c399d 100644 --- a/src/main/java/com/piuda/callcare/domain/ocrresult/dto/response/OcrResultResponse.java +++ b/src/main/java/com/piuda/callcare/domain/ocrresult/dto/response/OcrResultResponse.java @@ -3,6 +3,7 @@ import com.piuda.callcare.domain.ocrresult.dto.ParsedOcrData; import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDate; import java.util.List; @Schema(description = "OCR 분석 결과") @@ -15,5 +16,8 @@ public record OcrResultResponse( String rawText, @Schema(description = "파싱된 약 목록 — 단일 약이면 1개, 표 처방전이면 여러 개") - List parsedDrugs + List parsedDrugs, + + @Schema(description = "처방일 — 처방전에서 파싱 성공 시 채워짐, 실패 시 null (약 등록 시 prescriptionDate 기본값으로 사용)") + LocalDate prescriptionDate ) {} diff --git a/src/main/java/com/piuda/callcare/domain/ocrresult/service/OcrParser.java b/src/main/java/com/piuda/callcare/domain/ocrresult/service/OcrParser.java index 0edd1e7..c690fd4 100644 --- a/src/main/java/com/piuda/callcare/domain/ocrresult/service/OcrParser.java +++ b/src/main/java/com/piuda/callcare/domain/ocrresult/service/OcrParser.java @@ -6,6 +6,7 @@ import com.piuda.callcare.domain.ocrresult.enums.OcrType; import org.springframework.stereotype.Component; +import java.time.LocalDate; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -64,6 +65,14 @@ public class OcrParser { "1회\\s*투약량\\s*\\d|1일\\s*투여\\s*횟수\\s*\\d|총\\s*투약\\s*일수\\s*\\d" ); + // 처방일 우선, 없으면 조제일 fallback + private static final Pattern PRESCRIPTION_DATE_PATTERN = Pattern.compile( + "(?:처방일|처방일자|처방전발행일)\\s*[:\\-]?\\s*(\\d{4})\\s*[.년\\-]\\s*(\\d{1,2})\\s*[.월\\-]?\\s*(\\d{1,2})" + ); + private static final Pattern DISPENSE_DATE_PATTERN = Pattern.compile( + "(?:조제일|조제일자)\\s*[:\\-]?\\s*(\\d{4})\\s*[.년\\-]\\s*(\\d{1,2})\\s*[.월\\-]?\\s*(\\d{1,2})" + ); + private static final List DRUG_NAME_KEYWORDS = List.of("명칭", "약품명", "의약품"); private static final List DOSAGE_KEYWORDS = List.of("투약량", "복용량", "1회"); private static final List TIMES_KEYWORDS = List.of("투여횟수", "복용횟수", "횟수"); @@ -86,7 +95,7 @@ public OcrParseResult parse(List fields, OcrType ocrT parsedDrugs = List.of(parseByRegex(rawText)); } - return new OcrParseResult(rawText, parsedDrugs); + return new OcrParseResult(rawText, parsedDrugs, extractPrescriptionDate(rawText)); } // ── rawText 조립 ────────────────────────────────────────────────────────── @@ -463,6 +472,27 @@ private Integer extractTotalDays(String text) { return null; } + // ── 처방일 추출 ─────────────────────────────────────────────────────────── + + // 처방일 우선 파싱, 없으면 조제일 fallback + private LocalDate extractPrescriptionDate(String rawText) { + LocalDate date = tryExtractDate(PRESCRIPTION_DATE_PATTERN, rawText); + return date != null ? date : tryExtractDate(DISPENSE_DATE_PATTERN, rawText); + } + + private LocalDate tryExtractDate(Pattern pattern, String text) { + Matcher m = pattern.matcher(text); + if (!m.find()) return null; + try { + int year = Integer.parseInt(m.group(1)); + int month = Integer.parseInt(m.group(2).trim()); + int day = Integer.parseInt(m.group(3).trim()); + return LocalDate.of(year, month, day); + } catch (Exception e) { + return null; + } + } + // ── 좌표 유틸 ───────────────────────────────────────────────────────────── private double centerX(NaverOcrApiResponse.Field field) { diff --git a/src/main/java/com/piuda/callcare/domain/ocrresult/service/command/OcrCommandService.java b/src/main/java/com/piuda/callcare/domain/ocrresult/service/command/OcrCommandService.java index 5fd6211..06b3ca0 100644 --- a/src/main/java/com/piuda/callcare/domain/ocrresult/service/command/OcrCommandService.java +++ b/src/main/java/com/piuda/callcare/domain/ocrresult/service/command/OcrCommandService.java @@ -60,6 +60,6 @@ public OcrResultResponse processOcr(Long userId, Long seniorId, MultipartFile im log.info("OCR 처리 완료 - ocrResultId: {}, ocrType: {}, 파싱된 약 수: {}", saved.getId(), ocrType, parseResult.parsedDrugs().size()); - return ocrResultConverter.toResponse(saved, parseResult.parsedDrugs()); + return ocrResultConverter.toResponse(saved, parseResult.parsedDrugs(), parseResult.prescriptionDate()); } }