Commit: 690c1f6

Commit Details

SHA690c1f6ce426c62c29e87ac132dda0f8125192ff
Tree5a67fd55b56735ab4e469c7d06c1c73c4c2b4c20
Author<f69e50@finnacloud.com> 1766368110 +0300
Committer<f69e50@finnacloud.com> 1766368110 +0300
Message
initialize backend structure with controllers, DTOs, and configuration files
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlIo24eHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKwXYP/RvWx8mxXoZbKEVA
wQFC9UnzcoL/lElB5QMr9opKzRv4uGgFkKMDhbSnqE6NoET5H5VanOFQ9u5a4Khi
9PBTLIEBjbEqA1trC+aTDk3EplVtQYYbSn19CdMSCW7FXJNSg0IiyWKA44iH8Ts0
Xcxh59m6WcwvRDhxQDy6hCXqUa9ISNNk75KRnJS/qRGIEy94DwUYxVfCJpAfzyVu
VmdinE6kZM2GDj8MBTPQTzi6hMf/e9CcAg51tf4oNtd9tnW8QKpTsPsFy434VUDh
Vxtv/oAJ5tuTIprs2BSnyZ6Kb8RDwDdmQyuKjZMUIwZTH/TCE85SZFf5sa5tpYOH
2KekT52ffZgKw/DUtpNosW6qeHgCJlSvwY7BW7M90X5xJuahrKS04lEDBO04cIRn
bg0ayPFTp7Idhl1OuTRhWS6e344g44mJ/9sZK1sXd/0U8OKBbytk35AnCIPCEdSX
8vgjqBR9Wt3A/Kel5j2VcUFDhrAR72a9lJiQHNBicvcVu9Nd41vDnEwUDdNQv6Uc
6omEz3pkVkq+89/eW1KQM8LvrIuGQ/wIUgykvCNSCQ5oba2fjtAXzI+SmxpeCWOz
jTKZOEJyhIQE7uvaUj6/0D2JwlxbMG27fcUN7N3aKv6mSVP7hYnHaUbRLQ+f8/xU
VfU776FkUXS+4CfSooHtu+ioul9O
=ZuqE
-----END PGP SIGNATURE-----

✓ Verified

File: src/main/java/com/paymentlink/controller/api/CartApiController.java

1 package com.paymentlink.controller.api;
2
3 import com.paymentlink.model.entity.Product;
4 import com.paymentlink.reservation.ReservationService;
5 import com.paymentlink.service.ProductService;
6 import org.springframework.http.HttpStatus;
7 import org.springframework.http.ResponseEntity;
8 import org.springframework.web.bind.annotation.*;
9
10 import java.util.HashMap;
11 import java.util.Map;
12
13 @RestController
14 @RequestMapping("/api/cart")
15 public class CartApiController {
16
17 private final ReservationService reservationService;
18 private final ProductService productService;
19
20 public CartApiController(ReservationService reservationService, ProductService productService) {
21 this.reservationService = reservationService;
22 this.productService = productService;
23 }
24
25 /**
26 * POST /api/cart/reserve - Reserve stock for cart item
27 */
28 @PostMapping("/reserve")
29 public ResponseEntity<Map<String, Object>> reserveStock(
30 @RequestHeader(value = "x-session-id", required = false) String sessionId,
31 @RequestBody Map<String, Object> request) {
32
33 try {
34 if (sessionId == null || sessionId.isEmpty()) {
35 Map<String, Object> error = new HashMap<>();
36 error.put("success", false);
37 error.put("error", "Session ID is required");
38 return ResponseEntity.badRequest().body(error);
39 }
40
41 Long productId = toLong(request.get("productId"));
42 Integer quantity = toInteger(request.get("quantity"));
43
44 // Get product
45 Product product = productService.getProductByIdRaw(productId)
46 .orElseThrow(() -> new IllegalArgumentException("Product not found"));
47
48 // Check if product has stock tracking
49 if (product.getStock() == null) {
50 // Unlimited stock, no reservation needed
51 Map<String, Object> response = new HashMap<>();
52 response.put("success", true);
53 response.put("message", "No reservation needed (unlimited stock)");
54 return ResponseEntity.ok(response);
55 }
56
57 // Reserve stock
58 reservationService.reserve(sessionId, productId, quantity, product.getStock());
59
60 Map<String, Object> response = new HashMap<>();
61 response.put("success", true);
62 response.put("message", "Stock reserved successfully");
63 return ResponseEntity.ok(response);
64
65 } catch (IllegalStateException e) {
66 // Insufficient stock
67 Map<String, Object> error = new HashMap<>();
68 error.put("success", false);
69 error.put("error", e.getMessage());
70 return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
71
72 } catch (Exception e) {
73 Map<String, Object> error = new HashMap<>();
74 error.put("success", false);
75 error.put("error", e.getMessage());
76 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
77 }
78 }
79
80 /**
81 * POST /api/cart/release - Release reservation
82 */
83 @PostMapping("/release")
84 public ResponseEntity<Map<String, Object>> releaseStock(
85 @RequestHeader(value = "x-session-id", required = false) String sessionId,
86 @RequestBody Map<String, Object> request) {
87
88 try {
89 if (sessionId == null || sessionId.isEmpty()) {
90 Map<String, Object> error = new HashMap<>();
91 error.put("success", false);
92 error.put("error", "Session ID is required");
93 return ResponseEntity.badRequest().body(error);
94 }
95
96 Long productId = toLong(request.get("productId"));
97
98 // Release reservation
99 reservationService.release(sessionId, productId);
100
101 Map<String, Object> response = new HashMap<>();
102 response.put("success", true);
103 response.put("message", "Reservation released successfully");
104 return ResponseEntity.ok(response);
105
106 } catch (Exception e) {
107 Map<String, Object> error = new HashMap<>();
108 error.put("success", false);
109 error.put("error", e.getMessage());
110 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
111 }
112 }
113
114 // Helper methods to safely convert Object to Long/Integer
115 private Long toLong(Object value) {
116 if (value == null) return null;
117 if (value instanceof Number) {
118 return ((Number) value).longValue();
119 }
120 if (value instanceof String) {
121 return Long.parseLong((String) value);
122 }
123 throw new IllegalArgumentException("Cannot convert " + value.getClass() + " to Long");
124 }
125
126 private Integer toInteger(Object value) {
127 if (value == null) return null;
128 if (value instanceof Number) {
129 return ((Number) value).intValue();
130 }
131 if (value instanceof String) {
132 return Integer.parseInt((String) value);
133 }
134 throw new IllegalArgumentException("Cannot convert " + value.getClass() + " to Integer");
135 }
136 }
137
138