Skip to content

Commit

Permalink
✨ (195): Start integrating commons module
Browse files Browse the repository at this point in the history
  • Loading branch information
Manuel Klaus committed Dec 22, 2024
1 parent 4864460 commit bb70a13
Show file tree
Hide file tree
Showing 28 changed files with 338 additions and 252 deletions.
5 changes: 5 additions & 0 deletions backend/app.hopps.az-document-ai/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>app.hopps</groupId>
<artifactId>commons</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- quarkus -->
<dependency>
<groupId>io.quarkus</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,48 @@
package app.hopps;

import app.hopps.commons.DocumentData;
import app.hopps.commons.DocumentType;
import app.hopps.model.InvoiceData;
import app.hopps.model.DocumentImage;
import app.hopps.model.ReceiptData;
import jakarta.inject.Inject;
import org.eclipse.microprofile.reactive.messaging.*;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.reactive.messaging.Channel;
import org.eclipse.microprofile.reactive.messaging.Emitter;
import org.eclipse.microprofile.reactive.messaging.Incoming;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ApplicationScoped
public class DocumentKafkaConnector {
private static final Logger LOG = LoggerFactory.getLogger(DocumentKafkaConnector.class);

private final Logger LOGGER = LoggerFactory.getLogger(DocumentKafkaConnector.class);

@Inject
@Channel("invoices-out")
Emitter<InvoiceData> invoicesEmitter;

@Inject
@Channel("receipts-out")
Emitter<ReceiptData> receiptEmitter;
private final AzureAiService azureAi;
private final Emitter<InvoiceData> invoicesEmitter;
private final Emitter<ReceiptData> receiptEmitter;

@Inject
AzureAiService azureAi;
public DocumentKafkaConnector(AzureAiService azureAi, @Channel("receipts-out") Emitter<ReceiptData> receiptEmitter, @Channel("invoices-out") Emitter<InvoiceData> invoicesEmitter) {
this.invoicesEmitter = invoicesEmitter;
this.receiptEmitter = receiptEmitter;
this.azureAi = azureAi;
}

@Incoming("documents-in")
public void scanDocument(DocumentImage message) {
var image = message.imageUrl();
switch (message.documentType()) {
case Receipt -> {
var receipt = azureAi.scanReceipt(image);
if (receipt != null) {
receiptEmitter.send(receipt);
} else {
LOGGER.error("Document analysis failed for receipt");
}
public void scanDocument(DocumentData message) {
var image = message.internalFinUrl();
if (message.type() == DocumentType.RECEIPT) {
var receipt = azureAi.scanReceipt(image);
if (receipt != null) {
receiptEmitter.send(receipt);
} else {
LOG.error("Document analysis failed for receipt");
}
case Invoice -> {
var invoice = azureAi.scanInvoice(image);
if (invoice != null) {
invoicesEmitter.send(invoice);
} else {
LOGGER.error("Document analysis failed for invoice");
}
} else if (message.type() == DocumentType.INVOICE) {
var invoice = azureAi.scanInvoice(image);
if (invoice != null) {
invoicesEmitter.send(invoice);
} else {
LOG.error("Document analysis failed for invoice");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package app.hopps.model;

import app.hopps.commons.DocumentType;

import java.net.URL;

public record DocumentImage(URL imageUrl, DocumentType documentType) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package app.hopps;

import app.hopps.model.*;
import app.hopps.model.Address;
import app.hopps.model.DocumentImage;
import app.hopps.model.InvoiceData;
import app.hopps.model.ReceiptData;
import io.quarkus.test.InjectMock;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;

import io.smallrye.reactive.messaging.memory.InMemoryConnector;
import io.smallrye.reactive.messaging.memory.InMemorySink;
import io.smallrye.reactive.messaging.memory.InMemorySource;
import jakarta.inject.Inject;
import org.eclipse.microprofile.reactive.messaging.spi.Connector;
import org.junit.jupiter.api.Test;

import jakarta.inject.Inject;
import io.smallrye.reactive.messaging.memory.InMemoryConnector;
import org.mockito.Mockito;

import java.net.MalformedURLException;
Expand All @@ -20,6 +21,7 @@
import java.time.LocalDate;
import java.util.Optional;

import static app.hopps.commons.DocumentType.INVOICE;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
Expand All @@ -36,13 +38,13 @@ class DocumentKafkaConnectorTest {
AzureAiService azureAiServiceMock;

@Test
public void onlySendsToInvoices() throws URISyntaxException, MalformedURLException {
void onlySendsToInvoices() throws URISyntaxException, MalformedURLException {

InvoiceData invoiceData = fakeInvoiceData();

DocumentImage documentImage = new DocumentImage(
new URI("http://something.test/picture").toURL(),
DocumentType.Invoice);
INVOICE);

when(azureAiServiceMock.scanInvoice(Mockito.any()))
.thenReturn(invoiceData);
Expand All @@ -62,7 +64,7 @@ public void onlySendsToInvoices() throws URISyntaxException, MalformedURLExcepti
InvoiceData actual = invoiceOut.received().getFirst().getPayload();
assertEquals(invoiceData, actual);

assertEquals(receiptsOut.received().size(), 0);
assertEquals(0, receiptsOut.received().size());
}

private static InvoiceData fakeInvoiceData() {
Expand Down
22 changes: 22 additions & 0 deletions backend/app.hopps.commons/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>app.hopps</groupId>
<artifactId>hopps</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<artifactId>commons</artifactId>
<version>1.0.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package app.hopps.commons;

public record Address(
String countryOrRegion,
String postalCode,
String state,
String city,
String road,
String houseNumber) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package app.hopps.commons;

public interface Data {
Long referenceKey();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package app.hopps.commons;

import java.net.URL;

public record DocumentData(URL internalFinUrl, Long referenceKey, DocumentType type) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package app.hopps.commons;

public enum DocumentType {
RECEIPT,
INVOICE,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package app.hopps.commons;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Optional;

public record InvoiceData(
Long referenceKey,
BigDecimal total,
LocalDate invoiceDate,
String currencyCode,
Optional<String> customerName,
Optional<Address> billingAddress,
Optional<String> purchaseOrderNumber,
Optional<String> invoiceId,
Optional<LocalDate> dueDate,
Optional<BigDecimal> subTotal,
Optional<BigDecimal> amountDue) implements Data {

public InvoiceData(Long referenceKey, BigDecimal total, LocalDate invoiceDate, String currencyCode) {
this(referenceKey, total, invoiceDate, currencyCode, Optional.empty(), Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty(), Optional.empty(), Optional.empty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package app.hopps.commons;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Optional;

public record ReceiptData(
Long referenceKey,
BigDecimal total,
Optional<BigDecimal> subTotal,
Optional<String> storeName,
Optional<Address> storeAddress,
Optional<LocalDateTime> transactionTime) implements Data {

public ReceiptData(Long referenceKey, BigDecimal total) {
this(referenceKey, total, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty());
}
}
5 changes: 5 additions & 0 deletions backend/app.hopps.fin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>app.hopps</groupId>
<artifactId>commons</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- quarkus -->
<dependency>
<groupId>io.quarkus</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package app.hopps.fin;

import app.hopps.commons.Data;
import app.hopps.fin.jpa.TransactionRecordRepository;
import app.hopps.fin.jpa.entities.TransactionRecord;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;

import java.util.Optional;

@SuppressWarnings("java:S6813")
public abstract class AbstractDataHandler {
@Inject
TransactionRecordRepository repository;

@Transactional
public void handleData(Data data) {
TransactionRecord transactionRecord = getAndVerify(data.referenceKey());

updateData(transactionRecord, data);
repository.persist(transactionRecord);
}

private TransactionRecord getAndVerify(Long referenceKey) {
Optional<TransactionRecord> optionalTransactionRecord = repository.findByIdOptional(referenceKey);
if (optionalTransactionRecord.isEmpty()) {
throw new IllegalStateException("Reference key is not found!");
}
return optionalTransactionRecord.get();
}

protected abstract void updateData(TransactionRecord transactionRecord, Data data);
}
37 changes: 0 additions & 37 deletions backend/app.hopps.fin/src/main/java/app/hopps/fin/DataHandler.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package app.hopps.fin;

import app.hopps.commons.Data;
import app.hopps.commons.InvoiceData;
import app.hopps.fin.jpa.entities.TransactionRecord;
import app.hopps.fin.kafka.model.AddressHelper;
import jakarta.enterprise.context.ApplicationScoped;

import java.time.ZoneId;

@ApplicationScoped
@SuppressWarnings("java:S3740")
public class InvoiceDataHandler extends AbstractDataHandler {
@Override
protected void updateData(TransactionRecord transactionRecord, Data data) {
if (data instanceof InvoiceData invoiceData) {
handleInvoice(transactionRecord, invoiceData);
}
}

private void handleInvoice(TransactionRecord transactionRecord, InvoiceData data) {
transactionRecord.setTotal(data.total());

// Required
transactionRecord.setTransactionTime(data.invoiceDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
transactionRecord.setCurrencyCode(data.currencyCode());

// Optional
data.customerName().ifPresent(transactionRecord::setName);
data.billingAddress().ifPresent(address -> transactionRecord.setAddress(AddressHelper.convertToJpa(address)));
data.purchaseOrderNumber().ifPresent(transactionRecord::setOrderNumber);
data.invoiceId().ifPresent(transactionRecord::setInvoiceId);
data.dueDate()
.ifPresent(
dueDate -> transactionRecord
.setDueDate(dueDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
data.subTotal().ifPresent(transactionRecord::setSubTotal);
data.amountDue().ifPresent(transactionRecord::setAmountDue);
}
}
Loading

0 comments on commit bb70a13

Please sign in to comment.