CustomerCommandServiceImpl.java
package com.deveagles.be15_deveagles_be.features.customers.command.infrastructure.service;
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.auth.command.application.model.CustomUser;
import com.deveagles.be15_deveagles_be.features.customers.command.application.dto.request.CreateCustomerRequest;
import com.deveagles.be15_deveagles_be.features.customers.command.application.dto.request.UpdateCustomerRequest;
import com.deveagles.be15_deveagles_be.features.customers.command.application.dto.response.CustomerCommandResponse;
import com.deveagles.be15_deveagles_be.features.customers.command.application.service.CustomerCommandService;
import com.deveagles.be15_deveagles_be.features.customers.command.application.service.CustomerTagService;
import com.deveagles.be15_deveagles_be.features.customers.command.domain.aggregate.Customer;
import com.deveagles.be15_deveagles_be.features.customers.command.domain.repository.CustomerRepository;
import com.deveagles.be15_deveagles_be.features.customers.query.service.CustomerQueryService;
import com.deveagles.be15_deveagles_be.features.messages.command.application.service.AutomaticMessageTriggerService;
import com.deveagles.be15_deveagles_be.features.messages.command.domain.aggregate.AutomaticEventType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class CustomerCommandServiceImpl implements CustomerCommandService {
private final CustomerRepository customerRepository;
private final CustomerQueryService customerQueryService;
private final AutomaticMessageTriggerService automaticMessageTriggerService;
private final CustomerTagService customerTagService;
@Override
public CustomerCommandResponse createCustomer(CreateCustomerRequest request) {
Long currentShopId = getCurrentShopId();
Customer customer =
Customer.builder()
.shopId(currentShopId)
.customerName(request.customerName())
.phoneNumber(request.phoneNumber())
.gender(request.gender())
.birthdate(request.birthdate())
.customerGradeId(request.customerGradeId())
.staffId(request.staffId())
.channelId(request.channelId())
.memo(request.memo())
.marketingConsent(request.marketingConsent())
.notificationConsent(request.notificationConsent())
.build();
Customer savedCustomer = customerRepository.save(customer);
customerQueryService.syncCustomerToElasticsearch(savedCustomer.getId());
if (request.tags() != null && !request.tags().isEmpty()) {
request
.tags()
.forEach(
tagId ->
customerTagService.addTagToCustomer(savedCustomer.getId(), tagId, currentShopId));
}
log.info(
"자동 발송 메시지 실행 - 이벤트: {}, 고객ID: {}", AutomaticEventType.NEW_CUSTOMER, savedCustomer.getId());
automaticMessageTriggerService.triggerAutomaticSend(
savedCustomer, AutomaticEventType.NEW_CUSTOMER);
return CustomerCommandResponse.from(savedCustomer);
}
@Override
public CustomerCommandResponse updateCustomer(UpdateCustomerRequest request) {
Customer customer =
customerRepository
.findByIdAndShopId(request.customerId(), getCurrentShopId())
.orElseThrow(() -> new BusinessException(ErrorCode.CUSTOMER_NOT_FOUND));
customer.updateCustomerInfo(
request.customerName(),
request.phoneNumber(),
request.memo(),
request.gender(),
request.channelId());
// 추가 필드 업데이트
if (request.staffId() != null) {
customer.updateStaff(request.staffId());
}
if (request.customerGradeId() != null) {
customer.updateGrade(request.customerGradeId());
}
if (request.birthdate() != null) {
customer.updateBirthdate(request.birthdate());
}
if (request.marketingConsent() != null) {
customer.updateMarketingConsent(request.marketingConsent());
}
if (request.notificationConsent() != null) {
customer.updateNotificationConsent(request.notificationConsent());
}
Customer updatedCustomer = customerRepository.save(customer);
// Elasticsearch 동기화
customerQueryService.syncCustomerToElasticsearch(updatedCustomer.getId());
log.info("고객 정보 수정됨: ID={}, 이름={}", updatedCustomer.getId(), updatedCustomer.getCustomerName());
return CustomerCommandResponse.from(updatedCustomer);
}
@Override
public void deleteCustomer(Long customerId, Long shopId) {
Customer customer =
customerRepository
.findByIdAndShopId(customerId, shopId)
.orElseThrow(() -> new BusinessException(ErrorCode.CUSTOMER_NOT_FOUND));
customer.softDelete();
customerRepository.save(customer);
log.info("고객 삭제됨: ID={}, 매장ID={}", customerId, shopId);
// Elasticsearch 동기화
customerQueryService.syncCustomerToElasticsearch(customerId);
}
@Override
public CustomerCommandResponse updateMarketingConsent(
Long customerId, Long shopId, Boolean consent) {
Customer customer =
customerRepository
.findByIdAndShopId(customerId, shopId)
.orElseThrow(() -> new BusinessException(ErrorCode.CUSTOMER_NOT_FOUND));
customer.updateMarketingConsent(consent);
Customer updatedCustomer = customerRepository.save(customer);
return CustomerCommandResponse.from(updatedCustomer);
}
@Override
public CustomerCommandResponse updateNotificationConsent(
Long customerId, Long shopId, Boolean consent) {
Customer customer =
customerRepository
.findByIdAndShopId(customerId, shopId)
.orElseThrow(() -> new BusinessException(ErrorCode.CUSTOMER_NOT_FOUND));
customer.updateNotificationConsent(consent);
Customer updatedCustomer = customerRepository.save(customer);
return CustomerCommandResponse.from(updatedCustomer);
}
@Override
public CustomerCommandResponse addVisit(Long customerId, Long shopId, Integer revenue) {
Customer customer =
customerRepository
.findByIdAndShopId(customerId, shopId)
.orElseThrow(() -> new BusinessException(ErrorCode.CUSTOMER_NOT_FOUND));
customer.addVisit(revenue);
Customer updatedCustomer = customerRepository.save(customer);
log.info("고객 방문 추가됨: ID={}, 매출={}", customerId, revenue);
return CustomerCommandResponse.from(updatedCustomer);
}
@Override
public CustomerCommandResponse addNoshow(Long customerId, Long shopId) {
Customer customer =
customerRepository
.findByIdAndShopId(customerId, shopId)
.orElseThrow(() -> new BusinessException(ErrorCode.CUSTOMER_NOT_FOUND));
customer.addNoshow();
Customer updatedCustomer = customerRepository.save(customer);
log.info("고객 노쇼 추가됨: ID={}", customerId);
return CustomerCommandResponse.from(updatedCustomer);
}
// SecurityContext에서 현재 사용자의 shopId 가져오기
private Long getCurrentShopId() {
CustomUser user =
(CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return user.getShopId();
}
}