diff --git a/account-management/src/main/java/cz/muni/pa165/banking/application/controller/AccountController.java b/account-management/src/main/java/cz/muni/pa165/banking/application/controller/AccountController.java index d2a767c9dccd25a06c36ffee476973685dfd7e7d..dc2ed112fbc7c33a38667b730d73edf4aa1c0df5 100644 --- a/account-management/src/main/java/cz/muni/pa165/banking/application/controller/AccountController.java +++ b/account-management/src/main/java/cz/muni/pa165/banking/application/controller/AccountController.java @@ -3,7 +3,6 @@ package cz.muni.pa165.banking.application.controller; import cz.muni.pa165.banking.account.management.AccountApi; import cz.muni.pa165.banking.account.management.dto.*; import cz.muni.pa165.banking.application.facade.AccountFacade; -import cz.muni.pa165.banking.exception.EntityNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; diff --git a/m2m-banking-api/transaction-api/openapi.yaml b/m2m-banking-api/transaction-api/openapi.yaml index f44f9df748c9906e8b22027be1e05fb0b00526a9..1689d724cb59bb3b46a501368cc8b17324a5cf7d 100644 --- a/m2m-banking-api/transaction-api/openapi.yaml +++ b/m2m-banking-api/transaction-api/openapi.yaml @@ -99,6 +99,7 @@ components: - DEPOSIT - TRANSFER - SCHEDULED + - REFUND description: Enumaration defining a type for a transaction. Each type may have different certain implementations and validations. AccountDto: diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryImpl.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryImpl.java index 8d13fe11d21ad2ff03b54b8c1b0f139b40fa1460..40ca8f0b12af4481272aa54aee3aa5e84c8ed493 100644 --- a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryImpl.java +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryImpl.java @@ -2,31 +2,48 @@ package cz.muni.pa165.banking.application.repository; import cz.muni.pa165.banking.domain.process.Process; import cz.muni.pa165.banking.domain.process.repository.ProcessRepository; +import cz.muni.pa165.banking.domain.process.status.Status; +import cz.muni.pa165.banking.exception.EntityNotFoundException; import org.springframework.stereotype.Repository; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; @Repository public class ProcessRepositoryImpl implements ProcessRepository { - // TODO until app has no DB connection -> Milestone2 - private final Map<UUID, Process> inmemoryDb = new HashMap<>(); + private final ProcessRepositoryJpa repository; + + public ProcessRepositoryImpl(ProcessRepositoryJpa repository) { + this.repository = repository; + } @Override public boolean idExists(UUID uuid) { - return inmemoryDb.containsKey(uuid); + return repository.existsById(uuid.toString()); } @Override public Process findById(UUID uuid) { - return inmemoryDb.get(uuid); + Optional<Process> process = repository.findById(uuid.toString()); + if (process.isEmpty()) { + throw new EntityNotFoundException(String.format("Process with UUID %s not found", uuid)); + } + return process.get(); } @Override public void save(Process process) { - inmemoryDb.put(process.uuid(), process); + repository.save(process); + } + + @Override + public List<Process> findProcessOfStatus(Status status) { + return null; + } + + @Override + public Integer invalidateStaleProcesses() { + return null; } } diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryJpa.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryJpa.java new file mode 100644 index 0000000000000000000000000000000000000000..c018d0ed6b6a58c33c6fb619d2f89ea633031589 --- /dev/null +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/repository/ProcessRepositoryJpa.java @@ -0,0 +1,12 @@ +package cz.muni.pa165.banking.application.repository; + +import cz.muni.pa165.banking.domain.process.Process; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProcessRepositoryJpa extends JpaRepository<Process, String> { + + // TODO find podla statusu + + // TODO update zaseknute procesy starsie nez e.g. tyzden a zmenit na failed + nastavit message nejaky + +} diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/ScheduledPaymentService.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/ScheduledPaymentService.java new file mode 100644 index 0000000000000000000000000000000000000000..eee4667f2edbedbdfed086d31520084400a2f32a --- /dev/null +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/ScheduledPaymentService.java @@ -0,0 +1,81 @@ +package cz.muni.pa165.banking.application.service; + +import cz.muni.pa165.banking.account.management.AccountApi; +import cz.muni.pa165.banking.account.management.dto.ScheduledPaymentDto; +import cz.muni.pa165.banking.account.management.dto.ScheduledPaymentsDto; +import cz.muni.pa165.banking.domain.account.Account; +import cz.muni.pa165.banking.domain.messaging.MessageProducer; +import cz.muni.pa165.banking.domain.money.Money; +import cz.muni.pa165.banking.domain.process.Process; +import cz.muni.pa165.banking.domain.process.ProcessFactory; +import cz.muni.pa165.banking.domain.process.repository.ProcessRepository; +import cz.muni.pa165.banking.domain.process.repository.ProcessTransactionRepository; +import cz.muni.pa165.banking.domain.transaction.Transaction; +import cz.muni.pa165.banking.domain.transaction.TransactionType; +import cz.muni.pa165.banking.exception.ServerError; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.Currency; +import java.util.Objects; + +@Service +public class ScheduledPaymentService { + + private final Logger LOGGER = LoggerFactory.getLogger(ScheduledPaymentService.class); + + private final AccountApi accountApi; + + private final ProcessTransactionRepository processTransactionRepository; + + private final ProcessRepository processRepository; + + private final MessageProducer messageProducer; + + ScheduledPaymentService(AccountApi accountApi, + ProcessTransactionRepository processTransactionRepository, + ProcessRepository processRepository, + MessageProducer messageProducer) { + this.accountApi = accountApi; + this.processTransactionRepository = processTransactionRepository; + this.processRepository = processRepository; + this.messageProducer = messageProducer; + } + + @Scheduled(cron = "${scheduled-payments.cron.expression}") + public void executeScheduledPayments() { + LocalDate now = LocalDate.now(); + ResponseEntity<ScheduledPaymentsDto> response = accountApi.getScheduledPaymentsOf(now); + if (!response.getStatusCode().is2xxSuccessful()) { + throw new ServerError("Call to Account Management service unsuccessful."); + } + + ProcessFactory factory = new ProcessFactory(processTransactionRepository, processRepository); + ScheduledPaymentsDto payments = Objects.requireNonNull(response.getBody()); + for (ScheduledPaymentDto payment : payments.getScheduledPayments()) { + Transaction newTransaction = transactionForScheduledPayment(payment); + Process process = factory.create(newTransaction, messageProducer); + LOGGER.info("[Create Scheduled Payment Process] %s" + process.getUuid()); + } + + LOGGER.info("Finished creating processes for scheduled payments."); + } + + private Transaction transactionForScheduledPayment(ScheduledPaymentDto payment) { + Account source = new Account(payment.getSenderAccount()); + Account target = new Account(payment.getReceiverAccount()); + Money money = new Money(payment.getAmount(), Currency.getInstance(payment.getCurrencyCode())); + return new Transaction( + source, + target, + TransactionType.SCHEDULED, + money, + "Automatic execution of scheduled payment" + ); + } + +} diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionProcessesService.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionProcessesService.java index fb378e4d315bd5f0d9e2545fc386b334b5bfc13d..04cdaa984f9f437491e6d925659431f74664695e 100644 --- a/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionProcessesService.java +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/application/service/TransactionProcessesService.java @@ -1,6 +1,6 @@ package cz.muni.pa165.banking.application.service; -import cz.muni.pa165.banking.application.messaging.ProcessProducer; +import cz.muni.pa165.banking.domain.messaging.MessageProducer; import cz.muni.pa165.banking.domain.process.Process; import cz.muni.pa165.banking.domain.process.ProcessFactory; import cz.muni.pa165.banking.domain.process.ProcessTransaction; @@ -26,9 +26,11 @@ public class TransactionProcessesService { private final ProcessRepository processRepository; - private final ProcessProducer processProducer; + private final MessageProducer processProducer; - public TransactionProcessesService(ProcessTransactionRepository processTransactionRepository, ProcessRepository processRepository, ProcessProducer processProducer) { + public TransactionProcessesService(ProcessTransactionRepository processTransactionRepository, + ProcessRepository processRepository, + MessageProducer processProducer) { this.processTransactionRepository = processTransactionRepository; this.processRepository = processRepository; this.processProducer = processProducer; diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/Process.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/Process.java index 46275d0a8bda8b92f953cb06d9ca7c5ccb7c51da..b0e7aa0bb280d8b64298ee221a96afb7fae07083 100644 --- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/Process.java +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/Process.java @@ -10,15 +10,21 @@ import java.util.UUID; @Entity public class Process { - private final UUID uuid; + private UUID uuid; private StatusInformation currentStatus; - Process() { - uuid = UUID.randomUUID(); - currentStatus = new StatusInformation(Instant.now(), Status.CREATED, "Process created, waiting for processing."); + public static Process createNew() { + Process process = new Process(); + process.uuid = UUID.randomUUID(); + process.currentStatus = new StatusInformation(Instant.now(), Status.CREATED, "Process created, waiting for processing."); + + return process; } + @Deprecated // hibernate + public Process() {} + /** * Return a copy of Process UUID, ensuring the UUID is not modified or replaced. */ diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java index dfc89881046748ab50d575691e599c56c83a604b..66f2ff741138adfb85336467148984c02b384654 100644 --- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/ProcessFactory.java @@ -23,7 +23,7 @@ public class ProcessFactory { public Process create(Transaction transaction, MessageProducer messageProducer) { - Process newProcess = new Process(); + Process newProcess = Process.createNew(); processRepository.save(newProcess); ProcessTransaction assignedTransaction = new ProcessTransaction( diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/repository/ProcessRepository.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/repository/ProcessRepository.java index 12b56e54bbe890a148cbf3095ea7d3cb35f6b3ad..e9ff4917e4dc472adc8470556c456963a375993b 100644 --- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/repository/ProcessRepository.java +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/process/repository/ProcessRepository.java @@ -1,7 +1,9 @@ package cz.muni.pa165.banking.domain.process.repository; import cz.muni.pa165.banking.domain.process.Process; +import cz.muni.pa165.banking.domain.process.status.Status; +import java.util.List; import java.util.UUID; public interface ProcessRepository { @@ -12,4 +14,7 @@ public interface ProcessRepository { void save(Process process); + List<Process> findProcessOfStatus(Status status); + + Integer invalidateStaleProcesses(); } diff --git a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java index 35a7d1742f363bcd8753e546fbf1045b97e5b4c7..6b0ed7892a1349d1968d3737f502c36f6c54b219 100644 --- a/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java +++ b/transaction-processor/src/main/java/cz/muni/pa165/banking/domain/transaction/Transaction.java @@ -20,7 +20,8 @@ public class Transaction { // Hibernate } - public Transaction(Account source, Account target, TransactionType type, Money amount, String detail) { + public Transaction(Account source, Account target, + TransactionType type, Money amount, String detail) { this.source = source; this.target = target; this.type = type; diff --git a/transaction-processor/src/main/resources/application.yaml b/transaction-processor/src/main/resources/application.yaml index 5ab250940aa6ffa21489f70fb7f734693a19f96a..15fbc4b828b98697d15bedadc68a61e5dce71e68 100644 --- a/transaction-processor/src/main/resources/application.yaml +++ b/transaction-processor/src/main/resources/application.yaml @@ -1,6 +1,9 @@ db: hostname: localhost - +scheduled-payments: + cron: + expression: "00 7 * * *" + banking: apps: management: diff --git a/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessMock.java b/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessMock.java index 8cbf9dee8a40fe311c5263311d9621267869694b..9076a23e6dbefd934847d4c35713067f36624aac 100644 --- a/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessMock.java +++ b/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessMock.java @@ -1,9 +1,18 @@ package cz.muni.pa165.banking.domain.process; +import java.util.UUID; + public class ProcessMock extends Process { + private UUID uuid; + public ProcessMock() { super(); + this.uuid = UUID.randomUUID(); } + @Override + public UUID getUuid() { + return this.uuid; + } } diff --git a/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessOperationsTest.java b/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessOperationsTest.java index 7875ab10cfda45b539678a29d245bfd797339f04..61593a14e6f039ade5c177f81e79e3ffcb0e1601 100644 --- a/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessOperationsTest.java +++ b/transaction-processor/src/test/java/cz/muni/pa165/banking/domain/process/ProcessOperationsTest.java @@ -12,7 +12,7 @@ class ProcessOperationsTest { @Test void changeState() { - Process process = new Process(); + Process process = Process.createNew(); StatusInformation newStatus = new StatusInformation( Instant.now(),