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/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