```java package fnf.wp.online_store_backend.module.scheduler.launch; import fnf.wp.online_store_backend.module.core.common.core.alimtalk.adpater.in.MobilePushMessageNotifier; import fnf.wp.online_store_backend.module.core.common.core.alimtalk.domain.Message; import fnf.wp.online_store_backend.module.core.common.core.alimtalk.template.TalkManageNumberCode; import fnf.wp.online_store_backend.module.core.common.core.time.DateTimeProvider; import fnf.wp.online_store_backend.module.core.common.infrastructure.entity.enums.MallId; import fnf.wp.online_store_backend.module.core.member.member.core.member.Member; import fnf.wp.online_store_backend.module.core.member.member.core.member.MemberPort; import fnf.wp.online_store_backend.module.scheduler.launch.domain.Launch; import fnf.wp.online_store_backend.module.scheduler.launch.domain.LaunchNotification; import fnf.wp.online_store_backend.module.scheduler.launch.port.in.LaunchNotificationSender; import fnf.wp.online_store_backend.module.scheduler.launch.port.out.LaunchGateway; import fnf.wp.online_store_backend.module.scheduler.launch.port.out.LaunchNotificationGateway; import fnf.wp.online_store_backend.module.web.member.securedactions.redirectpages.FrontBaseUrlArgumentGateway; import fnf.wp.online_store_backend.mpush.enums.AlimtalkJobType; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.val; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service @Transactional(transactionManager = "headTransactionManager", readOnly = true) public class LaunchNotificationSendService implements LaunchNotificationSender { private final DateTimeProvider dateTimeProvider; private final LaunchGateway launchGateway; private final LaunchNotificationGateway launchNotificationGateway; private final FrontBaseUrlArgumentGateway frontBaseUrlArgumentGateway; private final MemberPort memberPort; private final MobilePushMessageNotifier pushMessageNotifier; @Override public void execute() { val nowDateTime = dateTimeProvider.now(); val launches = launchGateway.findAllByLaunchDateTime(nowDateTime); val notifications = launchNotificationGateway.findAllByLaunchIds( launches.stream().map(Launch::id).toList()); processLaunchNotification(notifications); } private void processLaunchNotification(@NonNull List<LaunchNotification> notifications) { val memberNos = notifications.stream().map(LaunchNotification::memberNo) .filter(Objects::nonNull).toList(); val memberNamesByMemberNos = memberPort.findMembers(memberNos) .stream() .collect(Collectors.toMap(Member::getMemberId, Member::getName)); notifications.stream().forEach(notification -> { val memberNo = notification.memberNo(); notify(notification, getMemberNo(memberNo), memberNamesByMemberNos.getOrDefault(memberNo, StringUtils.EMPTY)); } ); } private String getMemberNo(String memberNo) { if (memberNo == null) { // NMBR(NON-MEMBER): λΉ„νšŒμ› return "NMBR"; } return memberNo; } private void notify(@NonNull LaunchNotification notification, @NonNull String memberNo, @NonNull String memberName) { pushMessageNotifier.notify(createLaunchMessage( notification.launchesId(), memberNo, notification.getPhoneNumberWithoutHypen(), memberName, frontBaseUrlArgumentGateway.pc())); launchNotificationGateway.changeToComplete(notification.id()); } private Message createLaunchMessage(long launchesId, String memberNo, String phoneNo, String name, @NonNull String host) { val buttonLink = host + "/display/launches/detail/" + launchesId; return Message.builder() .mallId(MallId.DXM) .memberNo(memberNo) .phoneNumber(phoneNo) .talkManageNo(TalkManageNumberCode.DXM_LAUNCHES_GOODS_RECEIPT) .parameters(List.of(name, buttonLink)) .kakaoButtonLink1(buttonLink + "||" + buttonLink) .alimtalkJobType(AlimtalkJobType.SINGLE) .build(); } } ```