Skip to content

Commit

Permalink
Merge pull request #54 from cardano-foundation/reconcilation-refaktoring
Browse files Browse the repository at this point in the history
refak: adding last reconcilation linked to a transaction
  • Loading branch information
matiwinnetou authored Oct 1, 2024
2 parents 140f345 + 7f7ffd8 commit f568e56
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public String getId() {
@Getter
private Set<ReconcilationViolation> violations = new LinkedHashSet<>();

public void incrementMissingTxsCount(int delta) {
processedTxCount += delta;
}

public void addViolation(ReconcilationViolation violation) {
violations.add(violation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
public enum ReconcilationRejectionCode {

SOURCE_RECONCILATION_FAIL, // transaction version will have to be ignored because it cannot be extracted again
SINK_RECONCILATION_FAIL, // blockchain has different version of the transaction but why?
SOURCE_AND_SINK_RECONCILATION_FAIL, // both source and sink have different version of the transaction
SINK_RECONCILATION_FAIL, // blockchain is missing a transaction or it is not finalised yet

TX_NOT_IN_ERP, // transaction is not in ERP, typically this is a technical error
TX_NOT_IN_LOB // transaction is not in LOB, typically it has not been imported yet at all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
import org.cardanofoundation.lob.app.support.spring_audit.AuditEntity;
import org.javers.core.metamodel.annotation.DiffIgnore;
import org.springframework.data.domain.Persistable;

import javax.annotation.Nullable;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;

import static jakarta.persistence.EnumType.STRING;
import static jakarta.persistence.FetchType.EAGER;
import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.LedgerDispatchStatus.NOT_DISPATCHED;
import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.TransactionStatus.OK;
import static org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.ValidationStatus.FAILED;

@Getter
@Setter
@Entity(name = "accounting_reporting_core.TransactionEntity")
@Table(name = "accounting_core_transaction")
@NoArgsConstructor
Expand All @@ -34,30 +34,43 @@ public class TransactionEntity extends AuditEntity implements Persistable<String
@Id
@Column(name = "transaction_id", nullable = false)
@LOBVersionSourceRelevant
@Setter
private String id;

@Column(name = "transaction_internal_number", nullable = false)
@LOBVersionSourceRelevant
@Getter
@Setter
private String transactionInternalNumber;

@Column(name = "batch_id", nullable = false)
@DiffIgnore
@Getter
@Setter
private String batchId;

@Column(name = "accounting_period", nullable = false)
@Getter
@Setter
private YearMonth accountingPeriod;

@Column(name = "type", nullable = false)
@Enumerated(STRING)
@LOBVersionSourceRelevant
@Getter
@Setter
private TransactionType transactionType;

@Column(name = "entry_date", nullable = false)
@LOBVersionSourceRelevant
@Getter
@Setter
private LocalDate entryDate;

@Column(name = "ledger_dispatch_status", nullable = false)
@Enumerated(STRING)
@Getter
@Setter
private LedgerDispatchStatus ledgerDispatchStatus = NOT_DISPATCHED;

@Embedded
Expand All @@ -68,34 +81,52 @@ public class TransactionEntity extends AuditEntity implements Persistable<String
@AttributeOverride(name = "taxIdNumber", column = @Column(name = "organisation_tax_id_number")),
@AttributeOverride(name = "currencyId", column = @Column(name = "organisation_currency_id"))
})
@Getter
@Setter
private Organisation organisation;

@Column(name = "automated_validation_status", nullable = false)
@Enumerated(STRING)
@Getter
@Setter
private ValidationStatus automatedValidationStatus = ValidationStatus.VALIDATED;

@Column(name = "transaction_approved", nullable = false)
@Getter
@Setter
private Boolean transactionApproved = false;

@Column(name = "ledger_dispatch_approved", nullable = false)
@Getter
@Setter
private Boolean ledgerDispatchApproved = false;

@OneToMany(mappedBy = "transaction", orphanRemoval = true, fetch = EAGER)
@Getter
@Setter
private Set<TransactionItemEntity> items = new LinkedHashSet<>();

@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "reconcilation_id")
@Nullable
private ReconcilationEntity lastReconcilation;

@Column(name = "user_comment")
@Nullable
private String userComment;

@Column(name = "overall_status", nullable = false)
@Enumerated(STRING)
@DiffIgnore
@Getter
@Setter
private TransactionStatus overallStatus;

@Embedded
@AttributeOverrides({
@AttributeOverride(name = "source", column = @Column(name = "reconcilation_source", nullable = true)),
@AttributeOverride(name = "sink", column = @Column(name = "reconcilation_sink", nullable = true)),
@AttributeOverride(name = "finalStatus", column = @Column(name = "reconcilation_final_status", nullable = true))
@AttributeOverride(name = "source", column = @Column(name = "reconcilation_source")),
@AttributeOverride(name = "sink", column = @Column(name = "reconcilation_sink")),
@AttributeOverride(name = "finalStatus", column = @Column(name = "reconcilation_final_status"))
})
@Nullable
@DiffIgnore
Expand All @@ -113,6 +144,8 @@ public class TransactionEntity extends AuditEntity implements Persistable<String
@AttributeOverride(name = "bag", column = @Column(name = "bag", nullable = false))
})
@DiffIgnore
@Getter
@Setter
private Set<TransactionViolation> violations = new LinkedHashSet<>();

public boolean allApprovalsPassedForTransactionDispatch() {
Expand Down Expand Up @@ -170,6 +203,22 @@ public void setReconcilation(Optional<Reconcilation> reconcilation) {
this.reconcilation = reconcilation.orElse(null);
}

public Optional<ReconcilationEntity> getLastReconcilation() {
return Optional.ofNullable(lastReconcilation);
}

public void setLastReconcilation(Optional<ReconcilationEntity> parentReconcilation) {
this.lastReconcilation = parentReconcilation.orElse(null);
}

public Optional<String> getUserComment() {
return Optional.ofNullable(userComment);
}

public void setUserComment(Optional<String> userComment) {
this.userComment = userComment.orElse(null);
}

@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 @@ -38,8 +38,6 @@ public void run(TransactionEntity tx) {

val projectMappingM = organisationPublicApi.findProject(organisationId, customerCode);

log.info("Project mapping found: {}", projectMappingM);

if (projectMappingM.isEmpty()) {
val v = TransactionViolation.builder()
.code(PROJECT_DATA_NOT_FOUND)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ private void storeTransactions(String batchId,

private boolean isIncomingTransactionERPSame(TransactionEntity existingTx,
TransactionEntity incomingTx) {
val existingTxVersion = TransactionVersionCalculator.compute(Source.ERP, existingTx);
val incomingTxVersion = TransactionVersionCalculator.compute(Source.ERP, incomingTx);
val existingTxVersion = ERPSourceTransactionVersionCalculator.compute(existingTx);
val incomingTxVersion = ERPSourceTransactionVersionCalculator.compute(incomingTx);

log.info("Existing transaction version:{}, incomingTx:{}", existingTxVersion, incomingTxVersion);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.core.Source;
import org.cardanofoundation.lob.app.accounting_reporting_core.domain.entity.*;
import org.cardanofoundation.lob.app.support.calc.BigDecimals;
import org.cardanofoundation.lob.app.support.crypto.SHA3;

import java.util.Comparator;

@Slf4j
public class TransactionVersionCalculator {
public class ERPSourceTransactionVersionCalculator {

public static String compute(Source algo,
TransactionEntity transactionEntity) {
public static String compute(TransactionEntity transactionEntity) {
val b = new StringBuilder();

b.append(transactionEntity.getId());
b.append(transactionEntity.getTransactionInternalNumber());
b.append(compute(algo, transactionEntity.getOrganisation()));
b.append(compute(transactionEntity.getOrganisation()));
b.append(transactionEntity.getTransactionType());
b.append(transactionEntity.getEntryDate());

Expand All @@ -29,85 +27,85 @@ public static String compute(Source algo,
.toList();

for (val item : predictablySortedTxItems) {
b.append(compute(algo, item));
b.append(compute(item));
}

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, TransactionItemEntity item) {
private static String compute(TransactionItemEntity item) {
val b = new StringBuilder();

b.append(item.getId());

item.getAccountCredit().ifPresent(acc -> b.append(compute(algo, acc)));
item.getAccountDebit().ifPresent(acc -> b.append(compute(algo, acc)));
item.getAccountCredit().ifPresent(acc -> b.append(compute(acc)));
item.getAccountDebit().ifPresent(acc -> b.append(compute(acc)));

b.append(BigDecimals.normalise(item.getFxRate()));

b.append(BigDecimals.normalise(item.getAmountFcy()));
b.append(BigDecimals.normalise(item.getAmountLcy()));

item.getCostCenter().ifPresent(cc -> b.append(compute(algo, cc)));
item.getProject().ifPresent(p -> b.append(compute(algo, p)));
item.getDocument().ifPresent(d -> b.append(compute(algo, d)));
item.getCostCenter().ifPresent(cc -> b.append(compute(cc)));
item.getProject().ifPresent(p -> b.append(compute(p)));
item.getDocument().ifPresent(d -> b.append(compute(d)));

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, Document document) {
private static String compute(Document document) {
val b = new StringBuilder();

b.append(document.getNum());

document.getCounterparty().ifPresent(cp -> b.append(compute(algo, cp)));
document.getVat().ifPresent(v -> b.append(compute(algo, v)));
document.getCounterparty().ifPresent(cp -> b.append(compute(cp)));
document.getVat().ifPresent(v -> b.append(compute(v)));
b.append(document.getCurrency().getCustomerCode());

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, Vat vat) {
private static String compute(Vat vat) {
val b = new StringBuilder();

b.append(vat.getCustomerCode());

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, Counterparty counterparty) {
private static String compute(Counterparty counterparty) {
val b = new StringBuilder();

b.append(counterparty.getCustomerCode());

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, CostCenter costCenter) {
private static String compute(CostCenter costCenter) {
val b = new StringBuilder();

b.append(costCenter.getCustomerCode());

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, Project project) {
private static String compute(Project project) {
val b = new StringBuilder();

b.append(project.getCustomerCode());

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, Organisation org) {
private static String compute(Organisation org) {
val b = new StringBuilder();

b.append(org.getId());

return SHA3.digestAsHex(b.toString());
}

private static String compute(Source algo, Account acc) {
private static String compute(Account acc) {
val b = new StringBuilder();

b.append(acc.getCode());
Expand Down
Loading

0 comments on commit f568e56

Please sign in to comment.