Skip to content

Commit

Permalink
7873 Send a message with a link to the order by email when the order …
Browse files Browse the repository at this point in the history
…status is 'unpaid' (#1549)

* Added email notification for unpaid orders sent immediately after order creation

* fix(email): update logic to ensure proper email sending

* fix(test): update tests to align with new logic

* fix: incorrect value scaling for sumToPay

* fix(checkstyle): fixed the issue in the code

* Make @async method public

* test: Add test for notifying unpaid orders

* Fix issue

* Corrected imports

* Refactor: Update order notification mechanism for unpaid orders and update tests

* Fix issue

* Remove unused imports and refactor notification logic.
  • Loading branch information
Cr1stal423 authored Dec 13, 2024
1 parent 64d0c8a commit b77236c
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 14 deletions.
2 changes: 2 additions & 0 deletions core/src/main/java/greencity/UbsApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,6 +34,7 @@
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "user_notifications")
public class UserNotification {
@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,15 @@ PageableDto<NotificationShortDto> 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<NotificationParameter> parameters = initialiseNotificationParametersForUnpaidOrder(order, amount);
fillAndSendNotification(parameters, order, NotificationType.UNPAID_ORDER);
}
}

private Set<NotificationParameter> getNotificationParametersForNewOrder(Order order) {
Set<NotificationParameter> parameters = new HashSet<>();
parameters.add(NotificationParameter.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()) {
Expand All @@ -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()) {
Expand Down
48 changes: 48 additions & 0 deletions service/src/test/java/greencity/ModelUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2813,6 +2813,54 @@ private static Set<NotificationParameter> 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<NotificationParameter> createNotificationParameterForUnpaidOrder() {
double amountToPay = 10000.0;
Order order = createTestUnpaidOrder();
String orderUrl = getUnpaidOrderUrl();
Set<NotificationParameter> 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<NotificationParameter> createNotificationParameterSet2() {
Set<NotificationParameter> parameters = new HashSet<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,20 +82,25 @@
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;
import static greencity.ModelUtils.getBag4list;
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;
Expand Down Expand Up @@ -151,6 +153,12 @@ class NotificationServiceImplTest {
@Mock
private ExecutorService executorService;

@Mock
private Order mockOrder;

@Mock
private UserNotification mockUserNotification;

@Spy
@InjectMocks
private NotificationServiceImpl notificationService;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -789,7 +817,7 @@ void testNotifyCustom() {
@Test
void testNotifyInactiveAccounts() {
AbstractNotificationProvider abstractNotificationProvider =
Mockito.mock(AbstractNotificationProvider.class);
mock(AbstractNotificationProvider.class);
NotificationServiceImpl notificationService1 = new NotificationServiceImpl(
userRepository,
userNotificationRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -393,6 +394,9 @@ class UBSClientServiceImplTest {
@Mock
private OrderUtils orderUtils;

@Mock
private NotificationServiceImpl notificationServiceImpl;

@Value("${greencity.monobank.token}")
private String token;

Expand Down

0 comments on commit b77236c

Please sign in to comment.