cleaned up
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
ID;amount;parent_ID;book_ID;netAmount
|
||||
58040e66-1dcd-4ffb-ab10-fdce32028b79;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;201;11.11
|
||||
64e718c9-ff99-47f1-8ca3-950c850777d4;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;271;15
|
||||
e9641166-e050-4261-bfee-d1e797e6cb7f;2;64e718c9-ff99-47f1-8ca3-950c850777d4;252;28
|
||||
|
@@ -1,3 +0,0 @@
|
||||
ID;modifiedAt;createdAt;createdBy;modifiedBy;OrderNo;currency_code
|
||||
7e2f2640-6866-4dcf-8f4d-3027aa831cad;;2019-01-31;john.doe@test.com;;1;EUR
|
||||
64e718c9-ff99-47f1-8ca3-950c850777d4;;2019-01-30;jane.doe@test.com;;2;EUR
|
||||
|
@@ -1,5 +1,6 @@
|
||||
namespace sap.capire.bookshop;
|
||||
using { Currency, managed, cuid, sap } from '@sap/cds/common';
|
||||
// using { Currency, managed, sap } from '@sap/cds/common';
|
||||
using { Currency, managed, sap } from '@capire/common';
|
||||
|
||||
entity Books : managed {
|
||||
key ID : Integer;
|
||||
@@ -27,16 +28,3 @@ entity Genres : sap.common.CodeList {
|
||||
parent : Association to Genres;
|
||||
children : Composition of many Genres on children.parent = $self;
|
||||
}
|
||||
|
||||
entity Orders : cuid, managed {
|
||||
OrderNo : String @title:'Order Number'; //> readable key
|
||||
Items : Composition of many OrderItems on Items.parent = $self;
|
||||
total : Decimal(9,2) @readonly;
|
||||
currency : Currency;
|
||||
}
|
||||
entity OrderItems : cuid {
|
||||
parent : Association to Orders;
|
||||
book : Association to Books;
|
||||
amount : Integer;
|
||||
netAmount : Decimal(9,2);
|
||||
}
|
||||
|
||||
@@ -2,20 +2,13 @@
|
||||
"name": "@capire/bookshop",
|
||||
"version": "1.0.0",
|
||||
"description": "A simple bookshop application, build in a self-contained all-in-one fashion, i.e. w/o reusing other packages.",
|
||||
"license": "SAP SAMPLE CODE LICENSE",
|
||||
"dependencies": {
|
||||
"@capire/common": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"test:genres": "cds serve tests/genres.cds --in-memory",
|
||||
"start": "cds run --in-memory?",
|
||||
"watch": "cds watch",
|
||||
"test:genres": "cds serve tests/genres.cds --in-memory"
|
||||
"watch": "cds watch"
|
||||
},
|
||||
"cds": {
|
||||
"requires": {
|
||||
"db": {
|
||||
"kind": "sql"
|
||||
}
|
||||
}
|
||||
}
|
||||
"license": "SAP SAMPLE CODE LICENSE"
|
||||
}
|
||||
@@ -3,5 +3,4 @@ using { sap.capire.bookshop as my } from '../db/schema';
|
||||
service AdminService @(_requires:'authenticated-user') {
|
||||
entity Books as projection on my.Books;
|
||||
entity Authors as projection on my.Authors;
|
||||
entity Orders as select from my.Orders;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using { sap.capire.bookshop as my } from '../db/schema';
|
||||
|
||||
@path:'/browse'
|
||||
service CatalogService {
|
||||
service CatalogService @(path:'/browse') {
|
||||
|
||||
@readonly entity Books as SELECT from my.Books {*,
|
||||
author.name as author
|
||||
} excluding { createdBy, modifiedBy };
|
||||
|
||||
@requires_: 'authenticated-user'
|
||||
@insertonly entity Orders as projection on my.Orders;
|
||||
action order (book : Books.ID, amount: Integer);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
const cds = require('@sap/cds')
|
||||
const { Books } = cds.entities
|
||||
|
||||
/** Service implementation for CatalogService */
|
||||
module.exports = cds.service.impl(function() {
|
||||
this.after ('READ', 'Books', each => each.stock > 111 && _addDiscount2(each,11))
|
||||
this.before ('CREATE', 'Orders', _reduceStock)
|
||||
module.exports = cds.service.impl (function() {
|
||||
|
||||
// Get entity definitions from reflected model
|
||||
const { Books } = cds.entities
|
||||
|
||||
// Add some discount for overstocked books
|
||||
this.after ('READ', 'Books', each => {
|
||||
if (each.stock > 111) each.title += ` -- 11% discount!`
|
||||
})
|
||||
|
||||
// Reduce stock of ordered books if available stock suffices
|
||||
this.on ('order', async (req) => {
|
||||
const {UPDATE} = cds.ql(req), {book,amount} = req.data
|
||||
const n = await UPDATE (Books, book)
|
||||
.where ('stock >=', amount)
|
||||
.set ('stock -=', amount)
|
||||
n > 0 || req.error (409,`${amount} exceeds stock for book #${book}`)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
/** Add some discount for overstocked books */
|
||||
function _addDiscount2 (each,discount) {
|
||||
each.title += ` -- ${discount}% discount!`
|
||||
}
|
||||
|
||||
/** Reduce stock of ordered books if available stock suffices */
|
||||
async function _reduceStock (req) {
|
||||
const { Items: OrderItems } = req.data
|
||||
return cds.transaction(req) .run (()=> OrderItems.map (order =>
|
||||
UPDATE (Books) .set ('stock -=', order.amount)
|
||||
.where ('ID =', order.book_ID) .and ('stock >=', order.amount)
|
||||
)) .then (all => all.forEach ((affectedRows,i) => {
|
||||
if (affectedRows === 0) req.error (409,
|
||||
`${OrderItems[i].amount} exceeds stock for book #${OrderItems[i].book_ID}`
|
||||
)
|
||||
}))
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
const cds = require ('@sap/cds')
|
||||
const { expect } = require('chai').use (require('chai-deep-match'))
|
||||
const { expect } = require('chai') .use (require('chai-subset'))
|
||||
|
||||
describe('reading/writing hierarchies', ()=>{
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('reading/writing hierarchies', ()=>{
|
||||
})
|
||||
}) .where ({name:'Cat'})
|
||||
|
||||
) .to.deep.match (
|
||||
) .to.containSubset (
|
||||
|
||||
{ ID:101, parent:'Cat', children:[
|
||||
{ child:'Kitty' },
|
||||
@@ -53,7 +53,7 @@ describe('reading/writing hierarchies', ()=>{
|
||||
c.ID, c.name, c.children (c=>{ c.name },{levels:3})
|
||||
}) .where ({name:'Cat'})
|
||||
|
||||
) .to.deep.match (
|
||||
) .to.containSubset (
|
||||
|
||||
{ ID:101, name:'Cat', children:[
|
||||
{ name:'Kitty', children:[
|
||||
|
||||
@@ -1,18 +1,40 @@
|
||||
### Service Document
|
||||
GET http://localhost:4004/browse
|
||||
###
|
||||
|
||||
### Service $metadata document
|
||||
GET http://localhost:4004/browse/$metadata
|
||||
###
|
||||
|
||||
|
||||
### Browsing Books
|
||||
GET http://localhost:4004/browse/Books?
|
||||
# &$select=title,author
|
||||
# &$expand=currency
|
||||
&$select=title,stock
|
||||
&$expand=currency
|
||||
#> add @capire/common to see data for currencies
|
||||
# &sap-language=de
|
||||
###
|
||||
|
||||
|
||||
### Browsing Authors
|
||||
GET http://localhost:4004/admin/Authors?
|
||||
# &$select=name,dateOfBirth,placeOfBirth
|
||||
# &$expand=books($select=title;$expand=currency)
|
||||
&$expand=books($select=title;$expand=currency)
|
||||
#> add @capire/common to see data for currencies
|
||||
# &$filter=ID eq 101
|
||||
# &sap-language=de
|
||||
&sap-language=de
|
||||
###
|
||||
|
||||
|
||||
POST http://localhost:4004/browse/order
|
||||
# Run that three times to get out-of-stock message
|
||||
Content-Type: application/json
|
||||
|
||||
{ "book":201, "amount":5 }
|
||||
###
|
||||
|
||||
|
||||
|
||||
GET http://localhost:4004/browse/Genres?
|
||||
###
|
||||
|
||||
GET http://localhost:4004/browse/Genres?
|
||||
&$filter=parent_ID eq null&$select=name
|
||||
&$expand=children($select=name)
|
||||
###
|
||||
|
||||
Reference in New Issue
Block a user