PrepaidPassSalesCommandServiceImpl.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.CustomerPrepaidPassRegistRequest;
import com.deveagles.be15_deveagles_be.features.membership.command.application.service.CustomerPrepaidPassCommandService;
import com.deveagles.be15_deveagles_be.features.membership.command.domain.aggregate.ExpirationPeriodType;
import com.deveagles.be15_deveagles_be.features.membership.command.domain.aggregate.PrepaidPass;
import com.deveagles.be15_deveagles_be.features.membership.command.domain.repository.PrepaidPassRepository;
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.PrepaidPassSalesRequest;
import com.deveagles.be15_deveagles_be.features.sales.command.application.service.PrepaidPassSalesCommandService;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.aggregate.Payments;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.aggregate.PrepaidPassSales;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.aggregate.Sales;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.repository.PaymentsRepository;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.repository.PrepaidPassSalesRepository;
import com.deveagles.be15_deveagles_be.features.sales.command.domain.repository.SalesRepository;
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 PrepaidPassSalesCommandServiceImpl implements PrepaidPassSalesCommandService {

  private final PrepaidPassSalesRepository prepaidPassSalesRepository;
  private final PrepaidPassRepository prepaidPassRepository;
  private final SalesRepository salesRepository;
  private final PaymentsRepository paymentsRepository;
  private final CustomerPrepaidPassCommandService customerPrepaidPassCommandService;

  @Transactional
  @Override
  public void registPrepaidPassSales(PrepaidPassSalesRequest 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);
      }
    }

    // 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);

    // PrepaidPassSales 저장
    PrepaidPassSales prepaidPassSales =
        PrepaidPassSales.builder()
            .salesId(sales.getSalesId())
            .prepaidPassId(request.getPrepaidPassId())
            .build();
    prepaidPassSalesRepository.save(prepaidPassSales);

    // 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);

    // 고객 선불권 등록
    PrepaidPass prepaidPass =
        prepaidPassRepository
            .findById(request.getPrepaidPassId())
            .orElseThrow(() -> new BusinessException(ErrorCode.PREPAIDPASS_NOT_FOUND));

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

    int baseAmount = request.getRetailPrice();
    int bonusAmount = prepaidPass.getBonus() != null ? prepaidPass.getBonus() : 0;

    CustomerPrepaidPassRegistRequest passRequest = new CustomerPrepaidPassRegistRequest();
    passRequest.setCustomerId(request.getCustomerId());
    passRequest.setPrepaidPassId(prepaidPass.getPrepaidPassId());
    passRequest.setRemainingAmount(baseAmount + bonusAmount);
    passRequest.setExpirationDate(expirationDate);

    customerPrepaidPassCommandService.registCustomerPrepaidPass(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 updatePrepaidPassSales(Long salesId, PrepaidPassSalesRequest 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);
      }
    }

    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());

    prepaidPassSalesRepository.deleteBySalesId(salesId);
    PrepaidPassSales prepaidPassSales =
        PrepaidPassSales.builder()
            .salesId(salesId)
            .prepaidPassId(request.getPrepaidPassId())
            .build();
    prepaidPassSalesRepository.save(prepaidPassSales);

    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);
  }
}