From 8d0216501766a653cbba2364278dbc45e44a9a18 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Wed, 7 Aug 2024 17:24:55 +0200 Subject: [PATCH 1/9] feat: ability to reject multiple transactions. --- .../package-info.java | 1 + .../TransactionBatchRepositoryGateway.java | 5 +- .../TransactionRepositoryGateway.java | 290 +++++++++++------- .../resource/AccountingCoreResource.java | 73 +++-- ...AccountingCorePresentationViewService.java | 167 +++++----- .../resource/requests/TransactionApprove.java | 17 - .../TransactionsRejectionRequest.java | 44 +++ ...sApprove.java => TransactionsRequest.java} | 26 +- .../views/TransactionProcessView.java | 1 + .../internal/AccountingCoreService.java | 32 +- ...ctionViewIdTypeConverterPropertyTest.java} | 2 +- ...> TransactionViewIdTypeConverterTest.java} | 2 +- .../problem_support/IdentifiableProblem.java | 24 ++ 13 files changed, 397 insertions(+), 287 deletions(-) delete mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionApprove.java create mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java rename accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/{TransactionsApprove.java => TransactionsRequest.java} (68%) rename accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/{TransactionViewTypeConverterPropertyTest.java => TransactionViewIdTypeConverterPropertyTest.java} (96%) rename accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/{TransactionViewTypeConverterTest.java => TransactionViewIdTypeConverterTest.java} (97%) create mode 100644 support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/package-info.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/package-info.java index 3a9ba2c4..3d3c9f2c 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/package-info.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/package-info.java @@ -4,6 +4,7 @@ "notification_gateway", "notification_gateway::domain_core", "notification_gateway::domain_event", "organisation", "organisation::domain_core", "organisation::domain_entity", "support::audit", + "support::problem_support", "support::crypto", "support::collections", "support::reactive" diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionBatchRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionBatchRepositoryGateway.java index adda5f00..5c7e1136 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionBatchRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionBatchRepositoryGateway.java @@ -22,10 +22,8 @@ public Optional findById(String batchId) { return transactionBatchRepository.findById(batchId); } + // TODO: Pagination need to be implemented public List findByOrganisationId(String organisationId) { - /** - * Todo: Pagination need to be implemented. - */ return transactionBatchRepository.findAllByFilteringParametersOrganisationId(organisationId); } @@ -36,4 +34,5 @@ public List findByFilter(BatchSearchRequest body) { public Long findByFilterCount(BatchSearchRequest body) { return transactionBatchRepository.findByFilterCount(body); } + } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java index d5bb3aa2..a2a5794a 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java @@ -8,17 +8,28 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Rejection; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest.TransactionId; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.LedgerService; +import org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem; +import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.zalando.problem.Problem; +import org.zalando.problem.ThrowableProblem; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus.FAILED; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.FAIL; +import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION; +import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION_ITEM; +import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; +import static org.zalando.problem.Status.METHOD_NOT_ALLOWED; +import static org.zalando.problem.Status.NOT_FOUND; @Service @Slf4j @@ -30,152 +41,159 @@ public class TransactionRepositoryGateway { private final TransactionRepository transactionRepository; private final LedgerService ledgerService; - @Transactional - public Either approveTransaction(String transactionId) { + @Transactional(propagation = REQUIRES_NEW) + // TODO optimise performance because we have to load transaction from db each time and we don't save it in bulk + private Either approveTransaction(String transactionId) { log.info("Approving transaction: {}", transactionId); val txM = transactionRepository.findById(transactionId); if (txM.isEmpty()) { - return Either.left(Problem.builder() - .withTitle("TX_NOT_FOUND") - .withDetail(STR."Transaction with id \{transactionId} not found") - .with("transactionId", transactionId) - .build() - ); + return txNotFoundResponse(transactionId); } val tx = txM.orElseThrow(); - if (tx.getAutomatedValidationStatus() == FAILED) { - return Either.left(Problem.builder() - .withTitle("CANNOT_APPROVE_FAILED_TX") - .withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}") - .with("transactionId", transactionId) - .build() - ); + if (tx.getStatus() == FAIL) { + return transactionFailedResponse(transactionId); + } + if (tx.hasAnyRejection()) { + return transactionRejectedResponse(transactionId); } tx.setTransactionApproved(true); val savedTx = transactionRepository.save(tx); - val organisationId = savedTx.getOrganisation().getId(); - - if (savedTx.getTransactionApproved()) { - ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.of(savedTx)); - - return Either.right(savedTx.getTransactionApproved()); - } - return Either.right(false); + return Either.right(savedTx); } - @Transactional - public Set approveTransactions(String organisationId, Set transactionIds) { - log.info("Approving transactions: {}", transactionIds); - - val transactions = transactionRepository.findAllById(transactionIds) - .stream() - .filter(tx -> tx.getAutomatedValidationStatus() != FAILED) - .peek(tx -> tx.setTransactionApproved(true)) - .collect(Collectors.toSet()); - - val savedTxs = transactionRepository.saveAll(transactions); - - ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.copyOf(savedTxs)); - - return savedTxs.stream().map(TransactionEntity::getId).collect(Collectors.toSet()); - } - - @Transactional - public Set approveTransactionsDispatch(String organisationId, Set transactionIds) { - log.info("Approving transactions dispatch: {}", transactionIds); - - val transactions = transactionRepository.findAllById(transactionIds) - .stream() - .filter(tx -> tx.getAutomatedValidationStatus() != FAILED) - .peek(tx -> tx.setLedgerDispatchApproved(true)) - .collect(Collectors.toSet()); - - val savedTxs = transactionRepository.saveAll(transactions); - - ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.copyOf(savedTxs)); - - return savedTxs.stream().map(TransactionEntity::getId).collect(Collectors.toSet()); - } - - @Transactional - public Either approveTransactionDispatch(String transactionId) { - log.info("Approving transaction dispatch: {}", transactionId); + @Transactional(propagation = REQUIRES_NEW) + // TODO optimise performance because we have to load transaction from db each time and we don't save it in bulk + private Either approveTransactionsDispatch(String transactionId) { + log.info("Approving transaction to dispatch: {}", transactionId); val txM = transactionRepository.findById(transactionId); if (txM.isEmpty()) { - return Either.left(Problem.builder() + val problem = Problem.builder() .withTitle("TX_NOT_FOUND") .withDetail(STR."Transaction with id \{transactionId} not found") + .withStatus(NOT_FOUND) .with("transactionId", transactionId) - .build() - ); + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); } val tx = txM.orElseThrow(); - if (tx.getAutomatedValidationStatus() == FAILED) { - return Either.left(Problem.builder() + if (tx.getStatus() == FAIL) { + val problem = Problem.builder() .withTitle("CANNOT_APPROVE_FAILED_TX") - .withDetail(STR."Cannot approve dispatch for a failed transaction, transactionId: \{transactionId}") + .withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}") + .withStatus(METHOD_NOT_ALLOWED) .with("transactionId", transactionId) - .build() - ); + .build(); + + if (tx.hasAnyRejection()) { + return transactionRejectedResponse(transactionId); + } + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + } + + if (!tx.getTransactionApproved()) { + val problem = Problem.builder() + .withTitle("TX_NOT_APPROVED") + .withDetail(STR."Cannot approve for dispatch / publish a transaction that has not been approved before, transactionId: \{transactionId}") + .withStatus(METHOD_NOT_ALLOWED) + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); } tx.setLedgerDispatchApproved(true); val savedTx = transactionRepository.save(tx); - if (savedTx.getLedgerDispatchApproved()) { - ledgerService.checkIfThereAreTransactionsToDispatch(savedTx.getOrganisation().getId(), Set.of(savedTx)); + return Either.right(savedTx); + } + + public List> approveTransactions(TransactionsRequest transactionsRequest) { + val organisationId = transactionsRequest.getOrganisationId(); + + val transactionIds = transactionsRequest.getTransactionIds() + .stream() + .map(TransactionId::getId) + .collect(Collectors.toSet()); + + val transactionsApprovalResponseListE = new ArrayList>(); + for (val transactionId : transactionIds) { + try { + val transactionEntities = approveTransaction(transactionId); + + transactionsApprovalResponseListE.add(transactionEntities); + } catch (DataAccessException dae) { + log.error("Error approving transaction: {}", transactionId, dae); + + val problem = createDBError(transactionId, dae); - return Either.right(savedTx.getLedgerDispatchApproved()); + transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION))); + } } - return Either.right(false); + val transactionSuccesses = transactionsApprovalResponseListE.stream() + .filter(Either::isRight) + .map(Either::get) + .collect(Collectors.toSet()); + + ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, transactionSuccesses); + + return transactionsApprovalResponseListE; } - public Either changeTransactionComment(String txId, String userComment) { - val txM = transactionRepository.findById(txId); + public List> approveTransactionsDispatch(TransactionsRequest transactionsRequest) { + val organisationId = transactionsRequest.getOrganisationId(); - if (txM.isEmpty()) { - return Either.left(Problem.builder() - .withTitle("TX_NOT_FOUND") - .withDetail(STR."Transaction with id \{txId} not found") - .with("txId", txId) - .build() - ); - } + val transactionIds = transactionsRequest.getTransactionIds() + .stream() + .map(TransactionId::getId) + .collect(Collectors.toSet()); - val tx = txM.orElseThrow(); + val transactionsApprovalResponseListE = new ArrayList>(); + for (val transactionId : transactionIds) { + try { + val transactionEntities = approveTransactionsDispatch(transactionId); - tx.setUserComment(userComment); + transactionsApprovalResponseListE.add(transactionEntities); + } catch (DataAccessException dae) { + log.error("Error approving transaction publish: {}", transactionId, dae); - val savedTx = transactionRepository.save(tx); + val problem = createDBError(transactionId, dae); + + transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION))); + } + } + + val transactionSuccesses = transactionsApprovalResponseListE.stream() + .filter(Either::isRight) + .map(Either::get) + .collect(Collectors.toSet()); - return Either.right(savedTx.getUserComment().equals(userComment)); + ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, transactionSuccesses); + + return transactionsApprovalResponseListE; } - public Either changeTransactionItemRejection(String txId, - String txItemId, - Optional rejectionM) { + public Either rejectTransaction(String txId, + String txItemId, + Optional rejectionM) { val txM = transactionRepository.findById(txId); if (txM.isEmpty()) { - return Either.left(Problem.builder() - .withTitle("TX_NOT_FOUND") - .withDetail(STR."Transaction with id \{txId} not found") - .with("txId", txId) - .build() - ); + return txNotFoundResponse(txId); } val tx = txM.orElseThrow(); @@ -183,12 +201,13 @@ public Either changeTransactionItemRejection(String txId, val txItemM = tx.findItemById(txItemId); if (txItemM.isEmpty()) { - return Either.left(Problem.builder() + val problem = Problem.builder() .withTitle("TX_ITEM_NOT_FOUND") .withDetail(STR."Transaction item with id \{txItemId} not found") .with("txItemId", txItemId) - .build() - ); + .build(); + + return Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM)); } val txItem= txItemM.orElseThrow(); @@ -196,7 +215,7 @@ public Either changeTransactionItemRejection(String txId, val savedTxItem = transactionItemRepository.save(txItem); - return Either.right(savedTxItem.getRejection().equals(rejectionM)); + return Either.right(savedTxItem.getTransaction()); } public Optional findById(String transactionId) { @@ -205,17 +224,9 @@ public Optional findById(String transactionId) { } public List findByAllId(Set transactionIds) { - return transactionRepository.findAllById(transactionIds); } - private static Set transactionIds(Set transactions) { - return transactions - .stream() - .map(TransactionEntity::getId) - .collect(Collectors.toSet()); - } - public List findAllByStatus(String organisationId, List validationStatuses, List transactionType) { @@ -225,4 +236,67 @@ public List findAllByStatus(String organisationId, public List listAll() { return transactionRepository.findAll(); } + + private static Either transactionFailedResponse(String transactionId) { + val problem = Problem.builder() + .withTitle("CANNOT_APPROVE_FAILED_TX") + .withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}") + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + } + + private static Either transactionRejectedResponse(String transactionId) { + val problem = Problem.builder() + .withTitle("CANNOT_APPROVE_REJECTED_TX") + .withDetail(STR."Cannot approve a rejected transaction, transactionId: \{transactionId}") + .withStatus(METHOD_NOT_ALLOWED) + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + } + + private static Either txNotFoundResponse(String txId) { + val problem = Problem.builder() + .withTitle("TX_NOT_FOUND") + .withDetail(STR."Transaction with id \{txId} not found") + .with("txId", txId) + .build(); + + return Either.left(new IdentifiableProblem(txId, problem, TRANSACTION)); + } + + private static ThrowableProblem createDBError(String transactionId, DataAccessException dae) { + val problem = Problem.builder() + .withTitle("DB_ERROR") + .withDetail(STR."DB error approving transaction publish:\{transactionId}") + .with("transactionId", transactionId) + .with("error", dae.getMessage()) + .build(); + return problem; + } + } + +// public Either changeTransactionComment(String txId, String userComment) { +// val txM = transactionRepository.findById(txId); +// +// if (txM.isEmpty()) { +// return Either.left(Problem.builder() +// .withTitle("TX_NOT_FOUND") +// .withDetail(STR."Transaction with id \{txId} not found") +// .with("txId", txId) +// .build() +// ); +// } +// +// val tx = txM.orElseThrow(); +// +// tx.setUserComment(userComment); +// +// val savedTx = transactionRepository.save(tx); +// +// return Either.right(savedTx.getUserComment().equals(userComment)); +// } \ No newline at end of file diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java index 74719853..69c4a02e 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java @@ -18,7 +18,7 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.BatchSearchRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ExtractionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.SearchRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsApprove; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.BatchView; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.BatchsDetailView; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.TransactionProcessView; @@ -27,7 +27,6 @@ import org.json.JSONException; import org.json.JSONObject; import org.springframework.http.HttpStatusCode; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.zalando.problem.Problem; @@ -35,6 +34,9 @@ import java.util.List; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.zalando.problem.Status.OK; + @RestController @CrossOrigin(origins = "http://localhost:3000") @RequestMapping("/api") @@ -48,10 +50,10 @@ public class AccountingCoreResource { @Tag(name = "Transactions", description = "Transactions API") @Operation(description = "Transaction list", responses = { @ApiResponse(content = - {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = TransactionView.class)))} + {@Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = TransactionView.class)))} ) }) - @PostMapping(value = "/transactions", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/transactions", produces = APPLICATION_JSON_VALUE) public ResponseEntity listAllAction(@Valid @RequestBody SearchRequest body) { List transactions = accountingCorePresentationService.allTransactions(body); @@ -61,10 +63,10 @@ public ResponseEntity listAllAction(@Valid @RequestBody SearchRequest body) { @Tag(name = "Transactions", description = "Transactions API") @Operation(description = "Transaction detail", responses = { @ApiResponse(content = - {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = TransactionView.class))} + {@Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = TransactionView.class))} ) }) - @GetMapping(value = "/transactions/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(value = "/transactions/{id}", produces = APPLICATION_JSON_VALUE) public ResponseEntity transactionDetailSpecific(@Valid @PathVariable("id") @Parameter(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") String id) { val transactionEntity = accountingCorePresentationService.transactionDetailSpecific(id); @@ -84,10 +86,10 @@ public ResponseEntity transactionDetailSpecific(@Valid @PathVariable("id") @P @Tag(name = "Transactions", description = "Transactions API") @Operation(description = "Transaction types", responses = { @ApiResponse(content = - {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(example = "[{\"id\":\"CardCharge\",\"title\":\"Card Charge\"},{\"id\":\"VendorBill\",\"title\":\"Vendor Bill\"},{\"id\":\"CardRefund\",\"title\":\"Card Refund\"},{\"id\":\"Journal\",\"title\":\"Journal\"},{\"id\":\"FxRevaluation\",\"title\":\"Fx Revaluation\"},{\"id\":\"Transfer\",\"title\":\"Transfer\"},{\"id\":\"CustomerPayment\",\"title\":\"Customer Payment\"},{\"id\":\"ExpenseReport\",\"title\":\"Expense Report\"},{\"id\":\"VendorPayment\",\"title\":\"Vendor Payment\"},{\"id\":\"BillCredit\",\"title\":\"Bill Credit\"}]"))} + {@Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(example = "[{\"id\":\"CardCharge\",\"title\":\"Card Charge\"},{\"id\":\"VendorBill\",\"title\":\"Vendor Bill\"},{\"id\":\"CardRefund\",\"title\":\"Card Refund\"},{\"id\":\"Journal\",\"title\":\"Journal\"},{\"id\":\"FxRevaluation\",\"title\":\"Fx Revaluation\"},{\"id\":\"Transfer\",\"title\":\"Transfer\"},{\"id\":\"CustomerPayment\",\"title\":\"Customer Payment\"},{\"id\":\"ExpenseReport\",\"title\":\"Expense Report\"},{\"id\":\"VendorPayment\",\"title\":\"Vendor Payment\"},{\"id\":\"BillCredit\",\"title\":\"Bill Credit\"}]"))} ) }) - @GetMapping(value = "/transaction-types", produces = MediaType.APPLICATION_JSON_VALUE, name = "Transaction types") + @GetMapping(value = "/transaction-types", produces = APPLICATION_JSON_VALUE, name = "Transaction types") public ResponseEntity transactionType() throws JSONException { JSONArray jsonArray = new JSONArray(); @@ -106,20 +108,20 @@ public ResponseEntity transactionType() throws JSONException { @Tag(name = "Transactions", description = "Transactions API") @Operation(description = "Rejection types", responses = { @ApiResponse(content = - {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = RejectionCode.class)))} + {@Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = RejectionCode.class)))} ) }) - @GetMapping(value = "/rejection-types", produces = MediaType.APPLICATION_JSON_VALUE, name = "Rejection types") + @GetMapping(value = "/rejection-types", produces = APPLICATION_JSON_VALUE, name = "Rejection types") public ResponseEntity rejectionTypes() { return ResponseEntity.ok().body(RejectionCode.values()); } @Tag(name = "Transactions", description = "Transactions API") - @PostMapping(value = "/extraction", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/extraction", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @Operation(description = "Trigger the extraction from the ERP system(s)", responses = { @ApiResponse(content = - {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, + {@Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(example = "{\"event\": \"EXTRACTION\",\"message\":\"We have received your extraction request now. Please review imported transactions from the batch list.\"}"))}, responseCode = "202" ) @@ -159,35 +161,46 @@ public ResponseEntity extractionTrigger(@Valid @RequestBody ExtractionRequest .body(response.toString()); } - @Tag(name = "Transactions", description = "Transactions API") - @PostMapping(value = "/transactions/approve", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) - @Operation(description = "Approve transactions", + @Tag(name = "Transactions Approval", description = "Transactions Approval API") + @PostMapping(value = "/transactions/approve", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @Operation(description = "Approve one or more transactions", responses = { @ApiResponse(content = { - @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = TransactionProcessView.class))) + @Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = TransactionProcessView.class))) }) } ) - public ResponseEntity approveTransaction(@Valid @RequestBody TransactionsApprove transactionsApprove) { - val resul = accountingCorePresentationService.approveTransactions(transactionsApprove.getTransactionApproves()); + public ResponseEntity approveTransactions(@Valid @RequestBody TransactionsRequest transactionsRequest) { + val transactionProcessViewsResult = accountingCorePresentationService.approveTransactions(transactionsRequest); - if (resul.isEmpty()) { - return ResponseEntity - .status(HttpStatusCode.valueOf(404)) - .body(resul); - } + return ResponseEntity + .status(HttpStatusCode.valueOf(OK.getStatusCode())) + .body(transactionProcessViewsResult); + } + + @Tag(name = "Transactions Publish / Dispatch Approval", description = "Transactions Publish / Dispatch Approval API") + @PostMapping(value = "/transactions/approve", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @Operation(description = "Approve one or more transactions", + responses = { + @ApiResponse(content = { + @Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = TransactionProcessView.class))) + }) + } + ) + public ResponseEntity approveTransactionsPublish(@Valid @RequestBody TransactionsRequest transactionsRequest) { + val transactionProcessViewsResult = accountingCorePresentationService.approveTransactionsPublish(transactionsRequest); return ResponseEntity - .status(HttpStatusCode.valueOf(202)) - .body(resul); + .status(HttpStatusCode.valueOf(OK.getStatusCode())) + .body(transactionProcessViewsResult); } @Tag(name = "Batchs", description = "Batchs API") - @PostMapping(value = "/batchs", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/batchs", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @Operation(description = "Batch list", responses = { @ApiResponse(content = { - @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = BatchsDetailView.class))) + @Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = BatchsDetailView.class))) }) } ) @@ -203,13 +216,13 @@ public ResponseEntity listAllBatch(@Valid @RequestBody BatchSearchRequest bod } @Tag(name = "Batchs", description = "Batchs API") - @GetMapping(value = "/batchs/{batchId}", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(value = "/batchs/{batchId}", produces = APPLICATION_JSON_VALUE) @Operation(description = "Batch detail", responses = { @ApiResponse(content = { - @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = BatchView.class)) + @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = BatchView.class)) }), - @ApiResponse(responseCode = "404", description = "Error: response status is 404", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(example = "{\"title\": \"BATCH_NOT_FOUND\",\"status\": 404,\"detail\": \"Batch with id: {batchId} could not be found\"" + + @ApiResponse(responseCode = "404", description = "Error: response status is 404", content = {@Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(example = "{\"title\": \"BATCH_NOT_FOUND\",\"status\": 404,\"detail\": \"Batch with id: {batchId} could not be found\"" + "}"))}) } ) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java index 53eca2a4..2e827423 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java @@ -1,6 +1,5 @@ package org.cardanofoundation.lob.app.accounting_reporting_core.resource.model; -import io.vavr.control.Either; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -11,52 +10,57 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.BatchSearchRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ExtractionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.SearchRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionApprove; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.*; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.AccountingCoreService; import org.jmolecules.ddd.annotation.Service; -import org.springframework.dao.DataAccessException; import org.springframework.transaction.annotation.Transactional; -import org.zalando.problem.Problem; -import org.zalando.problem.Status; -import org.zalando.problem.ThrowableProblem; import java.math.BigDecimal; import java.time.LocalDate; -import java.util.*; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; +import static java.math.BigDecimal.ZERO; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Counterparty.Type.VENDOR; + @Service -@org.springframework.stereotype.Service @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) // presentation layer service public class AccountingCorePresentationViewService { + private final TransactionRepositoryGateway transactionRepositoryGateway; private final AccountingCoreService accountingCoreService; private final TransactionBatchRepositoryGateway transactionBatchRepositoryGateway; public List allTransactions(SearchRequest body) { - List transactions = transactionRepositoryGateway.findAllByStatus(body.getOrganisationId(), body.getStatus(), body.getTransactionType()); + val transactions = transactionRepositoryGateway.findAllByStatus( + body.getOrganisationId(), + body.getStatus(), + body.getTransactionType() + ); - return - transactions.stream().map(this::getTransactionView).toList() - ; + return transactions.stream() + .map(this::getTransactionView) + .toList(); } public Optional transactionDetailSpecific(String transactionId) { + val transactionEntity = transactionRepositoryGateway.findById(transactionId); - Optional transactionEntity = transactionRepositoryGateway.findById(transactionId); return transactionEntity.map(this::getTransactionView); } public Optional batchDetail(String batchId) { return transactionBatchRepositoryGateway.findById(batchId).map(transactionBatchEntity -> { - val transactions = this.getTransaction(transactionBatchEntity); - val statistic = this.getStatisticts(transactionBatchEntity.getBatchStatistics()); + val statistic = this.getStatistics(transactionBatchEntity.getBatchStatistics()); val filteringParameters = this.getFilteringParameters(transactionBatchEntity.getFilteringParameters()); + return new BatchView( transactionBatchEntity.getId(), transactionBatchEntity.getCreatedAt().toString(), @@ -68,25 +72,22 @@ public Optional batchDetail(String batchId) { statistic, filteringParameters, transactions - ); } ); } - private BatchStatisticsView getStatisticts(Optional batchStatistics) { - - Optional statistics = batchStatistics.stream().findFirst(); + private BatchStatisticsView getStatistics(Optional batchStatistics) { + val statisticsM = batchStatistics.stream().findFirst(); return new BatchStatisticsView( - statistics.flatMap(BatchStatistics::getApprovedTransactionsCount).orElse(0), - Math.abs(statistics.flatMap(BatchStatistics::getTotalTransactionsCount).orElse(0) - statistics.flatMap(BatchStatistics::getDispatchedTransactionsCount).orElse(0)), - statistics.flatMap(BatchStatistics::getFailedTransactionsCount).orElse(0), - statistics.flatMap(BatchStatistics::getDispatchedTransactionsCount).orElse(0), - statistics.flatMap(BatchStatistics::getCompletedTransactionsCount).orElse(0), - statistics.flatMap(BatchStatistics::getTotalTransactionsCount).orElse(0) + statisticsM.flatMap(BatchStatistics::getApprovedTransactionsCount).orElse(0), + Math.abs(statisticsM.flatMap(BatchStatistics::getTotalTransactionsCount).orElse(0) - statisticsM.flatMap(BatchStatistics::getDispatchedTransactionsCount).orElse(0)), + statisticsM.flatMap(BatchStatistics::getFailedTransactionsCount).orElse(0), + statisticsM.flatMap(BatchStatistics::getDispatchedTransactionsCount).orElse(0), + statisticsM.flatMap(BatchStatistics::getCompletedTransactionsCount).orElse(0), + statisticsM.flatMap(BatchStatistics::getTotalTransactionsCount).orElse(0) ); - } private FilteringParametersView getFilteringParameters(FilteringParameters filteringParameters) { @@ -101,28 +102,29 @@ private FilteringParametersView getFilteringParameters(FilteringParameters filte } public BatchsDetailView listAllBatch(BatchSearchRequest body) { - - BatchsDetailView batchDetail = new BatchsDetailView(); - - List batches = transactionBatchRepositoryGateway.findByFilter(body).stream().map( - - transactionBatchEntity -> new BatchView( - transactionBatchEntity.getId(), - transactionBatchEntity.getCreatedAt().toString(), - transactionBatchEntity.getUpdatedAt().toString(), - transactionBatchEntity.getCreatedBy(), - transactionBatchEntity.getUpdatedBy(), - transactionBatchEntity.getOrganisationId(), - transactionBatchEntity.getStatus(), - this.getStatisticts(transactionBatchEntity.getBatchStatistics()), - this.getFilteringParameters(transactionBatchEntity.getFilteringParameters()), - Set.of() - ) - ).toList(); - - batchDetail.setBatchs(batches); - batchDetail.setTotal(Long.valueOf(transactionBatchRepositoryGateway.findByFilterCount(body))); - return batchDetail; + val batchDetailView = new BatchsDetailView(); + + val batches = transactionBatchRepositoryGateway.findByFilter(body) + .stream() + .map( + transactionBatchEntity -> new BatchView( + transactionBatchEntity.getId(), + transactionBatchEntity.getCreatedAt().toString(), + transactionBatchEntity.getUpdatedAt().toString(), + transactionBatchEntity.getCreatedBy(), + transactionBatchEntity.getUpdatedBy(), + transactionBatchEntity.getOrganisationId(), + transactionBatchEntity.getStatus(), + this.getStatistics(transactionBatchEntity.getBatchStatistics()), + this.getFilteringParameters(transactionBatchEntity.getFilteringParameters()), + Set.of() + ) + ).toList(); + + batchDetailView.setBatchs(batches); + batchDetailView.setTotal(transactionBatchRepositoryGateway.findByFilterCount(body)); + + return batchDetailView; } @Transactional @@ -136,37 +138,28 @@ public void extractionTrigger(ExtractionRequest body) { .build(); accountingCoreService.scheduleIngestion(fp); - } - public List approveTransactions(List transactionApproves) { - - val transactionProcessViews = new ArrayList(List.of()); - for (val transactionAp : transactionApproves) { + public List approveTransactions(TransactionsRequest transactionsRequest) { + return transactionRepositoryGateway.approveTransactions(transactionsRequest) + .stream() + .map(txEntityE -> txEntityE.fold(txProblem -> { + return TransactionProcessView.createFail(txProblem.getId(), txProblem.getProblem()); + }, success -> { + return TransactionProcessView.createSucess(success.getId()); + })) + .toList(); + } - try { - Either approveTransactionE = accountingCoreService.approveTransaction(transactionAp.getId()); - val resu = approveTransactionE.fold(problem -> { - return TransactionProcessView.createFail(transactionAp.getId(), problem); + public List approveTransactionsPublish(TransactionsRequest transactionsRequest) { + return transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest) + .stream() + .map(txEntityE -> txEntityE.fold(txProblem -> { + return TransactionProcessView.createFail(txProblem.getId(), txProblem.getProblem()); }, success -> { - return TransactionProcessView.createSucess(transactionAp.getId()); - }); - - transactionProcessViews.add(resu); - } catch (DataAccessException exception) { - val problem = Problem.builder() - .withTitle("TRANSACTION_DB_ERROR") - .withDetail(STR."DAtabse serialsation problem for the ID: \{transactionAp.getId()}") - .with("transactionId", transactionAp.getId()) - .withStatus(Status.INTERNAL_SERVER_ERROR) - .with("cause", exception.getMessage()) - .build(); - transactionProcessViews.add(TransactionProcessView.createFail(transactionAp.getId(), problem)); - } - - } - - return transactionProcessViews; + return TransactionProcessView.createSucess(success.getId()); + })) + .toList(); } private Set getTransaction(TransactionBatchEntity transactionBatchEntity) { @@ -184,16 +177,15 @@ private TransactionView getTransactionView(TransactionEntity transactionEntity) transactionEntity.getAutomatedValidationStatus(), transactionEntity.getTransactionApproved(), transactionEntity.getLedgerDispatchApproved(), - getAmountLcy(transactionEntity), + getAmountLcyTotalForAllItems(transactionEntity), getTransactionItemView(transactionEntity), - getViolation(transactionEntity), + getViolations(transactionEntity), transactionEntity.getStatus() ); } private Set getTransactionItemView(TransactionEntity transaction) { return transaction.getItems().stream().map(item -> { - return new TransactionItemView( item.getId(), item.getAccountDebit().map(account -> account.getCode()).orElse(""), @@ -216,18 +208,15 @@ private Set getTransactionItemView(TransactionEntity transa item.getDocument().map(Document::getNum).orElse(""), item.getDocument().map(document -> document.getCurrency().getCustomerCode()).orElse(""), item.getDocument().flatMap(document -> document.getVat().map(Vat::getCustomerCode)).orElse(""), - item.getDocument().flatMap(document -> document.getVat().flatMap(Vat::getRate)).orElse(BigDecimal.ZERO), + item.getDocument().flatMap(document -> document.getVat().flatMap(Vat::getRate)).orElse(ZERO), item.getDocument().flatMap(d -> d.getCounterparty().map(Counterparty::getCustomerCode)).orElse(""), - item.getDocument().flatMap(d -> d.getCounterparty().map(Counterparty::getType)).orElse(org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Counterparty.Type.VENDOR), + item.getDocument().flatMap(d -> d.getCounterparty().map(Counterparty::getType)).orElse(VENDOR), item.getDocument().flatMap(document -> document.getCounterparty().flatMap(Counterparty::getName)).orElse("") - - ); }).collect(Collectors.toSet()); } - private Set getViolation(TransactionEntity transaction) { - + private Set getViolations(TransactionEntity transaction) { return transaction.getViolations().stream().map(violation -> new ViolationView( violation.getSeverity(), violation.getSource(), @@ -237,12 +226,10 @@ private Set getViolation(TransactionEntity transaction) { )).collect(Collectors.toSet()); } - private BigDecimal getAmountLcy(TransactionEntity tx) { - BigDecimal total = BigDecimal.ZERO; - for (val txItem : tx.getItems()) { - total = total.add(txItem.getAmountLcy()); - } - return total; + public BigDecimal getAmountLcyTotalForAllItems(TransactionEntity tx) { + return tx.getItems().stream() + .map(TransactionItemEntity::getAmountLcy) + .reduce(ZERO, BigDecimal::add); } } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionApprove.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionApprove.java deleted file mode 100644 index 55218efd..00000000 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionApprove.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class TransactionApprove { - //48335c2b63cffcef2a3cd0678b65c4fb16420f51110033024209957fbd58ec4e - @Schema(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") - private String id; -} diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java new file mode 100644 index 00000000..45a1cb00 --- /dev/null +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java @@ -0,0 +1,44 @@ +package org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests; + +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode; + +import java.util.Set; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class TransactionsRejectionRequest { + + @ArraySchema(arraySchema = @Schema(example = "[ {" + + "\"id\": \"7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4\"}," + + "{\"id\": \"7bce71783ff8e6501b33ce9797097f5633c069f17e4731d96467cdb311693fcb\"}," + + "{\"id\": \"38e7e04304c86c1156128f7bdc548d51f175d5bdf83df1b3edda1832cac385dd\"}," + + "{\"id\": \"95b5fb0d3ea32847d9d6bda2ff9da0be11bd5ba3175aad6f3cacafd14f9d28a3\"}," + + "{\"id\": \"8b346f4d914fe652bde477fa3f6b630fbcf7ffd9859daf8df4fc63cdd1562e5c\"}," + + "{\"id\": \"48335c2b63cffcef2a3cd0678b65c4fb16420f51110033024209957fbd58ec4e\"}" + + "]")) + + private String organisationId; + + private Set transactionRejections; + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + @EqualsAndHashCode + public static class TxRejectionRequest { + + @Schema(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") + private String id; + + @Schema(example = "INCORRECT_VAT_CODE") + private RejectionCode rejectionCode; + + } + +} diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsApprove.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java similarity index 68% rename from accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsApprove.java rename to accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java index 27c4834a..2af25cfe 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsApprove.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java @@ -2,18 +2,16 @@ import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; -import java.util.List; +import java.util.Set; @Getter @Setter @AllArgsConstructor @NoArgsConstructor -public class TransactionsApprove { +public class TransactionsRequest { + @ArraySchema(arraySchema = @Schema(example = "[ {" + "\"id\": \"7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4\"}," + "{\"id\": \"7bce71783ff8e6501b33ce9797097f5633c069f17e4731d96467cdb311693fcb\"}," + @@ -22,6 +20,20 @@ public class TransactionsApprove { "{\"id\": \"8b346f4d914fe652bde477fa3f6b630fbcf7ffd9859daf8df4fc63cdd1562e5c\"}," + "{\"id\": \"48335c2b63cffcef2a3cd0678b65c4fb16420f51110033024209957fbd58ec4e\"}" + "]")) + private String organisationId; + + private Set transactionIds; + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + @EqualsAndHashCode + public static class TransactionId { + + @Schema(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") + private String id; + + } - private List transactionApproves; } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java index 06ec9503..22a2824c 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java @@ -26,4 +26,5 @@ public static TransactionProcessView createSucess(String id) { public static TransactionProcessView createFail(String id, Problem error) { return new TransactionProcessView(id, false, Optional.of(error)); } + } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/AccountingCoreService.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/AccountingCoreService.java index e243b0dd..eb7465a0 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/AccountingCoreService.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/AccountingCoreService.java @@ -7,20 +7,17 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.UserExtractionParameters; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.event.ScheduledIngestionEvent; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionBatchRepository; -import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepositoryGateway; import org.cardanofoundation.lob.app.accounting_reporting_core.service.business_rules.ProcessorFlags; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.zalando.problem.Problem; import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Source.LOB; -import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus.FAILED; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.FAIL; import static org.zalando.problem.Status.NOT_FOUND; @Service @@ -31,7 +28,6 @@ public class AccountingCoreService { private final ApplicationEventPublisher applicationEventPublisher; private final TransactionBatchRepository transactionBatchRepository; private final ERPIncomingDataProcessor erpIncomingDataProcessor; - private final TransactionRepositoryGateway transactionRepositoryGateway; @Transactional public void scheduleIngestion(UserExtractionParameters userExtractionParameters) { @@ -60,7 +56,7 @@ public Either scheduleReIngestionForFailed(String batchId) { val txBatch = txBatchM.get(); val txs = txBatch.getTransactions().stream() - .filter(tx -> tx.getAutomatedValidationStatus() == FAILED) + .filter(tx -> tx.getStatus() == FAIL) // reprocess only the ones that have not been approved to dispatch yet, actually it is just a sanity check because it should never happen // and we should never allow approving failed transactions .filter(tx -> !tx.allApprovalsPassedForTransactionDispatch()) @@ -84,28 +80,4 @@ public Either scheduleReIngestionForFailed(String batchId) { return Either.right(true); } - @Transactional(propagation = Propagation.REQUIRES_NEW) - public Either approveTransaction(String txId) { - return transactionRepositoryGateway.approveTransaction(txId); - } - - @Transactional - public Either approveTransactionDispatch(String txId) { - return transactionRepositoryGateway.approveTransactionDispatch(txId); - } - - @Transactional - public Set approveTransactions(String organisationId, Set transactionIds) { - log.info("approveTransactions, transactionIds: {}", transactionIds); - - return transactionRepositoryGateway.approveTransactions(organisationId, transactionIds); - } - - @Transactional - public Set approveTransactionsDispatch(String organisationId, Set transactionIds) { - log.info("approveTransactionsDispatch, transactionIds: {}", transactionIds); - - return transactionRepositoryGateway.approveTransactionsDispatch(organisationId, transactionIds); - } - } diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterPropertyTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterPropertyTest.java similarity index 96% rename from accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterPropertyTest.java rename to accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterPropertyTest.java index 9c8bbe67..14bfb1e0 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterPropertyTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterPropertyTest.java @@ -7,7 +7,7 @@ import java.util.HashSet; import java.util.List; -class TransactionViewTypeConverterPropertyTest { +class TransactionViewIdTypeConverterPropertyTest { private final TransactionTypeConverter converter = new TransactionTypeConverter(); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterTest.java similarity index 97% rename from accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterTest.java rename to accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterTest.java index e78ed41e..2f78f085 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterTest.java @@ -9,7 +9,7 @@ import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionType.*; -public class TransactionViewTypeConverterTest { +public class TransactionViewIdTypeConverterTest { private final TransactionTypeConverter converter = new TransactionTypeConverter(); diff --git a/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java b/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java new file mode 100644 index 00000000..97c7990e --- /dev/null +++ b/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java @@ -0,0 +1,24 @@ +package org.cardanofoundation.lob.app.support.problem_support; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import org.zalando.problem.Problem; + +@RequiredArgsConstructor +@ToString +@Getter + +// TODO move to utils package???, it is not really specific to business domain but utility class +public class IdentifiableProblem { + + private final String id; + private final Problem problem; + private final IdType idType; + + public enum IdType { + TRANSACTION, + TRANSACTION_ITEM + } + +} From edb32211c1dd1572a138d3580ae7b05d36a7d1ff Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Thu, 8 Aug 2024 18:16:08 +0200 Subject: [PATCH 2/9] feat: added tx rejection and small refactorings. --- .../domain/entity/TransactionItemEntity.java | 40 ++++++++- .../TransactionRepositoryGateway.java | 79 +++++++++++++----- .../resource/AccountingCoreResource.java | 37 ++++++--- .../resource/model/AccountingCoreModel.java | 0 ...AccountingCorePresentationViewService.java | 39 +++++---- .../AccountingCoreResourceService.java | 8 +- .../TransactionItemsRejectionRequest.java | 45 +++++++++++ .../TransactionsRejectionRequest.java | 44 ---------- .../views/TransactionItemsProcessView.java | 36 +++++++++ .../views/TransactionProcessView.java | 5 +- .../AccountEventCodesConversionTaskItem.java | 10 +-- .../items/CostCenterConversionTaskItem.java | 7 +- .../items/DocumentConversionTaskItem.java | 2 +- ...ournalAccountCreditEnrichmentTaskItem.java | 15 ++-- .../items/ProjectConversionTaskItem.java | 7 +- .../internal/TransactionConverter.java | 18 ++--- ...countingCorePresentationConverterTest.java | 13 ++- ...countEventCodesConversionTaskItemTest.java | 16 ++-- .../AccountCodeCreditCheckTaskItemTest.java | 9 ++- .../AccountCodeDebitCheckTaskItemTest.java | 7 +- .../CostCenterConversionTaskItemTest.java | 8 +- .../items/DebitAccountCheckTaskItemTest.java | 81 ++++++++++--------- .../items/DocumentConversionTaskItemTest.java | 8 +- .../DocumentMustBePresentTaskItemTest.java | 9 ++- ...alAccountCreditEnrichmentTaskItemTest.java | 53 +++++++----- .../items/ProjectConversionTaskItemTest.java | 6 +- .../items/TxItemsCollapsingTaskItemTest.java | 42 ++++++---- .../TransactionVersionCalculatorTest.java | 27 ++++--- .../TransactionVersionPropertyBasedTest.java | 13 +-- .../service/TransactionConverter.java | 2 +- 30 files changed, 429 insertions(+), 257 deletions(-) delete mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCoreModel.java rename accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/{model => presentation_layer_service}/AccountingCorePresentationViewService.java (87%) rename accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/{model => presentation_layer_service}/AccountingCoreResourceService.java (91%) create mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java delete mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java create mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionItemEntity.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionItemEntity.java index 1e4f561d..b9784d0e 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionItemEntity.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionItemEntity.java @@ -12,8 +12,6 @@ import java.math.BigDecimal; import java.util.Optional; -@Getter -@Setter @Entity(name = "accounting_reporting_core.TransactionItemEntity") @Table(name = "accounting_core_transaction_item") @NoArgsConstructor @@ -26,6 +24,7 @@ public class TransactionItemEntity extends AuditEntity implements Persistable getRejection() { return Optional.ofNullable(rejection); } + // setters + public void setAccountDebit(Optional account) { + this.accountDebit = account.orElse(null); + } + + public void setAccountCredit(Optional account) { + this.accountCredit = account.orElse(null); + } + + public void setAccountEvent(Optional accountEvent) { + this.accountEvent = accountEvent.orElse(null); + } + + public void setProject(Optional project) { + this.project = project.orElse(null); + } + + public void setCostCenter(Optional costCenter) { + this.costCenter = costCenter.orElse(null); + } + + public void setDocument(Optional document) { + this.document = document.orElse(null); + } + + public void setRejection(Optional rejection) { + this.rejection = rejection.orElse(null); + } + public Optional getOperationType() { val amountLcy = this.amountLcy.intValue(); diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java index a2a5794a..dd5cbc0d 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java @@ -8,6 +8,8 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Rejection; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionItemEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionItemsRejectionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest.TransactionId; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.LedgerService; @@ -187,35 +189,76 @@ public List> approveTransactionsD return transactionsApprovalResponseListE; } - public Either rejectTransaction(String txId, - String txItemId, - Optional rejectionM) { - val txM = transactionRepository.findById(txId); + @Transactional + public List> rejectTransactionItems(TransactionItemsRejectionRequest transactionItemsRejectionRequest) { + log.info("Rejecting transaction items: {}", transactionItemsRejectionRequest); + + val organisationId = transactionItemsRejectionRequest.getOrganisationId(); + val transactionId = transactionItemsRejectionRequest.getTransactionId(); + + val txM = transactionRepository.findById(transactionId); + + val transactionItemEntitiesE = new ArrayList>(); if (txM.isEmpty()) { - return txNotFoundResponse(txId); + return notFoundTransactionResponse(transactionItemsRejectionRequest, transactionId); } val tx = txM.orElseThrow(); - val txItemM = tx.findItemById(txItemId); + for (val txItemRejection : transactionItemsRejectionRequest.getTransactionItemsRejections()) { + val txItemId = txItemRejection.getTxItemId(); + val rejectionCode = txItemRejection.getRejectionCode(); - if (txItemM.isEmpty()) { - val problem = Problem.builder() - .withTitle("TX_ITEM_NOT_FOUND") - .withDetail(STR."Transaction item with id \{txItemId} not found") - .with("txItemId", txItemId) - .build(); + val txItemM = transactionItemRepository.findById(txItemId); - return Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM)); - } + if (txItemM.isEmpty()) { + val problem = Problem.builder() + .withTitle("TX_ITEM_NOT_FOUND") + .withDetail(STR."Transaction item with id \{txItemId} not found") + .with("txItemId", txItemId) + .build(); + + transactionItemEntitiesE.add(Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM))); + continue; + } + + val txItem = txItemM.orElseThrow(); + if (tx.getLedgerDispatchApproved()) { + val problem = Problem.builder() + .withTitle("TX_ALREADY_APPROVED") + .withDetail(STR."Cannot reject transaction item \{txItemId} because transaction \{transactionId} has already been approved for dispatch") + .with("transactionId", transactionId) + .with("txItemId", txItemId) + .build(); + + transactionItemEntitiesE.add(Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM))); + continue; + } + + txItem.setRejection(Optional.of(new Rejection(rejectionCode))); - val txItem= txItemM.orElseThrow(); - txItem.setRejection(rejectionM.orElse(null)); + val savedTxItem = transactionItemRepository.save(txItem); - val savedTxItem = transactionItemRepository.save(txItem); + transactionItemEntitiesE.add(Either.right(savedTxItem)); + } + + return transactionItemEntitiesE; + } - return Either.right(savedTxItem.getTransaction()); + private static List> notFoundTransactionResponse(TransactionItemsRejectionRequest transactionItemsRejectionRequest, + String transactionId) { + return transactionItemsRejectionRequest.getTransactionItemsRejections() + .stream() + .map(txItemRejectionRequest -> { + val problem = Problem.builder() + .withTitle("TX_NOT_FOUND") + .withDetail(STR."Transaction with id \{transactionId} not found") + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + }).toList(); } public Optional findById(String transactionId) { diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java index 69c4a02e..634199be 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java @@ -13,16 +13,10 @@ import lombok.val; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionType; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.model.AccountingCorePresentationViewService; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.model.AccountingCoreResourceService; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.BatchSearchRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ExtractionRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.SearchRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.BatchView; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.BatchsDetailView; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.TransactionProcessView; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.TransactionView; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service.AccountingCorePresentationViewService; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service.AccountingCoreResourceService; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.*; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.*; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -171,11 +165,11 @@ public ResponseEntity extractionTrigger(@Valid @RequestBody ExtractionRequest } ) public ResponseEntity approveTransactions(@Valid @RequestBody TransactionsRequest transactionsRequest) { - val transactionProcessViewsResult = accountingCorePresentationService.approveTransactions(transactionsRequest); + val transactionProcessViews = accountingCorePresentationService.approveTransactions(transactionsRequest); return ResponseEntity .status(HttpStatusCode.valueOf(OK.getStatusCode())) - .body(transactionProcessViewsResult); + .body(transactionProcessViews); } @Tag(name = "Transactions Publish / Dispatch Approval", description = "Transactions Publish / Dispatch Approval API") @@ -188,7 +182,24 @@ public ResponseEntity approveTransactions(@Valid @RequestBody TransactionsReq } ) public ResponseEntity approveTransactionsPublish(@Valid @RequestBody TransactionsRequest transactionsRequest) { - val transactionProcessViewsResult = accountingCorePresentationService.approveTransactionsPublish(transactionsRequest); + val transactionProcessViewList = accountingCorePresentationService.approveTransactionsPublish(transactionsRequest); + + return ResponseEntity + .status(HttpStatusCode.valueOf(OK.getStatusCode())) + .body(transactionProcessViewList); + } + + @Tag(name = "Transaction Items Rejection", description = "Transaction Items Rejection API") + @PostMapping(value = "/transactions/reject", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @Operation(description = "Reject one or more transaction items per a given transaction", + responses = { + @ApiResponse(content = { + @Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema(schema = @Schema(implementation = TransactionItemsProcessView.class))) + }) + } + ) + public ResponseEntity rejectTransactionItems(@Valid @RequestBody TransactionItemsRejectionRequest transactionItemsRejectionRequest) { + val transactionProcessViewsResult = accountingCorePresentationService.rejectTransactionItems(transactionItemsRejectionRequest); return ResponseEntity .status(HttpStatusCode.valueOf(OK.getStatusCode())) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCoreModel.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCoreModel.java deleted file mode 100644 index e69de29b..00000000 diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java similarity index 87% rename from accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java rename to accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java index 2e827423..15e5a583 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationViewService.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java @@ -1,4 +1,4 @@ -package org.cardanofoundation.lob.app.accounting_reporting_core.resource.model; +package org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -7,13 +7,10 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionBatchRepositoryGateway; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepositoryGateway; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.BatchSearchRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ExtractionRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.SearchRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.*; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.*; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.AccountingCoreService; -import org.jmolecules.ddd.annotation.Service; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; @@ -27,6 +24,7 @@ import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Counterparty.Type.VENDOR; @Service +@org.jmolecules.ddd.annotation.Service @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) @@ -146,7 +144,7 @@ public List approveTransactions(TransactionsRequest tran .map(txEntityE -> txEntityE.fold(txProblem -> { return TransactionProcessView.createFail(txProblem.getId(), txProblem.getProblem()); }, success -> { - return TransactionProcessView.createSucess(success.getId()); + return TransactionProcessView.createSuccess(success.getId()); })) .toList(); } @@ -157,7 +155,20 @@ public List approveTransactionsPublish(TransactionsReque .map(txEntityE -> txEntityE.fold(txProblem -> { return TransactionProcessView.createFail(txProblem.getId(), txProblem.getProblem()); }, success -> { - return TransactionProcessView.createSucess(success.getId()); + return TransactionProcessView.createSuccess(success.getId()); + })) + .toList(); + } + + public List rejectTransactionItems(TransactionItemsRejectionRequest transactionItemsRejectionRequest) { + val transactionId = transactionItemsRejectionRequest.getTransactionId(); + + return transactionRepositoryGateway.rejectTransactionItems(transactionItemsRejectionRequest) + .stream() + .map(txItemEntityE -> txItemEntityE.fold(txProblem -> { + return TransactionItemsProcessView.createFail(transactionId, txProblem.getId(), txProblem.getProblem()); + }, success -> { + return TransactionItemsProcessView.createSuccess(transactionId, success.getId()); })) .toList(); } @@ -188,12 +199,12 @@ private Set getTransactionItemView(TransactionEntity transa return transaction.getItems().stream().map(item -> { return new TransactionItemView( item.getId(), - item.getAccountDebit().map(account -> account.getCode()).orElse(""), - item.getAccountDebit().flatMap(account -> account.getName()).orElse(""), - item.getAccountDebit().flatMap(account -> account.getRefCode()).orElse(""), - item.getAccountCredit().map(account -> account.getCode()).orElse(""), - item.getAccountCredit().flatMap(account -> account.getName()).orElse(""), - item.getAccountCredit().flatMap(account -> account.getRefCode()).orElse(""), + item.getAccountDebit().map(Account::getCode).orElse(""), + item.getAccountDebit().flatMap(Account::getName).orElse(""), + item.getAccountDebit().flatMap(Account::getRefCode).orElse(""), + item.getAccountCredit().map(Account::getCode).orElse(""), + item.getAccountCredit().flatMap(Account::getName).orElse(""), + item.getAccountCredit().flatMap(Account::getRefCode).orElse(""), item.getAmountFcy(), item.getAmountLcy(), item.getFxRate(), diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCoreResourceService.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCoreResourceService.java similarity index 91% rename from accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCoreResourceService.java rename to accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCoreResourceService.java index 0d090d71..bb33b4a4 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCoreResourceService.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCoreResourceService.java @@ -1,17 +1,17 @@ -package org.cardanofoundation.lob.app.accounting_reporting_core.resource.model; +package org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.cardanofoundation.lob.app.organisation.OrganisationPublicApi; import org.cardanofoundation.lob.app.organisation.domain.entity.Organisation; -import org.jmolecules.ddd.annotation.Service; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.util.Optional; @Service -@org.springframework.stereotype.Service +@org.jmolecules.ddd.annotation.Service @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) @@ -21,8 +21,8 @@ public class AccountingCoreResourceService { public Optional findOrganisationById(String organisationId){ return organisationPublicApi.findByOrganisationId(organisationId); - } + public boolean checkFromToDates(Organisation org, String dateFrom, String dateTo) { diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java new file mode 100644 index 00000000..d866ec90 --- /dev/null +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java @@ -0,0 +1,45 @@ +package org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.*; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode; + +import java.util.Set; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class TransactionItemsRejectionRequest { + + @Schema(example = "75f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020ca94") + @NotBlank + private String organisationId; + + @Schema(example = "abf95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020caff") + @NotBlank + private String transactionId; + + @NotNull + @Size(min = 1) + private Set transactionItemsRejections; + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + @EqualsAndHashCode + public static class TxItemRejectionRequest { + + @Schema(example = "12f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020caaa") + private String txItemId; + + @Schema(example = "INCORRECT_VAT_CODE") + private RejectionCode rejectionCode; + + } + +} diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java deleted file mode 100644 index 45a1cb00..00000000 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRejectionRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests; - -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode; - -import java.util.Set; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class TransactionsRejectionRequest { - - @ArraySchema(arraySchema = @Schema(example = "[ {" + - "\"id\": \"7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4\"}," + - "{\"id\": \"7bce71783ff8e6501b33ce9797097f5633c069f17e4731d96467cdb311693fcb\"}," + - "{\"id\": \"38e7e04304c86c1156128f7bdc548d51f175d5bdf83df1b3edda1832cac385dd\"}," + - "{\"id\": \"95b5fb0d3ea32847d9d6bda2ff9da0be11bd5ba3175aad6f3cacafd14f9d28a3\"}," + - "{\"id\": \"8b346f4d914fe652bde477fa3f6b630fbcf7ffd9859daf8df4fc63cdd1562e5c\"}," + - "{\"id\": \"48335c2b63cffcef2a3cd0678b65c4fb16420f51110033024209957fbd58ec4e\"}" + - "]")) - - private String organisationId; - - private Set transactionRejections; - - @Getter - @Setter - @AllArgsConstructor - @NoArgsConstructor - @EqualsAndHashCode - public static class TxRejectionRequest { - - @Schema(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") - private String id; - - @Schema(example = "INCORRECT_VAT_CODE") - private RejectionCode rejectionCode; - - } - -} diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java new file mode 100644 index 00000000..38b41a79 --- /dev/null +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java @@ -0,0 +1,36 @@ +package org.cardanofoundation.lob.app.accounting_reporting_core.resource.views; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.zalando.problem.Problem; + +import java.util.Optional; + +@Getter +@Setter +@AllArgsConstructor +public class TransactionItemsProcessView { + + private String transactionId; + private String transactionItemId; + private Boolean success; + private Optional error; + + public static TransactionItemsProcessView createSuccess(String transactionId, + String transactionItemId) { + return new TransactionItemsProcessView( + transactionId, + transactionItemId, + true, + Optional.empty() + ); + } + + public static TransactionItemsProcessView createFail(String transactionId, + String transactionItemId, + Problem error) { + return new TransactionItemsProcessView(transactionId, transactionItemId, false, Optional.of(error)); + } + +} diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java index 22a2824c..32465b12 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionProcessView.java @@ -1,6 +1,5 @@ package org.cardanofoundation.lob.app.accounting_reporting_core.resource.views; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -14,12 +13,10 @@ public class TransactionProcessView { private String id; - private Boolean success; - private Optional error; - public static TransactionProcessView createSucess(String id) { + public static TransactionProcessView createSuccess(String id) { return new TransactionProcessView(id, true, Optional.empty()); } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountEventCodesConversionTaskItem.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountEventCodesConversionTaskItem.java index 0f2ce768..c387f5a3 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountEventCodesConversionTaskItem.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountEventCodesConversionTaskItem.java @@ -68,12 +68,12 @@ private void setAccountCodeRef(Account account, switch (type) { case DEBIT: - item.setAccountDebit(account.toBuilder() + item.setAccountDebit(Optional.of(account.toBuilder() .refCode(chartOfAccount.getEventRefCode()) - .build()); + .build())); break; case CREDIT: - item.setAccountCredit(account.toBuilder().refCode(chartOfAccount.getEventRefCode()).build()); + item.setAccountCredit(Optional.of(account.toBuilder().refCode(chartOfAccount.getEventRefCode()).build())); break; } } @@ -136,10 +136,10 @@ private void setAccountEventCode(String organisationId, organisationPublicApi.findEventCode(organisationId, eventCode) .ifPresentOrElse( - event -> item.setAccountEvent(AccountEvent.builder() + event -> item.setAccountEvent(Optional.of(AccountEvent.builder() .code(eventCode) .name(event.getName()) - .build() + .build()) ), () -> addMissingEventViolation(eventCode, item, tx)); } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItem.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItem.java index 5af875d1..4904b4e6 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItem.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItem.java @@ -7,10 +7,11 @@ import org.cardanofoundation.lob.app.organisation.OrganisationPublicApiIF; import java.util.Map; +import java.util.Optional; -import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ViolationCode.COST_CENTER_DATA_NOT_FOUND; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Source.LOB; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Violation.Severity.ERROR; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ViolationCode.COST_CENTER_DATA_NOT_FOUND; @RequiredArgsConstructor public class CostCenterConversionTaskItem implements PipelineTaskItem { @@ -55,11 +56,11 @@ public void run(TransactionEntity tx) { val costCenterMapping = costCenterMappingM.orElseThrow(); - txItem.setCostCenter(costCenter.toBuilder() + txItem.setCostCenter(Optional.of(costCenter.toBuilder() .customerCode(customerCode) .externalCustomerCode(costCenterMapping.getExternalCustomerCode()) .name(costCenterMapping.getName()) - .build() + .build()) ); } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItem.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItem.java index 7fc3c135..1bea5ce2 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItem.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItem.java @@ -104,7 +104,7 @@ private void updateDocument(TransactionItemEntity txItem, .vat(getUpdatedVat(document, enrichedVatM)) .build(); - txItem.setDocument(updatedDocument); + txItem.setDocument(Optional.of(updatedDocument)); } @Nullable diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItem.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItem.java index 674c64ec..d937bab5 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItem.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItem.java @@ -22,6 +22,7 @@ public class JournalAccountCreditEnrichmentTaskItem implements PipelineTaskItem { public static final String DUMMY_ACCOUNT = "Dummy Account"; + private final OrganisationPublicApiIF organisationPublicApiIF; @Override @@ -55,10 +56,10 @@ public void run(TransactionEntity tx) { val operationTypeM = txItem.getOperationType(); if (operationTypeM.isEmpty()) { - txItem.setAccountCredit(Account.builder() + txItem.setAccountCredit(Optional.of(Account.builder() .code(dummyAccount) .name(DUMMY_ACCOUNT) - .build()); + .build())); continue; } @@ -66,23 +67,23 @@ public void run(TransactionEntity tx) { if (txItem.getAccountCredit().isEmpty() && operationType == CREDIT) { val accountDebit = txItem.getAccountDebit().orElseThrow(); - txItem.setAccountCredit(accountDebit); + txItem.setAccountCredit(Optional.of(accountDebit)); txItem.clearAccountCodeDebit(); } if (txItem.getAccountCredit().isEmpty()) { - txItem.setAccountCredit(Account.builder() + txItem.setAccountCredit(Optional.of(Account.builder() .code(dummyAccount) .name(DUMMY_ACCOUNT) - .build()); + .build())); } if (txItem.getAccountDebit().isEmpty()) { - txItem.setAccountDebit(Account.builder() + txItem.setAccountDebit(Optional.of(Account.builder() .code(dummyAccount) .name(DUMMY_ACCOUNT) - .build()); + .build())); } } } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItem.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItem.java index 21249648..25ef6776 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItem.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItem.java @@ -8,6 +8,7 @@ import org.cardanofoundation.lob.app.organisation.OrganisationPublicApiIF; import java.util.Map; +import java.util.Optional; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Source.LOB; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Violation.Severity.ERROR; @@ -60,13 +61,11 @@ public void run(TransactionEntity tx) { val projectMapping = projectMappingM.orElseThrow(); - val p = project.toBuilder() + txItem.setProject(Optional.of(project.toBuilder() .customerCode(projectMapping.getId().getCustomerCode()) .externalCustomerCode(projectMapping.getExternalCustomerCode()) .name(projectMapping.getName()) - .build(); - - txItem.setProject(p); + .build())); } } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java index a38eacce..66fe0f94 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java @@ -98,33 +98,33 @@ private TransactionEntity convertToDbDetached(Transaction transaction) { val txItemEntity = new TransactionItemEntity(); txItemEntity.setId(txItem.getId()); - txItemEntity.setDocument(doc); + txItemEntity.setDocument(Optional.of(doc)); txItemEntity.setAmountLcy(txItem.getAmountLcy()); txItemEntity.setAmountFcy(txItem.getAmountFcy()); - txItemEntity.setCostCenter(convertCostCenter(txItem.getCostCenter())); - txItemEntity.setProject(convertProject(txItem.getProject())); + txItemEntity.setCostCenter(Optional.of(convertCostCenter(txItem.getCostCenter()))); + txItemEntity.setProject(Optional.of(convertProject(txItem.getProject()))); txItemEntity.setFxRate(txItem.getFxRate()); txItem.getAccountCredit().ifPresent(creditAccount -> { - txItemEntity.setAccountCredit(Account.builder() + txItemEntity.setAccountCredit(Optional.of(Account.builder() .code(creditAccount.getCode()) .refCode(creditAccount.getRefCode().orElse(null)) .name(creditAccount.getName().orElse(null)) - .build()); + .build())); }); txItem.getAccountDebit().ifPresent(debitAccount -> { - txItemEntity.setAccountDebit(Account.builder() + txItemEntity.setAccountDebit(Optional.of(Account.builder() .code(debitAccount.getCode()) .refCode(debitAccount.getRefCode().orElse(null)) .name(debitAccount.getName().orElse(null)) - .build()); + .build())); }); txItem.getAccountEvent().ifPresent(accountEvent -> { - txItemEntity.setAccountEvent(AccountEvent.builder() + txItemEntity.setAccountEvent(Optional.of(AccountEvent.builder() .code(accountEvent.getCode()) .name(accountEvent.getName()) - .build()); + .build())); }); return txItemEntity; diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java index 598baa85..3d1a1106 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java @@ -6,6 +6,7 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionBatchRepositoryGateway; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepositoryGateway; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service.AccountingCorePresentationViewService; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.BatchSearchRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ExtractionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.SearchRequest; @@ -27,6 +28,7 @@ import java.time.format.DateTimeFormatter; import java.util.*; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ViolationCode.CORE_CURRENCY_NOT_FOUND; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -43,9 +45,6 @@ class AccountingCorePresentationConverterTest { @Mock private TransactionBatchRepositoryGateway transactionBatchRepositoryGateway; - @Mock - private AccountingCoreResourceService accountingCoreResourceService; - @InjectMocks private AccountingCorePresentationViewService accountingCorePresentationConverter; @@ -76,13 +75,13 @@ void testAllTransactions() { violation.setTxItemId(Optional.of(transactionItem.getId().toString())); violation.setSource(Source.ERP); violation.setSeverity(org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Violation.Severity.WARN); - violation.setCode(ViolationCode.CORE_CURRENCY_NOT_FOUND); + violation.setCode(CORE_CURRENCY_NOT_FOUND); transactionEntity.setItems(Set.of(transactionItem)); transactionEntity.setViolations(Set.of(violation)); - transactionItem.setAccountDebit(accountDebit); - transactionItem.setAccountCredit(accountCredit); + transactionItem.setAccountDebit(Optional.of(accountDebit)); + transactionItem.setAccountCredit(Optional.of(accountCredit)); transactionItem.setTransaction(transactionEntity); transactionItem.setAmountFcy(BigDecimal.valueOf(1000)); transactionItem.setAmountLcy(BigDecimal.valueOf(1000)); @@ -124,7 +123,7 @@ void testAllTransactions() { assertEquals(Source.ERP, result.get(0).getViolations().stream().findFirst().get().getSource()); assertEquals(org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Violation.Severity.WARN, result.get(0).getViolations().stream().findFirst().get().getSeverity()); - assertEquals(ViolationCode.CORE_CURRENCY_NOT_FOUND, result.get(0).getViolations().stream().findFirst().get().getCode()); + assertEquals(CORE_CURRENCY_NOT_FOUND, result.get(0).getViolations().stream().findFirst().get().getCode()); } @Test diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountAccountEventCodesConversionTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountAccountEventCodesConversionTaskItemTest.java index 670b7396..0134d8d6 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountAccountEventCodesConversionTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountAccountEventCodesConversionTaskItemTest.java @@ -59,15 +59,15 @@ public void testChartOfAccountsMappingFoundForBothDebitAndCredit() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "0")); - txItem.setAccountDebit(Account.builder() + txItem.setAccountDebit(Optional.of(Account.builder() .code(accountCodeDebit) .build() - ); + )); - txItem.setAccountCredit(Account.builder() + txItem.setAccountCredit(Optional.of(Account.builder() .code(accountCodeCredit) .build() - ); + )); val tx = new TransactionEntity(); tx.setId(txId); @@ -98,10 +98,10 @@ public void testChartOfAccountsMappingNotFoundForDebit() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "1")); - txItem.setAccountDebit(Account.builder() + txItem.setAccountDebit(Optional.of(Account.builder() .code(accountCodeDebit) .build() - ); + )); val tx = new TransactionEntity(); tx.setId(txId); @@ -129,10 +129,10 @@ public void testChartOfAccountsMappingNotFoundForCredit() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "2")); - txItem.setAccountCredit(Account.builder() + txItem.setAccountCredit(Optional.of(Account.builder() .code(accountCodeCredit) .build() - ); + )); val tx = new TransactionEntity(); tx.setId(txId); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeCreditCheckTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeCreditCheckTaskItemTest.java index e3daa556..ec278151 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeCreditCheckTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeCreditCheckTaskItemTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Optional; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +35,7 @@ public void testCreditWorks() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "0")); - txItem.setAccountCredit(Account.builder().code("1").build()); + txItem.setAccountCredit(Optional.of(Account.builder().code("1").build())); val tx = new TransactionEntity(); tx.setId(txId); @@ -100,7 +101,7 @@ public void testMixedCreditItems() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setAccountCredit(Account.builder().code("100").build()); + txItem1.setAccountCredit(Optional.of(Account.builder().code("100").build())); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "2")); @@ -149,7 +150,7 @@ public void testItemWithEmptyStringCredit() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setAccountCredit(Account.builder().code(" ").build()); + txItem1.setAccountCredit(Optional.of(Account.builder().code(" ").build())); val tx = new TransactionEntity(); tx.setId(txId); @@ -188,7 +189,7 @@ public void testValidCreditWithWhitespace() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "0")); - txItem.setAccountCredit(Account.builder().code(" 100 ").build()); + txItem.setAccountCredit(Optional.of(Account.builder().code(" 100 ").build())); val tx = new TransactionEntity(); tx.setId(txId); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeDebitCheckTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeDebitCheckTaskItemTest.java index 8d51ecbb..7dc85b49 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeDebitCheckTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/AccountCodeDebitCheckTaskItemTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Optional; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +35,7 @@ public void testDebitWorks() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "0")); - txItem.setAccountDebit(Account.builder().code("1").build()); + txItem.setAccountDebit(Optional.of(Account.builder().code("1").build())); val tx = new TransactionEntity(); tx.setId(txId); @@ -97,7 +98,7 @@ public void testMixedDebitItems() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "1")); - txItem1.setAccountDebit(Account.builder().code("100").build()); + txItem1.setAccountDebit(Optional.of(Account.builder().code("100").build())); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "2")); @@ -163,7 +164,7 @@ public void testValidDebitWithWhitespace() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "6")); - txItem.setAccountDebit(Account.builder().code(" 100 ").build()); + txItem.setAccountDebit(Optional.of(Account.builder().code(" 100 ").build())); val tx = new TransactionEntity(); tx.setId(txId); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItemTest.java index 4dbfbcd2..eba81fcb 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/CostCenterConversionTaskItemTest.java @@ -71,7 +71,7 @@ void testCostCenterConversionSuccess() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setCostCenter(new CostCenter("1", "2", "Cost Center 1")); + txItem1.setCostCenter(Optional.of(new CostCenter("1", "2", "Cost Center 1"))); val tx = new TransactionEntity(); tx.setId(txId); @@ -92,7 +92,7 @@ void testRunCostCenterNotFound() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setCostCenter(CostCenter.builder().customerCode("1").build()); + txItem1.setCostCenter(Optional.of(CostCenter.builder().customerCode("1").build())); val tx = new TransactionEntity(); tx.setId(txId); @@ -117,11 +117,11 @@ void testMultipleItemsWithMixedOutcomes() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setCostCenter(new CostCenter("1", "2", "Cost Center 1")); + txItem1.setCostCenter(Optional.of(new CostCenter("1", "2", "Cost Center 1"))); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "1")); - txItem2.setCostCenter(CostCenter.builder().customerCode("UNKNOWN").build()); + txItem2.setCostCenter(Optional.of(CostCenter.builder().customerCode("UNKNOWN").build())); val items = new LinkedHashSet<>(); items.add(txItem1); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DebitAccountCheckTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DebitAccountCheckTaskItemTest.java index 38df9315..2de8f98e 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DebitAccountCheckTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DebitAccountCheckTaskItemTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; import java.util.LinkedHashSet; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus.FAILED; @@ -30,24 +31,28 @@ void testRunWithoutCollapsing() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setAccountCredit(Account.builder() + txItem1.setAccountCredit(Optional.of(Account.builder() .code("1") - .build()); + .build()) + ); - txItem1.setAccountDebit(Account.builder() + txItem1.setAccountDebit(Optional.of(Account.builder() .code("2") - .build()); + .build()) + ); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "1")); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("1") - .build()); + .build()) + ); - txItem2.setAccountDebit(Account.builder() + txItem2.setAccountDebit(Optional.of(Account.builder() .code("2") - .build()); + .build()) + ); val txItems = new LinkedHashSet(); txItems.add(txItem1); @@ -71,24 +76,28 @@ void testRunWithCollapsing() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setAccountCredit(Account.builder() + txItem1.setAccountCredit(Optional.of(Account.builder() .code("1") - .build()); + .build()) + ); - txItem1.setAccountDebit(Account.builder() + txItem1.setAccountDebit(Optional.of(Account.builder() .code("1") - .build()); + .build()) + ); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "1")); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("1") - .build()); + .build()) + ); - txItem2.setAccountDebit(Account.builder() + txItem2.setAccountDebit(Optional.of(Account.builder() .code("2") - .build()); + .build()) + ); val txItems = new LinkedHashSet(); txItems.add(txItem1); @@ -111,28 +120,28 @@ void testRunWithCollapsingWithFailedTransactions() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setAccountCredit(Account.builder() + txItem1.setAccountCredit(Optional.of(Account.builder() .code("1") .build() - ); + )); - txItem1.setAccountDebit(Account.builder() + txItem1.setAccountDebit(Optional.of(Account.builder() .code("1") .build() - ); + )); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "1")); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("1") .build() - ); + )); - txItem2.setAccountDebit(Account.builder() + txItem2.setAccountDebit(Optional.of(Account.builder() .code("2") .build() - ); + )); val txItems = new LinkedHashSet(); txItems.add(txItem1); @@ -156,27 +165,27 @@ public void testMixedValidAndInvalidAccountCodes() { val txItem1 = new TransactionItemEntity(); txItem1.setId(TransactionItem.id(txId, "0")); - txItem1.setAccountCredit(Account.builder() + txItem1.setAccountCredit(Optional.of(Account.builder() .code("3") .build() - ); + )); - txItem1.setAccountDebit(Account.builder() + txItem1.setAccountDebit(Optional.of(Account.builder() .code("3") .build() - ); + )); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "1")); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("4") .build() - ); + )); - txItem2.setAccountDebit(Account.builder() + txItem2.setAccountDebit(Optional.of(Account.builder() .code("5") .build() - ); + )); val txItems = new LinkedHashSet(); txItems.add(txItem1); @@ -201,18 +210,18 @@ public void testTransactionItemsWithMissingAccountCodes() { txItem1.setId(TransactionItem.id(txId, "0")); txItem1.clearAccountCodeCredit(); - txItem1.setAccountCredit(Account.builder() + txItem1.setAccountCredit(Optional.of(Account.builder() .code("6") .build() - ); + )); val txItem2 = new TransactionItemEntity(); txItem2.setId(TransactionItem.id(txId, "1")); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("7") .build() - ); + )); txItem2.clearAccountCodeDebit(); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItemTest.java index 161f4e36..8604a32d 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentConversionTaskItemTest.java @@ -58,7 +58,7 @@ public void testVatDataNotFoundAddsViolation() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "0")); - txItem.setDocument(document); + txItem.setDocument(Optional.of(document)); val items = new LinkedHashSet(); items.add(txItem); @@ -95,7 +95,7 @@ public void testCurrencyNotFoundAddsViolation() { val txItem = new TransactionItemEntity(); txItem.setId(TransactionItem.id(txId, "0")); - txItem.setDocument(document); + txItem.setDocument(Optional.of(document)); val items = new LinkedHashSet(); items.add(txItem); @@ -135,7 +135,7 @@ public void testSuccessfulDocumentConversion() { .build(); val txItem = new TransactionItemEntity(); - txItem.setDocument(document); + txItem.setDocument(Optional.of(document)); val items = new LinkedHashSet(); items.add(txItem); @@ -188,7 +188,7 @@ public void testDocumentConversionWithMultipleViolations() { .build(); val txItem = new TransactionItemEntity(); - txItem.setDocument(document); + txItem.setDocument(Optional.of(document)); val items = new LinkedHashSet(); items.add(txItem); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentMustBePresentTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentMustBePresentTaskItemTest.java index c1e442d1..a19473a0 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentMustBePresentTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/DocumentMustBePresentTaskItemTest.java @@ -9,6 +9,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.Optional; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -29,7 +30,7 @@ void shouldNotModifyTransactionWhenAllDocumentsPresent() { val itemWithDocument = new TransactionItemEntity(); itemWithDocument.setId("itemWithDocument"); - itemWithDocument.setDocument(document); + itemWithDocument.setDocument(Optional.of(document)); val items = new HashSet(); items.add(itemWithDocument); @@ -49,7 +50,7 @@ void shouldNotModifyTransactionWhenAllDocumentsPresent() { void shouldAddViolationWhenDocumentIsMissing() { val itemWithoutDocument = new TransactionItemEntity(); itemWithoutDocument.setId("itemWithoutDocument"); - itemWithoutDocument.setDocument(null); + itemWithoutDocument.setDocument(Optional.empty()); val items = new HashSet(); items.add(itemWithoutDocument); @@ -71,11 +72,11 @@ void shouldHandleMixedDocumentPresenceCorrectly() { val itemWithDocument = new TransactionItemEntity(); itemWithDocument.setId("itemWithDocument"); - itemWithDocument.setDocument(document); + itemWithDocument.setDocument(Optional.of(document)); val itemWithoutDocument = new TransactionItemEntity(); itemWithoutDocument.setId("itemWithoutDocument"); - itemWithoutDocument.setDocument(null); + itemWithoutDocument.setDocument(Optional.empty()); Set items = new LinkedHashSet<>(); items.add(itemWithDocument); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItemTest.java index e8a9aa91..fde104d6 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/JournalAccountCreditEnrichmentTaskItemTest.java @@ -109,9 +109,10 @@ void should_Not_Run_Because_Not_All_Credit_Accounts_Are_Missing() { val txItem2 = new TransactionItemEntity(); txItem2.setId("2"); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("1234567890") - .build()); + .build()) + ); items.add(txItem2); transaction.setItems(items); @@ -140,17 +141,20 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item1 = new TransactionItemEntity(); item1.setId("1"); - item1.setAccountDebit(Account.builder() + item1.setAccountDebit(Optional.of(Account.builder() .code("4102110100") - .build()); + .build()) + ); + item1.setAmountLcy(BigDecimal.valueOf(988.86)); // positive implies debit items.add(item1); val item2 = new TransactionItemEntity(); item2.setId("2"); - item2.setAccountDebit(Account.builder() + item2.setAccountDebit(Optional.of(Account.builder() .code("4102120100") .build() + ) ); item2.setAmountLcy(BigDecimal.valueOf(-188.50)); // negative implies credit @@ -158,9 +162,10 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item3 = new TransactionItemEntity(); item3.setId("3"); - item3.setAccountDebit(Account.builder() + item3.setAccountDebit(Optional.of(Account.builder() .code("4102140100") - .build()); + .build()) + ); item3.setAmountLcy(BigDecimal.valueOf(148.64)); items.add(item3); @@ -168,9 +173,10 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item4 = new TransactionItemEntity(); item4.setId("4"); - item4.setAccountDebit(Account.builder() + item4.setAccountDebit(Optional.of(Account.builder() .code("5205140100") - .build()); + .build()) + ); item4.setAmountLcy(BigDecimal.valueOf(-949.00)); items.add(item4); @@ -178,9 +184,10 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item5 = new TransactionItemEntity(); item5.setId("5"); - item5.setAccountDebit(Account.builder() + item5.setAccountDebit(Optional.of(Account.builder() .code("5208110100") - .build()); + .build()) + ); item5.setAmountLcy(BigDecimal.valueOf(-528.5)); items.add(item5); @@ -188,18 +195,21 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item6 = new TransactionItemEntity(); item6.setId("6"); - item6.setAccountDebit(Account.builder() + item6.setAccountDebit(Optional.of(Account.builder() .code("5208120100") - .build()); + .build()) + + ); item6.setAmountLcy(BigDecimal.valueOf(-147.30)); items.add(item6); val item7 = new TransactionItemEntity(); item7.setId("7"); - item7.setAccountDebit(Account.builder() + item7.setAccountDebit(Optional.of(Account.builder() .code("5205140100") - .build()); + .build()) + ); item7.setAmountLcy(BigDecimal.valueOf(675.80)); items.add(item7); @@ -207,10 +217,10 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item8 = new TransactionItemEntity(); item8.setId("8"); - item8.setAccountDebit(Account.builder() + item8.setAccountDebit(Optional.of(Account.builder() .code("1203210100") .build() - ); + )); item8.setAmountLcy(BigDecimal.valueOf(-925.40)); items.add(item8); @@ -218,10 +228,10 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item9 = new TransactionItemEntity(); item9.setId("9"); - item9.setAccountDebit(Account.builder() + item9.setAccountDebit(Optional.of(Account.builder() .code("5205140100") .build() - ); + )); item9.setAmountLcy(BigDecimal.valueOf(925.40)); items.add(item9); @@ -229,9 +239,10 @@ void should_Set_Credit_From_Debit_If_Conditions_Met() { val item10 = new TransactionItemEntity(); item10.setId("10"); - item10.setAccountDebit(Account.builder() + item10.setAccountDebit(Optional.of(Account.builder() .code("5205140101") - .build()); + .build()) + ); item10.setAmountLcy(BigDecimal.valueOf(0)); items.add(item10); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItemTest.java index 69be8c65..d79b145b 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/ProjectConversionTaskItemTest.java @@ -40,7 +40,7 @@ public void testProjectFoundConversionSucceeds() { val txItem = new TransactionItemEntity(); txItem.setId("1:0"); - txItem.setProject(project); + txItem.setProject(Optional.of(project)); Set items = new HashSet<>(); items.add(txItem); @@ -68,7 +68,7 @@ public void testProjectFoundConversionSucceeds() { public void testMissingProjectResultsInConversionSuccess() { val txItem = new TransactionItemEntity(); txItem.setId("1:0"); - txItem.setProject(null); + txItem.setProject(Optional.empty()); Set items = new HashSet<>(); items.add(txItem); @@ -92,7 +92,7 @@ public void testMissingProjectResultsInViolationCreation() { val txItem = new TransactionItemEntity(); txItem.setId("1:0"); - txItem.setProject(project); + txItem.setProject(Optional.of(project)); Set items = new HashSet<>(); items.add(txItem); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/TxItemsCollapsingTaskItemTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/TxItemsCollapsingTaskItemTest.java index bc3aa2ef..d76cd103 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/TxItemsCollapsingTaskItemTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/business_rules/items/TxItemsCollapsingTaskItemTest.java @@ -28,17 +28,19 @@ public void setup() { void shouldNotCollapseItems() { val txItem1 = new TransactionItemEntity(); txItem1.setId("1:0"); - txItem1.setAccountEvent(AccountEvent.builder() + txItem1.setAccountEvent(Optional.of(AccountEvent.builder() .code("e12") - .build()); + .build()) + ); txItem1.setAmountLcy(BigDecimal.ONE); txItem1.setAmountFcy(BigDecimal.TEN); val txItem2 = new TransactionItemEntity(); txItem2.setId("1:1"); - txItem2.setAccountEvent(AccountEvent.builder() + txItem2.setAccountEvent(Optional.of(AccountEvent.builder() .code("e1212") - .build()); + .build()) + ); txItem2.setAmountLcy(BigDecimal.ONE); txItem2.setAmountFcy(BigDecimal.TEN); @@ -61,17 +63,21 @@ void shouldNotCollapseItems() { void shouldCollapseItems() { val txItem1 = new TransactionItemEntity(); txItem1.setId("1:0"); - txItem1.setAccountEvent(AccountEvent.builder() + txItem1.setAccountEvent(Optional.of(AccountEvent.builder() .code("e12") - .build()); + .build()) + ); + txItem1.setAmountLcy(BigDecimal.ONE); txItem1.setAmountFcy(BigDecimal.TEN); val txItem2 = new TransactionItemEntity(); txItem2.setId("1:1"); - txItem2.setAccountEvent(AccountEvent.builder() + txItem2.setAccountEvent(Optional.of(AccountEvent.builder() .code("e12") - .build()); + .build()) + ); + txItem2.setAmountLcy(BigDecimal.ONE); txItem2.setAmountFcy(BigDecimal.TEN); @@ -100,9 +106,10 @@ void shouldCollapseSomeItemsAndNotOthers() { TransactionItemEntity txItem1 = new TransactionItemEntity(); txItem1.setId("1:0"); - txItem1.setAccountEvent(AccountEvent.builder() + txItem1.setAccountEvent(Optional.of(AccountEvent.builder() .code("e12") - .build()); + .build()) + ); txItem1.setAmountLcy(BigDecimal.ONE); txItem1.setAmountFcy(BigDecimal.TEN); @@ -115,9 +122,10 @@ void shouldCollapseSomeItemsAndNotOthers() { TransactionItemEntity txItem2 = new TransactionItemEntity(); txItem2.setId("2:0"); - txItem2.setAccountEvent(AccountEvent.builder() + txItem2.setAccountEvent(Optional.of(AccountEvent.builder() .code("e34") - .build()); + .build()) + ); txItem2.setAmountLcy(BigDecimal.ONE); txItem2.setAmountFcy(BigDecimal.TEN); @@ -144,9 +152,10 @@ void mustNotCollapseTxItemsForFailedTransactions() { TransactionItemEntity txItem1 = new TransactionItemEntity(); txItem1.setId("1:0"); - txItem1.setAccountEvent(AccountEvent.builder() + txItem1.setAccountEvent(Optional.of(AccountEvent.builder() .code("e12") - .build()); + .build()) + ); txItem1.setAmountLcy(BigDecimal.ONE); txItem1.setAmountFcy(BigDecimal.TEN); @@ -154,9 +163,10 @@ void mustNotCollapseTxItemsForFailedTransactions() { TransactionItemEntity txItem2 = new TransactionItemEntity(); txItem2.setId("1:1"); - txItem2.setAccountEvent(AccountEvent.builder() + txItem2.setAccountEvent(Optional.of(AccountEvent.builder() .code("e12") - .build()); + .build()) + ); txItem2.setAmountLcy(BigDecimal.ONE); txItem2.setAmountFcy(BigDecimal.TEN); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionCalculatorTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionCalculatorTest.java index abc19a3a..d4e65c3d 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionCalculatorTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionCalculatorTest.java @@ -8,6 +8,7 @@ import java.math.BigDecimal; import java.time.LocalDate; +import java.util.Optional; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -45,21 +46,21 @@ public void compute() { txItem1.setAmountFcy(BigDecimal.valueOf(100.10)); txItem1.setAmountLcy(BigDecimal.valueOf(100.20)); - txItem1.setAccountDebit(Account.builder() + txItem1.setAccountDebit(Optional.of(Account.builder() .code("1000") .name("Cash") .refCode("r1000") .build() - ); + )); - txItem1.setAccountCredit(Account.builder() + txItem1.setAccountCredit(Optional.of(Account.builder() .code("2000") .name("Bank") .refCode("r2000") .build() - ); + )); - txItem1.setDocument(Document.builder() + txItem1.setDocument(Optional.of(Document.builder() .num("doc-1") .vat(Vat.builder() .customerCode("C100") @@ -71,28 +72,29 @@ public void compute() { .counterparty(Counterparty.builder() .customerCode("C100") .build()) - .build()); + .build()) + ); val txItem2 = new TransactionItemEntity(); txItem2.setId("2"); txItem2.setAmountFcy(BigDecimal.valueOf(100.10)); txItem2.setAmountLcy(BigDecimal.valueOf(100.20)); - txItem2.setAccountDebit(Account.builder() + txItem2.setAccountDebit(Optional.of(Account.builder() .code("2000") .name("Cash") .refCode("21000") - .build() + .build()) ); - txItem2.setAccountCredit(Account.builder() + txItem2.setAccountCredit(Optional.of(Account.builder() .code("4000") .name("Bank") .refCode("r3000") - .build() + .build()) ); - txItem2.setDocument(Document.builder() + txItem2.setDocument(Optional.of(Document.builder() .num("doc-2") .vat(Vat.builder() .customerCode("C200") @@ -104,7 +106,8 @@ public void compute() { .counterparty(Counterparty.builder() .customerCode("C200") .build()) - .build()); + .build()) + ); t.setItems(Set.of(txItem1, txItem2)); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionPropertyBasedTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionPropertyBasedTest.java index 380a86af..934c1c8f 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionPropertyBasedTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionVersionPropertyBasedTest.java @@ -10,6 +10,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.YearMonth; +import java.util.Optional; import java.util.Set; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -60,19 +61,19 @@ void compute_shouldChangeHashForDifferentFields(@ForAll("transactionTypes") Tran val txItem1 = new TransactionItemEntity(); txItem1.setId("1"); txItem1.setAmountFcy(amountFcy1); - txItem1.setAccountDebit(Account.builder() + txItem1.setAccountDebit(Optional.of(Account.builder() .code("1000") .name("Cash") .refCode("r1000") .build() - ); - txItem1.setAccountCredit(Account.builder() + )); + txItem1.setAccountCredit(Optional.of(Account.builder() .code("2000") .name("Bank") .refCode("r2000") .build() - ); - txItem1.setDocument(Document.builder() + )); + txItem1.setDocument(Optional.of(Document.builder() .num("doc-1") .vat(Vat.builder() .customerCode("C100") @@ -86,7 +87,7 @@ void compute_shouldChangeHashForDifferentFields(@ForAll("transactionTypes") Tran .type(VENDOR) .build()) .build() - ); + )); val t1 = new TransactionEntity(); t1.setTransactionType(transactionType1); diff --git a/netsuite_altavia_erp_adapter/src/main/java/org/cardanofoundation/lob/app/netsuite_altavia_erp_adapter/service/TransactionConverter.java b/netsuite_altavia_erp_adapter/src/main/java/org/cardanofoundation/lob/app/netsuite_altavia_erp_adapter/service/TransactionConverter.java index d33bfea3..5366cb14 100644 --- a/netsuite_altavia_erp_adapter/src/main/java/org/cardanofoundation/lob/app/netsuite_altavia_erp_adapter/service/TransactionConverter.java +++ b/netsuite_altavia_erp_adapter/src/main/java/org/cardanofoundation/lob/app/netsuite_altavia_erp_adapter/service/TransactionConverter.java @@ -175,7 +175,7 @@ private Either> createTransactionFromSearchRes private static List> humanReadable(Set> validationIssues) { return validationIssues.stream().map(c -> { - return Map.of( + return Map.of( "bean", c.getRootBean().getClass().getName(), "msg", c.getMessage(), "property", c.getPropertyPath().toString(), From 749239c368a6e629c0fee4e44579bb28ee9fac53 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Thu, 8 Aug 2024 18:23:35 +0200 Subject: [PATCH 3/9] refactor: code simplification --- .../TransactionRepositoryGateway.java | 11 ++------- .../resource/requests/BatchSearchRequest.java | 4 +++- .../TransactionItemsRejectionRequest.java | 2 ++ .../requests/TransactionsRequest.java | 23 ++++++++----------- .../resource/views/BatchsDetailView.java | 2 ++ 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java index dd5cbc0d..dffafe83 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java @@ -11,7 +11,6 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionItemEntity; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionItemsRejectionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest.TransactionId; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.LedgerService; import org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem; import org.springframework.dao.DataAccessException; @@ -126,10 +125,7 @@ private Either approveTransactionsDispat public List> approveTransactions(TransactionsRequest transactionsRequest) { val organisationId = transactionsRequest.getOrganisationId(); - val transactionIds = transactionsRequest.getTransactionIds() - .stream() - .map(TransactionId::getId) - .collect(Collectors.toSet()); + val transactionIds = transactionsRequest.getTransactionIds(); val transactionsApprovalResponseListE = new ArrayList>(); for (val transactionId : transactionIds) { @@ -159,10 +155,7 @@ public List> approveTransactions( public List> approveTransactionsDispatch(TransactionsRequest transactionsRequest) { val organisationId = transactionsRequest.getOrganisationId(); - val transactionIds = transactionsRequest.getTransactionIds() - .stream() - .map(TransactionId::getId) - .collect(Collectors.toSet()); + val transactionIds = transactionsRequest.getTransactionIds(); val transactionsApprovalResponseListE = new ArrayList>(); for (val transactionId : transactionIds) { diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/BatchSearchRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/BatchSearchRequest.java index 2c50c930..9e82f40a 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/BatchSearchRequest.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/BatchSearchRequest.java @@ -8,6 +8,7 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; @@ -31,6 +32,7 @@ public class BatchSearchRequest { @Schema(example = "75f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020ca94") + @NotBlank private String organisationId; @ArraySchema(arraySchema = @Schema(example = "[\"APPROVE\", \"PENDING\", \"INVALID\", \"PUBLISH\", \"PUBLISHED\"]", implementation = LedgerDispatchStatusView.class)) @@ -46,8 +48,8 @@ public class BatchSearchRequest { @Nullable private LocalDate from; - @Nullable @Schema(example = "2024-12-31") + @Nullable private LocalDate To; @JsonIgnore diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java index d866ec90..9f8c8aff 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionItemsRejectionRequest.java @@ -35,9 +35,11 @@ public class TransactionItemsRejectionRequest { public static class TxItemRejectionRequest { @Schema(example = "12f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020caaa") + @NotBlank private String txItemId; @Schema(example = "INCORRECT_VAT_CODE") + @NotNull private RejectionCode rejectionCode; } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java index 2af25cfe..b907c684 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java @@ -2,7 +2,12 @@ import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import java.util.Set; @@ -20,20 +25,10 @@ public class TransactionsRequest { "{\"id\": \"8b346f4d914fe652bde477fa3f6b630fbcf7ffd9859daf8df4fc63cdd1562e5c\"}," + "{\"id\": \"48335c2b63cffcef2a3cd0678b65c4fb16420f51110033024209957fbd58ec4e\"}" + "]")) + @NotBlank private String organisationId; - private Set transactionIds; - - @Getter - @Setter - @AllArgsConstructor - @NoArgsConstructor - @EqualsAndHashCode - public static class TransactionId { - - @Schema(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") - private String id; - - } + @Size(min = 1) + private Set transactionIds; } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/BatchsDetailView.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/BatchsDetailView.java index 9004f1df..c23e9c26 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/BatchsDetailView.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/BatchsDetailView.java @@ -9,6 +9,8 @@ @Setter //@AllArgsConstructor public class BatchsDetailView { + private Long total; private List batchs; + } From 72ca9c220c73065e8e898630af4ca9a87de68795 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Thu, 8 Aug 2024 18:26:45 +0200 Subject: [PATCH 4/9] fix: fix for REST path. --- .../resource/AccountingCoreResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java index 634199be..b42f3010 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java @@ -173,7 +173,7 @@ public ResponseEntity approveTransactions(@Valid @RequestBody TransactionsReq } @Tag(name = "Transactions Publish / Dispatch Approval", description = "Transactions Publish / Dispatch Approval API") - @PostMapping(value = "/transactions/approve", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @PostMapping(value = "/transactions/approve-dispatch", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @Operation(description = "Approve one or more transactions", responses = { @ApiResponse(content = { From c45efa9657af3ca252f2998deb23d72bbc0a9608 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Fri, 9 Aug 2024 09:55:40 +0200 Subject: [PATCH 5/9] feat: some code cleanup --- ...AccountingCorePresentationViewService.java | 2 +- .../service/internal/FailureResponses.java | 101 +++++++++++++++ .../TransactionRepositoryGateway.java | 116 +++--------------- ...countingCorePresentationConverterTest.java | 2 +- 4 files changed, 119 insertions(+), 102 deletions(-) create mode 100644 accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/FailureResponses.java rename accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/{repository => service/internal}/TransactionRepositoryGateway.java (64%) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java index 15e5a583..0aacc1df 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java @@ -6,7 +6,7 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.UserExtractionParameters; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionBatchRepositoryGateway; -import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepositoryGateway; +import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.TransactionRepositoryGateway; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.*; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.*; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.AccountingCoreService; diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/FailureResponses.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/FailureResponses.java new file mode 100644 index 00000000..75a7fbc3 --- /dev/null +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/FailureResponses.java @@ -0,0 +1,101 @@ +package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal; + +import io.vavr.control.Either; +import lombok.val; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionItemEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionItemsRejectionRequest; +import org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem; +import org.springframework.dao.DataAccessException; +import org.zalando.problem.Problem; +import org.zalando.problem.ThrowableProblem; + +import java.util.List; + +import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION; +import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION_ITEM; +import static org.zalando.problem.Status.METHOD_NOT_ALLOWED; + +public final class FailureResponses { + + public static Either transactionFailedResponse(String transactionId) { + val problem = Problem.builder() + .withTitle("CANNOT_APPROVE_FAILED_TX") + .withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}") + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + } + + public static Either transactionRejectedResponse(String transactionId) { + val problem = Problem.builder() + .withTitle("CANNOT_APPROVE_REJECTED_TX") + .withDetail(STR."Cannot approve a rejected transaction, transactionId: \{transactionId}") + .withStatus(METHOD_NOT_ALLOWED) + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + } + + public static Either transactionNotFoundResponse(String txId) { + val problem = Problem.builder() + .withTitle("TX_NOT_FOUND") + .withDetail(STR."Transaction with id \{txId} not found") + .with("txId", txId) + .build(); + + return Either.left(new IdentifiableProblem(txId, problem, TRANSACTION)); + } + + public static ThrowableProblem createTransactionDBError(String transactionId, DataAccessException dae) { + val problem = Problem.builder() + .withTitle("DB_ERROR") + .withDetail(STR."DB error approving transaction publish:\{transactionId}") + .with("transactionId", transactionId) + .with("error", dae.getMessage()) + .build(); + return problem; + } + + public static List> transactionNotFoundResponse(TransactionItemsRejectionRequest transactionItemsRejectionRequest, + String transactionId) { + return transactionItemsRejectionRequest.getTransactionItemsRejections() + .stream() + .map(txItemRejectionRequest -> { + val problem = Problem.builder() + .withTitle("TX_NOT_FOUND") + .withDetail(STR."Transaction with id \{transactionId} not found") + .with("transactionId", transactionId) + .build(); + + return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + }).toList(); + } + + public static Either transactionItemCannotRejectAlreadyApprovedResponse(String transactionId, + String txItemId) { + val problem = Problem.builder() + .withTitle("TX_ALREADY_APPROVED_CANNOT_REJECT_TX_ITEM") + .withDetail(STR."Cannot reject transaction item \{txItemId} because transaction \{transactionId} has already been approved for dispatch") + .with("transactionId", transactionId) + .with("transactionItemId", txItemId) + .build(); + + return Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM)); + } + + public static Either transactionItemNotFoundResponse(String transactionId, + String txItemId) { + val problem = Problem.builder() + .withTitle("TX_ITEM_NOT_FOUND") + .withDetail(STR."Transaction item with id \{txItemId} not found") + .with("transactionId", transactionId) + .with("transactionItemId", txItemId) + .build(); + + return Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM)); + } + +} diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java similarity index 64% rename from accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java rename to accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java index dffafe83..3ebf7ed3 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/repository/TransactionRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java @@ -1,4 +1,4 @@ -package org.cardanofoundation.lob.app.accounting_reporting_core.repository; +package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal; import io.vavr.control.Either; import lombok.RequiredArgsConstructor; @@ -9,15 +9,15 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Rejection; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionItemEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionItemRepository; +import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepository; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionItemsRejectionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; -import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.LedgerService; import org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.zalando.problem.Problem; -import org.zalando.problem.ThrowableProblem; import java.util.ArrayList; import java.util.List; @@ -26,13 +26,13 @@ import java.util.stream.Collectors; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.FAIL; +import static org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.FailureResponses.*; import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION; -import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION_ITEM; import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; import static org.zalando.problem.Status.METHOD_NOT_ALLOWED; -import static org.zalando.problem.Status.NOT_FOUND; @Service +@org.jmolecules.ddd.annotation.Service @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) @@ -50,7 +50,7 @@ private Either approveTransaction(String val txM = transactionRepository.findById(transactionId); if (txM.isEmpty()) { - return txNotFoundResponse(transactionId); + return transactionNotFoundResponse(transactionId); } val tx = txM.orElseThrow(); @@ -77,31 +77,17 @@ private Either approveTransactionsDispat val txM = transactionRepository.findById(transactionId); if (txM.isEmpty()) { - val problem = Problem.builder() - .withTitle("TX_NOT_FOUND") - .withDetail(STR."Transaction with id \{transactionId} not found") - .withStatus(NOT_FOUND) - .with("transactionId", transactionId) - .build(); - - return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + return transactionNotFoundResponse(transactionId); } val tx = txM.orElseThrow(); if (tx.getStatus() == FAIL) { - val problem = Problem.builder() - .withTitle("CANNOT_APPROVE_FAILED_TX") - .withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}") - .withStatus(METHOD_NOT_ALLOWED) - .with("transactionId", transactionId) - .build(); - - if (tx.hasAnyRejection()) { - return transactionRejectedResponse(transactionId); - } + return transactionFailedResponse(transactionId); + } - return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); + if (tx.hasAnyRejection()) { + return transactionRejectedResponse(transactionId); } if (!tx.getTransactionApproved()) { @@ -136,7 +122,7 @@ public List> approveTransactions( } catch (DataAccessException dae) { log.error("Error approving transaction: {}", transactionId, dae); - val problem = createDBError(transactionId, dae); + val problem = FailureResponses.createTransactionDBError(transactionId, dae); transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION))); } @@ -166,7 +152,7 @@ public List> approveTransactionsD } catch (DataAccessException dae) { log.error("Error approving transaction publish: {}", transactionId, dae); - val problem = createDBError(transactionId, dae); + val problem = createTransactionDBError(transactionId, dae); transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION))); } @@ -194,7 +180,7 @@ public List> rejectTransactio val transactionItemEntitiesE = new ArrayList>(); if (txM.isEmpty()) { - return notFoundTransactionResponse(transactionItemsRejectionRequest, transactionId); + return transactionNotFoundResponse(transactionItemsRejectionRequest, transactionId); } val tx = txM.orElseThrow(); @@ -206,26 +192,13 @@ public List> rejectTransactio val txItemM = transactionItemRepository.findById(txItemId); if (txItemM.isEmpty()) { - val problem = Problem.builder() - .withTitle("TX_ITEM_NOT_FOUND") - .withDetail(STR."Transaction item with id \{txItemId} not found") - .with("txItemId", txItemId) - .build(); - - transactionItemEntitiesE.add(Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM))); + transactionItemEntitiesE.add(transactionItemNotFoundResponse(transactionId, txItemId)); continue; } val txItem = txItemM.orElseThrow(); if (tx.getLedgerDispatchApproved()) { - val problem = Problem.builder() - .withTitle("TX_ALREADY_APPROVED") - .withDetail(STR."Cannot reject transaction item \{txItemId} because transaction \{transactionId} has already been approved for dispatch") - .with("transactionId", transactionId) - .with("txItemId", txItemId) - .build(); - - transactionItemEntitiesE.add(Either.left(new IdentifiableProblem(txItemId, problem, TRANSACTION_ITEM))); + transactionItemEntitiesE.add(transactionItemCannotRejectAlreadyApprovedResponse(transactionId, txItemId)); continue; } @@ -239,23 +212,7 @@ public List> rejectTransactio return transactionItemEntitiesE; } - private static List> notFoundTransactionResponse(TransactionItemsRejectionRequest transactionItemsRejectionRequest, - String transactionId) { - return transactionItemsRejectionRequest.getTransactionItemsRejections() - .stream() - .map(txItemRejectionRequest -> { - val problem = Problem.builder() - .withTitle("TX_NOT_FOUND") - .withDetail(STR."Transaction with id \{transactionId} not found") - .with("transactionId", transactionId) - .build(); - - return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); - }).toList(); - } - public Optional findById(String transactionId) { - return transactionRepository.findById(transactionId); } @@ -273,47 +230,6 @@ public List listAll() { return transactionRepository.findAll(); } - private static Either transactionFailedResponse(String transactionId) { - val problem = Problem.builder() - .withTitle("CANNOT_APPROVE_FAILED_TX") - .withDetail(STR."Cannot approve a failed transaction, transactionId: \{transactionId}") - .with("transactionId", transactionId) - .build(); - - return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); - } - - private static Either transactionRejectedResponse(String transactionId) { - val problem = Problem.builder() - .withTitle("CANNOT_APPROVE_REJECTED_TX") - .withDetail(STR."Cannot approve a rejected transaction, transactionId: \{transactionId}") - .withStatus(METHOD_NOT_ALLOWED) - .with("transactionId", transactionId) - .build(); - - return Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION)); - } - - private static Either txNotFoundResponse(String txId) { - val problem = Problem.builder() - .withTitle("TX_NOT_FOUND") - .withDetail(STR."Transaction with id \{txId} not found") - .with("txId", txId) - .build(); - - return Either.left(new IdentifiableProblem(txId, problem, TRANSACTION)); - } - - private static ThrowableProblem createDBError(String transactionId, DataAccessException dae) { - val problem = Problem.builder() - .withTitle("DB_ERROR") - .withDetail(STR."DB error approving transaction publish:\{transactionId}") - .with("transactionId", transactionId) - .with("error", dae.getMessage()) - .build(); - return problem; - } - } // public Either changeTransactionComment(String txId, String userComment) { diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java index 3d1a1106..8ea5129f 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/model/AccountingCorePresentationConverterTest.java @@ -5,7 +5,7 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Violation; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionBatchRepositoryGateway; -import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepositoryGateway; +import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.TransactionRepositoryGateway; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service.AccountingCorePresentationViewService; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.BatchSearchRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ExtractionRequest; From 958a64141f57530341bcc585683230c678fbca29 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Fri, 9 Aug 2024 14:15:19 +0200 Subject: [PATCH 6/9] feat: added tests. --- .../resource/AccountingCoreResource.java | 15 +- ...AccountingCorePresentationViewService.java | 16 +- .../views/TransactionItemsProcessView.java | 10 +- .../TransactionRepositoryGateway.java | 10 +- .../TransactionRepositoryGatewayTest.java | 495 ++++++++++++++++++ 5 files changed, 518 insertions(+), 28 deletions(-) create mode 100644 accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java index b42f3010..1edf14f3 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java @@ -29,6 +29,7 @@ import java.util.List; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.zalando.problem.Status.NOT_FOUND; import static org.zalando.problem.Status.OK; @RestController @@ -68,7 +69,7 @@ public ResponseEntity transactionDetailSpecific(@Valid @PathVariable("id") @P val issue = Problem.builder() .withTitle("TX_NOT_FOUND") .withDetail(STR."Transaction with id: {\{id}} could not be found") - .withStatus(Status.NOT_FOUND) + .withStatus(NOT_FOUND) .build(); return ResponseEntity.status(issue.getStatus().getStatusCode()).body(issue); @@ -127,7 +128,7 @@ public ResponseEntity extractionTrigger(@Valid @RequestBody ExtractionRequest val issue = Problem.builder() .withTitle("ORGANISATION_NOT_FOUND") .withDetail(STR."Unable to find Organisation by Id: \{body.getOrganisationId()}") - .withStatus(Status.NOT_FOUND) + .withStatus(NOT_FOUND) .build(); return ResponseEntity.status(issue.getStatus().getStatusCode()).body(issue); @@ -139,7 +140,7 @@ public ResponseEntity extractionTrigger(@Valid @RequestBody ExtractionRequest val issue = Problem.builder() .withTitle("ORGANISATION_DATE_MISMATCH") .withDetail(STR."the requested data is outside of accounting period for \{body.getOrganisationId()}") - .withStatus(Status.NOT_FOUND) + .withStatus(NOT_FOUND) .build(); return ResponseEntity.status(issue.getStatus().getStatusCode()).body(issue); @@ -155,7 +156,7 @@ public ResponseEntity extractionTrigger(@Valid @RequestBody ExtractionRequest .body(response.toString()); } - @Tag(name = "Transactions Approval", description = "Transactions Approval API") + @Tag(name = "Transactions", description = "Transactions Approval API") @PostMapping(value = "/transactions/approve", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @Operation(description = "Approve one or more transactions", responses = { @@ -172,7 +173,7 @@ public ResponseEntity approveTransactions(@Valid @RequestBody TransactionsReq .body(transactionProcessViews); } - @Tag(name = "Transactions Publish / Dispatch Approval", description = "Transactions Publish / Dispatch Approval API") + @Tag(name = "Transactions", description = "Transactions Publish / Dispatch Approval API") @PostMapping(value = "/transactions/approve-dispatch", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @Operation(description = "Approve one or more transactions", responses = { @@ -189,7 +190,7 @@ public ResponseEntity approveTransactionsPublish(@Valid @RequestBody Transact .body(transactionProcessViewList); } - @Tag(name = "Transaction Items Rejection", description = "Transaction Items Rejection API") + @Tag(name = "Transactions", description = "Transaction Items Rejection API") @PostMapping(value = "/transactions/reject", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) @Operation(description = "Reject one or more transaction items per a given transaction", responses = { @@ -245,7 +246,7 @@ public ResponseEntity batchDetail(@Valid @PathVariable("batchId") @Parameter( val issue = Problem.builder() .withTitle("BATCH_NOT_FOUND") .withDetail(STR."Batch with id: {\{batchId}} could not be found") - .withStatus(Status.NOT_FOUND) + .withStatus(NOT_FOUND) .build(); return ResponseEntity.status(issue.getStatus().getStatusCode()).body(issue); diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java index 0aacc1df..b0ddde97 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/presentation_layer_service/AccountingCorePresentationViewService.java @@ -6,10 +6,10 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.UserExtractionParameters; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*; import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionBatchRepositoryGateway; -import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.TransactionRepositoryGateway; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.*; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.*; import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.AccountingCoreService; +import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.TransactionRepositoryGateway; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,9 +18,9 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import static java.math.BigDecimal.ZERO; +import static java.util.stream.Collectors.toSet; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Counterparty.Type.VENDOR; @Service @@ -161,14 +161,12 @@ public List approveTransactionsPublish(TransactionsReque } public List rejectTransactionItems(TransactionItemsRejectionRequest transactionItemsRejectionRequest) { - val transactionId = transactionItemsRejectionRequest.getTransactionId(); - return transactionRepositoryGateway.rejectTransactionItems(transactionItemsRejectionRequest) .stream() .map(txItemEntityE -> txItemEntityE.fold(txProblem -> { - return TransactionItemsProcessView.createFail(transactionId, txProblem.getId(), txProblem.getProblem()); + return TransactionItemsProcessView.createFail(txProblem.getId(), txProblem.getProblem()); }, success -> { - return TransactionItemsProcessView.createSuccess(transactionId, success.getId()); + return TransactionItemsProcessView.createSuccess(success.getId()); })) .toList(); } @@ -176,7 +174,7 @@ public List rejectTransactionItems(TransactionItems private Set getTransaction(TransactionBatchEntity transactionBatchEntity) { return transactionBatchEntity.getTransactions().stream() .map(this::getTransactionView) - .collect(Collectors.toSet()); + .collect(toSet()); } private TransactionView getTransactionView(TransactionEntity transactionEntity) { @@ -224,7 +222,7 @@ private Set getTransactionItemView(TransactionEntity transa item.getDocument().flatMap(d -> d.getCounterparty().map(Counterparty::getType)).orElse(VENDOR), item.getDocument().flatMap(document -> document.getCounterparty().flatMap(Counterparty::getName)).orElse("") ); - }).collect(Collectors.toSet()); + }).collect(toSet()); } private Set getViolations(TransactionEntity transaction) { @@ -234,7 +232,7 @@ private Set getViolations(TransactionEntity transaction) { violation.getTxItemId(), violation.getCode(), violation.getBag() - )).collect(Collectors.toSet()); + )).collect(toSet()); } public BigDecimal getAmountLcyTotalForAllItems(TransactionEntity tx) { diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java index 38b41a79..b694e406 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/views/TransactionItemsProcessView.java @@ -12,25 +12,21 @@ @AllArgsConstructor public class TransactionItemsProcessView { - private String transactionId; private String transactionItemId; private Boolean success; private Optional error; - public static TransactionItemsProcessView createSuccess(String transactionId, - String transactionItemId) { + public static TransactionItemsProcessView createSuccess(String transactionItemId) { return new TransactionItemsProcessView( - transactionId, transactionItemId, true, Optional.empty() ); } - public static TransactionItemsProcessView createFail(String transactionId, - String transactionItemId, + public static TransactionItemsProcessView createFail(String transactionItemId, Problem error) { - return new TransactionItemsProcessView(transactionId, transactionItemId, false, Optional.of(error)); + return new TransactionItemsProcessView(transactionItemId, false, Optional.of(error)); } } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java index 3ebf7ed3..20218c1a 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java @@ -23,8 +23,8 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.FAIL; import static org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.FailureResponses.*; import static org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem.IdType.TRANSACTION; @@ -44,7 +44,7 @@ public class TransactionRepositoryGateway { @Transactional(propagation = REQUIRES_NEW) // TODO optimise performance because we have to load transaction from db each time and we don't save it in bulk - private Either approveTransaction(String transactionId) { + protected Either approveTransaction(String transactionId) { log.info("Approving transaction: {}", transactionId); val txM = transactionRepository.findById(transactionId); @@ -131,7 +131,7 @@ public List> approveTransactions( val transactionSuccesses = transactionsApprovalResponseListE.stream() .filter(Either::isRight) .map(Either::get) - .collect(Collectors.toSet()); + .collect(toSet()); ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, transactionSuccesses); @@ -150,7 +150,7 @@ public List> approveTransactionsD transactionsApprovalResponseListE.add(transactionEntities); } catch (DataAccessException dae) { - log.error("Error approving transaction publish: {}", transactionId, dae); + log.error("Error approving transaction publish / dispatch: {}", transactionId, dae); val problem = createTransactionDBError(transactionId, dae); @@ -161,7 +161,7 @@ public List> approveTransactionsD val transactionSuccesses = transactionsApprovalResponseListE.stream() .filter(Either::isRight) .map(Either::get) - .collect(Collectors.toSet()); + .collect(toSet()); ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, transactionSuccesses); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java new file mode 100644 index 00000000..fb66283c --- /dev/null +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java @@ -0,0 +1,495 @@ +package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal; + +import io.vavr.control.Either; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Rejection; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionItemEntity; +import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionItemRepository; +import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepository; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionItemsRejectionRequest; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; +import org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.dao.DataAccessException; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.OK; +import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode.INCORRECT_AMOUNT; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +class TransactionRepositoryGatewayTest { + + @Mock + private TransactionItemRepository transactionItemRepository; + + @Mock + private TransactionRepository transactionRepository; + + @Mock + private LedgerService ledgerService; + + @InjectMocks + private TransactionRepositoryGateway transactionRepositoryGateway; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void approveTransaction_shouldReturnNotFound_whenTransactionDoesNotExist() { + // Arrange + String transactionId = "nonexistent_tx_id"; + when(transactionRepository.findById(transactionId)).thenReturn(Optional.empty()); + + // Act + Either result = transactionRepositoryGateway.approveTransaction(transactionId); + + // Assert + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("TX_NOT_FOUND"); + } + + @Test + void approveTransaction_shouldReturnFailure_whenTransactionIsFailed() { + // Arrange + String transactionId = "failed_tx_id"; + TransactionEntity failedTransaction = new TransactionEntity(); + failedTransaction.setStatus(TransactionStatus.FAIL); + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(failedTransaction)); + + // Act + Either result = transactionRepositoryGateway.approveTransaction(transactionId); + + // Assert + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("CANNOT_APPROVE_FAILED_TX"); + } + + @Test + void approveTransaction_shouldApproveTransaction_whenTransactionIsValid() { + // Arrange + String transactionId = "valid_tx_id"; + TransactionEntity validTransaction = new TransactionEntity(); + validTransaction.setStatus(OK); // Assuming SUCCESS is a valid status for approval + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.save(validTransaction)).thenReturn(validTransaction); + + // Act + Either result = transactionRepositoryGateway.approveTransaction(transactionId); + + // Assert + assertThat(result.isRight()).isTrue(); + assertThat(result.get()).isSameAs(validTransaction); + verify(transactionRepository, times(1)).save(validTransaction); + } + + @Test + void approveTransactions_shouldApproveValidTransactionsAndHandleErrors() { + // Arrange + String validTransactionId = "valid_tx_id"; + String failedTransactionId = "failed_tx_id"; + + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(validTransactionId, failedTransactionId)); + + TransactionEntity validTransaction = new TransactionEntity(); + validTransaction.setStatus(OK); + when(transactionRepository.findById(validTransactionId)).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.findById(failedTransactionId)).thenReturn(Optional.empty()); // Simulating not found + + when(transactionRepository.save(validTransaction)).thenReturn(validTransaction); + + // Act + List> results = transactionRepositoryGateway.approveTransactions(transactionsRequest); + + // Assert + assertThat(results).hasSize(2); + + Either validResult = results.stream().filter(Either::isRight).findFirst().orElseThrow(); + Either failedResult = results.stream().filter(Either::isLeft).findFirst().orElseThrow(); + + assertThat(validResult.isRight()).isTrue(); + assertThat(failedResult.isLeft()).isTrue(); + assertThat(failedResult.getLeft().getProblem().getTitle()).isEqualTo("TX_NOT_FOUND"); + + verify(transactionRepository, times(1)).save(validTransaction); + } + + @Test + void approveTransactionsDispatch_shouldApproveDispatchForValidTransactions() { + // Arrange + String transactionId = "valid_tx_id"; + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(transactionId)); + + TransactionEntity validTransaction = new TransactionEntity(); + validTransaction.setStatus(OK); + validTransaction.setTransactionApproved(true); + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.save(validTransaction)).thenReturn(validTransaction); + + // Act + List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); + + // Assert + assertThat(results).hasSize(1); + Either result = results.get(0); + + assertThat(result.isRight()).isTrue(); + assertThat(result.get()).isSameAs(validTransaction); + + verify(transactionRepository, times(1)).save(validTransaction); + verify(ledgerService, times(1)).checkIfThereAreTransactionsToDispatch(any(), any()); + } + + @Test + void rejectTransactionItems_shouldRejectItemsProperly() { + // Arrange + String transactionId = "tx_id"; + String transactionItemId = "tx_item_id"; + + TransactionItemsRejectionRequest rejectionRequest = new TransactionItemsRejectionRequest(); + rejectionRequest.setTransactionId(transactionId); + rejectionRequest.setTransactionItemsRejections(Set.of(new TransactionItemsRejectionRequest.TxItemRejectionRequest(transactionItemId, INCORRECT_AMOUNT))); + + TransactionEntity transactionEntity = new TransactionEntity(); + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transactionEntity)); + + TransactionItemEntity transactionItemEntity = new TransactionItemEntity(); + when(transactionItemRepository.findById(transactionItemId)).thenReturn(Optional.of(transactionItemEntity)); + + when(transactionItemRepository.save(transactionItemEntity)).thenReturn(transactionItemEntity); + + // Act + List> results = transactionRepositoryGateway.rejectTransactionItems(rejectionRequest); + + // Assert + assertThat(results).isNotEmpty(); + + Either result = results.get(0); + + assertThat(result.isRight()).isTrue(); + assertThat(result.get().getRejection().orElseThrow().getRejectionCode()).isEqualTo(INCORRECT_AMOUNT); + + verify(transactionItemRepository, times(1)).save(transactionItemEntity); + } + + @Test + void findById_shouldReturnTransaction_whenExists() { + // Arrange + String transactionId = "tx_id"; + TransactionEntity transactionEntity = new TransactionEntity(); + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transactionEntity)); + + // Act + Optional result = transactionRepositoryGateway.findById(transactionId); + + // Assert + assertThat(result).isPresent(); + assertThat(result.get()).isSameAs(transactionEntity); + } + + @Test + void findById_shouldReturnEmpty_whenNotExists() { + // Arrange + String transactionId = "tx_id"; + when(transactionRepository.findById(transactionId)).thenReturn(Optional.empty()); + + // Act + Optional result = transactionRepositoryGateway.findById(transactionId); + + // Assert + assertThat(result).isEmpty(); + } + + @Test + void approveTransaction_shouldReturnRejectionResponse_whenTransactionHasRejection() { + // Arrange + String transactionId = "rejected_tx_id"; + + TransactionEntity rejectedTransaction = new TransactionEntity(); + rejectedTransaction.setStatus(OK); + rejectedTransaction.setTransactionApproved(false); + + TransactionItemEntity transactionItemEntity = new TransactionItemEntity(); + transactionItemEntity.setId("rejected_item_id"); + transactionItemEntity.setRejection(Optional.of(new Rejection(INCORRECT_AMOUNT))); + transactionItemEntity.setTransaction(rejectedTransaction); + + rejectedTransaction.setItems(Set.of(transactionItemEntity)); + + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(rejectedTransaction)); + + Either result = transactionRepositoryGateway.approveTransaction(transactionId); + + // Assert + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("CANNOT_APPROVE_REJECTED_TX"); + } + + @Test + void approveTransactionsDispatch_shouldReturnError_whenDispatchingUnapprovedTransaction() { + // Arrange + String transactionId = "unapproved_tx_id"; + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(transactionId)); + + TransactionEntity unapprovedTransaction = new TransactionEntity(); + unapprovedTransaction.setStatus(OK); + unapprovedTransaction.setTransactionApproved(false); // Not approved + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(unapprovedTransaction)); + + // Act + List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); + + // Assert + assertThat(results).hasSize(1); + Either result = results.get(0); + + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("TX_NOT_APPROVED"); + } + + @Test + void rejectTransactionItems_shouldReturnError_whenTransactionItemNotFound() { + // Arrange + String transactionId = "tx_id"; + String transactionItemId = "nonexistent_item_id"; + + TransactionItemsRejectionRequest rejectionRequest = new TransactionItemsRejectionRequest(); + rejectionRequest.setTransactionId(transactionId); + rejectionRequest.setTransactionItemsRejections(Set.of(new TransactionItemsRejectionRequest.TxItemRejectionRequest(transactionItemId, INCORRECT_AMOUNT))); + + TransactionEntity transactionEntity = new TransactionEntity(); + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transactionEntity)); + + when(transactionItemRepository.findById(transactionItemId)).thenReturn(Optional.empty()); + + // Act + List> results = transactionRepositoryGateway.rejectTransactionItems(rejectionRequest); + + // Assert + assertThat(results).isNotEmpty(); + Either result = results.get(0); + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("TX_ITEM_NOT_FOUND"); + + verify(transactionItemRepository, never()).save(any(TransactionItemEntity.class)); + } + + @Test + void rejectTransactionItems_shouldReturnError_whenTransactionAlreadyApprovedForDispatch() { + // Arrange + String transactionId = "tx_id"; + String transactionItemId = "tx_item_id"; + + TransactionItemsRejectionRequest rejectionRequest = new TransactionItemsRejectionRequest(); + rejectionRequest.setTransactionId(transactionId); + rejectionRequest.setTransactionItemsRejections(Set.of(new TransactionItemsRejectionRequest.TxItemRejectionRequest(transactionItemId, INCORRECT_AMOUNT))); + + TransactionEntity transactionEntity = new TransactionEntity(); + transactionEntity.setLedgerDispatchApproved(true); // Transaction already approved for dispatch + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transactionEntity)); + + TransactionItemEntity transactionItemEntity = new TransactionItemEntity(); + when(transactionItemRepository.findById(transactionItemId)).thenReturn(Optional.of(transactionItemEntity)); + + // Act + List> results = transactionRepositoryGateway.rejectTransactionItems(rejectionRequest); + + // Assert + assertThat(results).isNotEmpty(); + Either result = results.get(0); + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("TX_ALREADY_APPROVED_CANNOT_REJECT_TX_ITEM"); + + verify(transactionItemRepository, never()).save(any(TransactionItemEntity.class)); + } + + @Test + void approveTransactions_shouldHandleDataAccessExceptionDuringApproval() { + // Arrange + String transactionId = "tx_id"; + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(transactionId)); + + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(new TransactionEntity())); + when(transactionRepository.save(any(TransactionEntity.class))).thenThrow(new DataAccessException("Database error") {}); + + // Act + List> results = transactionRepositoryGateway.approveTransactions(transactionsRequest); + + // Assert + assertThat(results).hasSize(1); + Either result = results.get(0); + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("DB_ERROR"); + + verify(transactionRepository, times(1)).save(any(TransactionEntity.class)); + } + + @Test + void approveTransactionsDispatch_shouldHandleDataAccessExceptionDuringDispatchApproval() { + // Arrange + String transactionId = "tx_id"; + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(transactionId)); + + TransactionEntity validTransaction = new TransactionEntity(); + validTransaction.setStatus(OK); + validTransaction.setTransactionApproved(true); + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.save(validTransaction)).thenThrow(new DataAccessException("Database error") {}); + + // Act + List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); + + // Assert + assertThat(results).hasSize(1); + Either result = results.get(0); + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("DB_ERROR"); + + verify(transactionRepository, times(1)).save(validTransaction); + } + + + // start + + @Test + void approveTransaction_shouldReturnRejectionResponse_whenAnyTransactionItemHasRejection() { + // Arrange + String transactionId = "rejected_tx_id"; + TransactionEntity transaction = new TransactionEntity(); + transaction.setStatus(OK); + + TransactionItemEntity itemWithRejection = new TransactionItemEntity(); + itemWithRejection.setId("rejected_item_id1"); + itemWithRejection.setRejection(Optional.of(new Rejection(INCORRECT_AMOUNT))); + itemWithRejection.setTransaction(transaction); + + TransactionItemEntity validItem = new TransactionItemEntity(); + validItem.setId("rejected_item_id2"); + validItem.setRejection(Optional.empty()); + validItem.setTransaction(transaction); + + transaction.setItems(Set.of(itemWithRejection, validItem)); + + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transaction)); + + // Act + Either result = transactionRepositoryGateway.approveTransaction(transactionId); + + // Assert + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("CANNOT_APPROVE_REJECTED_TX"); + } + + @Test + void approveTransaction_shouldApproveTransaction_whenAllTransactionItemsAreValid() { + // Arrange + String transactionId = "valid_tx_id"; + TransactionEntity transaction = new TransactionEntity(); + transaction.setStatus(OK); + + TransactionItemEntity validItem1 = new TransactionItemEntity(); + validItem1.setId("valid_item_1"); + validItem1.setRejection(Optional.empty()); + validItem1.setTransaction(transaction); + + TransactionItemEntity validItem2 = new TransactionItemEntity(); + validItem2.setId("valid_item_2"); + validItem2.setRejection(Optional.empty()); + validItem2.setTransaction(transaction); + + transaction.setItems(Set.of(validItem1, validItem2)); + + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transaction)); + when(transactionRepository.save(transaction)).thenReturn(transaction); + + // Act + Either result = transactionRepositoryGateway.approveTransaction(transactionId); + + // Assert + assertThat(result.isRight()).isTrue(); + assertThat(result.get()).isSameAs(transaction); + verify(transactionRepository, times(1)).save(transaction); + } + + @Test + void approveTransactionsDispatch_shouldReturnError_whenAnyTransactionItemHasRejection() { + // Arrange + String transactionId = "tx_id"; + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(transactionId)); + + TransactionEntity transaction = new TransactionEntity(); + transaction.setStatus(OK); + transaction.setTransactionApproved(true); + + TransactionItemEntity itemWithRejection = new TransactionItemEntity(); + itemWithRejection.setRejection(Optional.of(new Rejection(RejectionCode.INCORRECT_VAT_CODE))); + itemWithRejection.setTransaction(transaction); + + transaction.setItems(Set.of(itemWithRejection)); + + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transaction)); + + // Act + List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); + + // Assert + assertThat(results).hasSize(1); + Either result = results.get(0); + + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft().getProblem().getTitle()).isEqualTo("CANNOT_APPROVE_REJECTED_TX"); + } + + @Test + void approveTransactionsDispatch_shouldApproveDispatch_whenAllTransactionItemsAreValid() { + // Arrange + String transactionId = "valid_tx_id"; + TransactionsRequest transactionsRequest = new TransactionsRequest(); + transactionsRequest.setTransactionIds(Set.of(transactionId)); + + TransactionEntity transaction = new TransactionEntity(); + transaction.setStatus(OK); + transaction.setTransactionApproved(true); + + TransactionItemEntity validItem = new TransactionItemEntity(); + validItem.setRejection(Optional.empty()); + validItem.setTransaction(transaction); + + transaction.setItems(Set.of(validItem)); + + when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transaction)); + when(transactionRepository.save(transaction)).thenReturn(transaction); + + // Act + List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); + + // Assert + assertThat(results).hasSize(1); + Either result = results.get(0); + + assertThat(result.isRight()).isTrue(); + assertThat(result.get()).isSameAs(transaction); + + verify(transactionRepository, times(1)).save(transaction); + verify(ledgerService, times(1)).checkIfThereAreTransactionsToDispatch(any(), any()); + } + +} \ No newline at end of file From 7df40c320029b89ccc97abc3bf3242ba7390c50b Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Fri, 9 Aug 2024 14:40:41 +0200 Subject: [PATCH 7/9] fix: reverted transactionid concept in approval requests --- .../resource/AccountingCoreResource.java | 12 +++---- .../requests/TransactionsRequest.java | 20 ++++++++--- .../TransactionRepositoryGateway.java | 12 +++---- ... => TransactionViewTypeConverterTest.java} | 2 +- .../TransactionRepositoryGatewayTest.java | 36 ++++++++++--------- .../problem_support/IdentifiableProblem.java | 2 -- 6 files changed, 48 insertions(+), 36 deletions(-) rename accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/{TransactionViewIdTypeConverterTest.java => TransactionViewTypeConverterTest.java} (97%) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java index 1edf14f3..f380ae46 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/AccountingCoreResource.java @@ -24,7 +24,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.zalando.problem.Problem; -import org.zalando.problem.Status; import java.util.List; @@ -240,7 +239,6 @@ public ResponseEntity listAllBatch(@Valid @RequestBody BatchSearchRequest bod ) public ResponseEntity batchDetail(@Valid @PathVariable("batchId") @Parameter(example = "TESTd12027c0788116d14723a4ab4a67636a7d6463d84f0c6f7adf61aba32c04") String batchId) { - val txBatchM = accountingCorePresentationService.batchDetail(batchId); if (txBatchM.isEmpty()) { val issue = Problem.builder() @@ -249,12 +247,14 @@ public ResponseEntity batchDetail(@Valid @PathVariable("batchId") @Parameter( .withStatus(NOT_FOUND) .build(); - return ResponseEntity.status(issue.getStatus().getStatusCode()).body(issue); + return ResponseEntity + .status(issue.getStatus().getStatusCode()) + .body(issue); } - return ResponseEntity.ok(). - - body(txBatchM.orElseThrow()); + return ResponseEntity + .ok() + .body(txBatchM.orElseThrow()); } } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java index b907c684..bd779e45 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/resource/requests/TransactionsRequest.java @@ -17,6 +17,10 @@ @NoArgsConstructor public class TransactionsRequest { + @Schema(example = "75f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020ca94") + @NotBlank + private String organisationId; + @ArraySchema(arraySchema = @Schema(example = "[ {" + "\"id\": \"7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4\"}," + "{\"id\": \"7bce71783ff8e6501b33ce9797097f5633c069f17e4731d96467cdb311693fcb\"}," + @@ -25,10 +29,18 @@ public class TransactionsRequest { "{\"id\": \"8b346f4d914fe652bde477fa3f6b630fbcf7ffd9859daf8df4fc63cdd1562e5c\"}," + "{\"id\": \"48335c2b63cffcef2a3cd0678b65c4fb16420f51110033024209957fbd58ec4e\"}" + "]")) - @NotBlank - private String organisationId; - @Size(min = 1) - private Set transactionIds; + private Set transactionIds; + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class TransactionId { + + @Schema(example = "7e9e8bcbb38a283b41eab57add98278561ab51d23a16f3e3baf3daa461b84ab4") + @NotBlank + private String id; + + } } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java index 20218c1a..8059a08c 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGateway.java @@ -116,15 +116,15 @@ public List> approveTransactions( val transactionsApprovalResponseListE = new ArrayList>(); for (val transactionId : transactionIds) { try { - val transactionEntities = approveTransaction(transactionId); + val transactionEntities = approveTransaction(transactionId.getId()); transactionsApprovalResponseListE.add(transactionEntities); } catch (DataAccessException dae) { log.error("Error approving transaction: {}", transactionId, dae); - val problem = FailureResponses.createTransactionDBError(transactionId, dae); + val problem = FailureResponses.createTransactionDBError(transactionId.getId(), dae); - transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION))); + transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId.getId(), problem, TRANSACTION))); } } @@ -146,15 +146,15 @@ public List> approveTransactionsD val transactionsApprovalResponseListE = new ArrayList>(); for (val transactionId : transactionIds) { try { - val transactionEntities = approveTransactionsDispatch(transactionId); + val transactionEntities = approveTransactionsDispatch(transactionId.getId()); transactionsApprovalResponseListE.add(transactionEntities); } catch (DataAccessException dae) { log.error("Error approving transaction publish / dispatch: {}", transactionId, dae); - val problem = createTransactionDBError(transactionId, dae); + val problem = createTransactionDBError(transactionId.getId(), dae); - transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId, problem, TRANSACTION))); + transactionsApprovalResponseListE.add(Either.left(new IdentifiableProblem(transactionId.getId(), problem, TRANSACTION))); } } diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterTest.java similarity index 97% rename from accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterTest.java rename to accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterTest.java index 2f78f085..e78ed41e 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewIdTypeConverterTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/TransactionViewTypeConverterTest.java @@ -9,7 +9,7 @@ import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionType.*; -public class TransactionViewIdTypeConverterTest { +public class TransactionViewTypeConverterTest { private final TransactionTypeConverter converter = new TransactionTypeConverter(); diff --git a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java index fb66283c..0ad56ca2 100644 --- a/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java +++ b/accounting_reporting_core/src/test/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionRepositoryGatewayTest.java @@ -1,6 +1,7 @@ package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal; import io.vavr.control.Either; +import lombok.val; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Rejection; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.RejectionCode; @@ -10,6 +11,7 @@ import org.cardanofoundation.lob.app.accounting_reporting_core.repository.TransactionRepository; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionItemsRejectionRequest; import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest; +import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.TransactionsRequest.TransactionId; import org.cardanofoundation.lob.app.support.problem_support.IdentifiableProblem; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -82,7 +84,7 @@ void approveTransaction_shouldApproveTransaction_whenTransactionIsValid() { // Arrange String transactionId = "valid_tx_id"; TransactionEntity validTransaction = new TransactionEntity(); - validTransaction.setStatus(OK); // Assuming SUCCESS is a valid status for approval + validTransaction.setStatus(OK); when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(validTransaction)); when(transactionRepository.save(validTransaction)).thenReturn(validTransaction); @@ -98,16 +100,16 @@ void approveTransaction_shouldApproveTransaction_whenTransactionIsValid() { @Test void approveTransactions_shouldApproveValidTransactionsAndHandleErrors() { // Arrange - String validTransactionId = "valid_tx_id"; - String failedTransactionId = "failed_tx_id"; + val validTransactionId = new TransactionId("valid_tx_id"); + val failedTransactionId = new TransactionId("failed_tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(validTransactionId, failedTransactionId)); TransactionEntity validTransaction = new TransactionEntity(); validTransaction.setStatus(OK); - when(transactionRepository.findById(validTransactionId)).thenReturn(Optional.of(validTransaction)); - when(transactionRepository.findById(failedTransactionId)).thenReturn(Optional.empty()); // Simulating not found + when(transactionRepository.findById(validTransactionId.getId())).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.findById(failedTransactionId.getId())).thenReturn(Optional.empty()); // Simulating not found when(transactionRepository.save(validTransaction)).thenReturn(validTransaction); @@ -130,14 +132,14 @@ void approveTransactions_shouldApproveValidTransactionsAndHandleErrors() { @Test void approveTransactionsDispatch_shouldApproveDispatchForValidTransactions() { // Arrange - String transactionId = "valid_tx_id"; + val transactionId = new TransactionId("valid_tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(transactionId)); TransactionEntity validTransaction = new TransactionEntity(); validTransaction.setStatus(OK); validTransaction.setTransactionApproved(true); - when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.findById(transactionId.getId())).thenReturn(Optional.of(validTransaction)); when(transactionRepository.save(validTransaction)).thenReturn(validTransaction); // Act @@ -242,14 +244,14 @@ void approveTransaction_shouldReturnRejectionResponse_whenTransactionHasRejectio @Test void approveTransactionsDispatch_shouldReturnError_whenDispatchingUnapprovedTransaction() { // Arrange - String transactionId = "unapproved_tx_id"; + val transactionId = new TransactionId("unapproved_tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(transactionId)); TransactionEntity unapprovedTransaction = new TransactionEntity(); unapprovedTransaction.setStatus(OK); unapprovedTransaction.setTransactionApproved(false); // Not approved - when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(unapprovedTransaction)); + when(transactionRepository.findById(transactionId.getId())).thenReturn(Optional.of(unapprovedTransaction)); // Act List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); @@ -321,11 +323,11 @@ void rejectTransactionItems_shouldReturnError_whenTransactionAlreadyApprovedForD @Test void approveTransactions_shouldHandleDataAccessExceptionDuringApproval() { // Arrange - String transactionId = "tx_id"; + val transactionId = new TransactionId("tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(transactionId)); - when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(new TransactionEntity())); + when(transactionRepository.findById(transactionId.getId())).thenReturn(Optional.of(new TransactionEntity())); when(transactionRepository.save(any(TransactionEntity.class))).thenThrow(new DataAccessException("Database error") {}); // Act @@ -343,14 +345,14 @@ void approveTransactions_shouldHandleDataAccessExceptionDuringApproval() { @Test void approveTransactionsDispatch_shouldHandleDataAccessExceptionDuringDispatchApproval() { // Arrange - String transactionId = "tx_id"; + val transactionId = new TransactionId("tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(transactionId)); TransactionEntity validTransaction = new TransactionEntity(); validTransaction.setStatus(OK); validTransaction.setTransactionApproved(true); - when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(validTransaction)); + when(transactionRepository.findById(transactionId.getId())).thenReturn(Optional.of(validTransaction)); when(transactionRepository.save(validTransaction)).thenThrow(new DataAccessException("Database error") {}); // Act @@ -431,7 +433,7 @@ void approveTransaction_shouldApproveTransaction_whenAllTransactionItemsAreValid @Test void approveTransactionsDispatch_shouldReturnError_whenAnyTransactionItemHasRejection() { // Arrange - String transactionId = "tx_id"; + val transactionId = new TransactionId("tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(transactionId)); @@ -445,7 +447,7 @@ void approveTransactionsDispatch_shouldReturnError_whenAnyTransactionItemHasReje transaction.setItems(Set.of(itemWithRejection)); - when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transaction)); + when(transactionRepository.findById(transactionId.getId())).thenReturn(Optional.of(transaction)); // Act List> results = transactionRepositoryGateway.approveTransactionsDispatch(transactionsRequest); @@ -461,7 +463,7 @@ void approveTransactionsDispatch_shouldReturnError_whenAnyTransactionItemHasReje @Test void approveTransactionsDispatch_shouldApproveDispatch_whenAllTransactionItemsAreValid() { // Arrange - String transactionId = "valid_tx_id"; + val transactionId = new TransactionId("valid_tx_id"); TransactionsRequest transactionsRequest = new TransactionsRequest(); transactionsRequest.setTransactionIds(Set.of(transactionId)); @@ -475,7 +477,7 @@ void approveTransactionsDispatch_shouldApproveDispatch_whenAllTransactionItemsAr transaction.setItems(Set.of(validItem)); - when(transactionRepository.findById(transactionId)).thenReturn(Optional.of(transaction)); + when(transactionRepository.findById(transactionId.getId())).thenReturn(Optional.of(transaction)); when(transactionRepository.save(transaction)).thenReturn(transaction); // Act diff --git a/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java b/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java index 97c7990e..466d786c 100644 --- a/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java +++ b/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/IdentifiableProblem.java @@ -8,8 +8,6 @@ @RequiredArgsConstructor @ToString @Getter - -// TODO move to utils package???, it is not really specific to business domain but utility class public class IdentifiableProblem { private final String id; From ceeadf93981a4f75f20aa8346252e8f2b68ec496 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Fri, 9 Aug 2024 17:16:34 +0200 Subject: [PATCH 8/9] fix: added problem_support annotation --- .../lob/app/support/problem_support/package-info.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/package-info.java diff --git a/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/package-info.java b/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/package-info.java new file mode 100644 index 00000000..cf4875e4 --- /dev/null +++ b/support/src/main/java/org/cardanofoundation/lob/app/support/problem_support/package-info.java @@ -0,0 +1,6 @@ +@org.springframework.lang.NonNullApi + +@org.springframework.modulith.NamedInterface("problem_support") +package org.cardanofoundation.lob.app.support.problem_support; + + From ae9d5ff33be0c552f8769a05c1c10f1b35af9014 Mon Sep 17 00:00:00 2001 From: Mateusz Czeladka Date: Fri, 9 Aug 2024 18:00:27 +0200 Subject: [PATCH 9/9] fix: fixed event deserialisation issues --- .../domain/core/Account.java | 1 + .../domain/core/AccountEvent.java | 1 + .../domain/core/CoreCurrency.java | 1 + .../domain/core/CostCenter.java | 1 + .../domain/core/Counterparty.java | 1 + .../domain/core/Currency.java | 1 + .../domain/core/Organisation.java | 6 ++-- .../domain/core/Vat.java | 1 + .../domain/entity/Account.java | 10 ++++++- .../internal/TransactionConverter.java | 28 +++++++------------ 10 files changed, 28 insertions(+), 23 deletions(-) diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Account.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Account.java index 902c5b1c..de65a79d 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Account.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Account.java @@ -11,6 +11,7 @@ @Builder(toBuilder = true) @EqualsAndHashCode @ToString +@NoArgsConstructor public class Account { @LOB_ERPSourceVersionRelevant diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/AccountEvent.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/AccountEvent.java index b2964c70..3e1d965a 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/AccountEvent.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/AccountEvent.java @@ -8,6 +8,7 @@ @Builder(toBuilder = true) @EqualsAndHashCode @ToString +@NoArgsConstructor public class AccountEvent { private @Size(min = 1, max = 255) String code; diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CoreCurrency.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CoreCurrency.java index c34bbd89..2a74643f 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CoreCurrency.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CoreCurrency.java @@ -10,6 +10,7 @@ @Builder @EqualsAndHashCode @ToString +@NoArgsConstructor public class CoreCurrency { private IsoStandard currencyISOStandard; diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CostCenter.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CostCenter.java index b6658857..764073d2 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CostCenter.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/CostCenter.java @@ -11,6 +11,7 @@ @Builder(toBuilder = true) @EqualsAndHashCode @ToString +@NoArgsConstructor public class CostCenter { @LOB_ERPSourceVersionRelevant diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Counterparty.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Counterparty.java index 58551852..c59f41c8 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Counterparty.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Counterparty.java @@ -14,6 +14,7 @@ @Builder(toBuilder = true) @EqualsAndHashCode @ToString +@NoArgsConstructor public class Counterparty { @LOB_ERPSourceVersionRelevant diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Currency.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Currency.java index d7adeaf8..d205733c 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Currency.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Currency.java @@ -11,6 +11,7 @@ @Builder(toBuilder = true) @EqualsAndHashCode @ToString +@NoArgsConstructor public class Currency { @NotBlank diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Organisation.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Organisation.java index f8d4134e..90c93751 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Organisation.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Organisation.java @@ -2,10 +2,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; +import lombok.*; import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.annotations.LOB_ERPSourceVersionRelevant; import java.util.Optional; @@ -14,6 +11,7 @@ @Getter @AllArgsConstructor @EqualsAndHashCode +@NoArgsConstructor public class Organisation { @LOB_ERPSourceVersionRelevant diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Vat.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Vat.java index 046bb8ba..7bda7509 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Vat.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/core/Vat.java @@ -13,6 +13,7 @@ @Builder(toBuilder = true) @EqualsAndHashCode @ToString +@NoArgsConstructor public class Vat { @LOB_ERPSourceVersionRelevant diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/Account.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/Account.java index 205495f1..b5cddbbf 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/Account.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/domain/entity/Account.java @@ -11,13 +11,13 @@ @Embeddable @AllArgsConstructor @NoArgsConstructor -@Getter @EqualsAndHashCode @Builder(toBuilder = true) public class Account { @NotBlank @LOB_ERPSourceVersionRelevant + @Getter private String code; @Nullable @@ -34,4 +34,12 @@ public Optional getName() { return Optional.ofNullable(name); } + public void setRefCode(Optional refCode) { + this.refCode = refCode.orElse(null); + } + + public void setName(Optional name) { + this.name = name.orElse(null); + } + } diff --git a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java index 66fe0f94..33a36582 100644 --- a/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java +++ b/accounting_reporting_core/src/main/java/org/cardanofoundation/lob/app/accounting_reporting_core/service/internal/TransactionConverter.java @@ -96,13 +96,12 @@ private TransactionEntity convertToDbDetached(Transaction transaction) { val doc = convertToDbDetached(txItem.getDocument()); val txItemEntity = new TransactionItemEntity(); - txItemEntity.setId(txItem.getId()); - txItemEntity.setDocument(Optional.of(doc)); + txItemEntity.setDocument(doc); txItemEntity.setAmountLcy(txItem.getAmountLcy()); txItemEntity.setAmountFcy(txItem.getAmountFcy()); - txItemEntity.setCostCenter(Optional.of(convertCostCenter(txItem.getCostCenter()))); - txItemEntity.setProject(Optional.of(convertProject(txItem.getProject()))); + txItemEntity.setCostCenter(convertCostCenter(txItem.getCostCenter())); + txItemEntity.setProject(convertProject(txItem.getProject())); txItemEntity.setFxRate(txItem.getFxRate()); txItem.getAccountCredit().ifPresent(creditAccount -> { txItemEntity.setAccountCredit(Optional.of(Account.builder() @@ -153,22 +152,20 @@ private TransactionEntity convertToDbDetached(Transaction transaction) { return txEntity; } - private Project convertProject(Optional projectM) { + private Optional convertProject(Optional projectM) { return projectM.map(p -> Project.builder() .customerCode(p.getCustomerCode()) .externalCustomerCode(p.getExternalCustomerCode().orElse(null)) .name(p.getName().orElse(null)) - .build()) - .orElse(null); + .build()); } - private CostCenter convertCostCenter(Optional costCenter) { + private Optional convertCostCenter(Optional costCenter) { return costCenter.map(cc -> CostCenter.builder() .customerCode(cc.getCustomerCode()) .externalCustomerCode(cc.getExternalCustomerCode().orElse(null)) .name(cc.getName().orElse(null)) - .build()) - .orElse(null); + .build()); } private static Organisation convertOrganisation(Transaction transaction) { @@ -182,7 +179,7 @@ private static Organisation convertOrganisation(Transaction transaction) { .build(); } - private org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Document convertToDbDetached(Optional docM) { + private Optional convertToDbDetached(Optional docM) { return docM.map(doc -> Document.builder() .num(doc.getNumber()) @@ -202,8 +199,7 @@ private org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Do .name(counterparty.getName().orElse(null)) .build()).orElse(null))) - .map(Document.DocumentBuilder::build) - .orElse(null); + .map(Document.DocumentBuilder::build); } private Transaction convertToDbDetached(TransactionEntity transactionEntity) { @@ -292,11 +288,7 @@ private Transaction convertToDbDetached(TransactionEntity transactionEntity) { .build(); } - private Optional convertToDbDetached(@Nullable Document doc) { - if (doc == null) { - return Optional.empty(); - } - + private Optional convertToDbDetached(Document doc) { return Optional.of(org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Document.builder() .number(doc.getNum()) .currency(org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Currency.builder()