[update] [todo 134622, 134623] 顧問/客戶 未處理預約單平台通知
¤ñ¹ï·sÀÉ®× |
| | |
| | | http get : |
| | | |
| | | http://localhost:8080/api/appointment/customer/expiring/newest |
| | | |
| | | ç°¡è¨åemailæä»¥è©²ç¶²åé²å
¥é¦é -> http://localhost:3000?notContactAppointmentId={ææ°ä¸çæªèçé ç´å®} |
| | | |
| | | response body: è¥ææå³200並給以ä¸è³æï¼è¥ç¡(æªæä»»ä½é¾ææªèçé ç´å®ï¼åæå404) |
| | | { |
| | | "id": 385, |
| | | "phone": "0911223344", |
| | | "email": "SDD", |
| | | "contactType": "phone", |
| | | "gender": "female", |
| | | "age": "21-30", |
| | | "job": "å
§å¤", |
| | | "requirement": "å¥åº·èä¿é", |
| | | "communicateStatus": "done", |
| | | "hopeContactTime": "'ææä¸,ææäº,ææä¸,ææå,ææäº,ææå
,æææ¥ã9:00~12:00,12:00~14:00,14:00~18:00,18:00~21:00'", |
| | | "otherRequirement": null, |
| | | "appointmentDate": "2021-12-16T07:11:05.400Z", |
| | | "lastModifiedDate": "2022-01-19T10:57:51.380Z", |
| | | "agentNo": "A568420", |
| | | "customerId": 139, |
| | | "name": "Angula-test", |
| | | "consultantViewTime": "2021-12-27T02:02:18.711Z", |
| | | "consultantReadTime": "2021-12-28T07:16:01.295Z", |
| | | "contactTime": "2021-12-28T07:16:37.004Z", |
| | | "satisfactionScore": null, |
| | | "appointmentMemoList": [], |
| | | "interviewRecordDTOs": [], |
| | | "appointmentNoticeLogs": [ |
| | | { |
| | | "id": 4, |
| | | "phone": "0912345678", |
| | | "email": "pollex@gmail.com", |
| | | "appointmentId": 385, |
| | | "content": "notice customer invterview time", |
| | | "createdDate": "2022-01-11T09:33:57.754Z", |
| | | "interviewDate": null |
| | | }, |
| | | { |
| | | "id": 6, |
| | | "phone": "0912345678", |
| | | "email": "pollex@gmail.com", |
| | | "appointmentId": 385, |
| | | "content": "notice customer invterview time", |
| | | "createdDate": "2022-01-19T10:38:42.187Z", |
| | | "interviewDate": "2022-11-01T08:00:00.000+00:00" |
| | | } |
| | | ], |
| | | "appointmentClosedInfo": { |
| | | "id": 9, |
| | | "policyholderIdentityId": "A123456789", |
| | | "planCode": "ATMdd", |
| | | "policyEntryDate": "2022-01-12T00:00:00.000+00:00", |
| | | "remark": "test remark", |
| | | "closedReason": "other2", |
| | | "closedOtherReason": "å¿æ
ä¸å¥½ä¸æ³è²·2", |
| | | "appointmentId": 385 |
| | | } |
| | | } |
| | |
| | | |
| | | response body: |
| | | { |
| | | "id": 401, |
| | | "phone": "0912345678", |
| | | "email": "wayne@pollex.com.tw", |
| | | "contactType": "EMAIL", |
| | | "gender": "male", |
| | | "age": "under_20", |
| | | "job": "123", |
| | | "requirement": "å¥åº·èä¿é,ä¿å®å¥æª¢/è¦å", |
| | | "communicateStatus": "contacted", |
| | | "id": 385, |
| | | "phone": "0911223344", |
| | | "email": "SDD", |
| | | "contactType": "phone", |
| | | "gender": "female", |
| | | "age": "21-30", |
| | | "job": "å
§å¤", |
| | | "requirement": "å¥åº·èä¿é", |
| | | "communicateStatus": "done", |
| | | "hopeContactTime": "'ææä¸,ææäº,ææä¸,ææå,ææäº,ææå
,æææ¥ã9:00~12:00,12:00~14:00,14:00~18:00,18:00~21:00'", |
| | | "otherRequirement": null, |
| | | "appointmentDate": "2021-12-21T08:13:50.154Z", |
| | | "lastModifiedDate": "2022-01-04T09:40:13.715Z", |
| | | "agentNo": "J149388015", |
| | | "customerId": 155, |
| | | "name": "123", |
| | | "consultantViewTime": "2021-12-24T07:27:48.681Z", |
| | | "consultantReadTime": null, |
| | | "contactTime": "2022-01-04T09:40:13.715Z", |
| | | "appointmentDate": "2021-12-16T07:11:05.400Z", |
| | | "lastModifiedDate": "2022-01-19T10:57:51.380Z", |
| | | "agentNo": "A568420", |
| | | "customerId": 139, |
| | | "name": "Angula-test", |
| | | "consultantViewTime": "2021-12-27T02:02:18.711Z", |
| | | "consultantReadTime": "2021-12-28T07:16:01.295Z", |
| | | "contactTime": "2021-12-28T07:16:37.004Z", |
| | | "satisfactionScore": null, |
| | | "appointmentMemoList": [] |
| | | "appointmentMemoList": [], |
| | | "interviewRecordDTOs": [], |
| | | "appointmentNoticeLogs": [ |
| | | { |
| | | "id": 4, |
| | | "phone": "0912345678", |
| | | "email": "pollex@gmail.com", |
| | | "appointmentId": 385, |
| | | "content": "notice customer invterview time", |
| | | "createdDate": "2022-01-11T09:33:57.754Z", |
| | | "interviewDate": null |
| | | }, |
| | | { |
| | | "id": 6, |
| | | "phone": "0912345678", |
| | | "email": "pollex@gmail.com", |
| | | "appointmentId": 385, |
| | | "content": "notice customer invterview time", |
| | | "createdDate": "2022-01-19T10:38:42.187Z", |
| | | "interviewDate": "2022-11-01T08:00:00.000+00:00" |
| | | } |
| | | ], |
| | | "appointmentClosedInfo": { |
| | | "id": 9, |
| | | "policyholderIdentityId": "A123456789", |
| | | "planCode": "ATMdd", |
| | | "policyEntryDate": "2022-01-12T00:00:00.000+00:00", |
| | | "remark": "test remark", |
| | | "closedReason": "other2", |
| | | "closedOtherReason": "å¿æ
ä¸å¥½ä¸æ³è²·2", |
| | | "appointmentId": 385 |
| | | } |
| | | } |
| | |
| | | appointmentMemoList : åè¨»è³æ |
| | | interviewRecordDTOs : ç´è¨ªç´é |
| | | |
| | | [ { |
| | | "id" : 385, |
| | | "phone" : "0911223344", |
| | | "email" : "SDD", |
| | | "contactType" : "phone", |
| | | "gender" : "female", |
| | | "age" : "21-30", |
| | | "job" : "å
§å¤", |
| | | "requirement" : "å¥åº·èä¿é", |
| | | "communicateStatus" : "contacted", |
| | | "hopeContactTime" : "'ææä¸,ææäº,ææä¸,ææå,ææäº,ææå
,æææ¥ã9:00~12:00,12:00~14:00,14:00~18:00,18:00~21:00'", |
| | | "otherRequirement" : null, |
| | | "appointmentDate" : "2021-12-16T07:11:05.400Z", |
| | | "lastModifiedDate" : "2021-12-28T07:16:37.004Z", |
| | | "agentNo" : "A568420", |
| | | "customerId" : 139, |
| | | "name" : "Angula-test", |
| | | "consultantViewTime" : "2021-12-27T02:02:18.711Z", |
| | | "consultantReadTime" : "2021-12-28T07:16:01.295Z", |
| | | "contactTime" : "2021-12-28T07:16:37.004Z", |
| | | "satisfactionScore" : null, |
| | | "appointmentMemoList" : [ ], |
| | | "interviewRecordDTOs" : [ { |
| | | "id" : 6, |
| | | "content" : "test record content", |
| | | "createdDate" : "2022-01-07T07:38:05.976Z", |
| | | "lastModifiedDate" : "2022-01-07T07:38:05.976Z", |
| | | "createdBy" : "A568420", |
| | | "lastModifiedBy" : "A568420", |
| | | "interviewDate" : "2021-01-01T08:00:00.000+00:00", |
| | | "appointmentId" : 385 |
| | | } ] |
| | | } ] |
| | | [ |
| | | { |
| | | "id": 385, |
| | | "phone": "0911223344", |
| | | "email": "SDD", |
| | | "contactType": "phone", |
| | | "gender": "female", |
| | | "age": "21-30", |
| | | "job": "å
§å¤", |
| | | "requirement": "å¥åº·èä¿é", |
| | | "communicateStatus": "done", |
| | | "hopeContactTime": "'ææä¸,ææäº,ææä¸,ææå,ææäº,ææå
,æææ¥ã9:00~12:00,12:00~14:00,14:00~18:00,18:00~21:00'", |
| | | "otherRequirement": null, |
| | | "appointmentDate": "2021-12-16T07:11:05.400Z", |
| | | "lastModifiedDate": "2022-01-19T10:57:51.380Z", |
| | | "agentNo": "A568420", |
| | | "customerId": 139, |
| | | "name": "Angula-test", |
| | | "consultantViewTime": "2021-12-27T02:02:18.711Z", |
| | | "consultantReadTime": "2021-12-28T07:16:01.295Z", |
| | | "contactTime": "2021-12-28T07:16:37.004Z", |
| | | "satisfactionScore": null, |
| | | "appointmentMemoList": [], |
| | | "interviewRecordDTOs": [], |
| | | "appointmentNoticeLogs": [ |
| | | { |
| | | "id": 4, |
| | | "phone": "0912345678", |
| | | "email": "pollex@gmail.com", |
| | | "appointmentId": 385, |
| | | "content": "notice customer invterview time", |
| | | "createdDate": "2022-01-11T09:33:57.754Z", |
| | | "interviewDate": null |
| | | }, |
| | | { |
| | | "id": 6, |
| | | "phone": "0912345678", |
| | | "email": "pollex@gmail.com", |
| | | "appointmentId": 385, |
| | | "content": "notice customer invterview time", |
| | | "createdDate": "2022-01-19T10:38:42.187Z", |
| | | "interviewDate": "2022-11-01T08:00:00.000+00:00" |
| | | } |
| | | ], |
| | | "appointmentClosedInfo": { |
| | | "id": 9, |
| | | "policyholderIdentityId": "A123456789", |
| | | "planCode": "ATMdd", |
| | | "policyEntryDate": "2022-01-12T00:00:00.000+00:00", |
| | | "remark": "test remark", |
| | | "closedReason": "other2", |
| | | "closedOtherReason": "å¿æ
ä¸å¥½ä¸æ³è²·2", |
| | | "appointmentId": 385 |
| | | } |
| | | } |
| | | ] |
¤ñ¹ï·sÀÉ®× |
| | |
| | | http get : |
| | | http://localhost:8080/api/appointment/consultant/pending/sum |
| | | |
| | | response body: |
| | | 2 |
| | |
| | | public static final String SYSTEM = "system"; |
| | | public static final String DEFAULT_LANGUAGE = "zh-tw"; |
| | | |
| | | /** |
| | | * é»è©±åemailå¨å»ºç«é ç´å®(T)å¾çN天è¦çºæªèçé ç´å® |
| | | * ç®åNçæ«å®çº2 |
| | | */ |
| | | public static final int APPOINTMENT_PENDING_PHONE_INTERVAL = 2; |
| | | public static final int APPOINTMENT_PENDING_EMAIL_INTERVAL = 2; |
| | | |
| | | /** |
| | | * é»è©±åemailå¨å»ºç«é ç´å®(T)å¾çN天æè¢«è¦çºæªèçé ç´å®ï¼ç¶å¤©æ¹æ¬¡æç¼éæé給顧å |
| | | * èå¨å¾ä¸å¤©(T+N+1)ï¼å°±æç¼éæ¹æ¬¡çµ¦å®¢æ¶åç¥ è©²é¡§åå¯è½å¿ç¢ç¡æ³èçï¼æ¯å¦éè¦åæ¶ |
| | | */ |
| | | public static final int APPOINTMENT_EXPIRING_PHONE_INTERVAL = APPOINTMENT_PENDING_PHONE_INTERVAL + 1; |
| | | public static final int APPOINTMENT_EXPIRING_EMAIL_INTERVAL = APPOINTMENT_PENDING_EMAIL_INTERVAL + 1; |
| | | |
| | | /** |
| | | * éç¥å®¢æ¶ç次æ¸éå¶ |
| | | */ |
| | | public static final int SEND_EXPIRING_NOTIFY_LIMIT = 1; |
| | | |
| | | private Constants() {} |
| | | } |
| | |
| | | |
| | | import java.util.List; |
| | | |
| | | import com.pollex.pam.domain.Appointment; |
| | | import com.pollex.pam.enums.AppointmentStatusEnum; |
| | | import com.pollex.pam.enums.ContactStatusEnum; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | |
| | | public interface AppointmentCustomerViewRepository extends JpaRepository<AppointmentCustomerView, Long>{ |
| | | List<AppointmentCustomerView> findByAgentNo(String agentNo); |
| | | List<AppointmentCustomerView> findByAgentNoAndCustomerId(String agentNo, Long customerId); |
| | | List<AppointmentCustomerView> findAllByCommunicateStatusAndStatus(ContactStatusEnum contactStatus, AppointmentStatusEnum status); |
| | | } |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | import java.time.Instant; |
| | | import java.time.LocalDate; |
| | | import java.time.ZoneId; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.Optional; |
| | |
| | | |
| | | import com.pollex.pam.appointment.process.AppointmentProcess; |
| | | import com.pollex.pam.config.ApplicationProperties; |
| | | import com.pollex.pam.service.dto.AppointmentUpdateDTO; |
| | | import com.pollex.pam.service.dto.ClosedProcessDTO; |
| | | import com.pollex.pam.service.dto.DoneProcessDTO; |
| | | import com.pollex.pam.service.dto.InterviewRecordDTO; |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.service.dto.*; |
| | | import com.pollex.pam.web.rest.errors.NotFoundExpiringAppointmentException; |
| | | import com.pollex.pam.web.rest.errors.SendEmailFailException; |
| | | import com.pollex.pam.web.rest.errors.SendSMSFailException; |
| | | import io.jsonwebtoken.lang.Assert; |
| | |
| | | |
| | | import com.pollex.pam.domain.Appointment; |
| | | import com.pollex.pam.domain.AppointmentCustomerView; |
| | | import com.pollex.pam.domain.InterviewRecord; |
| | | import com.pollex.pam.enums.ContactStatusEnum; |
| | | import com.pollex.pam.enums.InterviewRecordStatusEnum; |
| | | import com.pollex.pam.repository.AppointmentCustomerViewRepository; |
| | | import com.pollex.pam.repository.AppointmentRepository; |
| | | import com.pollex.pam.security.SecurityUtils; |
| | | import com.pollex.pam.service.dto.AppointmentCloseDTO; |
| | | import com.pollex.pam.service.dto.AppointmentCreateDTO; |
| | | import com.pollex.pam.service.dto.AppointmentCustomerViewDTO; |
| | | import com.pollex.pam.service.mapper.AppointmentCustomerViewMapper; |
| | | import com.pollex.pam.service.mapper.AppointmentDTOMapper; |
| | | import com.pollex.pam.web.rest.errors.AppointmentNotFoundException; |
| | |
| | | |
| | | @Autowired |
| | | SpringTemplateEngine springTemplateEngine; |
| | | |
| | | |
| | | @Autowired |
| | | InterviewRecordService interviewRecordService; |
| | | |
| | | |
| | | @Autowired |
| | | AppointmentProcess abstractAppointmentProcess; |
| | | |
| | | |
| | | @Autowired |
| | | PersonalNotificationService personalNotificationService; |
| | | |
| | |
| | | appointment.setCommunicateStatus(ContactStatusEnum.CANCEL); |
| | | appointmentRepository.save(appointment); |
| | | personalNotificationService.createMarkAppointmentDeletedToConsultant(appointment); |
| | | |
| | | |
| | | } |
| | | |
| | | public List<Appointment> findByAgentNo(String agentNo) { |
| | |
| | | Assert.notNull(appointment, "appointment entity cannot be null"); |
| | | |
| | | log.debug("is need send appointment notify msg? = {}", applicationProperties.isSendNotifyMsg()); |
| | | |
| | | |
| | | log.debug("sending appointment notify, appointmentId = {}", appointment.getId()); |
| | | sendAppointmentNotifyBySMS(appointment); |
| | | sendAppointmentNotifyByHtmlEmail(appointment); |
| | |
| | | public String getAppointmentDetailUrl(Long appointmentId) { |
| | | return applicationProperties.getFrontEndDomain() + "/myAppointmentList/contactedList?appointmentId=" + appointmentId; |
| | | } |
| | | |
| | | |
| | | public Appointment findById(Long id) { |
| | | return appointmentRepository.findById(id) |
| | | .orElseThrow(AppointmentNotFoundException::new); |
| | |
| | | abstractAppointmentProcess.process(dto); |
| | | } |
| | | } |
| | | |
| | | public Long getConsultantPendingAppointmentSum(String agentNo) { |
| | | return appointmentCustomerViewRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AVAILABLE) |
| | | .stream() |
| | | .filter(appointment -> agentNo.equals(appointment.getAgentNo())) |
| | | .filter(appointment -> isAppointmentDateNotInIntervalFromNow(appointment, Constants.APPOINTMENT_PENDING_PHONE_INTERVAL, Constants.APPOINTMENT_PENDING_EMAIL_INTERVAL)) |
| | | .count(); |
| | | } |
| | | |
| | | public AppointmentCustomerViewDTO getCustomerNewestExpiringAppointment(Long customerId) { |
| | | return appointmentCustomerViewRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AVAILABLE) |
| | | .stream() |
| | | .filter(appointment -> customerId.equals(appointment.getCustomerId())) |
| | | .filter(appointment -> isAppointmentDateNotInIntervalFromNow(appointment, Constants.APPOINTMENT_EXPIRING_PHONE_INTERVAL, Constants.APPOINTMENT_EXPIRING_EMAIL_INTERVAL)) |
| | | .max(Comparator.comparing(AppointmentCustomerView::getAppointmentDate)) |
| | | .map(appointmentCustomerView -> appointmentCustomerViewMapper.toAppointmentCustomerViewDTO(appointmentCustomerView)) |
| | | .orElse(null); |
| | | } |
| | | |
| | | public boolean isAppointmentDateNotInIntervalFromNow(AppointmentCustomerView 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; |
| | | } |
| | | } |
| | |
| | | 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.domain.Satisfaction; |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.*; |
| | | import com.pollex.pam.enums.AppointmentStatusEnum; |
| | | import com.pollex.pam.enums.ContactStatusEnum; |
| | | import com.pollex.pam.enums.SatisfactionStatusEnum; |
| | | import com.pollex.pam.repository.AppointmentCustomerViewRepository; |
| | | 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.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; |
| | |
| | | @Service |
| | | @Transactional |
| | | 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); |
| | |
| | | AppointmentService appointmentService; |
| | | |
| | | @Autowired |
| | | AppointmentRepository appointmentRepository; |
| | | AppointmentCustomerViewRepository appointmentCustomerViewRepository; |
| | | |
| | | @Autowired |
| | | SendMsgService sendMsgService; |
| | |
| | | public void sendAppointmentPendingNotifyToConsultant() { |
| | | log.info("Starting send appointment pending notify to consultant"); |
| | | |
| | | Map<String, List<Appointment>> consultantWithPendingAppointments = |
| | | appointmentRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AppointmentStatusEnum.AVAILABLE) |
| | | Map<String, List<AppointmentCustomerView>> consultantWithPendingAppointments = |
| | | appointmentCustomerViewRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AppointmentStatusEnum.AVAILABLE) |
| | | .stream() |
| | | .filter(appointment -> isAppointmentInInterval(appointment, APPOINTMENT_PENDING_PHONE_INTERVAL, APPOINTMENT_PENDING_EMAIL_INTERVAL)) |
| | | .collect(Collectors.groupingBy(Appointment::getAgentNo)); |
| | | .filter(appointment -> |
| | | appointmentService.isAppointmentDateNotInIntervalFromNow(appointment, Constants.APPOINTMENT_PENDING_PHONE_INTERVAL, Constants.APPOINTMENT_PENDING_EMAIL_INTERVAL) |
| | | ) |
| | | .collect(Collectors.groupingBy(AppointmentCustomerView::getAgentNo)); |
| | | |
| | | consultantWithPendingAppointments.forEach((agentNo, pendingAppointments) -> { |
| | | int pendingAppointmentsSum = pendingAppointments.size(); |
| | |
| | | public void sendAppointmentExpiringNotifyToCustomer() { |
| | | log.info("Starting send appointment expiring notify to customer"); |
| | | |
| | | List<Appointment> allByCommunicateStatus = |
| | | appointmentRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AppointmentStatusEnum.AVAILABLE) |
| | | List<AppointmentCustomerView> allByCommunicateStatus = |
| | | appointmentCustomerViewRepository.findAllByCommunicateStatusAndStatus(ContactStatusEnum.RESERVED, AppointmentStatusEnum.AVAILABLE) |
| | | .stream() |
| | | .filter(appointment -> isAppointmentInInterval(appointment, APPOINTMENT_EXPIRING_PHONE_INTERVAL, APPOINTMENT_EXPIRING_EMAIL_INTERVAL)) |
| | | .filter(appointment -> |
| | | appointmentService.isAppointmentDateNotInIntervalFromNow(appointment, Constants.APPOINTMENT_EXPIRING_PHONE_INTERVAL, Constants.APPOINTMENT_EXPIRING_EMAIL_INTERVAL) |
| | | ) |
| | | .filter(this::isAppointmentNotifyNotOnLimit) |
| | | .collect(Collectors.toList()); |
| | | |
| | |
| | | ); |
| | | } |
| | | |
| | | 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) { |
| | | private boolean isAppointmentNotifyNotOnLimit(AppointmentCustomerView appointment) { |
| | | int sendNotifyToCustomerRecordSum = |
| | | appointmentExpiringNotifyRecordRepository.findAllByAppointmentId(appointment.getId()).size(); |
| | | |
| | | return sendNotifyToCustomerRecordSum < SEND_EXPIRING_NOTIFY_LIMIT; |
| | | return sendNotifyToCustomerRecordSum < Constants.SEND_EXPIRING_NOTIFY_LIMIT; |
| | | } |
| | | |
| | | private String getAppointmentUrl(Long appointmentId) { |
| | |
| | | |
| | | import com.pollex.pam.appointment.process.AppointmentProcess; |
| | | import com.pollex.pam.domain.Appointment; |
| | | import com.pollex.pam.enums.ContactStatusEnum; |
| | | import com.pollex.pam.security.SecurityUtils; |
| | | import com.pollex.pam.service.SendMsgService; |
| | | import com.pollex.pam.service.dto.AppointmentUpdateDTO; |
| | | import com.pollex.pam.service.dto.ClosedProcessDTO; |
| | | import com.pollex.pam.service.dto.DoneProcessDTO; |
| | | |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import com.pollex.pam.service.AppointmentService; |
| | |
| | | import com.pollex.pam.service.dto.AppointmentCloseDTO; |
| | | import com.pollex.pam.service.dto.AppointmentCreateDTO; |
| | | import com.pollex.pam.service.dto.AppointmentCustomerViewDTO; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | @RestController |
| | | @RequestMapping("/api/appointment") |
| | |
| | | |
| | | @Autowired |
| | | SendMsgService sendMsgService; |
| | | |
| | | |
| | | @Autowired |
| | | AppointmentProcess abstractAppointmentProcess; |
| | | |
| | | |
| | | @Autowired |
| | | PersonalNotificationService personalNotificationService; |
| | | |
| | |
| | | appointmentService.recordConsultantReadTime(appointmentId); |
| | | return ResponseEntity.noContent().build(); |
| | | } |
| | | |
| | | |
| | | @PostMapping("/close") |
| | | public ResponseEntity<Void> closeAppointment(@RequestBody AppointmentCloseDTO closeDTO) { |
| | | appointmentService.closeAppointment(closeDTO); |
| | | return ResponseEntity.noContent().build(); |
| | | } |
| | | |
| | | |
| | | @GetMapping("/customer/expiring/newest") |
| | | public ResponseEntity<AppointmentCustomerViewDTO> getNewestExpiringAppointment() { |
| | | Long customerId = SecurityUtils.getCustomerDBId(); |
| | | AppointmentCustomerViewDTO customerNewestExpiringAppointment = appointmentService.getCustomerNewestExpiringAppointment(customerId); |
| | | |
| | | if(Objects.nonNull(customerNewestExpiringAppointment)) { |
| | | return new ResponseEntity<>(customerNewestExpiringAppointment, HttpStatus.OK); |
| | | } |
| | | else { |
| | | return new ResponseEntity<>(HttpStatus.NOT_FOUND); |
| | | } |
| | | } |
| | | |
| | | @GetMapping("/consultant/pending/sum") |
| | | public ResponseEntity<Long> getConsultantPendingAppointmentSum() { |
| | | String agentNo = SecurityUtils.getAgentNo(); |
| | | return new ResponseEntity<>(appointmentService.getConsultantPendingAppointmentSum(agentNo), HttpStatus.OK); |
| | | } |
| | | |
| | | // @PostMapping("/close/info/edit") |
| | | // public ResponseEntity<Void> editAppointmentClosedInfo(@RequestBody AppointmentCloseDTO closeDTO) { |
| | | // |
| | | // |
| | | // if(closeDTO.getContactStatus() == ContactStatusEnum.DONE) { |
| | | // DoneProcessDTO dto = new DoneProcessDTO(); |
| | | // BeanUtils.copyProperties(closeDTO, dto); |
| | |
| | | // }else { |
| | | // return ResponseEntity.notFound().build(); |
| | | // } |
| | | // |
| | | // |
| | | // return ResponseEntity.noContent().build(); |
| | | // } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.web.bind.annotation.ResponseStatus; |
| | | |
| | | @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "not found any expiring appointment") |
| | | public class NotFoundExpiringAppointmentException extends RuntimeException { |
| | | } |
| | |
| | | datasource: |
| | | type: com.zaxxer.hikari.HikariDataSource |
| | | url: jdbc:postgresql://dev.pollex.com.tw:5433/pam_p2 |
| | | #url: jdbc:postgresql://localhost:5432/omo?currentSchema=omo |
| | | #url: jdbc:postgresql://localhost:5432/omo?currentSchema=public |
| | | username: pamadmin |
| | | password: pamadmin |
| | | hikari: |