Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding operation type to transactionitem #170

Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ private PipelineTask preCleansingPipelineTask() {
return new DefaultPipelineTask(List.of(
new DiscardZeroBalanceTxItemsTaskItem(),
new JournalAccountCreditEnrichmentTaskItem(organisationPublicApi)
//new JournalAccountAmountsEnrichmentTaskItem() // this must be after JournalAccountCreditEnrichmentTaskItem
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public class TransactionItem {
@Builder.Default
private Optional<Document> document = Optional.empty(); // initially we allow empty but later as part of business rules we check if document is present

@NotNull
@LOBVersionSourceRelevant
private OperationType operationType;

@NotNull
@PositiveOrZero
@LOBVersionSourceRelevant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public String getId() {
@AttributeOverride(name = "counterparty.type", column = @Column(name = "document_counterparty_type")),
@AttributeOverride(name = "counterparty.name", column = @Column(name = "document_counterparty_name")),
})
@Nullable

private Document document;

@Column(name = "status", nullable = false)
Expand All @@ -139,6 +139,13 @@ public String getId() {
@JdbcType(PostgreSQLEnumJdbcType.class)
private TxItemValidationStatus status = TxItemValidationStatus.OK;

@Getter
@Setter
@Enumerated(EnumType.STRING)
@Column(name = "operation_type", nullable = false)
@JdbcType(PostgreSQLEnumJdbcType.class)
private OperationType operationType;

public void clearAccountCodeCredit() {
this.accountCredit = null;
}
Expand Down Expand Up @@ -204,14 +211,6 @@ public void setRejection(Optional<Rejection> rejection) {
this.rejection = rejection.orElse(null);
}

public Optional<OperationType> getOperationType() {
val amountLcy = this.amountLcy;

if (amountLcy.compareTo(BigDecimal.ZERO) == 0) return Optional.empty();

return amountLcy.compareTo(BigDecimal.ZERO) < 0 ? Optional.of(OperationType.CREDIT) : Optional.of(OperationType.DEBIT);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ private TransactionReconciliationTransactionsView getTransactionReconciliationVi
Optional.of(transactionEntity.getAutomatedValidationStatus()),
transactionEntity.getTransactionApproved(),
transactionEntity.getLedgerDispatchApproved(),
getAmountLcyTotalForAllItems(transactionEntity),
getAmountLcyTotalForAllDebitItems(transactionEntity),
false,
transactionEntity.getReconcilation().flatMap(reconcilation -> reconcilation.getSource().map(TransactionReconciliationTransactionsView.ReconciliationCodeView::of))
.orElse(TransactionReconciliationTransactionsView.ReconciliationCodeView.NEVER),
Expand Down Expand Up @@ -373,7 +373,7 @@ private TransactionView getTransactionView(TransactionEntity transactionEntity)
transactionEntity.getAutomatedValidationStatus(),
transactionEntity.getTransactionApproved(),
transactionEntity.getLedgerDispatchApproved(),
getAmountLcyTotalForAllItems(transactionEntity),
getAmountLcyTotalForAllDebitItems(transactionEntity),
transactionEntity.hasAnyRejection(),
transactionEntity.getReconcilation().flatMap(reconcilation -> reconcilation.getSource().map(TransactionView.ReconciliationCodeView::of))
.orElse(TransactionView.ReconciliationCodeView.NEVER),
Expand Down Expand Up @@ -512,11 +512,11 @@ private TransactionReconciliationTransactionsView getReconciliationTransactionsS
return getTransactionReconciliationViolationView();
}

public BigDecimal getAmountLcyTotalForAllItems(TransactionEntity tx) {
public BigDecimal getAmountLcyTotalForAllDebitItems(TransactionEntity tx) {
Set<TransactionItemEntity> items = tx.getItems();

if (tx.getTransactionType().equals(TransactionType.Journal)) {
items = tx.getItems().stream().filter(txItems -> txItems.getOperationType().equals(Optional.of(OperationType.DEBIT))).collect(toSet());
items = tx.getItems().stream().filter(txItems -> txItems.getOperationType().equals(OperationType.DEBIT)).collect(toSet());
}

return items.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;

import lombok.RequiredArgsConstructor;
import lombok.val;

import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.OperationType;
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.domain.entity.TransactionViolation;
Expand All @@ -20,14 +21,14 @@ public class AmountFcyBalanceZerosOutCheckTaskItem implements PipelineTaskItem {

@Override
public void run(TransactionEntity tx) {
val txItems = tx.getItems();
Set<TransactionItemEntity> txItems = tx.getItems();

val fcySum = txItems.stream()
.map(TransactionItemEntity::getAmountFcy)
.reduce(ZERO, BigDecimal::add);
BigDecimal fcySumDebit = getSumOfFcy(txItems, OperationType.DEBIT);
BigDecimal fcySumCredit = getSumOfFcy(txItems, OperationType.CREDIT);
BigDecimal fcySum = fcySumDebit.subtract(fcySumCredit);

if (fcySum.signum() != 0) {
val v = TransactionViolation.builder()
TransactionViolation v = TransactionViolation.builder()
.code(FCY_BALANCE_MUST_BE_ZERO)
.severity(ERROR)
.source(ERP)
Expand All @@ -43,4 +44,12 @@ public void run(TransactionEntity tx) {
}
}

private static BigDecimal getSumOfFcy(Set<TransactionItemEntity> txItems, OperationType credit) {
return txItems.stream()
.filter(transactionItemEntity -> transactionItemEntity.getOperationType().equals(credit))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also do: == for enums

.map(TransactionItemEntity::getAmountFcy)
.reduce(ZERO, BigDecimal::add);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;

import lombok.RequiredArgsConstructor;
import lombok.val;

import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.OperationType;
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.domain.entity.TransactionViolation;
Expand All @@ -21,14 +22,14 @@ public class AmountLcyBalanceZerosOutCheckTaskItem implements PipelineTaskItem {

@Override
public void run(TransactionEntity tx) {
val txItems = tx.getItems();
Set<TransactionItemEntity> txItems = tx.getItems();

val lcySum = txItems.stream()
.map(TransactionItemEntity::getAmountLcy)
.reduce(ZERO, BigDecimal::add);
BigDecimal lcySumDebit = getSumOfOperationType(txItems, OperationType.DEBIT);
BigDecimal lcySumCredit = getSumOfOperationType(txItems, OperationType.CREDIT);
BigDecimal lcySum = lcySumDebit.subtract(lcySumCredit);

if (lcySum.signum() != 0) {
val v = TransactionViolation.builder()
TransactionViolation v = TransactionViolation.builder()
.code(LCY_BALANCE_MUST_BE_ZERO)
.severity(ERROR)
.source(ERP)
Expand All @@ -44,4 +45,10 @@ public void run(TransactionEntity tx) {
}
}

private static BigDecimal getSumOfOperationType(Set<TransactionItemEntity> txItems, OperationType credit) {
return txItems.stream()
.filter(transactionItemEntity -> transactionItemEntity.getOperationType().equals(credit))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also do: == for enums

.map(TransactionItemEntity::getAmountLcy)
.reduce(ZERO, BigDecimal::add);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.OperationType;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionViolationCode;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.Account;
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.domain.entity.TransactionViolation;
import org.cardanofoundation.lob.app.organisation.OrganisationPublicApiIF;
import org.cardanofoundation.lob.app.organisation.domain.entity.Organisation;
Expand All @@ -32,12 +33,12 @@ public void run(TransactionEntity tx) {
return;
}

val dummyAccountM = organisationPublicApiIF.findByOrganisationId(tx.getOrganisation().getId())
Optional<String> dummyAccountM = organisationPublicApiIF.findByOrganisationId(tx.getOrganisation().getId())
.flatMap(Organisation::getDummyAccount);

if (!shouldTriggerNormalisation(tx, dummyAccountM)) {
if (dummyAccountM.isEmpty()) {
val v = TransactionViolation.builder()
TransactionViolation v = TransactionViolation.builder()
.code(TransactionViolationCode.JOURNAL_DUMMY_ACCOUNT_MISSING)
.processorModule(this.getClass().getSimpleName())
.source(LOB)
Expand All @@ -52,22 +53,12 @@ public void run(TransactionEntity tx) {
log.info("Normalising journal transaction with id: {}", tx.getId());

// at this point we can assume we have it, it is mandatory
val dummyAccount = dummyAccountM.orElseThrow();
for (val txItem : tx.getItems()) {
val operationTypeM = txItem.getOperationType();

if (operationTypeM.isEmpty()) {
txItem.setAccountCredit(Optional.of(Account.builder()
.code(dummyAccount)
.name(DUMMY_ACCOUNT)
.build()));
continue;
}

val operationType = operationTypeM.orElseThrow();
String dummyAccount = dummyAccountM.orElseThrow();
for (TransactionItemEntity txItem : tx.getItems()) {
OperationType operationType = txItem.getOperationType();

if (txItem.getAccountCredit().isEmpty() && operationType == CREDIT) {
val accountDebit = txItem.getAccountDebit().orElseThrow();
Account accountDebit = txItem.getAccountDebit().orElseThrow();
txItem.setAccountCredit(Optional.of(accountDebit));

txItem.clearAccountCodeDebit();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package org.cardanofoundation.lob.app.accounting_reporting_core.service.internal;

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

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.FatalError;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ReportStatusUpdate;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Transaction;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TxStatusUpdate;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.TransactionEntity;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.event.extraction.TransactionBatchChunkEvent;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.event.extraction.TransactionBatchFailedEvent;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.event.extraction.TransactionBatchStartedEvent;
Expand Down Expand Up @@ -37,7 +44,7 @@ public class AccountingCoreEventHandler {
public void handleLedgerUpdatedEvent(TxsLedgerUpdatedEvent event) {
log.info("Received handleLedgerUpdatedEvent event, event: {}", event.getStatusUpdates());

val txStatusUpdatesMap = event.statusUpdatesMap();
Map<String, TxStatusUpdate> txStatusUpdatesMap = event.statusUpdatesMap();

ledgerService.updateTransactionsWithNewStatuses(txStatusUpdatesMap);
transactionBatchService.updateBatchesPerTransactions(txStatusUpdatesMap);
Expand All @@ -49,7 +56,7 @@ public void handleLedgerUpdatedEvent(TxsLedgerUpdatedEvent event) {
public void handleReportsLedgerUpdated(ReportsLedgerUpdatedEvent event) {
log.info("Received handleReportsLedgerUpdated, event: {}", event);

val reportStatusUpdatesMap = event.statusUpdatesMap();
Map<String, ReportStatusUpdate> reportStatusUpdatesMap = event.statusUpdatesMap();

ledgerService.updateReportsWithNewStatuses(reportStatusUpdatesMap);

Expand All @@ -60,7 +67,7 @@ public void handleReportsLedgerUpdated(ReportsLedgerUpdatedEvent event) {
public void handleTransactionBatchFailedEvent(TransactionBatchFailedEvent event) {
log.info("Received handleTransactionBatchFailedEvent event, event: {}", event);

val error = event.getError();
FatalError error = event.getError();

transactionBatchService.failTransactionBatch(
event.getBatchId(),
Expand Down Expand Up @@ -92,8 +99,8 @@ public void handleTransactionBatchChunkEvent(TransactionBatchChunkEvent transact

log.info("Received handleTransactionBatchChunkEvent event...., event, batch_id: {}, chunk_size:{}", batchId, transactionBatchChunkEvent.getTransactions().size());

val txs = transactionBatchChunkEvent.getTransactions();
val detachedDbTxs = transactionConverter.convertToDbDetached(txs);
Set<Transaction> txs = transactionBatchChunkEvent.getTransactions();
Set<TransactionEntity> detachedDbTxs = transactionConverter.convertToDbDetached(txs);

erpIncomingDataProcessor.continueIngestion(
transactionBatchChunkEvent.getOrganisationId(),
Expand Down Expand Up @@ -134,12 +141,12 @@ public void handleReconcilationStartedEvent(ReconcilationStartedEvent event) {
public void handleReconcilationChunkEvent(ReconcilationChunkEvent event) {
log.info("Received handleReconcilationChunkEvent, event: {}", event);

val reconcilationId = event.getReconciliationId();
val organisationId = event.getOrganisationId();
val fromDate = event.getFrom();
val toDate = event.getTo();
val transactions = event.getTransactions();
val chunkDetachedTxEntities = transactionConverter.convertToDbDetached(transactions);
String reconcilationId = event.getReconciliationId();
String organisationId = event.getOrganisationId();
LocalDate fromDate = event.getFrom();
LocalDate toDate = event.getTo();
Set<Transaction> transactions = event.getTransactions();
Set<TransactionEntity> chunkDetachedTxEntities = transactionConverter.convertToDbDetached(transactions);

erpIncomingDataProcessor.continueReconcilation(
reconcilationId,
Expand Down
Loading