-
Notifications
You must be signed in to change notification settings - Fork 0
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
Suggestion: Better model for tutorial #2
base: master
Are you sure you want to change the base?
Conversation
Handler: package com.sap.cap.bookstore.handlers;
import cds.gen.ordersservice.OrdersService_;
import com.sap.cds.services.handler.EventHandler;
import com.sap.cds.services.handler.annotations.ServiceName;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Collections;
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.CqnService;
import com.sap.cds.services.handler.annotations.After;
import com.sap.cds.services.handler.annotations.Before;
import com.sap.cds.services.persistence.PersistenceService;
import cds.gen.ordersservice.Orders;
import cds.gen.ordersservice.Orders_;
import cds.gen.sap.capire.bookstore.Books;
import cds.gen.sap.capire.bookstore.Books_;
@Component
@ServiceName(OrdersService_.CDS_NAME)
public class OrdersService implements EventHandler {
@Autowired
PersistenceService db;
private void validateBookAndDecreaseStock(List<Orders.Items> items) {
for (Orders.Items 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 = CqnService.EVENT_CREATE, entity = Orders_.CDS_NAME)
public void validateBookAndDecreaseStockViaOrders(List<Orders> orders) {
for (Orders order : orders) {
if (order.getItems() != null) {
validateBookAndDecreaseStock(order.getItems());
calculateNetAmount(order.getItems());
}
}
}
@After(event = { CqnService.EVENT_READ, CqnService.EVENT_CREATE }, entity = Orders_.CDS_NAME)
public void calculateTotal(List<Orders> orders) {
for (Orders order : orders) {
// calculate net amount for expanded items
if (order.getItems() != null) {
calculateNetAmount(order.getItems());
}
// get all items of the order
CqnSelect selItems = Select.from(Orders_.class)
.columns(t -> t.expand(o -> o.items())).where(i -> i.ID().eq(order.getId()));
List<Orders.Items> allItems = db.run(selItems).first(Orders.class)
.map(o -> o.getItems()).orElse(Collections.emptyList());
// calculate net amount of all items
calculateNetAmount(allItems);
// calculate and set the orders total
BigDecimal total = new BigDecimal(0);
for (Orders.Items item : allItems) {
total = total.add(item.getNetAmount());
}
order.setTotal(total);
}
}
private void calculateNetAmount(List<Orders.Items> items) {
for (Orders.Items item : items) {
String bookId = item.getBookId();
// get the book that was ordered
CqnSelect sel = Select.from(Books_.class).where(b -> b.ID().eq(bookId));
Books book = db.run(sel).single(Books.class);
// calculate and set net amount
item.setNetAmount(book.getPrice().multiply(new BigDecimal(item.getAmount())));
}
}
} |
I am not sure if it's a general best practice to use inline types. However, for this scenario it makes sense. The OrderItems type is not reused anywhere. |
@@ -106,35 +106,32 @@ Now that you have created your bookstore project, you need to define the domain | |||
|
|||
```CDS | |||
namespace sap.capire.bookstore; | |||
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suppose the remove those blank lines. I understand that it improves readability, but in a tutorial where this is copied, it just increases the size of the document.
Merge pull request #2 from sap-tutorials/master
commit and push after git bash
We can change model a little to follow "better" best practice:
I do not remember why we have not done this last year. Probably either me being afraid to rewrite the whole tutorial or something else.
This will require a rewrite of the handler and some changes in the URLs here and there. I did a quick test locally and see no issues.