Skip to content

Commit

Permalink
#1214 [Storefront & Backoffice] Payment was successfully processed, …
Browse files Browse the repository at this point in the history
…but the status still shows as 'pending payment' in both the back office and storefront (#1222)

Co-authored-by: Danh Nguyen Van <[email protected]>
  • Loading branch information
danhnguyenv1 and Danh Nguyen Van authored Oct 24, 2024
1 parent b71e60a commit 9576d76
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public ResponseEntity<OrderVm> getOrderWithItemsById(@PathVariable long id) {
return ResponseEntity.ok(orderService.getOrderWithItemsById(id));
}

@GetMapping("/backoffice/orders/checkout/{id}")
public ResponseEntity<OrderGetVm> getOrderWithCheckoutId(@PathVariable String id) {
return ResponseEntity.ok(orderService.findOrderVmByCheckoutId(id));
}

@GetMapping("/backoffice/orders")
public ResponseEntity<OrderListVm> getOrders(
@RequestParam(value = "createdFrom", defaultValue = "#{new java.util.Date(1970-01-01)}", required = false)
Expand Down
5 changes: 5 additions & 0 deletions order/src/main/java/com/yas/order/service/OrderService.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ public List<OrderGetVm> getMyOrders(String productName, OrderStatus orderStatus)
return orders.stream().map(OrderGetVm::fromModel).toList();
}

public OrderGetVm findOrderVmByCheckoutId(String checkoutId) {
Order order = this.findOrderByCheckoutId(checkoutId);
return OrderGetVm.fromModel(order);
}

public Order findOrderByCheckoutId(String checkoutId) {
return this.orderRepository.findByCheckoutId(checkoutId)
.orElseThrow(() -> new NotFoundException(ORDER_NOT_FOUND, "of checkoutId " + checkoutId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ public record OrderVm(
DeliveryMethod deliveryMethod,
DeliveryStatus deliveryStatus,
PaymentStatus paymentStatus,
Set<OrderItemVm> orderItemVms
Set<OrderItemVm> orderItemVms,
String checkoutId

) {
public static OrderVm fromModel(Order order) {
Set<OrderItemVm> orderItemVms = order.getOrderItems().stream().map(
item -> OrderItemVm.fromModel(item))
OrderItemVm::fromModel)
.collect(Collectors.toSet());

return OrderVm.builder()
Expand All @@ -53,6 +54,7 @@ public static OrderVm fromModel(Order order) {
.deliveryStatus(order.getDeliveryStatus())
.paymentStatus(order.getPaymentStatus())
.orderItemVms(orderItemVms)
.checkoutId(order.getCheckoutId())
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand Down Expand Up @@ -225,8 +226,7 @@ void testGetLatestOrders_whenRequestIsValid_thenReturnOrderListVm() throws Excep
}

@Test
void testExportCsv_whenRequestIsValid_thenReturnCsvFile() throws Exception
{
void testExportCsv_whenRequestIsValid_thenReturnCsvFile() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
OrderRequest orderRequest = new OrderRequest();
Expand Down Expand Up @@ -296,7 +296,8 @@ private OrderVm getOrderVm() {
DeliveryMethod.GRAB_EXPRESS,
DeliveryStatus.PREPARING,
PaymentStatus.COMPLETED,
items
items,
UUID.randomUUID().toString()
);
}

Expand Down Expand Up @@ -412,4 +413,4 @@ private List<OrderItemPostVm> getOrderItemPostVms() {
return List.of(item1, item2);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -83,7 +84,8 @@ void testDeleteCartItems_ifNormalCase_shouldNoException() {
DeliveryMethod.GRAB_EXPRESS,
DeliveryStatus.CANCELLED,
PaymentStatus.PENDING,
items
items,
UUID.randomUUID().toString()
);
}

Expand Down Expand Up @@ -118,4 +120,4 @@ void testDeleteCartItems_ifNormalCase_shouldNoException() {
items.add(item2);
return items;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "yas.services")
public record ServiceUrlConfig(
String payment) {
public record ServiceUrlConfig(String payment, String order) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.yas.paymentpaypal.service;

import com.yas.paymentpaypal.config.ServiceUrlConfig;
import com.yas.paymentpaypal.viewmodel.CapturedPaymentVm;
import com.yas.paymentpaypal.viewmodel.OrderVm;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriComponentsBuilder;

@Service
@Slf4j
@RequiredArgsConstructor
public class OrderService extends AbstractCircuitBreakFallbackHandler {
private final RestClient restClient;
private final ServiceUrlConfig serviceUrlConfig;

@Retry(name = "restApi")
@CircuitBreaker(name = "restCircuitBreaker", fallbackMethod = "handleBodilessFallback")
public OrderVm getOrderByCheckoutId(String checkoutId) {
final String jwt =
((Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getTokenValue();
final URI url = UriComponentsBuilder
.fromHttpUrl(serviceUrlConfig.order())
.path("/backoffice/orders/checkout/" + checkoutId)
.buildAndExpand()
.toUri();

return restClient.get()
.uri(url)
.headers(h -> h.setBearerAuth(jwt))
.retrieve()
.body(OrderVm.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
public class PaypalService {
private final PayPalHttpClient payPalHttpClient;
private final PaymentService paymentService;
private final OrderService orderService;
private final BigDecimal maxPay = BigDecimal.valueOf(1000);
@Value("${yas.public.url}/capture")
private String returnUrl;
Expand All @@ -51,12 +52,12 @@ public PaypalRequestPayment createPayment(RequestPayment requestPayment) {
PurchaseUnitRequest purchaseUnitRequest = new PurchaseUnitRequest().amountWithBreakdown(amountWithBreakdown);
orderRequest.purchaseUnits(List.of(purchaseUnitRequest));
ApplicationContext applicationContext = new ApplicationContext()
.returnUrl(returnUrl)
.cancelUrl(cancelUrl)
.brandName(Constants.Yas.BRAND_NAME)
.landingPage("BILLING")
.userAction("PAY_NOW")
.shippingPreference("NO_SHIPPING");
.returnUrl(returnUrl)
.cancelUrl(cancelUrl)
.brandName(Constants.Yas.BRAND_NAME)
.landingPage("BILLING")
.userAction("PAY_NOW")
.shippingPreference("NO_SHIPPING");

orderRequest.applicationContext(applicationContext);
OrdersCreateRequest ordersCreateRequest = new OrdersCreateRequest().requestBody(orderRequest);
Expand All @@ -65,10 +66,10 @@ public PaypalRequestPayment createPayment(RequestPayment requestPayment) {
HttpResponse<Order> orderHttpResponse = payPalHttpClient.execute(ordersCreateRequest);
Order order = orderHttpResponse.result();
String redirectUrl = order.links().stream()
.filter(link -> "approve".equals(link.rel()))
.findFirst()
.orElseThrow(NoSuchElementException::new)
.href();
.filter(link -> "approve".equals(link.rel()))
.findFirst()
.orElseThrow(NoSuchElementException::new)
.href();

CheckoutIdHelper.setCheckoutId(requestPayment.checkoutId());
return new PaypalRequestPayment("success", order.id(), redirectUrl);
Expand All @@ -91,15 +92,17 @@ public CapturedPaymentVm capturePayment(String token) {
BigDecimal paymentFee = new BigDecimal(paypalFee);
BigDecimal amount = new BigDecimal(capture.amount().value());

var orderVm = orderService.getOrderByCheckoutId(CheckoutIdHelper.getCheckoutId());

CapturedPaymentVm capturedPayment = CapturedPaymentVm.builder()
.paymentFee(paymentFee)
.gatewayTransactionId(order.id())
.amount(amount)
.paymentStatus(order.status())
.paymentMethod("PAYPAL")
.checkoutId(CheckoutIdHelper.getCheckoutId())
.build();
.orderId(orderVm.id())
.paymentFee(paymentFee)
.gatewayTransactionId(order.id())
.amount(amount)
.paymentStatus(order.status())
.paymentMethod("PAYPAL")
.checkoutId(CheckoutIdHelper.getCheckoutId())
.build();

paymentService.capturePayment(capturedPayment);
return capturedPayment;
Expand All @@ -110,4 +113,4 @@ public CapturedPaymentVm capturePayment(String token) {
}
return CapturedPaymentVm.builder().failureMessage("Something Wrong!").build();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.yas.paymentpaypal.viewmodel;

public record OrderVm(Long id) {
}
1 change: 1 addition & 0 deletions payment-paypal/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://identity/realms/Yas

yas.services.payment=http://api.yas.local/payment
yas.services.order=http://api.yas.local/order
yas.public.url=http://storefront/complete-payment


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.yas.paymentpaypal.service;

import static com.yas.paymentpaypal.utils.SecurityContextUtils.setUpSecurityContext;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.yas.paymentpaypal.config.ServiceUrlConfig;
import java.net.URI;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriComponentsBuilder;

public class OrderServiceTest {
private RestClient restClient;

private ServiceUrlConfig serviceUrlConfig;

private OrderService orderService;

private RestClient.ResponseSpec responseSpec;

private static final String ORDER_URL = "http://api.yas.local/order";

@BeforeEach
void setUp() {
restClient = mock(RestClient.class);
serviceUrlConfig = mock(ServiceUrlConfig.class);
orderService = new OrderService(restClient, serviceUrlConfig);
responseSpec = Mockito.mock(RestClient.ResponseSpec.class);
setUpSecurityContext("test");
when(serviceUrlConfig.order()).thenReturn(ORDER_URL);
}

@Test
void testGetOrderByCheckoutId_ifNormalCase_returnOrderVm() {
String checkoutId = UUID.randomUUID().toString();

final URI url = UriComponentsBuilder
.fromHttpUrl(serviceUrlConfig.order())
.path("/backoffice/orders/checkout/" + checkoutId)
.buildAndExpand()
.toUri();

RestClient.RequestHeadersUriSpec requestBodyUriSpec = mock(RestClient.RequestHeadersUriSpec.class);
when(restClient.get()).thenReturn(requestBodyUriSpec);
when(requestBodyUriSpec.uri(url)).thenReturn(requestBodyUriSpec);
when(requestBodyUriSpec.headers(any())).thenReturn(requestBodyUriSpec);
when(requestBodyUriSpec.retrieve()).thenReturn(responseSpec);

orderService.getOrderByCheckoutId(checkoutId);

verify(restClient, times(1)).get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.paypal.orders.PurchaseUnit;
import com.yas.paymentpaypal.model.CheckoutIdHelper;
import com.yas.paymentpaypal.viewmodel.CapturedPaymentVm;
import com.yas.paymentpaypal.viewmodel.OrderVm;
import com.yas.paymentpaypal.viewmodel.PaypalRequestPayment;
import com.yas.paymentpaypal.viewmodel.RequestPayment;
import java.io.IOException;
Expand All @@ -41,11 +42,14 @@ class PaypalServiceTest {

private PaypalService paypalService;

private OrderService orderService;

@BeforeEach
void setUp() {
payPalHttpClient = mock(PayPalHttpClient.class);
paymentService = mock(PaymentService.class);
paypalService = new PaypalService(payPalHttpClient, paymentService);
orderService = mock(OrderService.class);
paypalService = new PaypalService(payPalHttpClient, paymentService, orderService);
CheckoutIdHelper.setCheckoutId("test-checkout-id");
}

Expand Down Expand Up @@ -136,8 +140,11 @@ void testCapturePayment_whenStatusNotNull_returnCapturedPaymentVm() throws IOExc
.status("COMPLETED")
.purchaseUnits(purchaseUnitList);

OrderVm orderVmRes = new OrderVm(12L);

HttpResponse mockResponse = mock(HttpResponse.class);
when(payPalHttpClient.execute(any(OrdersCaptureRequest.class))).thenReturn(mockResponse);
when(orderService.getOrderByCheckoutId(any(String.class))).thenReturn(orderVmRes);
when(mockResponse.result()).thenReturn(mockOrder);

String token = "test-token-1";
Expand Down Expand Up @@ -172,4 +179,4 @@ void testCapturePayment_whenIoException_returnCapturedPaymentVm() throws IOExcep
assertEquals("error message", result.failureMessage());
}

}
}
Loading

0 comments on commit 9576d76

Please sign in to comment.