Version 2 (modified by 42 hours ago) ( diff ) | ,
---|
Трансакции
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<InventoryBrandedmedicine> 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; }
Методот checkout е транзакциски метод за атомско креирање/поврзување на плаќањето, нарачката, и корекциите на залихи, кој врши промена на состојва на 4 различни ентитета.
Кодот пресметува цена според опционален попуст (со клуб-картичка), отвора плаѓање „во тек“, ја гради нарачката за секој брендиран лек од кошничката, ги намалува залихите
по објектите и на крај го финализира плаќањето и ја празни кошничката.
Транзакција обезбедува да нема ситуација во која залихата е намалена без валидна нарачка или плаќање, бидејќи секој неуспех фрла исклучок што иницира ROLLBACK.
- rollbackFor = Exception.class осигурува Rollback на проверени исклучоци, не само на runtime, за да нема полузавршени нарачки или плаќања.
- isolation = READ_COMMITED - забранува dirty reads за време на паралелни операции, ова е важно при намалување на залихата од брендирани лекови.
- timeout = 30 - прекинува долги транзакции за да спречи предолко или бесконечно извршеување на методот кој можеби има грешка.
По успех на транзакцијата, се прави COMMIT по што промените остануваат трајни.
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<Integer> 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<Brandedmedicineimage> toRemove = brandedMedicineImageRepository.findAllById(removeImageIds); for (Brandedmedicineimage img : toRemove) { if (!Objects.equals(img.getBrandedMedicine().getId(), saved.getId())) continue; deletePhysicalFileIfExists(img.getImage()); } brandedMedicineImageRepository.deleteAll(toRemove); } List<Brandedmedicineimage> 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<Brandedmedicineimage> 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<Brandedmedicineimage> 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); }