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