Aligned content with latest capire docs
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
"env": {
|
"env": {
|
||||||
|
"browser": true,
|
||||||
"node": true,
|
"node": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"jest": true
|
"jest": true
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Incorporate pre-build extensions from...
|
// Incorporate pre-build extensions from...
|
||||||
// using from '@capire/common';
|
|
||||||
using from '../../common'; //> work-around for mediocre cds-tests
|
using from '../../common'; //> work-around for mediocre cds-tests
|
||||||
|
// using from '@capire/common';
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
/* global Vue axios */ //> from vue.html
|
/* global Vue axios */ //> from vue.html
|
||||||
|
const $ = sel => document.querySelector(sel)
|
||||||
const GET = (url) => axios.get('/browse'+url)
|
const GET = (url) => axios.get('/browse'+url)
|
||||||
|
const POST = (cmd,data) => axios.post('/browse'+cmd,data)
|
||||||
|
|
||||||
const books = new Vue ({
|
const books = new Vue ({
|
||||||
|
|
||||||
@@ -7,7 +9,8 @@ const books = new Vue ({
|
|||||||
|
|
||||||
data: {
|
data: {
|
||||||
list: [],
|
list: [],
|
||||||
info: '( click on a row to see details... )',
|
book: { descr:'( click on a row to see details... )' },
|
||||||
|
order: { amount:1, succeeded:'', failed:'' }
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -15,16 +18,26 @@ const books = new Vue ({
|
|||||||
search: ({target:{value:v}}) => books.fetch (v && '$search='+v),
|
search: ({target:{value:v}}) => books.fetch (v && '$search='+v),
|
||||||
|
|
||||||
async fetch (_filter='') {
|
async fetch (_filter='') {
|
||||||
const columns = 'ID,title,author,price', details = 'genre,currency'
|
const columns = 'ID,title,author,price,stock', details = 'genre,currency'
|
||||||
const {data} = await GET(`/Books?$select=${columns}&$expand=${details}&${_filter}`)
|
const {data} = await GET(`/Books?$select=${columns}&$expand=${details}&${_filter}`)
|
||||||
books.list = data.value
|
books.list = data.value
|
||||||
},
|
},
|
||||||
|
|
||||||
async inspect ({currentTarget:{id}}) {
|
async inspect () {
|
||||||
const {data} = await GET(`/Books/${id}/descr/$value`)
|
const book = books.book = books.list [event.currentTarget.rowIndex-1]
|
||||||
books.info = data
|
book.descr || await GET(`/Books/${book.ID}/descr/$value`) .then (({data}) => book.descr = data)
|
||||||
|
books.order = { amount:1 }
|
||||||
|
setTimeout (()=> $('form > input').focus(), 111)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
submitOrder () { event.preventDefault()
|
||||||
|
const {book,order} = books, amount = parseInt (order.amount) || 1
|
||||||
|
POST(`/submitOrder`, { amount, book: book.ID })
|
||||||
|
.then (()=> books.order = { amount, succeeded: `Successfully orderd ${amount} item(s).` })
|
||||||
|
.catch (e=> books.order = { amount, failed: e.response.data.error.message })
|
||||||
|
GET(`/Books/${book.ID}/stock/$value`).then (res => book.stock = res.data)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,22 @@
|
|||||||
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
||||||
<style> #books tr:hover { background: #f2f2f2; cursor: pointer; } </style>
|
<style>
|
||||||
|
#books tr:hover { background: #f2f2f2; cursor: pointer; }
|
||||||
|
form { float:right; display:flex; flex-direction: row-reverse }
|
||||||
|
form #amount { width: 5em }
|
||||||
|
.is-success { color: #0d920d }
|
||||||
|
.has-error { color: #df1010 }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="small-container", style="margin-top: 70px;">
|
<body class="small-container", style="margin-top: 70px;">
|
||||||
<div id='app'>
|
<div id='app'>
|
||||||
|
|
||||||
<h1> Capire Books </h1>
|
<h1> Capire Books </h1>
|
||||||
|
|
||||||
<input type="text" placeholder="Search..." @input="search">
|
<input type="text" placeholder="Search..." @input="search">
|
||||||
|
|
||||||
<table id='books'>
|
<table id='books'>
|
||||||
<thead>
|
<thead>
|
||||||
<th> Book </th>
|
<th> Book </th>
|
||||||
@@ -27,7 +36,22 @@
|
|||||||
<td>{{ book.currency.symbol }} {{ book.price }}</td>
|
<td>{{ book.currency.symbol }} {{ book.price }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p> {{ info }} </p>
|
|
||||||
|
<div v-if="book.title">
|
||||||
|
<label style="text-align:right">
|
||||||
|
<span class="is-success"> {{ order.succeeded }} </span>
|
||||||
|
<span class="has-error"> {{ order.failed }} </span>
|
||||||
|
{{ book.stock }} in stock
|
||||||
|
</label>
|
||||||
|
<form @submit="submitOrder">
|
||||||
|
<input type="number" id="amount" v-model="order.amount" v-bind:class="{ 'has-error': order.failed }">
|
||||||
|
<input type="submit" value="Order:" class="muted-button">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4> {{ book.title }} </h4>
|
||||||
|
<p> {{ book.descr }} </p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ service CatalogService @(path:'/browse') {
|
|||||||
} excluding { createdBy, modifiedBy };
|
} excluding { createdBy, modifiedBy };
|
||||||
|
|
||||||
@requires_: 'authenticated-user'
|
@requires_: 'authenticated-user'
|
||||||
action order (book : Books.ID, amount: Integer);
|
action submitOrder (book : Books.ID, amount: Integer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
const cds = require('@sap/cds')
|
const cds = require('@sap/cds')
|
||||||
|
module.exports = async function (){
|
||||||
|
|
||||||
/** Service implementation for CatalogService */
|
const db = await cds.connect.to('db') // connect to database service
|
||||||
module.exports = cds.service.impl (function() {
|
const { Books } = db.entities // get reflected definitions
|
||||||
|
|
||||||
// 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
|
// Reduce stock of ordered books if available stock suffices
|
||||||
this.on ('order', async (req) => {
|
this.on ('submitOrder', async req => {
|
||||||
const {UPDATE} = cds.ql(req), {book,amount} = req.data
|
const {book,amount} = req.data
|
||||||
const n = await UPDATE (Books, book)
|
const n = await UPDATE (Books, book)
|
||||||
.where ('stock >=', amount)
|
.with ({ stock: {'-=': amount }})
|
||||||
.set ('stock -=', amount)
|
.where ({ stock: {'>=': amount }})
|
||||||
n > 0 || req.error (409,`${amount} exceeds stock for book #${book}`)
|
n > 0 || req.error (409,`${amount} exceeds stock for book #${book}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
// Add some discount for overstocked books
|
||||||
|
this.after ('READ','Books', each => {
|
||||||
|
if (each.stock > 111) each.title += ` -- 11% discount!`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ GET http://localhost:4004/admin/Authors?
|
|||||||
###
|
###
|
||||||
|
|
||||||
|
|
||||||
POST http://localhost:4004/browse/order
|
POST http://localhost:4004/browse/submitOrder
|
||||||
# Run that three times to get out-of-stock message
|
# Run that three times to get out-of-stock message
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user