11package com .trashheroesbe .feature .trash .application ;
22
3- import com .trashheroesbe .feature .trash .dto .response .PartCardResponse ;
4- import com .trashheroesbe .feature .trash .dto .response .TrashAnalysisResponseDto ;
3+ import com .fasterxml .jackson .databind .ObjectMapper ;
4+ import com .trashheroesbe .feature .disposal .infrastructure .DisposalRepository ;
5+ import com .trashheroesbe .feature .trash .dto .response .*;
56import com .trashheroesbe .feature .trash .domain .entity .TrashDescription ;
67import com .trashheroesbe .feature .trash .domain .Type ;
78import com .trashheroesbe .feature .trash .domain .entity .Trash ;
89import com .trashheroesbe .feature .trash .domain .entity .TrashItem ;
910import com .trashheroesbe .feature .trash .domain .entity .TrashType ;
1011import com .trashheroesbe .feature .trash .dto .request .CreateTrashRequest ;
11- import com .trashheroesbe .feature .trash .dto .response .TrashItemResponse ;
12- import com .trashheroesbe .feature .trash .dto .response .TrashResultResponse ;
1312import com .trashheroesbe .feature .trash .infrastructure .TrashDescriptionRepository ;
1413import com .trashheroesbe .feature .trash .infrastructure .TrashItemRepository ;
1514import com .trashheroesbe .feature .trash .infrastructure .TrashRepository ;
1615import com .trashheroesbe .feature .trash .infrastructure .TrashTypeRepository ;
1716import com .trashheroesbe .feature .user .domain .entity .User ;
17+ import com .trashheroesbe .feature .user .infrastructure .UserDistrictRepository ;
1818import com .trashheroesbe .global .exception .BusinessException ;
1919import com .trashheroesbe .global .response .type .ErrorCode ;
2020import com .trashheroesbe .global .util .FileUtils ;
@@ -43,6 +43,8 @@ public class TrashService implements TrashCreateUseCase {
4343 private final TrashTypeRepository trashTypeRepository ;
4444 private final TrashItemRepository trashItemRepository ;
4545 private final TrashDescriptionRepository trashDescriptionRepository ;
46+ private final DisposalRepository disposalRepository ;
47+ private final UserDistrictRepository userDistrictRepository ;
4648
4749 @ Override
4850 @ Transactional
@@ -53,7 +55,7 @@ public TrashResultResponse createTrash(CreateTrashRequest request, User user) {
5355 try {
5456 var file = request .imageFile ();
5557 String storedKey = FileUtils .generateStoredKey (
56- Objects .requireNonNull (file .getOriginalFilename ()), S3_TRASH_PREFIX );
58+ Objects .requireNonNull (file .getOriginalFilename ()), S3_TRASH_PREFIX );
5759 byte [] bytes = file .getBytes ();
5860 String contentType = file .getContentType ();
5961
@@ -62,12 +64,12 @@ public TrashResultResponse createTrash(CreateTrashRequest request, User user) {
6264
6365 // 2) 타입 결정
6466 Type analyzedType =
65- (step1 != null && step1 .type () != null && step1 .type ().getType () != null )
66- ? step1 .type ().getType () : Type .UNKNOWN ;
67+ (step1 != null && step1 .type () != null && step1 .type ().getType () != null )
68+ ? step1 .type ().getType () : Type .UNKNOWN ;
6769
68- // 3) 타입 엔티티 조회/없으면 생성 → 여기서 'type' 정의
70+ // 3) 타입 엔티티 조회/없으면 생성
6971 TrashType type = trashTypeRepository .findByType (analyzedType )
70- .orElseGet (() -> trashTypeRepository .save (TrashType .of (analyzedType )));
72+ .orElseGet (() -> trashTypeRepository .save (TrashType .of (analyzedType )));
7173
7274 // 4) 재활용군이면 세부 품목 분석
7375 String itemName = null ;
@@ -86,26 +88,35 @@ public TrashResultResponse createTrash(CreateTrashRequest request, User user) {
8688 if (itemName != null && !itemName .isBlank ()) {
8789 String key = itemName .trim ();
8890 var item = trashItemRepository .findByTrashTypeAndName (type , key )
89- .orElseGet (() -> trashItemRepository .save (TrashItem .builder ()
90- .trashType (type )
91- .name (key )
92- .build ()));
91+ .orElseGet (() -> trashItemRepository .save (TrashItem .builder ()
92+ .trashType (type )
93+ .name (key )
94+ .build ()));
9395 trash .applyItem (item );
9496 }
9597
9698 Trash saved = trashRepository .save (trash );
9799
98100 // 가이드/주의사항 조회
99101 var descOpt = trashDescriptionRepository .findByTrashType (type );
100- var steps = descOpt .map (TrashDescription ::steps ).orElse (java . util . List .of ());
102+ var steps = descOpt .map (TrashDescription ::steps ).orElse (List .of ());
101103 var caution = descOpt .map (TrashDescription ::getCautionNote ).orElse (null );
102104
105+ // 부품 카드
103106 var parts = suggestParts (type .getType ());
104107
108+ // 사용자 기본 자치구/배출요일
109+ var district = resolveUserDistrictSummary (user .getId ());
110+
105111 log .info ("쓰레기 생성 완료: id={}, userId={}, type={}, imageUrl={}" ,
106- saved .getId (), user .getId (), type .getType (), imageUrl );
112+ saved .getId (), user .getId (), type .getType (), imageUrl );
113+
114+ List <String > days = java .util .Collections .emptyList ();
115+ if (district != null ) {
116+ days = resolveDisposalDays (district .id (), TrashType .of (type .getType ()));
117+ }
107118
108- return TrashResultResponse .of (saved , steps , caution , parts );
119+ return TrashResultResponse .of (saved , steps , caution , days , parts , district );
109120
110121 } catch (BusinessException be ) {
111122 throw be ;
@@ -135,6 +146,39 @@ private List<PartCardResponse> suggestParts(Type baseType) {
135146 return List .of ();
136147 }
137148
149+ private List <String > parseDays (String json ) {
150+ if (json == null || json .isBlank ()) return List .of ();
151+ try {
152+ var node = new ObjectMapper ().readTree (json );
153+ if (!node .isArray ()) return List .of ();
154+ List <String > out = new java .util .ArrayList <>();
155+ node .forEach (n -> out .add (n .asText ()));
156+ return out ;
157+ } catch (Exception e ) {
158+ return List .of ();
159+ }
160+ }
161+
162+ private DistrictSummaryResponse resolveUserDistrictSummary (Long userId ) {
163+ var uds = userDistrictRepository .findByUserIdFetchJoin (userId );
164+ var udOpt = uds .stream ()
165+ .filter (ud -> Boolean .TRUE .equals (ud .getIsDefault ()))
166+ .findFirst ()
167+ .or (() -> uds .stream ().findFirst ());
168+ return udOpt .map (ud -> {
169+ var d = ud .getDistrict ();
170+ return new DistrictSummaryResponse (d .getId (), d .getSido (), d .getSigungu (), d .getEupmyeondong ());
171+ }).orElse (null );
172+ }
173+
174+ private List <String > resolveDisposalDays (String districtId , TrashType trashType ) {
175+ if (districtId == null || trashType == null ) return List .of ();
176+ return disposalRepository
177+ .findByDistrict_IdAndTrashType_Type (districtId , trashType .getType ())
178+ .map (d -> parseDays (d .getDays ()))
179+ .orElse (List .of ());
180+ }
181+
138182 /**
139183 * 특정 사용자의 모든 쓰레기를 최신순으로 조회
140184 */
@@ -156,14 +200,37 @@ public TrashResultResponse getTrash(Long trashId) {
156200 .orElseThrow (() -> new BusinessException (ErrorCode .NOT_EXISTS_TRASH_ITEM ));
157201
158202 var descOpt = trashDescriptionRepository .findByTrashType (trash .getTrashType ());
159- var steps = descOpt .map (TrashDescription ::steps ).orElse (java .util .List .of ());
160- var caution = descOpt .map (TrashDescription ::getCautionNote ).orElse (null );
203+ var steps = descOpt .map (TrashDescription ::steps )
204+ .orElse (java .util .List .of ());
205+ var caution = descOpt .map (TrashDescription ::getCautionNote )
206+ .orElse (null );
161207
162208 var parts = suggestParts (
163209 trash .getTrashType () != null ? trash .getTrashType ().getType () : Type .UNKNOWN
164210 );
165211
166- return TrashResultResponse .of (trash , steps , caution , parts );
212+ // 사용자 기본 자치구 요약
213+ var uds = userDistrictRepository .findByUserIdFetchJoin (trash .getUser ().getId ());
214+ var districtOpt = uds .stream ()
215+ .filter (ud -> Boolean .TRUE .equals (ud .getIsDefault ()))
216+ .findFirst ()
217+ .or (() -> uds .stream ().findFirst ());
218+
219+ DistrictSummaryResponse district = districtOpt .map (ud -> {
220+ var d = ud .getDistrict ();
221+ return new DistrictSummaryResponse (d .getId (), d .getSido (), d .getSigungu (), d .getEupmyeondong ());
222+ }).orElse (null );
223+
224+ // 자치구 + 타입(enum)으로 days 조회 (enum 기반)
225+ java .util .List <String > days = java .util .Collections .emptyList ();
226+ if (district != null && trash .getTrashType () != null ) {
227+ days = disposalRepository
228+ .findByDistrict_IdAndTrashType_Type (district .id (), trash .getTrashType ().getType ())
229+ .map (d -> parseDays (d .getDays ()))
230+ .orElse (java .util .List .of ());
231+ }
232+
233+ return TrashResultResponse .of (trash , steps , caution , days , parts , district );
167234 }
168235
169236 @ Transactional (readOnly = true )
@@ -201,14 +268,19 @@ public TrashResultResponse changeTrashItem(Long trashId, Long trashItemId, User
201268 trash .applyItem (item );
202269
203270 var descOpt = trashDescriptionRepository .findByTrashType (trash .getTrashType ());
204- var steps = descOpt .map (TrashDescription ::steps )
205- .orElse (java .util .List .of ());
206- var caution = descOpt .map (TrashDescription ::getCautionNote )
207- .orElse (null );
271+ var steps = descOpt .map (TrashDescription ::steps ).orElse (java .util .List .of ());
272+ var caution = descOpt .map (TrashDescription ::getCautionNote ).orElse (null );
208273
209274 var parts = suggestParts (trash .getTrashType ().getType ());
210275
211- return TrashResultResponse .of (trash , steps , caution , parts );
276+ // 사용자 기본 자치구 + 배출 요일(enum 기반)
277+ var district = resolveUserDistrictSummary (user .getId ());
278+ java .util .List <String > days = java .util .Collections .emptyList ();
279+ if (district != null && trash .getTrashType () != null ) {
280+ days = resolveDisposalDays (district .id (), TrashType .of (trash .getTrashType ().getType ()));
281+ }
282+
283+ return TrashResultResponse .of (trash , steps , caution , days , parts , district );
212284 }
213285
214286 @ Transactional
0 commit comments