diff --git a/src/main/java/com/project/core/controller/CustomerController.java b/src/main/java/com/project/core/controller/CustomerController.java index 6fc41a0..28c628a 100644 --- a/src/main/java/com/project/core/controller/CustomerController.java +++ b/src/main/java/com/project/core/controller/CustomerController.java @@ -1,23 +1,68 @@ package com.project.core.controller; -import com.project.core.controller.dto.request.FindCustomerRequest; +import java.util.List; + +import org.springframework.http.ResponseEntity; + +import com.project.core.controller.dto.request.ChangeEmailRequest; +import com.project.core.controller.dto.request.ChangeGradeRequest; +import com.project.core.controller.dto.response.ChangeEmailResponse; +import com.project.core.controller.dto.response.ChangeGradeResponse; import com.project.core.infra.entity.customer.Customer; import com.project.core.service.CustomerService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; + + @RestController @RequestMapping("/user") @RequiredArgsConstructor public class CustomerController { - private final CustomerService customerService; + private final CustomerService customerService; + + /** + * 고객 조회 (전화번호 기준) + */ + @GetMapping + public ResponseEntity> loadByContactEnc( + @RequestParam String contactEnc + ) { + List customers = customerService.loadByContactEnc(contactEnc); + return ResponseEntity.ok(customers); + } + + /** + * 이메일 변경 + * @throws Exception + */ + @PostMapping("/{userId}/email") + public ResponseEntity changeEmail( + @PathVariable Long userId, + @RequestBody ChangeEmailRequest request + ) throws Exception { + ChangeEmailResponse response = + customerService.changeEmailEnc(userId, request); + return ResponseEntity.ok(response); + } + + /** + * 고객 등급 변경 + */ + @PostMapping("/{userId}/grade") + public ResponseEntity changeGrade( + @PathVariable Long userId, + @RequestBody ChangeGradeRequest request + ) { + ChangeGradeResponse response = + customerService.changeUserGrade(userId, request); + return ResponseEntity.ok(response); + } - @GetMapping - public Long save(@RequestBody FindCustomerRequest request) { - Customer customer = customerService.loadByContactEnc(request.contactEnc()); - return customer.getCustomerId(); - } } diff --git a/src/main/java/com/project/core/infra/entity/discount/DiscountPolicy.java b/src/main/java/com/project/core/infra/entity/discount/DiscountPolicy.java new file mode 100644 index 0000000..ae58430 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/DiscountPolicy.java @@ -0,0 +1,53 @@ +package com.project.core.infra.entity.discount; + +import java.util.ArrayList; +import java.util.List; + +import com.project.core.infra.entity.discount.enums.Active; +import com.project.core.infra.entity.discount.enums.Category; +import com.project.core.infra.entity.discount.enums.DiscountType; +import com.project.core.infra.entity.discount.enums.TargetScope; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "discount_policy") +public class DiscountPolicy { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "discount_id") + private Long discountId; + + @Column(name = "name", nullable = false) + private String name; + + @Column(name = "discount_type", nullable = false) + private DiscountType discountType; + + @Column(name = "value", nullable = false) + private Double value; + + @Column(name = "category", nullable = false) + private Category category; + + @Column(name = "target_scope", nullable = false) + private TargetScope targetScope; + + @Column(name = "active", nullable = false) + private Active active; +//------------------------------------------------------------------ + @OneToMany(mappedBy = "discountPolicy", cascade = CascadeType.ALL) + private List discountHistory = new ArrayList<>(); +} diff --git a/src/main/java/com/project/core/infra/entity/discount/SubscriptionDiscount.java b/src/main/java/com/project/core/infra/entity/discount/SubscriptionDiscount.java new file mode 100644 index 0000000..cfa6930 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/SubscriptionDiscount.java @@ -0,0 +1,94 @@ +package com.project.core.infra.entity.discount; + +import java.time.LocalDateTime; + +import com.project.core.infra.entity.discount.enums.DiscountType; +import com.project.core.infra.entity.discount.enums.Status; +import com.project.core.infra.entity.discount.enums.TargetScope; +import com.project.core.infra.entity.subscription.Subscription; + +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.Table; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "subscription_discount") +public class SubscriptionDiscount { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "sd_id") + private Long sdId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "discount_id", nullable = false) + private DiscountPolicy discountPolicy; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "sub_id", nullable = false) + private Subscription subscription; + + @Column(name = "discount_type", nullable = false) + private DiscountType discountType; + + @Column(name = "value", nullable = false) + private Double value; + + @Column(name = "target_scope", nullable = false) + private TargetScope targetScope; + + @Column(name = "start_date", nullable = false) + private LocalDateTime startDate; + + @Column(name = "end_date") + private LocalDateTime endDate; + + @Column(name = "status", nullable = false) + private Status status; + + public void setEndDate(LocalDateTime endDate) { + this.endDate = endDate; + } + public void setStatusTerminated() { + this.status = Status.TERMINATED; + } + + @Builder + private SubscriptionDiscount( + DiscountPolicy discountPolicy, + Subscription subscription, + DiscountType discountType, + Double value, + TargetScope targetScope, + LocalDateTime startDate + ) { + if (discountPolicy == null) throw new IllegalArgumentException("discountPolicy는 필수입니다."); + if (subscription == null) throw new IllegalArgumentException("subscription은 필수입니다."); + if (discountType == null) throw new IllegalArgumentException("discountType는 필수입니다."); + if (value == null) throw new IllegalArgumentException("value는 필수입니다."); + if (targetScope == null) throw new IllegalArgumentException("targetScope는 필수입니다."); + + this.discountPolicy = discountPolicy; + this.subscription = subscription; + this.discountType = discountType; + this.value = value; + this.targetScope = targetScope; + this.startDate = startDate != null ? startDate : LocalDateTime.now(); + + // 기본값 + this.endDate = null; + this.status = Status.ACTIVE; + } +} diff --git a/src/main/java/com/project/core/infra/entity/discount/enums/Active.java b/src/main/java/com/project/core/infra/entity/discount/enums/Active.java new file mode 100644 index 0000000..8e98ff0 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/enums/Active.java @@ -0,0 +1,6 @@ +package com.project.core.infra.entity.discount.enums; + +public enum Active { + ACTIVE + ,INACTIVE +} diff --git a/src/main/java/com/project/core/infra/entity/discount/enums/Category.java b/src/main/java/com/project/core/infra/entity/discount/enums/Category.java new file mode 100644 index 0000000..5439a78 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/enums/Category.java @@ -0,0 +1,7 @@ +package com.project.core.infra.entity.discount.enums; + +public enum Category { + 복지 + ,프로모션 + ,결합 +} diff --git a/src/main/java/com/project/core/infra/entity/discount/enums/DiscountType.java b/src/main/java/com/project/core/infra/entity/discount/enums/DiscountType.java new file mode 100644 index 0000000..aad9fc1 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/enums/DiscountType.java @@ -0,0 +1,6 @@ +package com.project.core.infra.entity.discount.enums; + +public enum DiscountType { + Rate + ,Fixed +} diff --git a/src/main/java/com/project/core/infra/entity/discount/enums/Status.java b/src/main/java/com/project/core/infra/entity/discount/enums/Status.java new file mode 100644 index 0000000..7d193ba --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/enums/Status.java @@ -0,0 +1,6 @@ +package com.project.core.infra.entity.discount.enums; + +public enum Status { + ACTIVE + ,TERMINATED +} diff --git a/src/main/java/com/project/core/infra/entity/discount/enums/TargetScope.java b/src/main/java/com/project/core/infra/entity/discount/enums/TargetScope.java new file mode 100644 index 0000000..341e477 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/enums/TargetScope.java @@ -0,0 +1,6 @@ +package com.project.core.infra.entity.discount.enums; + +public enum TargetScope { + PLAN_FEE + ,TOTAL_AMOUNT +} diff --git a/src/main/java/com/project/core/infra/entity/subscription/Subscription.java b/src/main/java/com/project/core/infra/entity/subscription/Subscription.java index 8adb51f..d2f725a 100644 --- a/src/main/java/com/project/core/infra/entity/subscription/Subscription.java +++ b/src/main/java/com/project/core/infra/entity/subscription/Subscription.java @@ -73,4 +73,8 @@ public void terminate(Clock clock) { this.status = SubscriptionStatus.TERMINATED; this.endDate = LocalDateTime.now(clock); } -} + + public void setPhoneNumber(String maskedNum) { + this.phoneNumber = maskedNum; + } +} \ No newline at end of file diff --git a/src/main/java/com/project/core/infra/repository/customer/CustomerRepository.java b/src/main/java/com/project/core/infra/repository/customer/CustomerRepository.java index 6bd0929..16f4b73 100644 --- a/src/main/java/com/project/core/infra/repository/customer/CustomerRepository.java +++ b/src/main/java/com/project/core/infra/repository/customer/CustomerRepository.java @@ -1,9 +1,9 @@ package com.project.core.infra.repository.customer; +import java.util.List; import com.project.core.infra.entity.customer.Customer; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface CustomerRepository extends JpaRepository { - Optional findByContactEnc(String contactEnc); + List findByContactEnc(String contactEnc); } diff --git a/src/main/java/com/project/core/infra/repository/discount/DiscountPolicyRepository.java b/src/main/java/com/project/core/infra/repository/discount/DiscountPolicyRepository.java new file mode 100644 index 0000000..962e7a1 --- /dev/null +++ b/src/main/java/com/project/core/infra/repository/discount/DiscountPolicyRepository.java @@ -0,0 +1,9 @@ +package com.project.core.infra.repository.discount; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.project.core.infra.entity.discount.DiscountPolicy; + +public interface DiscountPolicyRepository extends JpaRepository { + +} diff --git a/src/main/java/com/project/core/infra/repository/discount/SubscriptionDiscountRepository.java b/src/main/java/com/project/core/infra/repository/discount/SubscriptionDiscountRepository.java new file mode 100644 index 0000000..09bd219 --- /dev/null +++ b/src/main/java/com/project/core/infra/repository/discount/SubscriptionDiscountRepository.java @@ -0,0 +1,13 @@ +package com.project.core.infra.repository.discount; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.project.core.infra.entity.discount.SubscriptionDiscount; + +public interface SubscriptionDiscountRepository extends JpaRepository { + List findBySubscription_SubId(Long subId); + Optional findBySdId(Long sdId); +} diff --git a/src/main/java/com/project/core/infra/repository/subscription/SubscriptionRepository.java b/src/main/java/com/project/core/infra/repository/subscription/SubscriptionRepository.java index 383b0e0..fd00c9d 100644 --- a/src/main/java/com/project/core/infra/repository/subscription/SubscriptionRepository.java +++ b/src/main/java/com/project/core/infra/repository/subscription/SubscriptionRepository.java @@ -3,12 +3,17 @@ import com.project.core.infra.entity.customer.Customer; import com.project.core.infra.entity.subscription.Subscription; import com.project.core.infra.entity.subscription.enums.SubscriptionStatus; + +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; public interface SubscriptionRepository extends JpaRepository { + List findByCustomer_CustomerId(Long customerId); + long countByCustomerAndStatus(Customer customer, SubscriptionStatus status); - + boolean existsByPhoneNumberAndStatus(String phoneNumber, SubscriptionStatus status); - + boolean existsByPhoneNumber(String phoneNumber); } diff --git a/src/main/java/com/project/core/service/CustomerService.java b/src/main/java/com/project/core/service/CustomerService.java index ec8b405..0613629 100644 --- a/src/main/java/com/project/core/service/CustomerService.java +++ b/src/main/java/com/project/core/service/CustomerService.java @@ -1,5 +1,10 @@ package com.project.core.service; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import com.project.core.controller.dto.request.ChangeEmailRequest; import com.project.core.controller.dto.request.ChangeGradeRequest; import com.project.core.controller.dto.response.ChangeEmailResponse; @@ -8,41 +13,36 @@ import com.project.core.infra.repository.customer.CustomerRepository; import com.project.global.exception.code.domain.core.CoreErrorCode; import com.project.global.exception.core.EntityNotFoundException; + import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -@Service -@RequiredArgsConstructor +@Service @RequiredArgsConstructor public class CustomerService { - private final CustomerRepository customerRepository; - - @Transactional - public Customer loadByContactEnc(String contactEnc) { - return customerRepository - .findByContactEnc(contactEnc) - .orElseThrow(() -> new EntityNotFoundException(CoreErrorCode.CUSTOMER_NOT_FOUND)); - } - - @Transactional - public ChangeEmailResponse changeEmailEnc(Long userId, ChangeEmailRequest request) { - Customer customer = - customerRepository - .findById(userId) - .orElseThrow(() -> new EntityNotFoundException(CoreErrorCode.CUSTOMER_NOT_FOUND)); - - customer.changeEmailEnc(request.emailEnc()); - return new ChangeEmailResponse(customer.getEmailEnc()); - } - - @Transactional - public ChangeGradeResponse changeUserGrade(Long userId, ChangeGradeRequest request) { - Customer customer = - customerRepository - .findById(userId) - .orElseThrow(() -> new EntityNotFoundException(CoreErrorCode.CUSTOMER_NOT_FOUND)); - - customer.changeGrade(request.grade()); - return new ChangeGradeResponse(customer.getGrade()); - } + private final CustomerRepository customerRepository; + + @Transactional + public List loadByContactEnc(String contactEnc) {//유저 조회 + List customers = customerRepository.findByContactEnc(contactEnc); + if(customers.isEmpty()) { + throw new EntityNotFoundException(CoreErrorCode.CUSTOMER_NOT_FOUND); + + } + return customers; + } + + @Transactional + public ChangeEmailResponse changeEmailEnc(Long userId, ChangeEmailRequest request) {//이메일 변경 + Customer customer = customerRepository.findById(userId).orElseThrow(()-> new EntityNotFoundException(CoreErrorCode.CUSTOMER_NOT_FOUND)); + + customer.changeEmailEnc(request.emailEnc()); + return new ChangeEmailResponse(customer.getEmailEnc()); + } + + @Transactional + public ChangeGradeResponse changeUserGrade(Long userId, ChangeGradeRequest request) {//등급 변경 + Customer customer = customerRepository.findById(userId).orElseThrow(()-> new EntityNotFoundException(CoreErrorCode.CUSTOMER_NOT_FOUND)); + + customer.changeGrade(request.grade()); + return new ChangeGradeResponse(customer.getGrade()); + } } diff --git a/src/main/java/com/project/core/service/DiscountService.java b/src/main/java/com/project/core/service/DiscountService.java new file mode 100644 index 0000000..4423a22 --- /dev/null +++ b/src/main/java/com/project/core/service/DiscountService.java @@ -0,0 +1,76 @@ +package com.project.core.service; + +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.project.core.infra.entity.discount.DiscountPolicy; +import com.project.core.infra.entity.discount.SubscriptionDiscount; +import com.project.core.infra.entity.subscription.Subscription; +import com.project.core.infra.repository.discount.DiscountPolicyRepository; +import com.project.core.infra.repository.discount.SubscriptionDiscountRepository; +import com.project.core.infra.repository.subscription.SubscriptionRepository; + +import lombok.RequiredArgsConstructor; + +@Service @RequiredArgsConstructor +public class DiscountService { + + private final SubscriptionDiscountRepository subscriptionDiscountRepository; + private final SubscriptionRepository subscriptionRepository; + private final DiscountPolicyRepository discountPolicyRepository; + + @Transactional(readOnly = true) //회선에 적용 된 할인 정책 확인 + public List loadRequiredBySubId(Long subId) { + + List discounts = + subscriptionDiscountRepository.findBySubscription_SubId(subId); + + if (discounts.isEmpty()) { + throw new IllegalStateException("해당 회선에 적용된 할인이 없습니다"); + } + + return discounts; + } + + @Transactional + public Long addDiscount(Long subId, Long discountId) { + + Subscription subscription = + subscriptionRepository.findById(subId) + .orElseThrow(() -> new IllegalArgumentException("회선이 존재하지 않습니다")); + + DiscountPolicy policy = + discountPolicyRepository.findById(discountId) + .orElseThrow(() -> new IllegalArgumentException("할인 정책이 존재하지 않습니다")); + + SubscriptionDiscount discount = + SubscriptionDiscount.builder() + .discountPolicy(policy) + .subscription(subscription) + .discountType(policy.getDiscountType()) + .value(policy.getValue()) + .targetScope(policy.getTargetScope()) + .startDate(LocalDateTime.now()) + .build(); + + subscriptionDiscountRepository.save(discount); + + return discount.getSdId(); + } + + + @Transactional + public Long changeDiscount(Long discountId,Long sdId) { //할인 변경 + SubscriptionDiscount discount = + subscriptionDiscountRepository.findBySdId(sdId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 할인입니다.")); + //내부 정보 수정 - 기존 할인 종료 + discount.setEndDate(LocalDateTime.now()); + discount.setStatusTerminated(); + //새로운 할인 적용 + return addDiscount(discount.getSubscription().getSubId(),discountId); //생성된 할인 테이블 아이디 반환 + } +} diff --git a/src/main/java/com/project/core/service/SubscriptionService.java b/src/main/java/com/project/core/service/SubscriptionService.java new file mode 100644 index 0000000..12ff840 --- /dev/null +++ b/src/main/java/com/project/core/service/SubscriptionService.java @@ -0,0 +1,38 @@ +package com.project.core.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.project.core.infra.entity.subscription.Subscription; +import com.project.core.infra.repository.subscription.SubscriptionRepository; +import com.project.global.util.AESUtil; + +import lombok.RequiredArgsConstructor; + +@Service @RequiredArgsConstructor +public class SubscriptionService { + + private final SubscriptionRepository subscriptionRepository; + private final AESUtil aesUtil; + + @Transactional + public List findSubscription(Long customerId) throws Exception { + List subscriptions = + subscriptionRepository.findByCustomer_CustomerId(customerId); + + if (subscriptions.isEmpty()) { + throw new IllegalStateException("보유중인 회선이 없습니다."); + }else { + //복호화 -> 마스킹 + for (int i = 0; i < subscriptions.size(); i++) { + String num = aesUtil.decrypt(subscriptions.get(i).getPhoneNumber()); + String maskedNum = num.substring(0,4)+"**"+num.substring(6,9)+"**"+num.substring(11,12); //"010-**34-**78" + subscriptions.get(i).setPhoneNumber(maskedNum); + } + } + + return subscriptions; + } +}