Skip to content

Commit 53de636

Browse files
author
Danh Nguyen Van
committed
#1214 [Storefront & Backoffice] Payment was successfully processed, but the status still shows as 'pending payment' in both the back office and storefront
1 parent 9e83bcd commit 53de636

File tree

14 files changed

+189
-47
lines changed

14 files changed

+189
-47
lines changed

order/src/main/java/com/yas/order/controller/OrderController.java

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ public ResponseEntity<OrderVm> getOrderWithItemsById(@PathVariable long id) {
6666
return ResponseEntity.ok(orderService.getOrderWithItemsById(id));
6767
}
6868

69+
@GetMapping("/backoffice/orders/checkout/{id}")
70+
public ResponseEntity<OrderGetVm> getOrderWithCheckoutId(@PathVariable String id) {
71+
return ResponseEntity.ok(orderService.findOrderVmByCheckoutId(id));
72+
}
73+
6974
@GetMapping("/backoffice/orders")
7075
public ResponseEntity<OrderListVm> getOrders(
7176
@RequestParam(value = "createdFrom", defaultValue = "#{new java.util.Date(1970-01-01)}", required = false)

order/src/main/java/com/yas/order/service/OrderService.java

+5
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ public List<OrderGetVm> getMyOrders(String productName, OrderStatus orderStatus)
214214
return orders.stream().map(OrderGetVm::fromModel).toList();
215215
}
216216

217+
public OrderGetVm findOrderVmByCheckoutId(String checkoutId) {
218+
Order order = this.findOrderByCheckoutId(checkoutId);
219+
return OrderGetVm.fromModel(order);
220+
}
221+
217222
public Order findOrderByCheckoutId(String checkoutId) {
218223
return this.orderRepository.findByCheckoutId(checkoutId)
219224
.orElseThrow(() -> new NotFoundException(ORDER_NOT_FOUND, "of checkoutId " + checkoutId));

order/src/main/java/com/yas/order/viewmodel/order/OrderVm.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ public record OrderVm(
2828
DeliveryMethod deliveryMethod,
2929
DeliveryStatus deliveryStatus,
3030
PaymentStatus paymentStatus,
31-
Set<OrderItemVm> orderItemVms
31+
Set<OrderItemVm> orderItemVms,
32+
String checkoutId
3233

3334
) {
3435
public static OrderVm fromModel(Order order) {
3536
Set<OrderItemVm> orderItemVms = order.getOrderItems().stream().map(
36-
item -> OrderItemVm.fromModel(item))
37+
OrderItemVm::fromModel)
3738
.collect(Collectors.toSet());
3839

3940
return OrderVm.builder()
@@ -53,6 +54,7 @@ public static OrderVm fromModel(Order order) {
5354
.deliveryStatus(order.getDeliveryStatus())
5455
.paymentStatus(order.getPaymentStatus())
5556
.orderItemVms(orderItemVms)
57+
.checkoutId(order.getCheckoutId())
5658
.build();
5759
}
58-
}
60+
}

order/src/test/java/com/yas/order/controller/OrderControllerTest.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.HashSet;
4040
import java.util.List;
4141
import java.util.Set;
42+
import java.util.UUID;
4243
import org.junit.jupiter.api.BeforeEach;
4344
import org.junit.jupiter.api.Test;
4445
import org.junit.jupiter.api.extension.ExtendWith;
@@ -225,8 +226,7 @@ void testGetLatestOrders_whenRequestIsValid_thenReturnOrderListVm() throws Excep
225226
}
226227

227228
@Test
228-
void testExportCsv_whenRequestIsValid_thenReturnCsvFile() throws Exception
229-
{
229+
void testExportCsv_whenRequestIsValid_thenReturnCsvFile() throws Exception {
230230
ObjectMapper mapper = new ObjectMapper();
231231
mapper.registerModule(new JavaTimeModule());
232232
OrderRequest orderRequest = new OrderRequest();
@@ -296,7 +296,8 @@ private OrderVm getOrderVm() {
296296
DeliveryMethod.GRAB_EXPRESS,
297297
DeliveryStatus.PREPARING,
298298
PaymentStatus.COMPLETED,
299-
items
299+
items,
300+
UUID.randomUUID().toString()
300301
);
301302
}
302303

@@ -412,4 +413,4 @@ private List<OrderItemPostVm> getOrderItemPostVms() {
412413
return List.of(item1, item2);
413414
}
414415

415-
}
416+
}

order/src/test/java/com/yas/order/service/CartServiceTest.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.HashSet;
2020
import java.util.List;
2121
import java.util.Set;
22+
import java.util.UUID;
2223
import org.jetbrains.annotations.NotNull;
2324
import org.junit.jupiter.api.BeforeEach;
2425
import org.junit.jupiter.api.Test;
@@ -83,7 +84,8 @@ void testDeleteCartItems_ifNormalCase_shouldNoException() {
8384
DeliveryMethod.GRAB_EXPRESS,
8485
DeliveryStatus.CANCELLED,
8586
PaymentStatus.PENDING,
86-
items
87+
items,
88+
UUID.randomUUID().toString()
8789
);
8890
}
8991

@@ -118,4 +120,4 @@ void testDeleteCartItems_ifNormalCase_shouldNoException() {
118120
items.add(item2);
119121
return items;
120122
}
121-
}
123+
}

payment-paypal/src/main/java/com/yas/paymentpaypal/config/ServiceUrlConfig.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@
33
import org.springframework.boot.context.properties.ConfigurationProperties;
44

55
@ConfigurationProperties(prefix = "yas.services")
6-
public record ServiceUrlConfig(
7-
String payment) {
6+
public record ServiceUrlConfig(String payment, String order) {
87
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.yas.paymentpaypal.service;
2+
3+
import com.yas.paymentpaypal.config.ServiceUrlConfig;
4+
import com.yas.paymentpaypal.viewmodel.CapturedPaymentVm;
5+
import com.yas.paymentpaypal.viewmodel.OrderVm;
6+
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
7+
import io.github.resilience4j.retry.annotation.Retry;
8+
import java.net.URI;
9+
import lombok.RequiredArgsConstructor;
10+
import lombok.extern.slf4j.Slf4j;
11+
import org.springframework.security.core.context.SecurityContextHolder;
12+
import org.springframework.security.oauth2.jwt.Jwt;
13+
import org.springframework.stereotype.Service;
14+
import org.springframework.web.client.RestClient;
15+
import org.springframework.web.util.UriComponentsBuilder;
16+
17+
@Service
18+
@Slf4j
19+
@RequiredArgsConstructor
20+
public class OrderService extends AbstractCircuitBreakFallbackHandler {
21+
private final RestClient restClient;
22+
private final ServiceUrlConfig serviceUrlConfig;
23+
24+
@Retry(name = "restApi")
25+
@CircuitBreaker(name = "restCircuitBreaker", fallbackMethod = "handleBodilessFallback")
26+
public OrderVm getOrderByCheckoutId(String checkoutId) {
27+
final String jwt =
28+
((Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getTokenValue();
29+
final URI url = UriComponentsBuilder
30+
.fromHttpUrl(serviceUrlConfig.order())
31+
.path("/backoffice/orders/checkout/" + checkoutId)
32+
.buildAndExpand()
33+
.toUri();
34+
35+
return restClient.get()
36+
.uri(url)
37+
.headers(h -> h.setBearerAuth(jwt))
38+
.retrieve()
39+
.body(OrderVm.class);
40+
}
41+
}

payment-paypal/src/main/java/com/yas/paymentpaypal/service/PaypalService.java

+21-18
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
public class PaypalService {
3131
private final PayPalHttpClient payPalHttpClient;
3232
private final PaymentService paymentService;
33+
private final OrderService orderService;
3334
private final BigDecimal maxPay = BigDecimal.valueOf(1000);
3435
@Value("${yas.public.url}/capture")
3536
private String returnUrl;
@@ -51,12 +52,12 @@ public PaypalRequestPayment createPayment(RequestPayment requestPayment) {
5152
PurchaseUnitRequest purchaseUnitRequest = new PurchaseUnitRequest().amountWithBreakdown(amountWithBreakdown);
5253
orderRequest.purchaseUnits(List.of(purchaseUnitRequest));
5354
ApplicationContext applicationContext = new ApplicationContext()
54-
.returnUrl(returnUrl)
55-
.cancelUrl(cancelUrl)
56-
.brandName(Constants.Yas.BRAND_NAME)
57-
.landingPage("BILLING")
58-
.userAction("PAY_NOW")
59-
.shippingPreference("NO_SHIPPING");
55+
.returnUrl(returnUrl)
56+
.cancelUrl(cancelUrl)
57+
.brandName(Constants.Yas.BRAND_NAME)
58+
.landingPage("BILLING")
59+
.userAction("PAY_NOW")
60+
.shippingPreference("NO_SHIPPING");
6061

6162
orderRequest.applicationContext(applicationContext);
6263
OrdersCreateRequest ordersCreateRequest = new OrdersCreateRequest().requestBody(orderRequest);
@@ -65,10 +66,10 @@ public PaypalRequestPayment createPayment(RequestPayment requestPayment) {
6566
HttpResponse<Order> orderHttpResponse = payPalHttpClient.execute(ordersCreateRequest);
6667
Order order = orderHttpResponse.result();
6768
String redirectUrl = order.links().stream()
68-
.filter(link -> "approve".equals(link.rel()))
69-
.findFirst()
70-
.orElseThrow(NoSuchElementException::new)
71-
.href();
69+
.filter(link -> "approve".equals(link.rel()))
70+
.findFirst()
71+
.orElseThrow(NoSuchElementException::new)
72+
.href();
7273

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

95+
var orderVm = orderService.getOrderByCheckoutId(CheckoutIdHelper.getCheckoutId());
9496

9597
CapturedPaymentVm capturedPayment = CapturedPaymentVm.builder()
96-
.paymentFee(paymentFee)
97-
.gatewayTransactionId(order.id())
98-
.amount(amount)
99-
.paymentStatus(order.status())
100-
.paymentMethod("PAYPAL")
101-
.checkoutId(CheckoutIdHelper.getCheckoutId())
102-
.build();
98+
.orderId(orderVm.id())
99+
.paymentFee(paymentFee)
100+
.gatewayTransactionId(order.id())
101+
.amount(amount)
102+
.paymentStatus(order.status())
103+
.paymentMethod("PAYPAL")
104+
.checkoutId(CheckoutIdHelper.getCheckoutId())
105+
.build();
103106

104107
paymentService.capturePayment(capturedPayment);
105108
return capturedPayment;
@@ -110,4 +113,4 @@ public CapturedPaymentVm capturePayment(String token) {
110113
}
111114
return CapturedPaymentVm.builder().failureMessage("Something Wrong!").build();
112115
}
113-
}
116+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.yas.paymentpaypal.viewmodel;
2+
3+
public record OrderVm(Long id) {
4+
}

payment-paypal/src/main/resources/application.properties

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-
1313
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://identity/realms/Yas
1414

1515
yas.services.payment=http://api.yas.local/payment
16+
yas.services.order=http://api.yas.local/order
1617
yas.public.url=http://storefront/complete-payment
1718

1819

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.yas.paymentpaypal.service;
2+
3+
import static com.yas.paymentpaypal.utils.SecurityContextUtils.setUpSecurityContext;
4+
import static org.mockito.ArgumentMatchers.any;
5+
import static org.mockito.Mockito.mock;
6+
import static org.mockito.Mockito.times;
7+
import static org.mockito.Mockito.verify;
8+
import static org.mockito.Mockito.when;
9+
10+
import com.yas.paymentpaypal.config.ServiceUrlConfig;
11+
import java.net.URI;
12+
import java.util.UUID;
13+
import org.junit.jupiter.api.BeforeEach;
14+
import org.junit.jupiter.api.Test;
15+
import org.mockito.Mockito;
16+
import org.springframework.web.client.RestClient;
17+
import org.springframework.web.util.UriComponentsBuilder;
18+
19+
public class OrderServiceTest {
20+
private RestClient restClient;
21+
22+
private ServiceUrlConfig serviceUrlConfig;
23+
24+
private OrderService orderService;
25+
26+
private RestClient.ResponseSpec responseSpec;
27+
28+
private static final String ORDER_URL = "http://api.yas.local/order";
29+
30+
@BeforeEach
31+
void setUp() {
32+
restClient = mock(RestClient.class);
33+
serviceUrlConfig = mock(ServiceUrlConfig.class);
34+
orderService = new OrderService(restClient, serviceUrlConfig);
35+
responseSpec = Mockito.mock(RestClient.ResponseSpec.class);
36+
setUpSecurityContext("test");
37+
when(serviceUrlConfig.order()).thenReturn(ORDER_URL);
38+
}
39+
40+
@Test
41+
void testGetOrderByCheckoutId_ifNormalCase_returnOrderVm() {
42+
String checkoutId = UUID.randomUUID().toString();
43+
44+
final URI url = UriComponentsBuilder
45+
.fromHttpUrl(serviceUrlConfig.order())
46+
.path("/backoffice/orders/checkout/" + checkoutId)
47+
.buildAndExpand()
48+
.toUri();
49+
50+
RestClient.RequestHeadersUriSpec requestBodyUriSpec = mock(RestClient.RequestHeadersUriSpec.class);
51+
when(restClient.get()).thenReturn(requestBodyUriSpec);
52+
when(requestBodyUriSpec.uri(url)).thenReturn(requestBodyUriSpec);
53+
when(requestBodyUriSpec.headers(any())).thenReturn(requestBodyUriSpec);
54+
when(requestBodyUriSpec.retrieve()).thenReturn(responseSpec);
55+
56+
orderService.getOrderByCheckoutId(checkoutId);
57+
58+
verify(restClient, times(1)).get();
59+
}
60+
}

payment-paypal/src/test/java/com/yas/paymentpaypal/service/PaypalServiceTest.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.paypal.orders.PurchaseUnit;
2424
import com.yas.paymentpaypal.model.CheckoutIdHelper;
2525
import com.yas.paymentpaypal.viewmodel.CapturedPaymentVm;
26+
import com.yas.paymentpaypal.viewmodel.OrderVm;
2627
import com.yas.paymentpaypal.viewmodel.PaypalRequestPayment;
2728
import com.yas.paymentpaypal.viewmodel.RequestPayment;
2829
import java.io.IOException;
@@ -41,11 +42,14 @@ class PaypalServiceTest {
4142

4243
private PaypalService paypalService;
4344

45+
private OrderService orderService;
46+
4447
@BeforeEach
4548
void setUp() {
4649
payPalHttpClient = mock(PayPalHttpClient.class);
4750
paymentService = mock(PaymentService.class);
48-
paypalService = new PaypalService(payPalHttpClient, paymentService);
51+
orderService = mock(OrderService.class);
52+
paypalService = new PaypalService(payPalHttpClient, paymentService, orderService);
4953
CheckoutIdHelper.setCheckoutId("test-checkout-id");
5054
}
5155

@@ -136,8 +140,11 @@ void testCapturePayment_whenStatusNotNull_returnCapturedPaymentVm() throws IOExc
136140
.status("COMPLETED")
137141
.purchaseUnits(purchaseUnitList);
138142

143+
OrderVm orderVmRes = new OrderVm(12L);
144+
139145
HttpResponse mockResponse = mock(HttpResponse.class);
140146
when(payPalHttpClient.execute(any(OrdersCaptureRequest.class))).thenReturn(mockResponse);
147+
when(orderService.getOrderByCheckoutId(any(String.class))).thenReturn(orderVmRes);
141148
when(mockResponse.result()).thenReturn(mockOrder);
142149

143150
String token = "test-token-1";
@@ -172,4 +179,4 @@ void testCapturePayment_whenIoException_returnCapturedPaymentVm() throws IOExcep
172179
assertEquals("error message", result.failureMessage());
173180
}
174181

175-
}
182+
}

0 commit comments

Comments
 (0)