Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions samples/bookshop/app/supplier-invoices/fiori-service.cds
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ annotate service.SupplierInvoices with @(
]
);

annotate service.SupplierInvoices with {
invoiceNumber @title: '{i18n>InvoiceNumber}';
supplier @title: '{i18n>Supplier}';
status @title: '{i18n>Status}';
}
Comment thread
lisajulia marked this conversation as resolved.

annotate service.SupplierInvoices with {
supplier @Common: {
Text : supplier.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ b1e2c3d4-5f6a-7b8c-9d0e-1f2a3b4c5d6e;Springer Nature;DE;orders@springernature.co
c2f3d4e5-6a7b-8c9d-0e1f-2a3b4c5d6e7f;O'Reilly Media;US;invoices@oreilly.com
d3a4b5c6-7d8e-9f0a-1b2c-3d4e5f6a7b8c;Elsevier;NL;ap@elsevier.com
e4b5c6d7-8e9f-0a1b-2c3d-4e5f6a7b8c9d;Pearson Education;GB;finance@pearson.com
e4b5c6d7-8e9f-0a1b-2c3d-4e5f6a7b8c9f;Studio Salford;US;ap@studiosalford.com
4 changes: 4 additions & 0 deletions samples/bookshop/db/schema.cds
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,7 @@ entity SupplierInvoices : managed, cuid {
status : Association to InvoiceStatus;
documentAiJobId : String;
}

annotate SupplierInvoices with {
status @UI.RecommendationState: 0;
Comment thread
lisajulia marked this conversation as resolved.
}
2 changes: 1 addition & 1 deletion samples/bookshop/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<cds.services.version>5.0.0</cds.services.version>
<spring.boot.version>4.1.0</spring.boot.version>
<cds-starter-ai.version>0.0.1-alpha</cds-starter-ai.version>
<cds-feature-sap-document-ai.version>0.0.1-alpha</cds-feature-sap-document-ai.version>
<cds-feature-sap-document-ai.version>0.0.2-alpha</cds-feature-sap-document-ai.version>
<cds-feature-attachments.version>1.5.0</cds-feature-attachments.version>

</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

import cds.gen.sap.capire.bookshop.SupplierInvoices;
import cds.gen.sap.capire.bookshop.SupplierInvoices_;
import cds.gen.sap.capire.bookshop.Suppliers;
import cds.gen.sap.capire.bookshop.Suppliers_;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sap.cds.feature.documentai.generated.cds4j.sap.document.ai.documentaiservice.DocumentExtractionResult;
import com.sap.cds.feature.documentai.generated.cds4j.sap.document.ai.documentaiservice.DocumentExtractionResultContext;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.Update;
import com.sap.cds.services.cds.ApplicationService;
import com.sap.cds.services.handler.EventHandler;
Expand All @@ -17,7 +20,9 @@
import com.sap.cds.services.persistence.PersistenceService;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -26,7 +31,7 @@
/**
* Handles extraction results from the SAP Document AI plugin. Parses the extraction JSON returned
* by the DIE service and populates the corresponding SupplierInvoice entity with the extracted
* header fields (invoice number, date, total amount, currency).
* header fields (invoice number, date, total amount, currency, and matched supplier).
*/
@Component
@ServiceName(value = "*", type = ApplicationService.class)
Expand All @@ -50,18 +55,15 @@ public void onExtractionCompleted(DocumentExtractionResultContext context) {
JsonNode root = objectMapper.readTree(data.getExtractionResult());
JsonNode headerFields = root.path("extraction").path("headerFields");

// Extract relevant header fields from the DIE response
String documentNumber = getHeaderFieldValue(headerFields, "documentNumber");
String documentDate = getHeaderFieldValue(headerFields, "documentDate");
String currencyCode = getHeaderFieldValue(headerFields, "currencyCode");
BigDecimal grossAmount = getHeaderFieldNumber(headerFields, "grossAmount");
String senderName = getHeaderFieldValue(headerFields, "senderName");

logger.info(
"[bookshop] Extracted: number={}, date={}, amount={} {}",
documentNumber,
documentDate,
grossAmount,
currencyCode);
"[bookshop] Extracted: number={}, date={}, amount={} {}, sender={}",
documentNumber, documentDate, grossAmount, currencyCode, senderName);

// Update the invoice that is currently in EXTRACTING status.
// In a production app you would correlate by a stored jobId; for this sample
Expand All @@ -73,6 +75,18 @@ public void onExtractionCompleted(DocumentExtractionResultContext context) {
if (grossAmount != null) updateData.put(SupplierInvoices.TOTAL_AMOUNT, grossAmount);
if (currencyCode != null) updateData.put(SupplierInvoices.CURRENCY_CODE, currencyCode);

// Match extracted sender name to a Supplier record (case-insensitive)
if (senderName != null) {
findSupplierByName(senderName)
.ifPresentOrElse(
supplier -> {
updateData.put(SupplierInvoices.SUPPLIER_ID, supplier.getId());
logger.info(
"[bookshop] Matched supplier: {} ({})", supplier.getName(), supplier.getId());
},
() -> logger.warn("[bookshop] No supplier found for sender name: {}", senderName));
}

long updated =
db.run(
Update.entity(SupplierInvoices_.CDS_NAME)
Expand All @@ -93,6 +107,16 @@ public void onExtractionCompleted(DocumentExtractionResultContext context) {
context.setCompleted();
}

private Optional<Suppliers> findSupplierByName(String name) {
String normalized = name.toLowerCase(Locale.ROOT);
return db.run(Select.from(Suppliers_.class)
.where(s -> s.name().eq(name)))
.listOf(Suppliers.class)
.stream()
.filter(s -> s.getName() != null && normalized.equals(s.getName().toLowerCase(Locale.ROOT)))
.findFirst();
}

private String getHeaderFieldValue(JsonNode headerFields, String fieldName) {
for (JsonNode field : headerFields) {
if (fieldName.equals(field.path("name").asText())) {
Expand Down
Loading