You’ll now add a method to the OrdersService
Java class to decrease the stock whenever a new order item is posted.
-
Add the following code to your OrdersService
Java class and make sure you Save the file:
@Autowired
PersistenceService db;
@Before(event = CdsService.EVENT_CREATE, entity = "OrdersService.OrderItems")
public void validateBookAndDecreaseStock(List<OrderItems> items) {
for (OrderItems item : items) {
String bookId = item.getBookId();
Integer amount = item.getAmount();
// check if the book that should be ordered is existing
CqnSelect sel = Select.from(Books_.class).columns(b -> b.stock()).where(b -> b.ID().eq(bookId));
Books book = db.run(sel).first(Books.class)
.orElseThrow(() -> new ServiceException(ErrorStatuses.NOT_FOUND, "Book does not exist"));
// check if order could be fulfilled
int stock = book.getStock();
if (stock < amount) {
throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Not enough books on stock");
}
// update the book with the new stock, means minus the order amount
book.setStock(stock - amount);
CqnUpdate update = Update.entity(Books_.class).data(book).where(b -> b.ID().eq(bookId));
db.run(update);
}
}
@Before(event = CdsService.EVENT_CREATE, entity = "OrdersService.Orders")
public void validateBookAndDecreaseStockViaOrders(List<Orders> orders) {
for (Orders order : orders) {
if (order.getItems() != null) {
validateBookAndDecreaseStock(order.getItems());
}
}
}
-
Add the following import statements to the top of the OrdersService
Java class and make sure you Save the file:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.Update;
import com.sap.cds.ql.cqn.CqnSelect;
import com.sap.cds.ql.cqn.CqnUpdate;
import com.sap.cds.services.ErrorStatuses;
import com.sap.cds.services.ServiceException;
import com.sap.cds.services.cds.CdsService;
import com.sap.cds.services.handler.annotations.Before;
import com.sap.cds.services.persistence.PersistenceService;
import cds.gen.ordersservice.OrderItems;
import cds.gen.ordersservice.Orders;
import cds.gen.sap.capire.bookstore.Books;
import cds.gen.sap.capire.bookstore.Books_;
import java.math.BigDecimal;
import cds.gen.sap.capire.bookstore.OrderItems_;
import com.sap.cds.services.handler.annotations.After;
Let’s break down what is happening:
-
The method validateBookAndDecreaseStock
is registered using the @Before
annotation. This means that the method is called before the OrderItems
entities are persisted. The annotation also specifies, that the method should be called whenever an entity OrderItems
is created.
-
The method has a parameter items
, which gives access to the list of OrderItems
. The interface used here is generated by CAP Java. It generates a POJO interface for each entity defined in the CDS model.
-
The CqnSelect sel
variable defines a database query to retrieve the book that is referenced by the order item. The query is performed and the returned entity data is accessed using the POJO interface for Books
.
-
After that the available stock of the book is compared against the ordered amount. If enough stock is available the stock is decreased on the book and the book is updated within the database.
-
As order items can also be created via a deep insert on the Orders
entity, the same validation is triggered by the validateBookAndDecreaseStockViaOrders
method.
It’s important to note, that the CAP Java SDK automatically takes care of combining all database queries and updates in a single transaction. This means, that if the creation of the order item fails for some reason, the stock of the book won’t be decreased.
The complete OrdersService.java file should now have the following format:
package com.sap.cap.bookstore.handlers;
import com.sap.cds.services.handler.EventHandler;
import com.sap.cds.services.handler.annotations.ServiceName;
import org.springframework.stereotype.Component;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.Update;
import com.sap.cds.ql.cqn.CqnSelect;
import com.sap.cds.ql.cqn.CqnUpdate;
import com.sap.cds.services.ErrorStatuses;
import com.sap.cds.services.ServiceException;
import com.sap.cds.services.cds.CdsService;
import com.sap.cds.services.handler.annotations.Before;
import com.sap.cds.services.persistence.PersistenceService;
import cds.gen.ordersservice.OrderItems;
import cds.gen.ordersservice.Orders;
import cds.gen.sap.capire.bookstore.Books;
import cds.gen.sap.capire.bookstore.Books_;
import java.math.BigDecimal;
import cds.gen.sap.capire.bookstore.OrderItems_;
import com.sap.cds.services.handler.annotations.After;
@Component
@ServiceName("OrdersService")
public class OrdersService implements EventHandler {
@Autowired
PersistenceService db;
@Before(event = CdsService.EVENT_CREATE, entity = "OrdersService.OrderItems")
public void validateBookAndDecreaseStock(List<OrderItems> items) {
for (OrderItems item : items) {
String bookId = item.getBookId();
Integer amount = item.getAmount();
// check if the book that should be ordered is existing
CqnSelect sel = Select.from(Books_.class).columns(b -> b.stock()).where(b -> b.ID().eq(bookId));
Books book = db.run(sel).first(Books.class)
.orElseThrow(() -> new ServiceException(ErrorStatuses.NOT_FOUND, "Book does not exist"));
// check if order could be fulfilled
int stock = book.getStock();
if (stock < amount) {
throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Not enough books on stock");
}
// update the book with the new stock, means minus the order amount
book.setStock(stock - amount);
CqnUpdate update = Update.entity(Books_.class).data(book).where(b -> b.ID().eq(bookId));
db.run(update);
}
}
@Before(event = CdsService.EVENT_CREATE, entity = "OrdersService.Orders")
public void validateBookAndDecreaseStockViaOrders(List<Orders> orders) {
for (Orders order : orders) {
if (order.getItems() != null) {
validateBookAndDecreaseStock(order.getItems());
}
}
}
}