Skip to content

Commit db49052

Browse files
authored
Merge pull request #60 from BrainPix/feat/#59/applystatus
[FEAT] 지원현황 API 구현(#59)
2 parents dea5223 + 7ad10ab commit db49052

24 files changed

+872
-1
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.brainpix.api.code.error;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
8+
@Getter
9+
@RequiredArgsConstructor
10+
public enum CollectionErrorCode implements ErrorCode {
11+
COLLECTION_NOT_FOUND(HttpStatus.NOT_FOUND, "COLLECTION404", "지원 내역이 존재하지 않습니다."),
12+
NOT_AUTHORIZED(HttpStatus.FORBIDDEN, "COLLECTION403", "본인이 지원한 항목이 아닙니다."),
13+
INVALID_STATUS(HttpStatus.BAD_REQUEST, "COLLECTION400", "거절 상태가 아닌 항목은 삭제할 수 없습니다.");
14+
15+
private final HttpStatus httpStatus;
16+
private final String code;
17+
private final String message;
18+
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.brainpix.api.code.error;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
8+
@Getter
9+
@RequiredArgsConstructor
10+
public enum PurchasingErrorCode implements ErrorCode {
11+
COLLECTION_NOT_FOUND(HttpStatus.NOT_FOUND, "PURCHASING404", "지원 내역이 존재하지 않습니다."),
12+
NOT_AUTHORIZED(HttpStatus.FORBIDDEN, "PURCHASING403", "본인이 지원한 항목이 아닙니다."),
13+
INVALID_STATUS(HttpStatus.BAD_REQUEST, "PURCHASING400", "거절 상태가 아닌 항목은 삭제할 수 없습니다.");
14+
15+
private final HttpStatus httpStatus;
16+
private final String code;
17+
private final String message;
18+
19+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.brainpix.joining.controller;
2+
3+
import org.springframework.data.domain.Page;
4+
import org.springframework.data.domain.Pageable;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.DeleteMapping;
7+
import org.springframework.web.bind.annotation.GetMapping;
8+
import org.springframework.web.bind.annotation.PathVariable;
9+
import org.springframework.web.bind.annotation.RequestMapping;
10+
import org.springframework.web.bind.annotation.RequestParam;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
import com.brainpix.api.ApiResponse;
14+
import com.brainpix.joining.dto.AcceptedCollaborationDto;
15+
import com.brainpix.joining.dto.RejectedCollaborationDto;
16+
import com.brainpix.joining.service.SupportCollaborationService;
17+
18+
import lombok.RequiredArgsConstructor;
19+
20+
@RestController
21+
@RequestMapping("/supports/collaborations")
22+
@RequiredArgsConstructor
23+
public class SupportCollaborationController {
24+
25+
private final SupportCollaborationService supportCollaborationService;
26+
27+
@GetMapping("/rejected")
28+
public ResponseEntity<ApiResponse<Page<RejectedCollaborationDto>>> getRejectedList(
29+
@RequestParam Long userId,
30+
Pageable pageable) {
31+
32+
Page<RejectedCollaborationDto> dtos = supportCollaborationService.getRejectedList(userId, pageable);
33+
return ResponseEntity.ok(ApiResponse.success(dtos));
34+
}
35+
36+
@GetMapping("/accepted")
37+
public ResponseEntity<ApiResponse<Page<AcceptedCollaborationDto>>> getAcceptedList(
38+
@RequestParam Long userId,
39+
Pageable pageable) {
40+
41+
Page<AcceptedCollaborationDto> dtos = supportCollaborationService.getAcceptedList(userId, pageable);
42+
return ResponseEntity.ok(ApiResponse.success(dtos));
43+
}
44+
45+
/**
46+
* [DELETE] 거절 항목 삭제
47+
*/
48+
@DeleteMapping("/{collectionGatheringId}")
49+
public ResponseEntity<ApiResponse<Void>> deleteRejected(
50+
@PathVariable Long collectionGatheringId,
51+
@RequestParam Long userId) {
52+
53+
supportCollaborationService.deleteRejected(userId, collectionGatheringId);
54+
return ResponseEntity.ok(ApiResponse.successWithNoData());
55+
}
56+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.brainpix.joining.controller;
2+
3+
import org.springframework.data.domain.Pageable;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.RequestMapping;
7+
import org.springframework.web.bind.annotation.RequestParam;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
import com.brainpix.api.ApiResponse;
11+
import com.brainpix.api.CommonPageResponse;
12+
import com.brainpix.joining.dto.IdeaMarketPurchaseDto;
13+
import com.brainpix.joining.service.SupportIdeaMarketService;
14+
15+
import lombok.RequiredArgsConstructor;
16+
17+
@RestController
18+
@RequestMapping("/supports/idea-market")
19+
@RequiredArgsConstructor
20+
public class SupportIdeaMarketController {
21+
22+
private final SupportIdeaMarketService supportIdeaMarketService;
23+
24+
@GetMapping("/purchases")
25+
public ResponseEntity<ApiResponse<CommonPageResponse<IdeaMarketPurchaseDto>>> getPurchases(
26+
@RequestParam Long userId,
27+
Pageable pageable
28+
) {
29+
CommonPageResponse<IdeaMarketPurchaseDto> response = supportIdeaMarketService.getMyPurchases(userId, pageable);
30+
return ResponseEntity.ok(ApiResponse.success(response));
31+
}
32+
33+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.brainpix.joining.controller;
2+
3+
import org.springframework.data.domain.Pageable;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.DeleteMapping;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PathVariable;
8+
import org.springframework.web.bind.annotation.RequestMapping;
9+
import org.springframework.web.bind.annotation.RequestParam;
10+
import org.springframework.web.bind.annotation.RestController;
11+
12+
import com.brainpix.api.ApiResponse;
13+
import com.brainpix.api.CommonPageResponse;
14+
import com.brainpix.joining.dto.AcceptedRequestTaskPurchasingDto;
15+
import com.brainpix.joining.dto.RejectedRequestTaskPurchasingDto;
16+
import com.brainpix.joining.service.SupportRequestTaskService;
17+
18+
import lombok.RequiredArgsConstructor;
19+
20+
@RestController
21+
@RequestMapping("/supports/request-tasks")
22+
@RequiredArgsConstructor
23+
public class SupportRequestTaskController {
24+
25+
private final SupportRequestTaskService supportRequestTaskService;
26+
27+
@GetMapping("/rejected")
28+
public ResponseEntity<ApiResponse<CommonPageResponse<RejectedRequestTaskPurchasingDto>>> getRejectedList(
29+
@RequestParam Long userId,
30+
Pageable pageable
31+
) {
32+
CommonPageResponse<RejectedRequestTaskPurchasingDto> response =
33+
supportRequestTaskService.getRejectedList(userId, pageable);
34+
return ResponseEntity.ok(ApiResponse.success(response));
35+
}
36+
37+
@GetMapping("/accepted")
38+
public ResponseEntity<ApiResponse<CommonPageResponse<AcceptedRequestTaskPurchasingDto>>> getAcceptedList(
39+
@RequestParam Long userId,
40+
Pageable pageable
41+
) {
42+
CommonPageResponse<AcceptedRequestTaskPurchasingDto> response =
43+
supportRequestTaskService.getAcceptedList(userId, pageable);
44+
return ResponseEntity.ok(ApiResponse.success(response));
45+
}
46+
47+
@DeleteMapping("/{purchasingId}")
48+
public ResponseEntity<ApiResponse<Void>> deleteRejectedPurchasing(
49+
@PathVariable Long purchasingId,
50+
@RequestParam Long userId) {
51+
supportRequestTaskService.deleteRejectedPurchasing(userId, purchasingId);
52+
return ResponseEntity
53+
.ok(ApiResponse.successWithNoData());
54+
}
55+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package com.brainpix.joining.converter;
2+
3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
6+
import org.springframework.stereotype.Component;
7+
8+
import com.brainpix.joining.dto.AcceptedCollaborationDto;
9+
import com.brainpix.joining.dto.RejectedCollaborationDto;
10+
import com.brainpix.joining.dto.TeamMemberInfoDto;
11+
import com.brainpix.joining.entity.purchasing.CollectionGathering;
12+
import com.brainpix.joining.entity.quantity.Gathering;
13+
import com.brainpix.post.entity.collaboration_hub.CollaborationHub;
14+
import com.brainpix.post.entity.collaboration_hub.CollaborationRecruitment;
15+
import com.brainpix.user.entity.Individual;
16+
import com.brainpix.user.entity.User;
17+
18+
@Component
19+
public class CollectionGatheringConverter {
20+
21+
/**
22+
* [A] 거절된 협업 목록 DTO
23+
*/
24+
public RejectedCollaborationDto toRejectedDto(CollectionGathering cg) {
25+
CollaborationRecruitment recruitment = cg.getCollaborationRecruitment();
26+
CollaborationHub hub = recruitment.getParentCollaborationHub();
27+
28+
return RejectedCollaborationDto.builder()
29+
.collectionGatheringId(cg.getId())
30+
.firstImage(hub.getFirstImage()) // Post#getFirstImage()
31+
.postCreatedAt(hub.getCreatedAt()) // BaseTimeEntity
32+
.postTitle(hub.getTitle())
33+
.postCategory("협업 광장 > " + hub.getSpecialization())
34+
.domain(recruitment.getDomain())
35+
.build();
36+
}
37+
38+
/**
39+
* [B] 수락된 협업 상세 DTO
40+
* - 본인이 지원한 CollectionGathering + 게시글 정보 + 팀원 정보
41+
*/
42+
public AcceptedCollaborationDto toAcceptedDto(CollectionGathering cg,
43+
List<TeamMemberInfoDto> teamInfoList) {
44+
CollaborationRecruitment recruitment = cg.getCollaborationRecruitment();
45+
CollaborationHub hub = recruitment.getParentCollaborationHub();
46+
47+
// 작성자 정보
48+
User writer = hub.getWriter();
49+
String writerName = writer.getName();
50+
String writerType = (writer instanceof Individual) ? "개인" : "회사";
51+
52+
return AcceptedCollaborationDto.builder()
53+
.collectionGatheringId(cg.getId())
54+
.firstImage(hub.getFirstImage())
55+
.postCreatedAt(hub.getCreatedAt())
56+
.postTitle(hub.getTitle())
57+
.postCategory("협업 광장 > " + hub.getSpecialization())
58+
.domain(recruitment.getDomain())
59+
.writerName(writerName)
60+
.writerType(writerType)
61+
.teamInfoList(teamInfoList)
62+
.build();
63+
}
64+
65+
/**
66+
* [C] 팀원 정보(TeamMemberInfoDto) 생성
67+
* - 게시글의 모든 CollaborationRecruitment 목록을 순회하며
68+
* - 각 도메인별 Gathering(totalQuantity)와 (accepted= true or initialGathering= true) 참가자들
69+
*/
70+
public List<TeamMemberInfoDto> createTeamInfoList(CollaborationHub hub) {
71+
List<CollaborationRecruitment> recruitments = hub.getCollaborations();
72+
73+
return recruitments.stream()
74+
.map(this::toTeamMemberInfoDto)
75+
.collect(Collectors.toList());
76+
}
77+
78+
private TeamMemberInfoDto toTeamMemberInfoDto(CollaborationRecruitment recruitment) {
79+
80+
Gathering gathering = recruitment.getGathering();
81+
Long total = (gathering != null) ? gathering.getTotalQuantity() : 0L;
82+
Long occupied = (gathering != null) ? gathering.getOccupiedQuantity() : 0L;
83+
84+
List<CollectionGathering> joined =
85+
findAcceptedOrInitial(recruitment.getCollectionGatherings());
86+
87+
List<String> joinerIds = joined.stream()
88+
.map(cg -> cg.getJoiner().getName())
89+
.collect(Collectors.toList());
90+
91+
return TeamMemberInfoDto.builder()
92+
.domain(recruitment.getDomain())
93+
.occupied(occupied)
94+
.total(total)
95+
.joinerIds(joinerIds)
96+
.build();
97+
}
98+
99+
private List<CollectionGathering> findAcceptedOrInitial(List<CollectionGathering> cgs) {
100+
return cgs.stream()
101+
.filter(cg -> Boolean.TRUE.equals(cg.getAccepted())
102+
|| Boolean.TRUE.equals(cg.getInitialGathering()))
103+
.collect(Collectors.toList());
104+
}
105+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.brainpix.joining.converter;
2+
3+
import java.time.LocalDateTime;
4+
5+
import org.springframework.stereotype.Component;
6+
7+
import com.brainpix.joining.dto.IdeaMarketPurchaseDto;
8+
import com.brainpix.joining.entity.purchasing.IdeaMarketPurchasing;
9+
import com.brainpix.joining.entity.quantity.Price;
10+
import com.brainpix.post.entity.idea_market.IdeaMarket;
11+
import com.brainpix.post.entity.idea_market.IdeaMarketType;
12+
import com.brainpix.user.entity.Individual;
13+
import com.brainpix.user.entity.User;
14+
15+
@Component
16+
public class IdeaMarketPurchasingConverter {
17+
18+
public IdeaMarketPurchaseDto toPurchaseDto(IdeaMarketPurchasing purchasing) {
19+
Long purchasingId = purchasing.getId();
20+
LocalDateTime purchasedAt = purchasing.getCreatedAt();
21+
22+
// 게시글
23+
IdeaMarket ideaMarket = purchasing.getIdeaMarket();
24+
String category = "아이디어마켓 > " + ideaMarket.getSpecialization();
25+
String title = ideaMarket.getTitle();
26+
27+
// 작성자
28+
User writer = ideaMarket.getWriter();
29+
String writerName = writer.getName();
30+
String writerType = (writer instanceof Individual) ? "개인" : "회사";
31+
32+
// 아이디어마켓 타입
33+
IdeaMarketType type = ideaMarket.getIdeaMarketType();
34+
35+
// 수량 결정 (IDEA_SOLUTION → 1, MARKET_PLACE → price.totalQuantity)
36+
Price priceEntity = ideaMarket.getPrice();
37+
Long quantity = (type == IdeaMarketType.IDEA_SOLUTION)
38+
? 1L
39+
: priceEntity.getTotalQuantity();
40+
41+
// 금액 계산
42+
long basePrice = priceEntity.getPrice() * quantity;
43+
long fee = (long)(basePrice * 0.01); // 1% 예시
44+
long finalPrice = basePrice + fee;
45+
46+
return IdeaMarketPurchaseDto.builder()
47+
.purchasingId(purchasingId)
48+
.purchasedAt(purchasedAt)
49+
.category(category)
50+
.title(title)
51+
.writerName(writerName)
52+
.writerType(writerType)
53+
.quantity(quantity)
54+
.fee(fee)
55+
.finalPrice(finalPrice)
56+
.build();
57+
}
58+
}
59+

0 commit comments

Comments
 (0)