Skip to content

Commit

Permalink
feat: reconciliation_trigget
Browse files Browse the repository at this point in the history
  • Loading branch information
M4rc0Russ0 committed Oct 7, 2024
1 parent f568e56 commit 6f81f16
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionType;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ReconciliationFilterStatusRequest;

import java.util.List;
import java.util.Set;

public interface CustomTransactionRepository {
List<TransactionEntity> findAllByStatus(String organisationId,
List<ValidationStatus> validationStatuses,
List<TransactionType> transactionType);

public List<TransactionEntity> findAllReconciliation(ReconciliationFilterStatusRequest filter);

public Object[] findCalcReconciliationStatistic();
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ReconcilationCode;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionType;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ReconciliationFilterStatusRequest;

import java.util.List;

Expand Down Expand Up @@ -42,4 +41,54 @@ public List<TransactionEntity> findAllByStatus(String organisationId,
return em.createQuery(criteriaQuery).getResultList();
}

@Override
public List<TransactionEntity> findAllReconciliation(ReconciliationFilterStatusRequest filter) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<TransactionEntity> criteriaQuery = builder.createQuery(TransactionEntity.class);
Root<TransactionEntity> rootEntry = criteriaQuery.from(TransactionEntity.class);

criteriaQuery.select(rootEntry);
switch (filter) {
case ReconciliationFilterStatusRequest.RENCONCILED -> {
criteriaQuery.where(builder.equal(rootEntry.get("reconcilation").get("source"), ReconcilationCode.OK));
}
case ReconciliationFilterStatusRequest.UNRENCONCILED -> {
criteriaQuery.where(builder.equal(rootEntry.get("reconcilation").get("source"), ReconcilationCode.NOK));
}
case ReconciliationFilterStatusRequest.UNPROCESSED -> {
criteriaQuery.where(builder.isNull(rootEntry.get("reconcilation").get("source")));
}
}

return em.createQuery(criteriaQuery).getResultList();
}

@Override
public Object[] findCalcReconciliationStatistic() {
CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaQuery<Object[]> mainQuery = builder.createQuery(Object[].class);

Subquery<Long> countQueryNOK = mainQuery.subquery(Long.class);
Root<TransactionEntity> rootEntryNOK = countQueryNOK.from(TransactionEntity.class);
countQueryNOK.select(builder.count(rootEntryNOK));
countQueryNOK.where(builder.equal(rootEntryNOK.get("reconcilation").get("source"), ReconcilationCode.NOK));


Subquery<Long> countQueryOK = mainQuery.subquery(Long.class);
Root<TransactionEntity> rootEntryOK = countQueryOK.from(TransactionEntity.class);
countQueryOK.select(builder.count(rootEntryOK));
countQueryOK.where(builder.equal(rootEntryOK.get("reconcilation").get("source"), ReconcilationCode.OK));

Subquery<Long> countQueryNull = mainQuery.subquery(Long.class);
Root<TransactionEntity> rootEntryNull = countQueryNull.from(TransactionEntity.class);
countQueryNull.select(builder.count(rootEntryNull));
countQueryNull.where(builder.isNull(rootEntryNull.get("reconcilation").get("source")));

mainQuery.multiselect(countQueryOK.getSelection().alias("OK"), countQueryNOK.getSelection().alias("NOK"), countQueryNull.getSelection().alias("NOTYET"));

return em.createQuery(mainQuery).getSingleResult();

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.resource;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.presentation_layer_service.AccountingCorePresentationViewService;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ReconciliationFilterRequest;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.ReconciliationRequest;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.requests.SearchRequest;
import org.cardanofoundation.lob.app.accounting_reporting_core.resource.views.*;
import org.cardanofoundation.lob.app.accounting_reporting_core.service.internal.AccountingCoreService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

@RestController
@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping("/api")
@RequiredArgsConstructor
@Slf4j
public class AccountingCoreResourceReconciliation {
private final AccountingCorePresentationViewService accountingCorePresentationService;
private final AccountingCoreService accountingCoreService;

@Tag(name = "Reconciliation", description = "Reconciliation API")
@Operation(description = "Transaction list", responses = {
@ApiResponse(content =
{@Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = ReconcileResponseView.class))}
)
})
@PostMapping(value = "/reconcile/trigger", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<?> reconcileTriggerAction(@Valid @RequestBody ReconciliationRequest body) {

return accountingCoreService.scheduleReconcilation(body.getOrganisationId(), body.getDateFrom(), body.getDateTo()).fold(problem -> {

return ResponseEntity.status(problem.getStatus().getStatusCode()).body(ReconcileResponseView.createFail(problem.getTitle(), problem));
}, success -> {
return ResponseEntity.ok(ReconcileResponseView.createSuccess("We have received your reconcile request now."));

});

}

@Operation(description = "Transaction list", responses = {
@ApiResponse(content =
{@Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = TransactionReconciliationStatisticView.class))}
)
})
@Tag(name = "Reconciliation", description = "Reconciliation API")
@PostMapping(value = "/transactions-reconcile", produces = "application/json")
public ResponseEntity<?> reconcileStart(@Valid @RequestBody ReconciliationFilterRequest body) {
TransactionReconciliationStatisticView transactions = accountingCorePresentationService.allReconciliationTransaction(body);


return ResponseEntity.ok().body(transactions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Reconcilation;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ReconcilationCode;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.UserExtractionParameters;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*;
Expand Down Expand Up @@ -41,6 +43,24 @@ public class AccountingCorePresentationViewService {
private final AccountingCoreService accountingCoreService;
private final TransactionBatchRepositoryGateway transactionBatchRepositoryGateway;

public TransactionReconciliationStatisticView allReconciliationTransaction(ReconciliationFilterRequest body) {
Object[] transactionsStatistic = transactionRepositoryGateway.findReconciliationStatistic();
val transactions = transactionRepositoryGateway.findReconciliation(body.getFilter());

return new TransactionReconciliationStatisticView(
(Long) transactionsStatistic[0],
(Long) transactionsStatistic[1],
(Long) transactionsStatistic[2],
(Long) transactionsStatistic[0] + (Long) transactionsStatistic[1] + (Long) transactionsStatistic[2],
transactions.stream()
.limit(10L)
.map(this::getTransactionReconciliationView)

.collect(toSet())
);

}

public List<TransactionView> allTransactions(SearchRequest body) {
val transactions = transactionRepositoryGateway.findAllByStatus(
body.getOrganisationId(),
Expand Down Expand Up @@ -251,6 +271,27 @@ private TransactionView getTransactionView(TransactionEntity transactionEntity)
);
}

private TransactionReconciliationView getTransactionReconciliationView(TransactionEntity transactionEntity) {
return new TransactionReconciliationView(
transactionEntity.getId(),
transactionEntity.getTransactionInternalNumber(),
transactionEntity.getEntryDate(),
transactionEntity.getTransactionType(),
transactionEntity.getOverallStatus(),
getTransactionDispatchStatus(transactionEntity),
transactionEntity.getAutomatedValidationStatus(),
transactionEntity.getTransactionApproved(),
transactionEntity.getLedgerDispatchApproved(),
getAmountLcyTotalForAllItems(transactionEntity),
false,
getTransactionItemView(transactionEntity),
getViolations(transactionEntity),
transactionEntity.getReconcilation().flatMap(Reconcilation::getSource).orElse(null),
transactionEntity.getReconcilation().flatMap(Reconcilation::getSink).orElse(null),
transactionEntity.getReconcilation().flatMap(Reconcilation::getFinalStatus).orElse(null)

);
}

public LedgerDispatchStatusView getTransactionDispatchStatus(TransactionEntity transactionEntity) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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;
import lombok.extern.slf4j.Slf4j;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ReconcilationCode;

import java.time.LocalDate;
import java.util.Set;

@Getter
@Setter
@AllArgsConstructor
//@Builder todo: For testing
@NoArgsConstructor
@Slf4j
public class ReconciliationFilterRequest {
@Schema(example = "75f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020ca94")
private String organisationId;

private ReconciliationFilterStatusRequest filter;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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;
import lombok.extern.slf4j.Slf4j;

public enum ReconciliationFilterStatusRequest {
RENCONCILED,

UNRENCONCILED,

UNPROCESSED

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;
import java.time.LocalDate;

@Getter
@Setter
@AllArgsConstructor
//@Builder todo: For testing
@NoArgsConstructor
@Slf4j
public class ReconciliationRequest {
@Schema(example = "75f95560c1d883ee7628993da5adf725a5d97a13929fd4f477be0faf5020ca94")
private String organisationId;

@Schema(example = "2014-01-01")
private LocalDate dateFrom;

@Schema(example = "2024-07-31")
private LocalDate dateTo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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 ReconcileResponseView {

private String message;
private String event = "RECONCILIATION";
private Boolean success;
private Optional<Problem> error;

public static ReconcileResponseView createSuccess(String message) {
return new ReconcileResponseView(
message,
"RECONCILIATION",
true,
Optional.empty()
);
}

public static ReconcileResponseView createFail(String message,
Problem error) {
return new ReconcileResponseView(message, "RECONCILIATION", false, Optional.of(error));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.resource.views;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.util.HashSet;
import java.util.Set;

@Getter
@Setter
@AllArgsConstructor
public class TransactionReconciliationStatisticView {

private Long ok = 0L;

private Long nok = 0L;

private Long none = 0L;

private Long total = 0L;
@JsonProperty("transactions")
private Set<TransactionReconciliationView> transactionReconciliationViewList = new HashSet<>();
}
Loading

0 comments on commit 6f81f16

Please sign in to comment.