Commit: e6d1548

Commit Details

SHAe6d1548c463d8763fb5547ff07a35c521f15c296
Tree2d2b62527861022ccf13eb205ea2bf7c0e4013fd
Author<f69e50@finnacloud.com> 1766442769 +0300
Committer<f69e50@finnacloud.com> 1766442769 +0300
Message
add initial test workflow file
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlJxxEeHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKb7YP/2QctdaPuHu4+vFn
fh0Opgqt1brKy9JQxV9JZ9tF5XA+rWVi6pyIZK4lywX+a4er+h29sQY7TEHZt9Xn
meAyRUhPbRPmIpRJMMCgstfILUpjNMkMcPE80kJfpp6+ZmLtO8vC4TnW3ATCK1tv
XISV00T4ajCAhZUmYTveNsvSiMMv/Tq4sF9Is4ix+JN7O/lSLseRtuUE1Vv7T7nY
citxLPwR42Eb/1CYhy0JbRYXP816cbe6dGeDeiDZp7EHKx5D8VAqULKRsAL19tSX
hup8N7owBXieuzNQ4RyaDfDJAfNoN3o9pFeD6vQPq8s7x6AloN625g58p0ssxfK+
CGhR0YHR7atR0pEens22p7g2dVJ7NsrKqDBE3TTeUOpfXfjOwqpVh1Bn/v7a2Vg9
o9mhIClSOLfYv2SXJ06+fn8l6oc70nLJkBfcTevmeF//Z9yGH7TXZNUcedxuBbFg
xfEHeJibTamiE3Z1SfHW1YLwe7QqbBogCIxq4RrpYtN15a65vT5HxyLHDJDGG20V
7z34QJhKXIni/AIGscZqx2kE/C42KSD2fBvqvA4YnPwEUQyMvnSSDSKuJ6flXPTv
RsPZMdNsWWWyJ8P/NTo0Y/PPwA/28p9pX064H2lHFNvSEzUYJdKyQXNV3pGWYAvc
PR8Z+nHfbK/EF5jOVJ8+erXzzXUN
=COmA
-----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