Commit: f0438c2

Commit Details

SHAf0438c2cbc2d838bb66a4d8129dd25b5d48d28ee
Treeb8e53d050248c8b632fa3de86003489acae4670b
Author<f69e50@finnacloud.com> 1766443042 +0300
Committer<f69e50@finnacloud.com> 1766443042 +0300
Message
increment once more
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlJyCIeHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKtrgP/04FZPSa4Hmx9WpR
gOamzjIXc+1+pBvGQDairLZU6rtDSgNkoryrsqOOLIXZWkkxZ70q8/aXQBFThr+t
YyDIz85u9GiwPOV8o1X4sxzF7bupOd6YmOOPqS2vco1aibpB8w9N9EwlMzW95Otw
vnQ/h0kz8MTp0wfXeRJqvLg8DVPnLgW70ly1TZQe19jEA4NwBZOyK2ksTis8iycX
HUM4WW8Velo8O+OtygAbwISr2dILKvkclTLn9kgfpN5esvBvJu4K+xA5T5alDchc
PY3FFeZteQf3GX4v0EH8K3c/q8OcQFMxuRGO31uYGqNbjbOB7zdZVs3N0B1m1efv
vhCgZ6gyxlz0kiozgO6Sx5WFOzHuTlguCK+x0JOtzCokRL/VLiPzmW5Umt280eJz
AlD7u7Dah3khoqDkzXfCL1lxch9tRMVMUYWRMayxC3iculCFM6OCLgzY9hay5y1j
WP1ZOdy/x9jKPoLv5USnw0KlH4rZIHH+aDMDEzWmWUWYDpShylG7sKafXg75bnho
5LbAfCucnDrkjN+rx1dxaKrZswQlIJ8iZ5Q6DzHnDzl4TaFcN1E3exS+xp46H7va
SbR94UfpCyjpTQ2hHdOS7XHINFUDIzWF3mUZ8gqyEANiqpgJ+RcOGX66s69oILpr
vD20SIdMHWDqJH3G6GMNsg1g5/QU
=YrcG
-----END PGP SIGNATURE-----

✓ Verified

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

1 package com.paymentlink.service;
2
3 import com.paymentlink.model.entity.PaymentLink;
4 import com.paymentlink.model.entity.PaymentLinkItem;
5 import com.paymentlink.model.entity.Product;
6 import com.paymentlink.repository.PaymentLinkRepository;
7 import com.paymentlink.reservation.ReservationService;
8 import com.paymentlink.util.IdGenerator;
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 import org.springframework.stereotype.Service;
12 import org.springframework.transaction.annotation.Transactional;
13
14 import java.util.List;
15 import java.util.Optional;
16
17 @Service
18 public class PaymentLinkService {
19
20 private static final Logger logger = LoggerFactory.getLogger(PaymentLinkService.class);
21
22 private final PaymentLinkRepository paymentLinkRepository;
23 private final ProductService productService;
24 private final TaxService taxService;
25 private final ShippingService shippingService;
26 private final ReservationService reservationService;
27 private final NodeIdService nodeIdService;
28
29 public PaymentLinkService(PaymentLinkRepository paymentLinkRepository,
30 ProductService productService,
31 TaxService taxService,
32 ShippingService shippingService,
33 ReservationService reservationService,
34 NodeIdService nodeIdService) {
35 this.paymentLinkRepository = paymentLinkRepository;
36 this.productService = productService;
37 this.taxService = taxService;
38 this.shippingService = shippingService;
39 this.reservationService = reservationService;
40 this.nodeIdService = nodeIdService;
41 }
42
43 /**
44 * Create a payment link
45 */
46 @Transactional
47 public PaymentLink createPaymentLink(List<PaymentLinkItem> items,
48 String customerEmail, String customerName, String customerPhone,
49 String shippingAddress, String shippingCity, String shippingState,
50 String shippingZip, String shippingCountry, String shippingMethod,
51 String sessionId) {
52
53 logger.info("Creating payment link for customer: {}", customerEmail);
54
55 // Validate stock and calculate totals
56 long subtotal = 0;
57 String currency = "USD";
58
59 for (PaymentLinkItem item : items) {
60 Optional<Product> productOpt = productService.getProductByIdRaw(item.getProductId());
61 if (productOpt.isEmpty()) {
62 throw new IllegalArgumentException("Product not found: " + item.getProductId());
63 }
64
65 Product product = productOpt.get();
66 currency = product.getCurrency();
67
68 // Check stock availability
69 if (product.getStock() != null) {
70 int reservedByOthers = reservationService.getReservedCountExcludingSession(
71 product.getId(), sessionId
72 );
73 int effectiveStock = product.getStock() - reservedByOthers;
74
75 if (effectiveStock < item.getQuantity()) {
76 throw new IllegalStateException(
77 String.format("Insufficient stock for %s. Only %d available.",
78 product.getName(), effectiveStock)
79 );
80 }
81 }
82
83 // Set item details
84 item.setProductName(product.getName());
85 item.setPrice(product.getPrice());
86 subtotal += product.getPrice() * item.getQuantity();
87 }
88
89 // Calculate shipping
90 long shippingCost = shippingService.calculateShippingCost(shippingMethod, shippingCountry);
91
92 // Calculate tax
93 long taxAmount = taxService.calculateTax(subtotal, shippingCountry, shippingState);
94
95 // Calculate total
96 long total = subtotal + shippingCost + taxAmount;
97
98 // Create payment link
99 PaymentLink paymentLink = PaymentLink.builder()
100 .linkId(IdGenerator.generatePaymentLinkId())
101 .status("pending")
102 .subtotal(subtotal)
103 .amount(total)
104 .shippingCost(shippingCost)
105 .taxAmount(taxAmount)
106 .currency(currency)
107 .customerEmail(customerEmail)
108 .customerName(customerName)
109 .customerPhone(customerPhone)
110 .shippingAddress(shippingAddress)
111 .shippingCity(shippingCity)
112 .shippingState(shippingState)
113 .shippingZip(shippingZip)
114 .shippingCountry(shippingCountry)
115 .shippingMethod(shippingMethod)
116 .nodeId(nodeIdService.getNodeId())
117 .build();
118
119 // Add items
120 for (PaymentLinkItem item : items) {
121 paymentLink.addItem(item);
122 }
123
124 // Save payment link
125 paymentLink = paymentLinkRepository.save(paymentLink);
126 logger.info("Created payment link: {}", paymentLink.getLinkId());
127
128 return paymentLink;
129 }
130
131 /**
132 * Get payment link by ID
133 */
134 public Optional<PaymentLink> getPaymentLinkById(String linkId) {
135 return paymentLinkRepository.findByLinkIdWithItems(linkId);
136 }
137
138 /**
139 * Update payment link status
140 */
141 @Transactional
142 public Optional<PaymentLink> updateStatus(String linkId, String status) {
143 return paymentLinkRepository.findByLinkId(linkId).map(link -> {
144 link.setStatus(status);
145 return paymentLinkRepository.save(link);
146 });
147 }
148
149 /**
150 * Associate payment link with Stripe payment intent
151 */
152 @Transactional
153 public Optional<PaymentLink> setStripePaymentIntent(String linkId, String paymentIntentId) {
154 return paymentLinkRepository.findByLinkId(linkId).map(link -> {
155 link.setStripePaymentIntentId(paymentIntentId);
156 return paymentLinkRepository.save(link);
157 });
158 }
159
160 /**
161 * Associate payment link with order
162 */
163 @Transactional
164 public Optional<PaymentLink> setOrderId(String linkId, String orderId) {
165 return paymentLinkRepository.findByLinkId(linkId).map(link -> {
166 link.setOrderId(orderId);
167 return paymentLinkRepository.save(link);
168 });
169 }
170
171 /**
172 * Complete payment link (mark as paid)
173 */
174 @Transactional
175 public void completePaymentLink(String linkId, String orderId) {
176 Optional<PaymentLink> linkOpt = paymentLinkRepository.findByLinkId(linkId);
177 if (linkOpt.isEmpty()) {
178 throw new IllegalArgumentException("Payment link not found: " + linkId);
179 }
180
181 PaymentLink link = linkOpt.get();
182 link.setStatus("paid");
183 link.setOrderId(orderId);
184 paymentLinkRepository.save(link);
185
186 logger.info("Completed payment link: {} -> order: {}", linkId, orderId);
187 }
188 }
189
190