diff --git a/src/main/java/com/project/core/controller/CustomerController.java b/src/main/java/com/project/core/controller/CustomerController.java index 6fc41a0..33ea2e6 100644 --- a/src/main/java/com/project/core/controller/CustomerController.java +++ b/src/main/java/com/project/core/controller/CustomerController.java @@ -1,23 +1,62 @@ package com.project.core.controller; -import com.project.core.controller.dto.request.FindCustomerRequest; +import java.util.List; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +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.controller.dto.response.CustomerResponse; 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.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") @RequiredArgsConstructor public class CustomerController { - private final CustomerService customerService; - @GetMapping - public Long save(@RequestBody FindCustomerRequest request) { - Customer customer = customerService.loadByContactEnc(request.contactEnc()); - return customer.getCustomerId(); - } + private final CustomerService customerService; + + /** + * 고객 조회 (전화번호 기준) + */ + @GetMapping + public ResponseEntity> loadByContactEnc(@RequestParam String contactEnc) { + List customers = customerService.loadByContactEnc(contactEnc); + + List response = customers.stream() + .map(CustomerResponse::from) + .toList(); + + return ResponseEntity.ok(response); + } + + /** + * 이메일 변경 + */ + @PostMapping("/{userId}/email") + public ResponseEntity changeEmail( + @PathVariable Long userId, + @RequestBody ChangeEmailRequest request + ) { + 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); + } } diff --git a/src/main/java/com/project/core/controller/DiscountController.java b/src/main/java/com/project/core/controller/DiscountController.java new file mode 100644 index 0000000..a76cb7a --- /dev/null +++ b/src/main/java/com/project/core/controller/DiscountController.java @@ -0,0 +1,99 @@ +package com.project.core.controller; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +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.RestController; + +import com.project.core.controller.dto.response.SubscriptionDiscountResponse; +import com.project.core.infra.entity.discount.SubscriptionDiscount; +import com.project.core.service.DiscountService; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/discounts") +@RequiredArgsConstructor +public class DiscountController { + + private final DiscountService discountService; + + /** + * 회선(subId)에 적용된 할인 목록 조회 + * GET /discounts/subscriptions/{subId} + */ + @GetMapping("/subscriptions/{subId}") + public ResponseEntity> getDiscountsBySubscription(@PathVariable Long subId) { + List discounts = discountService.loadRequiredBySubId(subId); + + List response = discounts.stream() + .map(SubscriptionDiscountResponse::from) + .toList(); + + return ResponseEntity.ok(response); + } + + /** + * 회선(subId)에 할인 정책(discountId) 추가(적용) + * POST /discounts + */ + @PostMapping + public ResponseEntity addDiscount(@RequestBody CreateDiscountRequest request) { + Long sdId = discountService.addDiscount(request.getSubId(), request.getDiscountId()); + return ResponseEntity.status(HttpStatus.CREATED).body(new CreateDiscountResponse(sdId)); + } + + /** + * 기존 할인(sdId)을 종료하고, 새로운 할인 정책(discountId)로 변경 + * PATCH /discounts/{sdId} + */ + @PatchMapping("/{sdId}") + public ResponseEntity changeDiscount( + @PathVariable Long sdId, + @RequestBody ChangeDiscountRequest request + ) { + Long newSdId = discountService.changeDiscount(request.getDiscountId(), sdId); + return ResponseEntity.ok(new ChangeDiscountResponse(newSdId)); + } + + // ===== DTOs ===== + + public static class CreateDiscountRequest { + private Long subId; + private Long discountId; + + public Long getSubId() { return subId; } + public Long getDiscountId() { return discountId; } + + public void setSubId(Long subId) { this.subId = subId; } + public void setDiscountId(Long discountId) { this.discountId = discountId; } + } + + public static class CreateDiscountResponse { + private final Long sdId; + + public CreateDiscountResponse(Long sdId) { this.sdId = sdId; } + public Long getSdId() { return sdId; } + } + + public static class ChangeDiscountRequest { + private Long discountId; + + public Long getDiscountId() { return discountId; } + public void setDiscountId(Long discountId) { this.discountId = discountId; } + } + + public static class ChangeDiscountResponse { + private final Long newSdId; + + public ChangeDiscountResponse(Long newSdId) { this.newSdId = newSdId; } + public Long getNewSdId() { return newSdId; } + } +} \ No newline at end of file diff --git a/src/main/java/com/project/core/controller/dto/request/ChangeEmailRequest.java b/src/main/java/com/project/core/controller/dto/request/ChangeEmailRequest.java index fcaebeb..36bf90c 100644 --- a/src/main/java/com/project/core/controller/dto/request/ChangeEmailRequest.java +++ b/src/main/java/com/project/core/controller/dto/request/ChangeEmailRequest.java @@ -1,3 +1,3 @@ package com.project.core.controller.dto.request; -public record ChangeEmailRequest(String emailEnc) {} +public record ChangeEmailRequest(String email) {} diff --git a/src/main/java/com/project/core/controller/dto/response/CustomerResponse.java b/src/main/java/com/project/core/controller/dto/response/CustomerResponse.java new file mode 100644 index 0000000..e43cee4 --- /dev/null +++ b/src/main/java/com/project/core/controller/dto/response/CustomerResponse.java @@ -0,0 +1,27 @@ +package com.project.core.controller.dto.response; + +import com.project.core.infra.entity.customer.Customer; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class CustomerResponse { + + private Long customerId; + private String name; + private String grade; + + // 필요하면 마스킹된 연락처만 제공(원본/암호화값은 노출 금지) + private String maskedContact; + + public static CustomerResponse from(Customer c) { + return CustomerResponse.builder() + .customerId(c.getCustomerId()) + .name(c.getName()) + .grade(String.valueOf(c.getGrade())) // grade가 enum이면 적절히 변환 + // maskedContact는 "복호화 가능한 원본"이 있을 때만 넣는 걸 권장 + .maskedContact(null) + .build(); + } +} diff --git a/src/main/java/com/project/core/controller/dto/response/SubscriptionDiscountResponse.java b/src/main/java/com/project/core/controller/dto/response/SubscriptionDiscountResponse.java new file mode 100644 index 0000000..45c06c9 --- /dev/null +++ b/src/main/java/com/project/core/controller/dto/response/SubscriptionDiscountResponse.java @@ -0,0 +1,74 @@ +package com.project.core.controller.dto.response; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import com.project.core.infra.entity.discount.SubscriptionDiscount; +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 lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class SubscriptionDiscountResponse { + + private Long sdId; + private Long subId; + private String maskedPhoneNumber; + + private Long discountId; + private DiscountType discountType; + private BigDecimal value; + private TargetScope targetScope; + + private LocalDateTime startDate; + private LocalDateTime endDate; + private Status status; + + public static SubscriptionDiscountResponse from(SubscriptionDiscount sd) { + + String phone = sd.getSubscription().getPhoneNumber(); + + return SubscriptionDiscountResponse.builder() + .sdId(sd.getSdId()) + .subId(sd.getSubscription().getSubId()) + .maskedPhoneNumber(maskPhone(phone)) + + .discountId(sd.getDiscountPolicy().getDiscountId()) + .discountType(sd.getDiscountType()) + .value(sd.getValue()) + .targetScope(sd.getTargetScope()) + + .startDate(sd.getStartDate()) + .endDate(sd.getEndDate()) + .status(sd.getStatus()) + .build(); + } + + /** + * 010-1234-1212 -> 010-**12-**12 + * 01012341212 -> 010-**12-**12 + */ + private static String maskPhone(String phone) { + if (phone == null || phone.isBlank()) return null; + + // 숫자만 추출 + String digits = phone.replaceAll("\\D", ""); + if (digits.length() != 11) { + return "****"; // 예상 못 한 형식은 전체 마스킹 + } + + String p1 = digits.substring(0, 3); // 010 + String p2 = digits.substring(3, 7); // 1234 + String p3 = digits.substring(7, 11); // 1212 + + // **12 / **12 + String masked2 = "**" + p2.substring(2); + String masked3 = "**" + p3.substring(2); + + return String.format("%s-%s-%s", p1, masked2, masked3); + } +} 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..cc36da4 --- /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.math.BigDecimal; +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 BigDecimal 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") + 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..ec17be1 --- /dev/null +++ b/src/main/java/com/project/core/infra/entity/discount/SubscriptionDiscount.java @@ -0,0 +1,95 @@ +package com.project.core.infra.entity.discount; + +import java.math.BigDecimal; +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 BigDecimal 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, + BigDecimal 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..8c3aa27 --- /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..531608a --- /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 { + WELFARE, + PROMOTION, + COMBINATION +} 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..5443035 --- /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..13d4d59 --- /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..7aadc3b 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,5 @@ public void terminate(Clock clock) { this.status = SubscriptionStatus.TERMINATED; this.endDate = LocalDateTime.now(clock); } -} + +} \ 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..9b91a1a 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,40 @@ 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 com.project.global.util.AESUtil; + 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; + private final AESUtil aesUtil; + + @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)); + + String emailEnc = aesUtil.encrypt(request.email()); + customer.changeEmailEnc(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..596baa5 --- /dev/null +++ b/src/main/java/com/project/core/service/DiscountService.java @@ -0,0 +1,84 @@ +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 com.project.global.exception.code.domain.core.CoreErrorCode; +import com.project.global.exception.core.EntityNotFoundException; + +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 EntityNotFoundException(CoreErrorCode.DISCOUNT_NOT_FOUND); + } + + return discounts; + } + + @Transactional + public Long addDiscount(Long subId, Long discountId) { + + Subscription subscription = + subscriptionRepository.findById(subId) + .orElseThrow(() -> new EntityNotFoundException(CoreErrorCode.SUBSCRIPTION_NOT_FOUND)); + + DiscountPolicy policy = + discountPolicyRepository.findById(discountId) + .orElseThrow(() -> new EntityNotFoundException(CoreErrorCode.DISCOUNT_POLICY_NOT_FOUND)); + + 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(); + } + + + /** + * 기존 할인을 종료하고 새로운 할인으로 교체합니다. + * @param discountId 새로 적용할 할인 정책 ID + * @param sdId 종료할 기존 구독 할인 ID + * @return 새로 생성된 구독 할인 ID + */ + @Transactional + public Long changeDiscount(Long discountId, Long sdId) { + SubscriptionDiscount discount = + subscriptionDiscountRepository.findBySdId(sdId) + .orElseThrow(() -> new EntityNotFoundException(CoreErrorCode.DISCOUNT_NOT_FOUND)); + //내부 정보 수정 - 기존 할인 종료 + 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..d68ba39 --- /dev/null +++ b/src/main/java/com/project/core/service/SubscriptionService.java @@ -0,0 +1,33 @@ +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.exception.code.domain.core.CoreErrorCode; +import com.project.global.exception.core.EntityNotFoundException; +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) { + List subscriptions = + subscriptionRepository.findByCustomer_CustomerId(customerId); + + if (subscriptions.isEmpty()) { + throw new EntityNotFoundException(CoreErrorCode.SUBSCRIPTION_NOT_FOUND); + } + + return subscriptions; + } +} diff --git a/src/main/java/com/project/global/exception/code/domain/core/CoreErrorCode.java b/src/main/java/com/project/global/exception/code/domain/core/CoreErrorCode.java index 3f8a4e9..de40fe8 100644 --- a/src/main/java/com/project/global/exception/code/domain/core/CoreErrorCode.java +++ b/src/main/java/com/project/global/exception/code/domain/core/CoreErrorCode.java @@ -10,6 +10,12 @@ public enum CoreErrorCode implements BaseErrorCode { // 고객 CUSTOMER_NOT_FOUND(HttpStatus.NOT_FOUND, "CUSTOMER_001", "존재하지 않는 고객입니다."), + + // 할인정책 + DISCOUNT_POLICY_NOT_FOUND(HttpStatus.NOT_FOUND, "DISCOUNT_POLICY_001", "존재하지 않는 할인 정책입니다."), + + // 할인 + DISCOUNT_NOT_FOUND(HttpStatus.NOT_FOUND, "DISCOUNT_001", "존재하지 않는 할인입니다."), // 요금제 PLAN_NOT_FOUND(HttpStatus.NOT_FOUND, "PLAN_001", "존재하지 않는 요금제입니다."),