diff --git a/core/src/main/java/greencity/UbsApplication.java b/core/src/main/java/greencity/UbsApplication.java index a11c89a80..b442acf78 100644 --- a/core/src/main/java/greencity/UbsApplication.java +++ b/core/src/main/java/greencity/UbsApplication.java @@ -5,11 +5,13 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableFeignClients @EnableCaching +@EnableAsync public class UbsApplication { /** * Main method of SpringBoot app. diff --git a/dao/src/main/java/greencity/entity/notifications/UserNotification.java b/dao/src/main/java/greencity/entity/notifications/UserNotification.java index 96b973cd8..b3c7753d9 100644 --- a/dao/src/main/java/greencity/entity/notifications/UserNotification.java +++ b/dao/src/main/java/greencity/entity/notifications/UserNotification.java @@ -20,6 +20,7 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.Builder; import org.hibernate.annotations.Cascade; import java.time.LocalDateTime; import java.time.ZoneId; @@ -33,6 +34,7 @@ @Entity @NoArgsConstructor @AllArgsConstructor +@Builder @Table(name = "user_notifications") public class UserNotification { @Id diff --git a/service-api/src/main/java/greencity/service/ubs/NotificationService.java b/service-api/src/main/java/greencity/service/ubs/NotificationService.java index d131142cd..07b0d83a9 100644 --- a/service-api/src/main/java/greencity/service/ubs/NotificationService.java +++ b/service-api/src/main/java/greencity/service/ubs/NotificationService.java @@ -233,4 +233,15 @@ PageableDto getAllNotificationsForUser(String userUuid, * @author Roman Kasarab */ void deleteNotification(Long notificationId, String userUuid); + + /** + * Notify user that order has unpaid status when it was created and not paid. + * This method is used one time when user create new order. + * + * @param order the order to send notification for + * @param sumToPay the sum to pay + * + * @author Vladyslav Haliara + */ + void notifyUnpaidOrderPermanently(Order order, Long sumToPay); } diff --git a/service-api/src/main/java/greencity/service/ubs/UBSClientService.java b/service-api/src/main/java/greencity/service/ubs/UBSClientService.java index cb36a1e86..75c6503ad 100644 --- a/service-api/src/main/java/greencity/service/ubs/UBSClientService.java +++ b/service-api/src/main/java/greencity/service/ubs/UBSClientService.java @@ -3,7 +3,16 @@ import greencity.dto.CreateAddressRequestDto; import greencity.dto.LocationsDto; import greencity.dto.TariffInfoByLocationDto; +import greencity.dto.order.EventDto; +import greencity.dto.order.OrderAddressDtoRequest; import greencity.dto.order.OrderAddressExportDetailsDtoUpdate; +import greencity.dto.order.OrderCancellationReasonDto; +import greencity.dto.order.OrderPaymentDetailDto; +import greencity.dto.order.OrderResponseDto; +import greencity.dto.order.OrderWayForPayClientDto; +import greencity.dto.order.OrderWithAddressesResponseDto; +import greencity.dto.order.OrdersDataForUserDto; +import greencity.dto.order.PaymentSystemResponse; import greencity.dto.payment.PaymentResponseDto; import greencity.dto.payment.monobank.MonoBankPaymentResponseDto; import greencity.dto.user.DeactivateUserRequestDto; @@ -16,15 +25,6 @@ import greencity.dto.customer.UbsCustomersDtoUpdate; import greencity.dto.employee.UserEmployeeAuthorityDto; import greencity.dto.location.api.DistrictDto; -import greencity.dto.order.EventDto; -import greencity.dto.order.PaymentSystemResponse; -import greencity.dto.order.OrderAddressDtoRequest; -import greencity.dto.order.OrderCancellationReasonDto; -import greencity.dto.order.OrderPaymentDetailDto; -import greencity.dto.order.OrderResponseDto; -import greencity.dto.order.OrderWayForPayClientDto; -import greencity.dto.order.OrderWithAddressesResponseDto; -import greencity.dto.order.OrdersDataForUserDto; import greencity.dto.pageble.PageableDto; import greencity.dto.payment.PaymentWayForPayRequestDto; import greencity.dto.payment.PaymentResponseWayForPay; diff --git a/service/src/main/java/greencity/service/notification/NotificationServiceImpl.java b/service/src/main/java/greencity/service/notification/NotificationServiceImpl.java index 93cfa9a55..9c7dcac6f 100644 --- a/service/src/main/java/greencity/service/notification/NotificationServiceImpl.java +++ b/service/src/main/java/greencity/service/notification/NotificationServiceImpl.java @@ -109,6 +109,7 @@ public class NotificationServiceImpl implements NotificationService { private static final int MAX_NOTIFICATION_ORDER_AGE_MONTHS = 1; private static final int MIN_NOTIFICATION_ORDER_AGE_DAYS = 3; private static final int MAX_NOTIFICATIONS_PER_WEEK = 1; + private static final double PERCENTAGE_DIVISOR = 100.0; private final OrderBagService orderBagService; @@ -787,6 +788,16 @@ public void deleteNotification(Long notificationId, String userUuid) { userNotificationRepository.markAsDeletedUserNotificationByIdAndUserId(notificationId, userId); } + @Override + public void notifyUnpaidOrderPermanently(Order order, Long amountToPay) { + boolean isOrderPayed = order.getOrderPaymentStatus() == OrderPaymentStatus.PAID; + if (!isOrderPayed) { + Double amount = amountToPay.doubleValue() / PERCENTAGE_DIVISOR; + Set parameters = initialiseNotificationParametersForUnpaidOrder(order, amount); + fillAndSendNotification(parameters, order, NotificationType.UNPAID_ORDER); + } + } + private Set getNotificationParametersForNewOrder(Order order) { Set parameters = new HashSet<>(); parameters.add(NotificationParameter.builder() diff --git a/service/src/main/java/greencity/service/ubs/UBSClientServiceImpl.java b/service/src/main/java/greencity/service/ubs/UBSClientServiceImpl.java index b97f5992b..42581426f 100644 --- a/service/src/main/java/greencity/service/ubs/UBSClientServiceImpl.java +++ b/service/src/main/java/greencity/service/ubs/UBSClientServiceImpl.java @@ -130,6 +130,7 @@ import greencity.service.DistanceCalculationUtils; import greencity.service.google.GoogleApiService; import greencity.service.locations.LocationApiService; +import greencity.service.notification.NotificationServiceImpl; import greencity.service.phone.UAPhoneNumberUtil; import greencity.util.Bot; import greencity.util.EncryptionUtil; @@ -144,6 +145,7 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; @@ -261,6 +263,7 @@ public class UBSClientServiceImpl implements UBSClientService { private final CityRepository cityRepository; private final DistrictRepository districtRepository; private final MonoBankClient monoBankClient; + private final NotificationServiceImpl notificationServiceImpl; @Value("${greencity.bots.viber-bot-uri}") private String viberBotUri; @@ -573,6 +576,8 @@ public PaymentSystemResponse saveFullOrderToDB(OrderResponseDto dto, String uuid getOrder(dto, currentUser, bagsOrdered, sumToPayInCoins, order, orderCertificates, userData); eventService.save(OrderHistory.ORDER_FORMED, OrderHistory.CLIENT, order); + checkIfOrderIsNotPayedAndSendEmailAsync(order, sumToPayInCoins); + notificationService.notifyCreatedOrder(order); if (sumToPayInCoins <= 0 || !dto.isShouldBePaid()) { @@ -582,6 +587,11 @@ public PaymentSystemResponse saveFullOrderToDB(OrderResponseDto dto, String uuid return processPayment(dto, order, sumToPayInCoins, currentUser); } + @Async + public void checkIfOrderIsNotPayedAndSendEmailAsync(Order order, Long sumToPayInCoins) { + notificationServiceImpl.notifyUnpaidOrderPermanently(order, sumToPayInCoins); + } + private PaymentSystemResponse processPayment(OrderResponseDto dto, Order order, long sumToPayInCoins, User currentUser) { return switch (dto.getPaymentSystem()) { diff --git a/service/src/test/java/greencity/ModelUtils.java b/service/src/test/java/greencity/ModelUtils.java index c9c23d9c2..1a8978c1a 100644 --- a/service/src/test/java/greencity/ModelUtils.java +++ b/service/src/test/java/greencity/ModelUtils.java @@ -2813,6 +2813,54 @@ private static Set createNotificationParameterSet() { return parameters; } + private static User createTestUser() { + return User.builder().id(1L).build(); + } + + private static Order createTestUnpaidOrder() { + return Order.builder().id(1L).user(createTestUser()).build(); + } + + public static String getUnpaidOrderUrl() { + Order order = createTestUnpaidOrder(); + return "http://localhost:4200/#/ubs/order?existingOrderId=" + order.getId(); + } + + public static Set createNotificationParameterForUnpaidOrder() { + double amountToPay = 10000.0; + Order order = createTestUnpaidOrder(); + String orderUrl = getUnpaidOrderUrl(); + Set notificationParameters = new HashSet<>(); + notificationParameters.add(NotificationParameter.builder() + .key("orderNumber") + .value(order.getId().toString()) + .build()); + + notificationParameters.add(NotificationParameter.builder() + .key("amountToPay") + .value(String.format("%.2f", amountToPay)) + .build()); + + notificationParameters.add(NotificationParameter.builder() + .key("payButton") + .value(orderUrl) + .build()); + return notificationParameters; + } + + public static UserNotification getUserNotificationForUnpaidOrder() { + User user = createTestUser(); + Order order = createTestUnpaidOrder(); + return UserNotification.builder() + .id(1L) + .user(user) + .order(order) + .notificationType(NotificationType.UNPAID_ORDER) + .notificationTime(LocalDateTime.now(fixedClock)) + .parameters(createNotificationParameterForUnpaidOrder()) + .build(); + } + private static Set createNotificationParameterSet2() { Set parameters = new HashSet<>(); diff --git a/service/src/test/java/greencity/service/notification/NotificationServiceImplTest.java b/service/src/test/java/greencity/service/notification/NotificationServiceImplTest.java index bf0309d34..f42144e8b 100644 --- a/service/src/test/java/greencity/service/notification/NotificationServiceImplTest.java +++ b/service/src/test/java/greencity/service/notification/NotificationServiceImplTest.java @@ -41,11 +41,8 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import java.time.Clock; @@ -85,6 +82,8 @@ import static greencity.ModelUtils.TEST_USER_NOTIFICATION_6; import static greencity.ModelUtils.TEST_USER_NOTIFICATION_7; import static greencity.ModelUtils.TEST_VIOLATION; +import static greencity.ModelUtils.getUnpaidOrderUrl; +import static greencity.ModelUtils.getNotifyInternallyFormedOrder; import static greencity.ModelUtils.createUserNotificationForViolationWithParameters; import static greencity.ModelUtils.createViolationNotificationDto; import static greencity.ModelUtils.getBag1list; @@ -92,13 +91,16 @@ import static greencity.ModelUtils.getActiveCertificateWith10Points; import static greencity.ModelUtils.getUser; import static greencity.ModelUtils.getViolation; -import static greencity.ModelUtils.getNotifyInternallyFormedOrder; import static greencity.enums.NotificationReceiverType.SITE; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; @@ -151,6 +153,12 @@ class NotificationServiceImplTest { @Mock private ExecutorService executorService; + @Mock + private Order mockOrder; + + @Mock + private UserNotification mockUserNotification; + @Spy @InjectMocks private NotificationServiceImpl notificationService; @@ -269,6 +277,26 @@ void notifyPaidOrder() { verify(notificationParameterRepository).saveAll(Set.of(orderNumber)); } + @Test + void notifyUnpaidOrderPermanentlyTest() { + String orderUrl = getUnpaidOrderUrl(); + + Double amountToPay = 10000.0; + when(mockOrder.getOrderPaymentStatus()).thenReturn(OrderPaymentStatus.UNPAID); + when(mockUserNotification.getOrder()).thenReturn(mockOrder); + when(internalUrlConfigProp.getOrderUrl()).thenReturn(orderUrl); + when(userNotificationRepository.save(any(UserNotification.class))).thenReturn(mockUserNotification); + when(notificationParameterRepository.saveAll(any())).thenAnswer(invocation -> { + return new ArrayList<>(invocation.getArgument(0)); + }); + + assertDoesNotThrow(() -> notificationService.notifyUnpaidOrderPermanently(mockUserNotification.getOrder(), + amountToPay.longValue())); + + verify(userNotificationRepository).save(any(UserNotification.class)); + verify(notificationParameterRepository).saveAll(any()); + } + @Test void testNotifyCourierItineraryFormed() { Order order = getNotifyInternallyFormedOrder(); @@ -789,7 +817,7 @@ void testNotifyCustom() { @Test void testNotifyInactiveAccounts() { AbstractNotificationProvider abstractNotificationProvider = - Mockito.mock(AbstractNotificationProvider.class); + mock(AbstractNotificationProvider.class); NotificationServiceImpl notificationService1 = new NotificationServiceImpl( userRepository, userNotificationRepository, diff --git a/service/src/test/java/greencity/service/ubs/UBSClientServiceImplTest.java b/service/src/test/java/greencity/service/ubs/UBSClientServiceImplTest.java index 1e1d9ce27..8a0d02777 100644 --- a/service/src/test/java/greencity/service/ubs/UBSClientServiceImplTest.java +++ b/service/src/test/java/greencity/service/ubs/UBSClientServiceImplTest.java @@ -106,6 +106,7 @@ import greencity.repository.ViberBotRepository; import greencity.service.google.GoogleApiService; import greencity.service.locations.LocationApiService; +import greencity.service.notification.NotificationServiceImpl; import greencity.util.Bot; import greencity.util.EncryptionUtil; import greencity.util.OrderUtils; @@ -393,6 +394,9 @@ class UBSClientServiceImplTest { @Mock private OrderUtils orderUtils; + @Mock + private NotificationServiceImpl notificationServiceImpl; + @Value("${greencity.monobank.token}") private String token;