Commit: 9c24ca4

Commit Details

SHA9c24ca40dbca995b0007e09659176f7c90e13392
Tree4c630341b69f778f78daa19bfebcc1bfdebe1836
Author<f69e50@finnacloud.com> 1766442705 +0300
Committer<f69e50@finnacloud.com> 1766442705 +0300
Message
add CI configuration and test script for Jenkins build
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlJxtEeHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKwOEP/RJdPEnaGlYKr4zE
NkU5vATgzcYMHxCO6p3T6JqsfHsvv2d65vedOJ8LsSHFtT9AN/yXqZKV2722R5CG
WLsPzbVYJSXexKVZ8D7Zpf+DTu+/OAlWUE+XHMm+bJYVpDmqUo0ak/qX6vz6VYtW
bSRPMtM9g8WZKZqbBxLK7Sg1IkYFsFjEWmvn6mbD9C7k/0y4Sxp6Xee26xAx1sdI
+srAjwFgF+wJw0OAQoBA2jykTOiib93n9gdc9wbgl4AYUvdcaX3Hxv8LTl3Bu88N
2rqaL+OmjXtkFkEAiBaruvZZCt+aqp14gTgOM0wcLp1I1FP7uOFNOg0F0zSUawzY
Fuw3w6CKebkpbixGfxtJqrLl1IbPAhd92TxRVerZbDEnWpXW3a9HoGWRu5KFX/ny
ww+8M53ziWFNcHqpIyI5adRjG74C+5MdvC04J0/Sh1X8mykWcjE96Wu2/iRY9XQe
07I94ZVO0RaBSjSUnIItfhAgBXi03nzx+ZPw2tM4VHosn2zZjpzT8+KNQ0EXYhuT
AzgqcOKV94ZkM+48ZePvUFXsJxhMSkpXIQxGWWBnU9gjm3QAUsuCyqZGKXgVY9Vo
mDlLBl83Nhx+/7V8AFJO2gUmaph9YB01p3SMDfE++lLqX1BwdguFVrQib30OsRnq
e86d/6MrRABKf+FjtaulHY9+e8LS
=9ZJj
-----END PGP SIGNATURE-----

✓ Verified

File: src/main/java/com/paymentlink/service/ProductService.java

1 package com.paymentlink.service;
2
3 import com.paymentlink.model.entity.Product;
4 import com.paymentlink.repository.ProductRepository;
5 import com.paymentlink.reservation.ReservationService;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8 import org.springframework.stereotype.Service;
9 import org.springframework.transaction.annotation.Transactional;
10
11 import java.util.List;
12 import java.util.Optional;
13
14 @Service
15 public class ProductService {
16
17 private static final Logger logger = LoggerFactory.getLogger(ProductService.class);
18
19 private final ProductRepository productRepository;
20 private final ReservationService reservationService;
21 private final NodeIdService nodeIdService;
22
23 public ProductService(ProductRepository productRepository,
24 ReservationService reservationService,
25 NodeIdService nodeIdService) {
26 this.productRepository = productRepository;
27 this.reservationService = reservationService;
28 this.nodeIdService = nodeIdService;
29 }
30
31 /**
32 * Get all products with adjusted stock (minus reservations)
33 */
34 public List<Product> getAllProducts() {
35 List<Product> products = productRepository.findAll();
36 return adjustStockForReservations(products);
37 }
38
39 /**
40 * Get products by category with adjusted stock
41 */
42 public List<Product> getProductsByCategory(String category) {
43 List<Product> products = productRepository.findByCategory(category);
44 return adjustStockForReservations(products);
45 }
46
47 /**
48 * Search products with adjusted stock
49 */
50 public List<Product> searchProducts(String query, String category) {
51 List<Product> products;
52 if (category != null && !category.isEmpty()) {
53 products = productRepository.searchProductsByCategory(query, category);
54 } else {
55 products = productRepository.searchProducts(query);
56 }
57 return adjustStockForReservations(products);
58 }
59
60 /**
61 * Get products in stock (after reservations)
62 */
63 public List<Product> getProductsInStock() {
64 List<Product> products = productRepository.findAll();
65 products = adjustStockForReservations(products);
66 return products.stream()
67 .filter(p -> p.getStock() == null || p.getStock() > 0)
68 .toList();
69 }
70
71 /**
72 * Get product by ID with adjusted stock
73 */
74 public Optional<Product> getProductById(Long id) {
75 Optional<Product> product = productRepository.findById(id);
76 if (product.isPresent()) {
77 Product p = product.get();
78 if (p.getStock() != null) {
79 int reserved = reservationService.getReservedCount(p.getId());
80 p.setStock(Math.max(0, p.getStock() - reserved));
81 }
82 }
83 return product;
84 }
85
86 /**
87 * Get product by ID without adjustment (for internal use)
88 */
89 public Optional<Product> getProductByIdRaw(Long id) {
90 return productRepository.findById(id);
91 }
92
93 /**
94 * Get all categories
95 */
96 public List<String> getAllCategories() {
97 return productRepository.findDistinctCategories();
98 }
99
100 /**
101 * Create a new product
102 */
103 @Transactional
104 public Product createProduct(Product product) {
105 product.setNodeId(nodeIdService.getNodeId());
106 logger.info("Creating product: {}", product.getName());
107 return productRepository.save(product);
108 }
109
110 /**
111 * Update a product
112 */
113 @Transactional
114 public Optional<Product> updateProduct(Long id, Product updates) {
115 return productRepository.findById(id).map(existing -> {
116 if (updates.getName() != null) existing.setName(updates.getName());
117 if (updates.getDescription() != null) existing.setDescription(updates.getDescription());
118 if (updates.getPrice() != null) existing.setPrice(updates.getPrice());
119 if (updates.getCurrency() != null) existing.setCurrency(updates.getCurrency());
120 if (updates.getImage() != null) existing.setImage(updates.getImage());
121 if (updates.getStock() != null) existing.setStock(updates.getStock());
122 if (updates.getCategory() != null) existing.setCategory(updates.getCategory());
123 if (updates.getTaxIncluded() != null) existing.setTaxIncluded(updates.getTaxIncluded());
124
125 logger.info("Updating product: {}", id);
126 return productRepository.save(existing);
127 });
128 }
129
130 /**
131 * Delete a product
132 */
133 @Transactional
134 public boolean deleteProduct(Long id) {
135 if (productRepository.existsById(id)) {
136 productRepository.deleteById(id);
137 logger.info("Deleted product: {}", id);
138 return true;
139 }
140 return false;
141 }
142
143 /**
144 * Update stock for a product
145 */
146 @Transactional
147 public void updateStock(Long productId, int newStock) {
148 productRepository.findById(productId).ifPresent(product -> {
149 product.setStock(newStock);
150 productRepository.save(product);
151 logger.info("Updated stock for product {}: {}", productId, newStock);
152 });
153 }
154
155 /**
156 * Decrease stock (for order completion)
157 */
158 @Transactional
159 public void decreaseStock(Long productId, int quantity) {
160 productRepository.findById(productId).ifPresent(product -> {
161 if (product.getStock() != null) {
162 int newStock = product.getStock() - quantity;
163 product.setStock(Math.max(0, newStock));
164 productRepository.save(product);
165 logger.info("Decreased stock for product {}: {} -> {}",
166 productId, product.getStock() + quantity, newStock);
167 }
168 });
169 }
170
171 /**
172 * Adjust stock counts for reservations
173 */
174 private List<Product> adjustStockForReservations(List<Product> products) {
175 return products.stream().map(p -> {
176 if (p.getStock() != null) {
177 int reserved = reservationService.getReservedCount(p.getId());
178 p.setStock(Math.max(0, p.getStock() - reserved));
179 }
180 return p;
181 }).toList();
182 }
183 }
184
185