SessionPassSalesCommandServiceImpl.java

package com.deveagles.be15_deveagles_be.features.sales.command.application.service.impl;

import com.deveagles.be15_deveagles_be.common.exception.BusinessException;
import com.deveagles.be15_deveagles_be.common.exception.ErrorCode;
import com.deveagles.be15_deveagles_be.features.membership.command.application.dto.request.CustomerSessionPassRegistRequest;
import com.deveagles.be15_deveagles_be.features.membership.command.application.service.CustomerSessionPassCommandService;
import com.deveagles.be15_deveagles_be.features.membership.command.domain.aggregate.ExpirationPeriodType;
import com.deveagles.be15_deveagles_be.features.membership.command.domain.aggregate.SessionPass;
import com.deveagles.be15_deveagles_be.features.membership.command.domain.repository.SessionPassRepository;
import com.deveagles.be15_deveagles_be.features.sales.command.application.dto.request.PaymentsInfo;
import com.deveagles.be15_deveagles_be.features.sales.command.application.dto.request.SessionPassSalesRequest;
import com.deveagles.be15_deveagles_be.features.sales.command.application.service.SessionPassSalesCommandService;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.aggregate.Payments;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.aggregate.Sales;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.aggregate.SessionPassSales;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.repository.PaymentsRepository;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.repository.SalesRepository;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.repository.SessionPassSalesRepository;
import jakarta.transaction.Transactional;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class SessionPassSalesCommandServiceImpl implements SessionPassSalesCommandService {

  private final SessionPassSalesRepository sessionPassSalesRepository;
  private final SessionPassRepository sessionPassRepository;
  private final SalesRepository salesRepository;
  private final PaymentsRepository paymentsRepository;
  private final CustomerSessionPassCommandService customerSessionPassCommandService;

  @Transactional
  @Override
  public void registSessionPassSales(SessionPassSalesRequest request) {
    if (request.getRetailPrice() < 0) {
      throw new BusinessException(ErrorCode.SALES_RETAILPRICE_REQUIRED);
    }
    if (request.getTotalAmount() < 0) {
      throw new BusinessException(ErrorCode.SALES_TOTALAMOUNT_REQUIRED);
    }
    for (PaymentsInfo payment : request.getPayments()) {
      if (payment.getAmount() == null || payment.getAmount() <= 0) {
        throw new BusinessException(ErrorCode.SALES_PAYMENTSAMOUNT_REQUIRED);
      }
      if (payment.getPaymentsMethod() == null) {
        throw new BusinessException(ErrorCode.SALES_PAYMENTMETHOD_REQUIRED);
      }
    }

    // 1. Sales 저장
    Sales sales =
        Sales.builder()
            .shopId(request.getShopId())
            .customerId(request.getCustomerId())
            .staffId(request.getStaffId())
            .reservationId(request.getReservationId())
            .retailPrice(request.getRetailPrice())
            .discountRate(request.getDiscountRate())
            .discountAmount(request.getDiscountAmount())
            .totalAmount(request.getTotalAmount())
            .salesMemo(request.getSalesMemo())
            .salesDate(request.getSalesDate())
            .isRefunded(false)
            .build();
    salesRepository.save(sales);

    // 2. SessionPassSales 저장
    SessionPassSales sessionPassSales =
        SessionPassSales.builder()
            .salesId(sales.getSalesId())
            .sessionPassId(request.getSessionPassId())
            .build();
    sessionPassSalesRepository.save(sessionPassSales);

    // 3. Payments 저장
    List<Payments> payments =
        request.getPayments().stream()
            .map(
                p ->
                    Payments.builder()
                        .salesId(sales.getSalesId())
                        .paymentsMethod(p.getPaymentsMethod())
                        .amount(p.getAmount())
                        .build())
            .toList();
    payments.forEach(paymentsRepository::save);

    // 4. 고객 횟수권 등록
    SessionPass sessionPass =
        sessionPassRepository
            .findById(request.getSessionPassId())
            .orElseThrow(() -> new BusinessException(ErrorCode.SESSIONPASS_NOT_FOUND));

    Date expirationDate =
        calculateExpirationDate(
            sessionPass.getExpirationPeriod(), sessionPass.getExpirationPeriodType());

    int baseCount = sessionPass.getSession();
    int bonusCount = sessionPass.getBonus() != null ? sessionPass.getBonus() : 0;

    CustomerSessionPassRegistRequest passRequest = new CustomerSessionPassRegistRequest();
    passRequest.setCustomerId(request.getCustomerId());
    passRequest.setSessionPassId(sessionPass.getSessionPassId());
    passRequest.setRemainingCount(baseCount + bonusCount);
    passRequest.setExpirationDate(expirationDate);

    customerSessionPassCommandService.registCustomerSessionPass(passRequest);
  }

  private Date calculateExpirationDate(int period, ExpirationPeriodType type) {
    Calendar calendar = Calendar.getInstance();
    switch (type) {
      case DAY -> calendar.add(Calendar.DAY_OF_YEAR, period);
      case WEEK -> calendar.add(Calendar.WEEK_OF_YEAR, period);
      case MONTH -> calendar.add(Calendar.MONTH, period);
      case YEAR -> calendar.add(Calendar.YEAR, period);
    }
    return calendar.getTime();
  }

  @Transactional
  @Override
  public void updateSessionPassSales(Long salesId, SessionPassSalesRequest request) {
    if (request.getRetailPrice() < 0) {
      throw new BusinessException(ErrorCode.SALES_RETAILPRICE_REQUIRED);
    }
    if (request.getTotalAmount() < 0) {
      throw new BusinessException(ErrorCode.SALES_TOTALAMOUNT_REQUIRED);
    }
    for (PaymentsInfo payment : request.getPayments()) {
      if (payment.getAmount() == null || payment.getAmount() <= 0) {
        throw new BusinessException(ErrorCode.SALES_PAYMENTSAMOUNT_REQUIRED);
      }
      if (payment.getPaymentsMethod() == null) {
        throw new BusinessException(ErrorCode.SALES_PAYMENTMETHOD_REQUIRED);
      }
    }

    // 1. 기존 Sales 조회 및 업데이트
    Sales sales =
        salesRepository
            .findById(salesId)
            .orElseThrow(() -> new BusinessException(ErrorCode.SALES_NOT_FOUND));

    sales.update(
        request.getShopId(),
        request.getCustomerId(),
        request.getStaffId(),
        request.getReservationId(),
        request.getRetailPrice(),
        request.getDiscountRate(),
        request.getDiscountAmount(),
        request.getTotalAmount(),
        request.getSalesMemo(),
        request.getSalesDate());

    // 2. 기존 SessionPassSales 삭제 후 저장
    sessionPassSalesRepository.deleteBySalesId(salesId);
    SessionPassSales sessionPassSales =
        SessionPassSales.builder()
            .salesId(salesId)
            .sessionPassId(request.getSessionPassId())
            .build();
    sessionPassSalesRepository.save(sessionPassSales);

    // 3. 기존 Payments 삭제 후 재등록
    paymentsRepository.deleteBySalesId(salesId);
    List<Payments> payments =
        request.getPayments().stream()
            .map(
                p ->
                    Payments.builder()
                        .salesId(salesId)
                        .paymentsMethod(p.getPaymentsMethod())
                        .amount(p.getAmount())
                        .build())
            .toList();
    payments.forEach(paymentsRepository::save);
  }
}