package com.pollex.pam.service;
|
|
import com.pollex.pam.config.ApplicationProperties;
|
import com.pollex.pam.domain.Appointment;
|
import com.pollex.pam.domain.AppointmentExpiringNotifyRecord;
|
import com.pollex.pam.domain.Consultant;
|
import com.pollex.pam.enums.AppointmentStatusEnum;
|
import com.pollex.pam.enums.ContactStatusEnum;
|
import com.pollex.pam.repository.AppointmentExpiringNotifyRecordRepository;
|
import com.pollex.pam.repository.AppointmentRepository;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
import org.thymeleaf.context.Context;
|
import org.thymeleaf.spring5.SpringTemplateEngine;
|
|
import java.time.Instant;
|
import java.time.LocalDate;
|
import java.time.ZoneId;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Optional;
|
import java.util.stream.Collectors;
|
|
@Service
|
public class ScheduleTaskService {
|
|
/**
|
* 電話及email在建立預約單(T)後的N天視為未處理預約單
|
* 目前N皆暫定為2
|
*/
|
private static final int APPOINTMENT_PENDING_PHONE_INTERVAL = 2;
|
private static final int APPOINTMENT_PENDING_EMAIL_INTERVAL = 2;
|
|
/**
|
* 電話及email在建立預約單(T)後的N天會被視為未處理預約單,當天批次會發送提醒給顧問
|
* 而在後一天(T+N+1),就會發送批次給客戶告知 該顧問可能忙碌無法處理,是否需要取消
|
*/
|
private static final int APPOINTMENT_EXPIRING_PHONE_INTERVAL = APPOINTMENT_PENDING_PHONE_INTERVAL + 1;
|
private static final int APPOINTMENT_EXPIRING_EMAIL_INTERVAL = APPOINTMENT_PENDING_EMAIL_INTERVAL + 1;
|
|
/**
|
* 通知客戶的次數限制
|
*/
|
private static final int SEND_EXPIRING_NOTIFY_LIMIT = 1;
|
|
private static final String NOT_CONTACTED_NOTIFY_SUBJECT = "預約單未進行聯繫通知";
|
private static final Logger log = LoggerFactory.getLogger(ScheduleTaskService.class);
|
|
@Autowired
|
ConsultantService consultantService;
|
|
@Autowired
|
AppointmentService appointmentService;
|
|
@Autowired
|
AppointmentRepository appointmentRepository;
|
|
@Autowired
|
SendMsgService sendMsgService;
|
|
@Autowired
|
SpringTemplateEngine springTemplateEngine;
|
|
@Autowired
|
ApplicationProperties applicationProperties;
|
|
@Autowired
|
AppointmentExpiringNotifyRecordRepository appointmentExpiringNotifyRecordRepository;
|
|
@Scheduled(cron = "0 30 8 * * *")
|
public void sendAppointmentPendingNotifyToConsultant() {
|
log.info("Starting send appointment pending notify to consultant");
|
|
Map<String, List<Appointment>> consultantWithPendingAppointments =
|
appointmentRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AppointmentStatusEnum.AVAILABLE)
|
.stream()
|
.filter(appointment -> isAppointmentInInterval(appointment, APPOINTMENT_PENDING_PHONE_INTERVAL, APPOINTMENT_PENDING_EMAIL_INTERVAL))
|
.collect(Collectors.groupingBy(Appointment::getAgentNo));
|
|
consultantWithPendingAppointments.forEach((agentNo, pendingAppointments) -> {
|
int pendingAppointmentsSum = pendingAppointments.size();
|
Consultant consultant = consultantService.findByAgentNo(agentNo);
|
String consultantPhoneNumber = consultant.getPhoneNumber();
|
String consultantEmail = consultant.getEmail();
|
String emailContent = getAppointmentPendingNotifyEmailContent(pendingAppointmentsSum);
|
|
sendMsgService.sendMsgBySMS(consultantPhoneNumber, String.format("您有%s則預約單未進行聯繫,請盡速處理", pendingAppointmentsSum));
|
sendMsgService.sendMsgByEmail(consultantEmail, NOT_CONTACTED_NOTIFY_SUBJECT, emailContent, true);
|
});
|
|
log.info("Sending appointment pending notify to consultant finish");
|
}
|
|
@Scheduled(cron = "0 30 8 * * *")
|
public void sendAppointmentExpiringNotifyToCustomer() {
|
log.info("Starting send appointment expiring notify to customer");
|
|
List<Appointment> allByCommunicateStatus =
|
appointmentRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AppointmentStatusEnum.AVAILABLE)
|
.stream()
|
.filter(appointment -> isAppointmentInInterval(appointment, APPOINTMENT_EXPIRING_PHONE_INTERVAL, APPOINTMENT_EXPIRING_EMAIL_INTERVAL))
|
.filter(this::isAppointmentNotifyNotOnLimit)
|
.collect(Collectors.toList());
|
|
allByCommunicateStatus.forEach(appointment -> {
|
Consultant consultant = consultantService.findByAgentNo(appointment.getAgentNo());
|
Optional<String> optionalPhone = Optional.ofNullable(appointment.getPhone()).filter(StringUtils::hasText);
|
Optional<String> optionalEmail = Optional.ofNullable(appointment.getEmail()).filter(StringUtils::hasText);
|
|
optionalPhone.ifPresent(phone ->
|
sendMsgService.sendMsgBySMS(phone, String.format("很抱歉!您預約%s顧問正忙碌中,請您取消預約並改選其他顧問,請點擊網址:%s"
|
, consultant.getName(), getAppointmentUrl(appointment.getId())))
|
);
|
optionalEmail.ifPresent(email ->
|
sendMsgService.sendMsgByEmail(email, NOT_CONTACTED_NOTIFY_SUBJECT, getAppointmentExpiringNotifyEmail(consultant.getName(), getAppointmentUrl(appointment.getId())), true)
|
);
|
|
AppointmentExpiringNotifyRecord record = new AppointmentExpiringNotifyRecord();
|
record.setAppointmentId(appointment.getId());
|
record.setSendTime(Instant.now());
|
|
appointmentExpiringNotifyRecordRepository.save(record);
|
});
|
|
log.info("Sending appointment expiring notify to customer finish");
|
}
|
|
private boolean isAppointmentInInterval(Appointment appointment, int phoneInterval, int emailInterval) {
|
final boolean isHavePhone = StringUtils.hasText(appointment.getPhone());
|
final boolean isHaveEmail = StringUtils.hasText(appointment.getEmail());
|
|
LocalDate appointmentDate = appointment.getAppointmentDate().atZone(ZoneId.systemDefault()).toLocalDate();
|
LocalDate nowDate = Instant.now().atZone(ZoneId.systemDefault()).toLocalDate();
|
long intervalDays = nowDate.toEpochDay() - appointmentDate.toEpochDay();
|
|
final boolean isAppointmentExpiringByPhone = isHavePhone && intervalDays >= phoneInterval;
|
final boolean isAppointmentExpiringByEmail = isHaveEmail && intervalDays >= emailInterval;
|
|
return isAppointmentExpiringByPhone || isAppointmentExpiringByEmail;
|
}
|
|
private boolean isAppointmentNotifyNotOnLimit(Appointment appointment) {
|
int sendNotifyToCustomerRecordSum =
|
appointmentExpiringNotifyRecordRepository.findAllByAppointmentId(appointment.getId()).size();
|
|
return sendNotifyToCustomerRecordSum < SEND_EXPIRING_NOTIFY_LIMIT;
|
}
|
|
private String getAppointmentUrl(Long appointmentId) {
|
return applicationProperties.getFrontEndDomain() + "?notContactAppointmentId=" + appointmentId;
|
}
|
|
private String getAppointmentPendingNotifyEmailContent(int sum) {
|
Context context = new Context();
|
context.setVariable("pendingAppointmentSum", sum);
|
return springTemplateEngine.process("mail/appointmentPendingNotifyEmail", context);
|
}
|
|
private String getAppointmentExpiringNotifyEmail(String consultantName, String notifyUrl) {
|
Context context = new Context();
|
context.setVariable("consultantName", consultantName);
|
context.setVariable("notifyUrl", notifyUrl);
|
return springTemplateEngine.process("mail/appointmentExpiringNotifyEmail", context);
|
}
|
}
|