diff --git a/src/main/java/io/oduck/api/domain/admin/entity/Admin.java b/src/main/java/io/oduck/api/domain/admin/entity/Admin.java new file mode 100644 index 00000000..23ff17c6 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/admin/entity/Admin.java @@ -0,0 +1,64 @@ +package io.oduck.api.domain.admin.entity; + +import io.oduck.api.domain.contact.entity.Answer; +import io.oduck.api.domain.contact.entity.FeedbackType; +import io.oduck.api.domain.contact.service.AnswerHolder; +import io.oduck.api.domain.contact.service.AnswerUpdateHolder; +import io.oduck.api.global.exception.BadRequestException; +import io.oduck.api.global.exception.NotFoundException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.util.ArrayList; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "member") +@Entity +public class Admin { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToMany(mappedBy = "admin", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + private List answers = new ArrayList<>(); + + public void answer(AnswerHolder holder) { + Answer answer = Answer.builder() + .content(holder.getContent()) + .helpful(FeedbackType.NONE) + .check(false) + .contact(holder.getContact()) + .admin(this) + .build(); + answers.add(answer); + + answer.answer(); + } + + public void updateAnswer(AnswerUpdateHolder holder) { + Answer answer = answers.stream() + .filter(a -> a.getId() == holder.getAnswerId()) + .findFirst() + .orElseThrow(() -> new NotFoundException("answer")); + + if(answer.isCheck() == true) { + throw new BadRequestException("이미 고객이 확인한 문의입니다."); + } + + answer.update(holder.getContent()); + } +} diff --git a/src/main/java/io/oduck/api/domain/admin/repository/AdminRepository.java b/src/main/java/io/oduck/api/domain/admin/repository/AdminRepository.java new file mode 100644 index 00000000..65c2eb68 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/admin/repository/AdminRepository.java @@ -0,0 +1,13 @@ +package io.oduck.api.domain.admin.repository; + +import io.oduck.api.domain.admin.entity.Admin; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface AdminRepository extends JpaRepository { + + @Query("select distinct a from Admin a join fetch a.answers where a.id = :id") + Optional findWithAnswerById(@Param("id") Long id); +} diff --git a/src/main/java/io/oduck/api/domain/inquiry/dto/AnswerFeedback.java b/src/main/java/io/oduck/api/domain/contact/dto/AnswerFeedback.java similarity index 79% rename from src/main/java/io/oduck/api/domain/inquiry/dto/AnswerFeedback.java rename to src/main/java/io/oduck/api/domain/contact/dto/AnswerFeedback.java index 30231aab..d18cab0a 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/dto/AnswerFeedback.java +++ b/src/main/java/io/oduck/api/domain/contact/dto/AnswerFeedback.java @@ -1,6 +1,6 @@ -package io.oduck.api.domain.inquiry.dto; +package io.oduck.api.domain.contact.dto; -import io.oduck.api.domain.inquiry.entity.FeedbackType; +import io.oduck.api.domain.contact.entity.FeedbackType; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactId.java b/src/main/java/io/oduck/api/domain/contact/dto/ContactId.java similarity index 87% rename from src/main/java/io/oduck/api/domain/inquiry/dto/ContactId.java rename to src/main/java/io/oduck/api/domain/contact/dto/ContactId.java index 8e2e3aa0..74adf4cb 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactId.java +++ b/src/main/java/io/oduck/api/domain/contact/dto/ContactId.java @@ -1,4 +1,4 @@ -package io.oduck.api.domain.inquiry.dto; +package io.oduck.api.domain.contact.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactReq.java b/src/main/java/io/oduck/api/domain/contact/dto/ContactReq.java similarity index 73% rename from src/main/java/io/oduck/api/domain/inquiry/dto/ContactReq.java rename to src/main/java/io/oduck/api/domain/contact/dto/ContactReq.java index 60715314..9467dbf0 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactReq.java +++ b/src/main/java/io/oduck/api/domain/contact/dto/ContactReq.java @@ -1,6 +1,6 @@ -package io.oduck.api.domain.inquiry.dto; +package io.oduck.api.domain.contact.dto; -import io.oduck.api.domain.inquiry.entity.InquiryType; +import io.oduck.api.domain.contact.entity.InquiryType; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Getter; @@ -29,8 +29,16 @@ public static class PostReq { @Getter @AllArgsConstructor public static class AnswerReq { - private Long id; + @NotBlank + @Length(min = 1, max = 1000, + message = "글자 수는 1~1000를 허용합니다.") + private String content; + } + + @Getter + @AllArgsConstructor + public static class AnswerUpdateReq { @NotBlank @Length(min = 1, max = 1000, message = "글자 수는 1~1000를 허용합니다.") diff --git a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactRequestHolder.java b/src/main/java/io/oduck/api/domain/contact/dto/ContactRequestHolder.java similarity index 77% rename from src/main/java/io/oduck/api/domain/inquiry/dto/ContactRequestHolder.java rename to src/main/java/io/oduck/api/domain/contact/dto/ContactRequestHolder.java index f86a913b..628f6c83 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactRequestHolder.java +++ b/src/main/java/io/oduck/api/domain/contact/dto/ContactRequestHolder.java @@ -1,7 +1,7 @@ -package io.oduck.api.domain.inquiry.dto; +package io.oduck.api.domain.contact.dto; -import io.oduck.api.domain.inquiry.dto.ContactReq.PostReq; -import io.oduck.api.domain.inquiry.entity.Contact; +import io.oduck.api.domain.contact.dto.ContactReq.PostReq; +import io.oduck.api.domain.contact.entity.Contact; import io.oduck.api.domain.member.entity.Member; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -18,7 +18,7 @@ public static ContactRequestHolder from(PostReq request, Member member) { .content(request.getContent()) .type(request.getType()) .answered(false) - .member(member) + .customer(member) .build(); return new ContactRequestHolder(contact); } diff --git a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactRes.java b/src/main/java/io/oduck/api/domain/contact/dto/ContactRes.java similarity index 91% rename from src/main/java/io/oduck/api/domain/inquiry/dto/ContactRes.java rename to src/main/java/io/oduck/api/domain/contact/dto/ContactRes.java index 1b0f6563..375f8ddd 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/dto/ContactRes.java +++ b/src/main/java/io/oduck/api/domain/contact/dto/ContactRes.java @@ -1,6 +1,6 @@ -package io.oduck.api.domain.inquiry.dto; +package io.oduck.api.domain.contact.dto; -import io.oduck.api.domain.inquiry.entity.Contact; +import io.oduck.api.domain.contact.entity.Contact; import java.time.LocalDate; import java.time.LocalDateTime; import lombok.AllArgsConstructor; diff --git a/src/main/java/io/oduck/api/domain/inquiry/entity/Answer.java b/src/main/java/io/oduck/api/domain/contact/entity/Answer.java similarity index 63% rename from src/main/java/io/oduck/api/domain/inquiry/entity/Answer.java rename to src/main/java/io/oduck/api/domain/contact/entity/Answer.java index 00105543..ea422815 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/entity/Answer.java +++ b/src/main/java/io/oduck/api/domain/contact/entity/Answer.java @@ -1,10 +1,15 @@ -package io.oduck.api.domain.inquiry.entity; +package io.oduck.api.domain.contact.entity; +import io.oduck.api.domain.admin.entity.Admin; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.AllArgsConstructor; @@ -31,9 +36,13 @@ public class Answer { @Column(name = "check_answer") private boolean check = false; - @OneToOne(mappedBy = "answer") + @OneToOne(mappedBy = "answer", cascade = CascadeType.PERSIST) private Contact contact; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Admin admin; + public void check() { check = true; } @@ -41,4 +50,12 @@ public void check() { public void feedback(FeedbackType helpful) { this.helpful = helpful; } + + public void update(String content) { + this.content = content; + } + + public void answer() { + contact.answer(); + } } diff --git a/src/main/java/io/oduck/api/domain/inquiry/entity/Contact.java b/src/main/java/io/oduck/api/domain/contact/entity/Contact.java similarity index 92% rename from src/main/java/io/oduck/api/domain/inquiry/entity/Contact.java rename to src/main/java/io/oduck/api/domain/contact/entity/Contact.java index 90201391..4c232745 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/entity/Contact.java +++ b/src/main/java/io/oduck/api/domain/contact/entity/Contact.java @@ -1,4 +1,4 @@ -package io.oduck.api.domain.inquiry.entity; +package io.oduck.api.domain.contact.entity; import io.oduck.api.domain.member.entity.Member; import io.oduck.api.global.audit.BaseEntity; @@ -31,7 +31,7 @@ public class Contact extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") - private Member member; + private Member customer; @Column(nullable = false, length = 100) private String title; @@ -51,4 +51,8 @@ public class Contact extends BaseEntity { public void feedback(FeedbackType helpful) { answer.feedback(helpful); } + + public void answer() { + answered = true; + } } diff --git a/src/main/java/io/oduck/api/domain/inquiry/entity/FeedbackType.java b/src/main/java/io/oduck/api/domain/contact/entity/FeedbackType.java similarity index 50% rename from src/main/java/io/oduck/api/domain/inquiry/entity/FeedbackType.java rename to src/main/java/io/oduck/api/domain/contact/entity/FeedbackType.java index ea65828c..31185832 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/entity/FeedbackType.java +++ b/src/main/java/io/oduck/api/domain/contact/entity/FeedbackType.java @@ -1,7 +1,7 @@ -package io.oduck.api.domain.inquiry.entity; +package io.oduck.api.domain.contact.entity; public enum FeedbackType { HELPFUL, NOT_HELPFUL, - NOT_SELECT + NONE } diff --git a/src/main/java/io/oduck/api/domain/inquiry/entity/InquiryType.java b/src/main/java/io/oduck/api/domain/contact/entity/InquiryType.java similarity index 63% rename from src/main/java/io/oduck/api/domain/inquiry/entity/InquiryType.java rename to src/main/java/io/oduck/api/domain/contact/entity/InquiryType.java index 827b6d78..81e1035c 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/entity/InquiryType.java +++ b/src/main/java/io/oduck/api/domain/contact/entity/InquiryType.java @@ -1,4 +1,4 @@ -package io.oduck.api.domain.inquiry.entity; +package io.oduck.api.domain.contact.entity; public enum InquiryType { ADD_REQUEST, diff --git a/src/main/java/io/oduck/api/domain/inquiry/entity/Result.java b/src/main/java/io/oduck/api/domain/contact/entity/Result.java similarity index 55% rename from src/main/java/io/oduck/api/domain/inquiry/entity/Result.java rename to src/main/java/io/oduck/api/domain/contact/entity/Result.java index 534856ce..79519318 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/entity/Result.java +++ b/src/main/java/io/oduck/api/domain/contact/entity/Result.java @@ -1,4 +1,4 @@ -package io.oduck.api.domain.inquiry.entity; +package io.oduck.api.domain.contact.entity; public enum Result { DELETE, diff --git a/src/main/java/io/oduck/api/domain/inquiry/entity/Status.java b/src/main/java/io/oduck/api/domain/contact/entity/Status.java similarity index 61% rename from src/main/java/io/oduck/api/domain/inquiry/entity/Status.java rename to src/main/java/io/oduck/api/domain/contact/entity/Status.java index 94a7424c..4c1091af 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/entity/Status.java +++ b/src/main/java/io/oduck/api/domain/contact/entity/Status.java @@ -1,4 +1,4 @@ -package io.oduck.api.domain.inquiry.entity; +package io.oduck.api.domain.contact.entity; public enum Status { WAITING, diff --git a/src/main/java/io/oduck/api/domain/contact/repository/AnswerRepository.java b/src/main/java/io/oduck/api/domain/contact/repository/AnswerRepository.java new file mode 100644 index 00000000..23515744 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/contact/repository/AnswerRepository.java @@ -0,0 +1,8 @@ +package io.oduck.api.domain.contact.repository; + +import io.oduck.api.domain.contact.entity.Answer; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AnswerRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepository.java b/src/main/java/io/oduck/api/domain/contact/repository/ContactRepository.java similarity index 67% rename from src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepository.java rename to src/main/java/io/oduck/api/domain/contact/repository/ContactRepository.java index 90f82e44..a33bed29 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepository.java +++ b/src/main/java/io/oduck/api/domain/contact/repository/ContactRepository.java @@ -1,6 +1,6 @@ -package io.oduck.api.domain.inquiry.repository; +package io.oduck.api.domain.contact.repository; -import io.oduck.api.domain.inquiry.entity.Contact; +import io.oduck.api.domain.contact.entity.Contact; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -8,6 +8,6 @@ public interface ContactRepository extends JpaRepository, ContactRepositoryCustom { - @Query("select c from Contact c join fetch c.member where c.id = :id") + @Query("select c from Contact c join fetch c.customer where c.id = :id") Optional findWithMemberById(@Param("id") Long id); } diff --git a/src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepositoryCustom.java b/src/main/java/io/oduck/api/domain/contact/repository/ContactRepositoryCustom.java similarity index 71% rename from src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepositoryCustom.java rename to src/main/java/io/oduck/api/domain/contact/repository/ContactRepositoryCustom.java index 0ce6b07b..4cf01ff2 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepositoryCustom.java +++ b/src/main/java/io/oduck/api/domain/contact/repository/ContactRepositoryCustom.java @@ -1,6 +1,6 @@ -package io.oduck.api.domain.inquiry.repository; +package io.oduck.api.domain.contact.repository; -import io.oduck.api.domain.inquiry.dto.ContactRes.MyInquiry; +import io.oduck.api.domain.contact.dto.ContactRes.MyInquiry; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; diff --git a/src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/contact/repository/ContactRepositoryCustomImpl.java similarity index 86% rename from src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepositoryCustomImpl.java rename to src/main/java/io/oduck/api/domain/contact/repository/ContactRepositoryCustomImpl.java index 7e3f4fa7..e90990b9 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/repository/ContactRepositoryCustomImpl.java +++ b/src/main/java/io/oduck/api/domain/contact/repository/ContactRepositoryCustomImpl.java @@ -1,13 +1,13 @@ -package io.oduck.api.domain.inquiry.repository; +package io.oduck.api.domain.contact.repository; -import static io.oduck.api.domain.inquiry.entity.QAnswer.answer; -import static io.oduck.api.domain.inquiry.entity.QContact.contact; +import static io.oduck.api.domain.contact.entity.QAnswer.answer; +import static io.oduck.api.domain.contact.entity.QContact.contact; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; -import io.oduck.api.domain.inquiry.dto.ContactRes.MyInquiry; +import io.oduck.api.domain.contact.dto.ContactRes.MyInquiry; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -65,6 +65,6 @@ private BooleanExpression idEq(Long id) { } private BooleanExpression memberIdEq(Long memberId) { - return memberId == null ? null : contact.member.id.eq(memberId); + return memberId == null ? null : contact.customer.id.eq(memberId); } } diff --git a/src/main/java/io/oduck/api/domain/contact/service/AnswerHolder.java b/src/main/java/io/oduck/api/domain/contact/service/AnswerHolder.java new file mode 100644 index 00000000..3b2094f9 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/contact/service/AnswerHolder.java @@ -0,0 +1,17 @@ +package io.oduck.api.domain.contact.service; + +import io.oduck.api.domain.contact.dto.ContactReq.AnswerReq; +import io.oduck.api.domain.contact.entity.Contact; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class AnswerHolder { + private Contact contact; + private String content; + + public static AnswerHolder from(Contact contact, AnswerReq request) { + return new AnswerHolder(contact, request.getContent()); + } +} diff --git a/src/main/java/io/oduck/api/domain/contact/service/AnswerUpdateHolder.java b/src/main/java/io/oduck/api/domain/contact/service/AnswerUpdateHolder.java new file mode 100644 index 00000000..d2b84703 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/contact/service/AnswerUpdateHolder.java @@ -0,0 +1,17 @@ +package io.oduck.api.domain.contact.service; + +import io.oduck.api.domain.contact.dto.ContactReq.AnswerUpdateReq; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class AnswerUpdateHolder { + private Long answerId; + private String content; + + public static AnswerUpdateHolder from(Long answerId, AnswerUpdateReq request) { + return new AnswerUpdateHolder(answerId, request.getContent()); + } +} diff --git a/src/main/java/io/oduck/api/domain/inquiry/service/ContactPolicy.java b/src/main/java/io/oduck/api/domain/contact/service/ContactPolicy.java similarity index 69% rename from src/main/java/io/oduck/api/domain/inquiry/service/ContactPolicy.java rename to src/main/java/io/oduck/api/domain/contact/service/ContactPolicy.java index e88ae59f..a0ad1d48 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/service/ContactPolicy.java +++ b/src/main/java/io/oduck/api/domain/contact/service/ContactPolicy.java @@ -1,6 +1,6 @@ -package io.oduck.api.domain.inquiry.service; +package io.oduck.api.domain.contact.service; -import io.oduck.api.domain.inquiry.entity.Contact; +import io.oduck.api.domain.contact.entity.Contact; import io.oduck.api.domain.member.entity.Member; import io.oduck.api.global.exception.ForbiddenException; import org.springframework.stereotype.Component; @@ -12,10 +12,10 @@ public void isAccessOwnInquiry(Contact contact, Member member) { if(!isOwnInquiry(contact, member)) { throw new ForbiddenException("not has permission"); } - contact.getMember().getId(); + contact.getCustomer().getId(); } private boolean isOwnInquiry(Contact contact, Member member) { - return contact.getMember().getId().equals(member.getId()); + return contact.getCustomer().getId().equals(member.getId()); } } \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/contact/service/ContactService.java b/src/main/java/io/oduck/api/domain/contact/service/ContactService.java new file mode 100644 index 00000000..0868c855 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/contact/service/ContactService.java @@ -0,0 +1,27 @@ +package io.oduck.api.domain.contact.service; + +import io.oduck.api.domain.contact.dto.ContactReq.AnswerReq; +import io.oduck.api.domain.contact.dto.ContactReq.AnswerUpdateReq; +import io.oduck.api.domain.contact.dto.ContactReq.PostReq; +import io.oduck.api.domain.contact.dto.ContactRes.DetailRes; +import io.oduck.api.domain.contact.dto.ContactRes.MyInquiry; +import io.oduck.api.domain.contact.entity.FeedbackType; +import io.oduck.api.global.common.PageResponse; + +public interface ContactService { + void inquiry(Long memberId, PostReq request); + + PageResponse getAllByMemberId(Long memberId, int page, int size); + + DetailRes getByMemberId(Long inquiryId, Long memberId); + + boolean hasNotCheckedAnswer(Long id, Long memberId); + + void feedbackAnswer(Long id, Long memberId, FeedbackType helpful); + +// Page getAll(); +// + void answer(Long id, Long adminId, AnswerReq request); + + void update(Long answerId, Long adminId, AnswerUpdateReq request); +} diff --git a/src/main/java/io/oduck/api/domain/inquiry/service/ContactServiceImpl.java b/src/main/java/io/oduck/api/domain/contact/service/ContactServiceImpl.java similarity index 64% rename from src/main/java/io/oduck/api/domain/inquiry/service/ContactServiceImpl.java rename to src/main/java/io/oduck/api/domain/contact/service/ContactServiceImpl.java index 60faff82..c570c83e 100644 --- a/src/main/java/io/oduck/api/domain/inquiry/service/ContactServiceImpl.java +++ b/src/main/java/io/oduck/api/domain/contact/service/ContactServiceImpl.java @@ -1,15 +1,19 @@ -package io.oduck.api.domain.inquiry.service; - -import static io.oduck.api.domain.inquiry.dto.ContactReq.PostReq; -import static io.oduck.api.domain.inquiry.dto.ContactRes.MyInquiry; - -import io.oduck.api.domain.inquiry.dto.AnswerFeedback; -import io.oduck.api.domain.inquiry.dto.ContactId; -import io.oduck.api.domain.inquiry.dto.ContactRequestHolder; -import io.oduck.api.domain.inquiry.dto.ContactRes.DetailRes; -import io.oduck.api.domain.inquiry.entity.Contact; -import io.oduck.api.domain.inquiry.entity.FeedbackType; -import io.oduck.api.domain.inquiry.repository.ContactRepository; +package io.oduck.api.domain.contact.service; + +import static io.oduck.api.domain.contact.dto.ContactReq.PostReq; +import static io.oduck.api.domain.contact.dto.ContactRes.MyInquiry; + +import io.oduck.api.domain.admin.entity.Admin; +import io.oduck.api.domain.admin.repository.AdminRepository; +import io.oduck.api.domain.contact.dto.AnswerFeedback; +import io.oduck.api.domain.contact.dto.ContactId; +import io.oduck.api.domain.contact.dto.ContactReq.AnswerReq; +import io.oduck.api.domain.contact.dto.ContactReq.AnswerUpdateReq; +import io.oduck.api.domain.contact.dto.ContactRequestHolder; +import io.oduck.api.domain.contact.dto.ContactRes.DetailRes; +import io.oduck.api.domain.contact.entity.Contact; +import io.oduck.api.domain.contact.entity.FeedbackType; +import io.oduck.api.domain.contact.repository.ContactRepository; import io.oduck.api.domain.member.entity.Member; import io.oduck.api.domain.member.repository.MemberRepository; import io.oduck.api.global.common.PageResponse; @@ -29,6 +33,7 @@ public class ContactServiceImpl implements ContactService { private final ContactRepository contactRepository; private final ContactPolicy contactPolicy; + private final AdminRepository adminRepository; @Override @Transactional @@ -93,14 +98,24 @@ public void feedbackAnswer(Long id, Long memberId, FeedbackType helpful) { // return null; // } -// @Override -// @Transactional -// public void answer(Long adminId, AnswerReq request) { -// } + @Override + @Transactional + public void answer(Long id, Long adminId, AnswerReq request) { + Contact contact = contactRepository.findWithMemberById(id) + .orElseThrow(() -> new NotFoundException("inquiry")); -// @Override -// @Transactional -// public void update(Long id) { -// -// } + Admin admin = adminRepository.findWithAnswerById(adminId) + .orElseThrow(() -> new NotFoundException("admin")); + + admin.answer(AnswerHolder.from(contact, request)); + } + + @Override + @Transactional + public void update(Long answerId, Long adminId, AnswerUpdateReq request) { + Admin admin = adminRepository.findWithAnswerById(adminId) + .orElseThrow(() -> new NotFoundException("admin")); + + admin.updateAnswer(AnswerUpdateHolder.from(answerId, request)); + } } diff --git a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java index 0cfed9cd..73a09ea6 100644 --- a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java +++ b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java @@ -22,10 +22,12 @@ public class GenreRepositoryCustomImpl implements GenreRepositoryCustom{ public List findAllByAnimeId(Long animeId) { JPAQuery genreJPAQuery = queryFactory.select(genre) .from(genre) - .join(animeGenre).on(animeGenre.anime.id.eq(animeId)) + .join(animeGenre).on(genre.id.eq(animeGenre.genre.id)) .where( + animeGenre.anime.id.eq(animeId), genre.deletedAt.isNull() - ); + ) + .limit(3); return genreJPAQuery.fetch(); } diff --git a/src/main/java/io/oduck/api/domain/inquiry/service/AnswerHolder.java b/src/main/java/io/oduck/api/domain/inquiry/service/AnswerHolder.java deleted file mode 100644 index e8e5ebb3..00000000 --- a/src/main/java/io/oduck/api/domain/inquiry/service/AnswerHolder.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.oduck.api.domain.inquiry.service; - -import io.oduck.api.domain.inquiry.dto.ContactReq.AnswerReq; -import io.oduck.api.domain.inquiry.entity.Contact; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public class AnswerHolder { - private Contact contact; - private AnswerReq request; - public static AnswerHolder from(Contact contact, AnswerReq request) { - return new AnswerHolder(contact, request); - } -} diff --git a/src/main/java/io/oduck/api/domain/inquiry/service/ContactService.java b/src/main/java/io/oduck/api/domain/inquiry/service/ContactService.java deleted file mode 100644 index 5556846e..00000000 --- a/src/main/java/io/oduck/api/domain/inquiry/service/ContactService.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.oduck.api.domain.inquiry.service; - -import io.oduck.api.domain.inquiry.dto.ContactReq.PostReq; -import io.oduck.api.domain.inquiry.dto.ContactRes.DetailRes; -import io.oduck.api.domain.inquiry.dto.ContactRes.MyInquiry; -import io.oduck.api.domain.inquiry.entity.FeedbackType; -import io.oduck.api.global.common.PageResponse; - -public interface ContactService { - void inquiry(Long memberId, PostReq request); - - PageResponse getAllByMemberId(Long memberId, int page, int size); - - DetailRes getByMemberId(Long inquiryId, Long memberId); - - boolean hasNotCheckedAnswer(Long id, Long memberId); - - void feedbackAnswer(Long id, Long memberId, FeedbackType helpful); - -// Page getAll(); -// -// void answer(Long adminId, AnswerReq request); -// -// void update(Long id); -} diff --git a/src/main/java/io/oduck/api/domain/member/entity/Member.java b/src/main/java/io/oduck/api/domain/member/entity/Member.java index 988716b7..5f78db2e 100644 --- a/src/main/java/io/oduck/api/domain/member/entity/Member.java +++ b/src/main/java/io/oduck/api/domain/member/entity/Member.java @@ -2,10 +2,10 @@ import io.oduck.api.domain.attractionPoint.entity.AttractionPoint; import io.oduck.api.domain.bookmark.entity.Bookmark; -import io.oduck.api.domain.inquiry.dto.AnswerFeedback; -import io.oduck.api.domain.inquiry.dto.ContactId; -import io.oduck.api.domain.inquiry.dto.ContactRequestHolder; -import io.oduck.api.domain.inquiry.entity.Contact; +import io.oduck.api.domain.contact.dto.AnswerFeedback; +import io.oduck.api.domain.contact.dto.ContactId; +import io.oduck.api.domain.contact.dto.ContactRequestHolder; +import io.oduck.api.domain.contact.entity.Contact; import io.oduck.api.domain.review.entity.ShortReview; import io.oduck.api.domain.reviewLike.entity.ShortReviewLike; import io.oduck.api.domain.starRating.entity.StarRating; @@ -71,7 +71,7 @@ public class Member extends BaseEntity { @OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST) private List attractionPoints; - @OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST) + @OneToMany(mappedBy = "customer", cascade = CascadeType.PERSIST) private List contacts = new ArrayList<>(); @Builder diff --git a/src/test/java/io/oduck/api/unit/contact/domain/AnswerTest.java b/src/test/java/io/oduck/api/unit/contact/domain/AnswerTest.java new file mode 100644 index 00000000..d6fa24a0 --- /dev/null +++ b/src/test/java/io/oduck/api/unit/contact/domain/AnswerTest.java @@ -0,0 +1,84 @@ +package io.oduck.api.unit.contact.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.oduck.api.domain.admin.entity.Admin; +import io.oduck.api.domain.contact.dto.ContactReq.AnswerReq; +import io.oduck.api.domain.contact.dto.ContactReq.AnswerUpdateReq; +import io.oduck.api.domain.contact.entity.Answer; +import io.oduck.api.domain.contact.entity.Contact; +import io.oduck.api.domain.contact.service.AnswerHolder; +import io.oduck.api.domain.contact.service.AnswerUpdateHolder; +import io.oduck.api.global.exception.BadRequestException; +import java.util.ArrayList; +import org.junit.jupiter.api.Test; + +public class AnswerTest { + + @Test + void 관리자는_문의할_수_있다() { + // given + Contact contact = Contact.builder() + .answered(false) + .build(); + + Admin admin = Admin.builder() + .answers(new ArrayList<>()) + .build(); + + AnswerReq request = new AnswerReq("문의"); + + // when + admin.answer(AnswerHolder.from(contact, request)); + + // then + assertThat(admin.getAnswers().get(0).getContact().isAnswered()).isTrue(); + assertThat(admin.getAnswers().get(0).getContent()).isEqualTo("문의"); + } + + @Test + void 관리자는_답변을_수정할_수있다() { + // given + Contact contact = Contact.builder() + .answered(false) + .build(); + + Admin admin = Admin.builder() + .answers(new ArrayList<>()) + .build(); + + AnswerReq request = new AnswerReq("문의"); + admin.answer(AnswerHolder.from(contact, request)); + + // when + admin.updateAnswer(AnswerUpdateHolder.from(null, new AnswerUpdateReq("문의 수정"))); + + // then + assertThat(admin.getAnswers().get(0).getContent()).isEqualTo("문의 수정"); + } + + @Test + void 관리자는_확인한_답변을_수정할_수_없다() { + // given + Contact contact = Contact.builder() + .answered(false) + .build(); + + Admin admin = Admin.builder() + .answers(new ArrayList<>()) + .build(); + + AnswerReq request = new AnswerReq("문의"); + admin.answer(AnswerHolder.from(contact, request)); + + Answer answer = admin.getAnswers().get(0); + answer.check(); + + // when + // then + assertThatThrownBy(() -> admin.updateAnswer(AnswerUpdateHolder.from(null, new AnswerUpdateReq("문의 수정")))) + .isInstanceOf(BadRequestException.class) + .hasMessageContaining("이미 고객이 확인한 문의입니다."); + } +} diff --git a/src/test/java/io/oduck/api/unit/inquiry/domain/ContactPolicyTest.java b/src/test/java/io/oduck/api/unit/contact/domain/ContactPolicyTest.java similarity index 76% rename from src/test/java/io/oduck/api/unit/inquiry/domain/ContactPolicyTest.java rename to src/test/java/io/oduck/api/unit/contact/domain/ContactPolicyTest.java index 1e8e6245..535948f5 100644 --- a/src/test/java/io/oduck/api/unit/inquiry/domain/ContactPolicyTest.java +++ b/src/test/java/io/oduck/api/unit/contact/domain/ContactPolicyTest.java @@ -1,9 +1,9 @@ -package io.oduck.api.unit.inquiry.domain; +package io.oduck.api.unit.contact.domain; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import io.oduck.api.domain.inquiry.entity.Contact; -import io.oduck.api.domain.inquiry.service.ContactPolicy; +import io.oduck.api.domain.contact.entity.Contact; +import io.oduck.api.domain.contact.service.ContactPolicy; import io.oduck.api.domain.member.entity.Member; import io.oduck.api.global.exception.ForbiddenException; import org.junit.jupiter.api.Test; @@ -17,7 +17,7 @@ public class ContactPolicyTest { //given Member writer = Member.builder().id(1L).build(); - Contact contact = Contact.builder().member(writer).build(); + Contact contact = Contact.builder().customer(writer).build(); Member target = Member.builder().id(2L).build(); diff --git a/src/test/java/io/oduck/api/unit/inquiry/domain/ContactTest.java b/src/test/java/io/oduck/api/unit/contact/domain/ContactTest.java similarity index 80% rename from src/test/java/io/oduck/api/unit/inquiry/domain/ContactTest.java rename to src/test/java/io/oduck/api/unit/contact/domain/ContactTest.java index 0c7477ed..1ecd25d7 100644 --- a/src/test/java/io/oduck/api/unit/inquiry/domain/ContactTest.java +++ b/src/test/java/io/oduck/api/unit/contact/domain/ContactTest.java @@ -1,16 +1,16 @@ -package io.oduck.api.unit.inquiry.domain; +package io.oduck.api.unit.contact.domain; import static org.assertj.core.api.Assertions.assertThat; -import io.oduck.api.domain.inquiry.dto.ContactId; -import io.oduck.api.domain.inquiry.dto.AnswerFeedback; -import io.oduck.api.domain.inquiry.dto.ContactReq.PostReq; -import io.oduck.api.domain.inquiry.dto.ContactRequestHolder; -import io.oduck.api.domain.inquiry.entity.Answer; -import io.oduck.api.domain.inquiry.entity.Contact; -import io.oduck.api.domain.inquiry.entity.FeedbackType; -import io.oduck.api.domain.inquiry.entity.InquiryType; +import io.oduck.api.domain.contact.dto.ContactId; +import io.oduck.api.domain.contact.dto.AnswerFeedback; +import io.oduck.api.domain.contact.dto.ContactReq.PostReq; +import io.oduck.api.domain.contact.dto.ContactRequestHolder; +import io.oduck.api.domain.contact.entity.Answer; +import io.oduck.api.domain.contact.entity.Contact; +import io.oduck.api.domain.contact.entity.FeedbackType; +import io.oduck.api.domain.contact.entity.InquiryType; import io.oduck.api.domain.member.entity.Member; import java.util.ArrayList; import java.util.List; @@ -67,7 +67,7 @@ public class ContactTest { void 회원은_운영진의_답변에_피드백_할_수_있다() { //given Answer answer = Answer.builder() - .helpful(FeedbackType.NOT_SELECT) + .helpful(FeedbackType.NONE) .build(); Contact contact = Contact.builder() diff --git a/src/test/java/io/oduck/api/unit/inquiry/repository/ContactRepositoryTest.java b/src/test/java/io/oduck/api/unit/contact/repository/ContactRepositoryTest.java similarity index 84% rename from src/test/java/io/oduck/api/unit/inquiry/repository/ContactRepositoryTest.java rename to src/test/java/io/oduck/api/unit/contact/repository/ContactRepositoryTest.java index fd2f3d50..db478b8d 100644 --- a/src/test/java/io/oduck/api/unit/inquiry/repository/ContactRepositoryTest.java +++ b/src/test/java/io/oduck/api/unit/contact/repository/ContactRepositoryTest.java @@ -1,11 +1,11 @@ -package io.oduck.api.unit.inquiry.repository; +package io.oduck.api.unit.contact.repository; import static org.assertj.core.api.Assertions.assertThat; -import io.oduck.api.domain.inquiry.dto.ContactReq.PostReq; -import io.oduck.api.domain.inquiry.dto.ContactRequestHolder; -import io.oduck.api.domain.inquiry.entity.InquiryType; -import io.oduck.api.domain.inquiry.repository.ContactRepository; +import io.oduck.api.domain.contact.dto.ContactReq.PostReq; +import io.oduck.api.domain.contact.dto.ContactRequestHolder; +import io.oduck.api.domain.contact.entity.InquiryType; +import io.oduck.api.domain.contact.repository.ContactRepository; import io.oduck.api.domain.member.entity.Member; import io.oduck.api.domain.member.repository.MemberRepository; import java.util.ArrayList;