== Трансакции == === 1. Транзакција за креирање на нарачка од страна на Клиент === {{{ @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED, timeout = 30) public Clientorder checkout(Client client, Shoppingcart cart, Integer paymentMethodId, Integer deliveryCompanyId, boolean useCard) { BigDecimal total = shoppingCartService.getTotal(cart); int baseAmount = total.intValue(); int discount = 0; if (useCard) { var cardOpt = clubCardService.getByClientId(client.getId()); if (cardOpt.isPresent()) { Clubcard card = cardOpt.get(); Integer pts = card.getPoints(); int points = pts == null ? 0 : pts; discount = Math.min(points / 2, baseAmount); if (discount > 0) { card.setPoints(0); } } } int finalAmount = Math.max(0, baseAmount - discount); Paymentmethod method = paymentmethodRepo.findById(paymentMethodId) .orElseThrow(() -> new IllegalArgumentException("Payment method not found")); Payment payment = new Payment(); payment.setClient(client); payment.setPaymentMethod(method); payment.setPaymentDate(LocalDate.now()); payment.setAmount(finalAmount); //payment.setStatus("во тек"); paymentRepo.save(payment); Deliverycompany deliveryCompany = deliveryRepo.findById(deliveryCompanyId) .orElseThrow(() -> new IllegalArgumentException("Delivery company not found")); Clientorder order = new Clientorder(); order.setClient(client); order.setDeliveryCompany(deliveryCompany); order.setPayment(payment); order.setOrderDate(LocalDate.now()); order.setExpectedArrivalDate(LocalDate.now().plusDays(7)); order.setStatus("во тек"); order.setTotalPrice(finalAmount); shoppingCartService.getMedicinesInCart(cart).forEach((medicine, qty) -> { ClientorderBrandedmedicine line = new ClientorderBrandedmedicine(); ClientorderBrandedmedicineId id = new ClientorderBrandedmedicineId(); id.setBrandedMedicineId(medicine.getId()); line.setId(id); line.setOrder(order); line.setBrandedMedicine(medicine); line.setQuantity(qty); order.getItems().add(line); }); for (ClientorderBrandedmedicine line : order.getItems()) { int remaining = line.getQuantity(); Integer bmId = line.getBrandedMedicine().getId(); List facilities = inventoryBrandedmedicineRepository.lockAllByMedicineInPharmacies(bmId); for (InventoryBrandedmedicine ibm : facilities) { if (remaining <= 0) break; int take = Math.min(ibm.getQuantity(), remaining); if (take <= 0) continue; ibm.setQuantity(ibm.getQuantity() - take); ibm.setLastChanged(LocalDate.now()); inventoryBrandedmedicineRepository.save(ibm); remaining -= take; } if (remaining > 0) { throw new IllegalStateException("Insufficient stock for medicine id=" + bmId); } } order.setStatus("во тек"); orderRepo.save(order); payment.setStatus("завршено"); paymentRepo.save(payment); shoppingCartService.clearCart(cart); return order; } }}} === 2. Зачувување на брендиран лек === {{{ @Transactional( rollbackFor = { Exception.class, java.io.IOException.class }, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, timeout = 30 ) public void saveAll(Integer id, Integer manufacturerId, BigDecimal price, String description, String dosageForm, String strength, String originCountry, String name, MultipartFile[] newImages, List removeImageIds, Integer mainExistingId, Integer mainNewIndex) throws IOException { Brandedmedicine bm; if (id == null) { bm = new Brandedmedicine(); } else { bm = brandedMedicineRepository.findById(id) .orElseThrow(() -> new EntityNotFoundException("Branded medicine not found: " + id)); } Manufacturer m = manufacturerRepository.findById(manufacturerId) .orElseThrow(() -> new EntityNotFoundException("Manufacturer not found: " + manufacturerId)); bm.setManufacturer(m); bm.setPrice(price); bm.setDescription(description); bm.setDosageForm(dosageForm); bm.setStrength(strength); bm.setOriginCountry(originCountry); bm.setName(name); Brandedmedicine saved = brandedMedicineRepository.save(bm); if (removeImageIds != null && !removeImageIds.isEmpty()) { List toRemove = brandedMedicineImageRepository.findAllById(removeImageIds); for (Brandedmedicineimage img : toRemove) { if (!Objects.equals(img.getBrandedMedicine().getId(), saved.getId())) continue; deletePhysicalFileIfExists(img.getImage()); } brandedMedicineImageRepository.deleteAll(toRemove); } List appended = new ArrayList<>(); if (newImages != null) { Path base = ensureUploadPath(); long ts = System.currentTimeMillis(); int seq = 0; for (MultipartFile file : newImages) { if (file == null || file.isEmpty()) continue; validateImageFile(file); String original = Optional.ofNullable(file.getOriginalFilename()).orElse("image"); String ext = getFileExtension(original).toLowerCase(Locale.ROOT); String filename = String.format("branded_medicine_%d_%d_%03d.%s", saved.getId(), ts, ++seq, ext); Path dest = base.resolve(filename); Files.copy(file.getInputStream(), dest, StandardCopyOption.REPLACE_EXISTING); String url = "/uploads/images/branded_medicine/" + filename; Brandedmedicineimage img = new Brandedmedicineimage(); img.setBrandedMedicine(saved); img.setImage(url); img.setMainImage(false); appended.add(brandedMedicineImageRepository.save(img)); } } Integer targetMainId = null; if (mainExistingId != null) { brandedMedicineImageRepository.findById(mainExistingId).ifPresent(img -> { if (Objects.equals(img.getBrandedMedicine().getId(), saved.getId())) { // capture via array holder } }); if (brandedMedicineImageRepository.findById(mainExistingId) .filter(img -> Objects.equals(img.getBrandedMedicine().getId(), saved.getId())) .isPresent()) { targetMainId = mainExistingId; } } if (targetMainId == null && mainNewIndex != null) { if (mainNewIndex >= 0 && mainNewIndex < appended.size()) { targetMainId = appended.get(mainNewIndex).getId(); } } if (targetMainId == null) { Optional curMain = brandedMedicineImageRepository .findFirstByBrandedMedicineIdAndMainImageTrue(saved.getId()); if (curMain.isPresent()) { targetMainId = curMain.get().getId(); } else { targetMainId = brandedMedicineImageRepository .findFirstByBrandedMedicineIdOrderByIdAsc(saved.getId()) .map(Brandedmedicineimage::getId).orElse(null); } } if (targetMainId != null) { List all = brandedMedicineImageRepository.findByBrandedMedicineId(saved.getId()); for (Brandedmedicineimage img : all) { boolean shouldBeMain = Objects.equals(img.getId(), targetMainId); if (img.isMainImage() != shouldBeMain) { img.setMainImage(shouldBeMain); brandedMedicineImageRepository.save(img); } } } } }}} === 3. Потврда за апликација на клиент да биде верифициран корисник == {{{ @Override @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED, timeout = 10) public void approve(Integer id) { Sensitiveclientdata row = sensitiveRepo.findById(id) .orElseThrow(() -> new EntityNotFoundException("Application not found")); row.setVerificationStatus("одобрена"); sensitiveRepo.save(row); Integer clientId = row.getClient().getId(); Client client = clientRepo.findById(clientId) .orElseThrow(() -> new EntityNotFoundException("Client not found")); client.setIsVerified(Boolean.TRUE); clientRepo.save(client); } }}}