Compare commits
30 Commits
sandboxed
...
openSAP-we
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f28bfbb768 | ||
|
|
7d8ca4d4a1 | ||
|
|
61aa81a806 | ||
|
|
e7c395671b | ||
|
|
cd245c4641 | ||
|
|
d081438a6a | ||
|
|
79c3a22224 | ||
|
|
9c30ad7584 | ||
|
|
c58bcf905f | ||
|
|
50ab059c13 | ||
|
|
46960159d1 | ||
|
|
02228e5a96 | ||
|
|
d4793177fc | ||
|
|
2787284aad | ||
|
|
61a318b250 | ||
|
|
6e42e5a173 | ||
|
|
bf162c23cc | ||
|
|
9b41615ac8 | ||
|
|
29840afc0b | ||
|
|
fa880e2987 | ||
|
|
90881558dc | ||
|
|
6d3e9a211a | ||
|
|
e694fbaf13 | ||
|
|
43d0373d70 | ||
|
|
b632013b16 | ||
|
|
a6deddf022 | ||
|
|
513bf9711f | ||
|
|
00c99c0e0b | ||
|
|
e042317f82 | ||
|
|
04ab69c48f |
@@ -1,14 +1,12 @@
|
|||||||
{
|
{
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
|
||||||
"node": true,
|
"node": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"jest": true,
|
"jest": true
|
||||||
"mocha": true
|
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2018
|
"ecmaVersion": 2017
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"SELECT": true,
|
"SELECT": true,
|
||||||
|
|||||||
28
.github/workflows/node.js.yml
vendored
28
.github/workflows/node.js.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
||||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
||||||
|
|
||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [10.x, 12.16.2]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- run: npm install
|
|
||||||
- run: npm test
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,5 +13,3 @@ target/
|
|||||||
connection.properties
|
connection.properties
|
||||||
default-env.json
|
default-env.json
|
||||||
packages/messageBox
|
packages/messageBox
|
||||||
reviews/msg-box
|
|
||||||
reviews/db/test.db
|
|
||||||
|
|||||||
20
.vscode/extensions.json
vendored
20
.vscode/extensions.json
vendored
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
|
||||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
|
||||||
|
|
||||||
// List of extensions which should be recommended for users of this workspace.
|
|
||||||
"recommendations": [
|
|
||||||
// "CDS Editor !",
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"mechatroner.rainbow-csv",
|
|
||||||
"humao.rest-client",
|
|
||||||
"alexcvzz.vscode-sqlite",
|
|
||||||
"hbenl.vscode-mocha-test-adapter",
|
|
||||||
"sdras.night-owl"
|
|
||||||
],
|
|
||||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
|
||||||
"unwantedRecommendations": [
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
37
.vscode/launch.json
vendored
37
.vscode/launch.json
vendored
@@ -5,35 +5,38 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "bookshop",
|
"name": "cds run",
|
||||||
"cwd": "${workspaceFolder}/bookshop",
|
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"runtimeExecutable": "npx",
|
"runtimeExecutable": "npx",
|
||||||
"runtimeArgs": ["-n"],
|
"runtimeArgs": ["-n"],
|
||||||
"args": ["--", "cds", "run", "--with-mocks", "--in-memory?"],
|
"args": ["--", "cds", "run", "--with-mocks", "--in-memory?"], // the leading "--" arg ensures it works with as well as without debugging
|
||||||
|
"cwd": "${workspaceFolder}/packages/${input:service}",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"skipFiles": ["<node_internals>/**"]
|
"serverReadyAction": {
|
||||||
|
"pattern": "server listening on (https?://\\S+|[0-9]+)",
|
||||||
|
"uriFormat": "http://localhost:%s",
|
||||||
|
"action": "openExternally"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Fiori App",
|
|
||||||
"cwd": "${workspaceFolder}/fiori",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "node",
|
|
||||||
"runtimeExecutable": "npx",
|
|
||||||
"runtimeArgs": ["-n"],
|
|
||||||
"args": ["--", "cds", "run", "--with-mocks", "--in-memory?"],
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"skipFiles": ["<node_internals>/**"]
|
"skipFiles": ["<node_internals>/**"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"type": "pickString",
|
"type": "pickString",
|
||||||
"id": "sample",
|
"id": "service",
|
||||||
"description": "Which sample do you want to start?",
|
"description": "Which service do you want to start?",
|
||||||
"options": ["bookshop", "fiori", "reviews", "reviews/test/bookshop"],
|
"options": [
|
||||||
"default": "bookshop"
|
"bookshop",
|
||||||
|
"bookstore",
|
||||||
|
"media-server",
|
||||||
|
"office-supplies",
|
||||||
|
"orders-service",
|
||||||
|
"products-service",
|
||||||
|
"reviews-service",
|
||||||
|
"user-service"
|
||||||
|
],
|
||||||
|
"default": "bookstore"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"**/.gitignore": true,
|
"**/.gitignore": false,
|
||||||
"**/.vscode": true
|
"**/.git": false,
|
||||||
|
"**/.vscode": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
.vscode/tasks.json
vendored
23
.vscode/tasks.json
vendored
@@ -4,12 +4,23 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "shell", "label": "cds run bookshop",
|
||||||
"script": "jest",
|
"command": "npx", "args": [ "cds", "watch", "packages/bookshop" ],
|
||||||
"group": {
|
"presentation": { "group": "A" },
|
||||||
"kind": "test",
|
"problemMatcher": []
|
||||||
"isDefault": true
|
},
|
||||||
}
|
{
|
||||||
|
"type": "shell", "label": "cds run bookshop-enhanced",
|
||||||
|
"command": "npx", "args": [ "cds", "watch", "packages/bookshop-enhanced" ],
|
||||||
|
"presentation": { "group": "A" },
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "shell", "label": "cds run reviews-service",
|
||||||
|
"command": "npx", "args": [ "cds", "watch", "packages/reviews-service" ],
|
||||||
|
"options": {"env": { "PORT":"5005" }},
|
||||||
|
"presentation": { "group": "A" },
|
||||||
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
379
LICENSE
379
LICENSE
@@ -1,217 +1,190 @@
|
|||||||
Apache License
|
SAP SAMPLE CODE LICENSE AGREEMENT
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
Please scroll down and read the following SAP Sample Code License Agreement
|
||||||
|
carefully ("Agreement"). By downloading, installing, or otherwise using the
|
||||||
|
SAP sample code or any materials that accompany the sample code documentation
|
||||||
|
(collectively, the "Sample Code"), You agree that this Agreement forms a legally
|
||||||
|
binding agreement between You ("You" or "Your") and SAP SE, for and on behalf
|
||||||
|
of itself and its subsidiaries and affiliates (as defined in Section 15 of the
|
||||||
|
German Stock Corporation Act), and You agree to be bound by all of the terms
|
||||||
|
and conditions stated in this Agreement. If You are trying to access or download
|
||||||
|
the Sample Code on behalf of Your employer or as a consultant or agent of a
|
||||||
|
third party (either "Your Company"), You represent and warrant that You have
|
||||||
|
the authority to act on behalf of and bind Your Company to the terms of this
|
||||||
|
Agreement and everywhere in this Agreement that refers to 'You' or 'Your' shall
|
||||||
|
also include Your Company. If You do not agree to these terms, do not attempt
|
||||||
|
to access or use the Sample Code.
|
||||||
|
|
||||||
1. Definitions.
|
1. LICENSE: Subject to the terms of this Agreement, SAP grants You a nonexclusive,
|
||||||
|
non-transferable, non-sublicensable, revocable, royalty-free,
|
||||||
|
limited license to use, copy, and modify the Sample Code solely for Your internal
|
||||||
|
business purposes.
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
2. RESTRICTIONS: You must not use the Sample Code to: (a) impair, degrade or
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
reduce the performance or security of any SAP products, services or related
|
||||||
|
technology (collectively, "SAP Products"); (b) enable the bypassing or
|
||||||
|
circumventing of SAP's license restrictions and/or provide users with access to
|
||||||
|
the SAP Products to which such users are not licensed; or (c) permit mass data
|
||||||
|
extraction from an SAP Product to a non-SAP Product, including use,
|
||||||
|
modification, saving or other processing of such data in the non-SAP Product.
|
||||||
|
Further, You must not: (i) provide or make the Sample Code available to any
|
||||||
|
third party other than your authorized employees, contractors and agents
|
||||||
|
(collectively, “Representatives”) and solely to be used by Your Representatives
|
||||||
|
for Your own internal business purposes; ii) remove or modify any marks or
|
||||||
|
proprietary notices from the Sample Code; iii) assign this Agreement, or any
|
||||||
|
interest therein, to any third party; (iv) use any SAP name, trademark or logo
|
||||||
|
without the prior written authorization of SAP; or (v) use the Sample Code to
|
||||||
|
modify an SAP Product or decompile, disassemble or reverse engineer an SAP
|
||||||
|
Product (except to the extent permitted by applicable law). You are responsible
|
||||||
|
for any breach of the terms of this Agreement by You or Your Representatives.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
3. INTELLECTUAL PROPERTY: SAP or its licensors retain all ownership and
|
||||||
the copyright owner that is granting the License.
|
intellectual property rights in and to the Sample Code and SAP Products. In
|
||||||
|
exchange for the right to use, copy and modify the Sample Code provided under
|
||||||
|
this Agreement, You covenant not to assert any intellectual property rights in
|
||||||
|
or to any of Your products, services, or related technology that are based on
|
||||||
|
or incorporate the Sample Code against any individual or entity in respect of
|
||||||
|
any current or future SAP Products.
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
4. SAP AND THIRD PARTY APIS: The Sample Code may include API (application
|
||||||
other entities that control, are controlled by, or are under common
|
programming interface) calls to SAP and third-party products or services. The
|
||||||
control with that entity. For the purposes of this definition,
|
access or use of the third-party products and services to which the API calls
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
are directed may be subject to additional terms and conditions between you and
|
||||||
direction or management of such entity, whether by contract or
|
SAP or such third parties. You (and not SAP) are solely responsible for
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
understanding and complying with any additional terms and conditions that apply
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
to the access or use of those APIs and/or third-party products and services.
|
||||||
|
SAP does not grant You any rights in or to these APIs, products or services
|
||||||
|
under this Agreement.
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
5. FREE AND OPEN SOURCE COMPONENTS: The Sample Code may include third party
|
||||||
exercising permissions granted by this License.
|
free or open source components ("FOSS Components"). You may have additional
|
||||||
|
rights in such FOSS Components that are provided by the third party licensors
|
||||||
|
of those components.
|
||||||
|
6. THIRD PARTY DEPENDENCIES: The Sample Code may require third party software
|
||||||
|
dependencies ("Dependencies") for the use or operation of the Sample Code. These
|
||||||
|
Dependencies may be identified by SAP in Maven POM files, documentation or by
|
||||||
|
other means. SAP does not grant You any rights in or to such Dependencies under
|
||||||
|
this Agreement. You are solely responsible for the acquisition, installation
|
||||||
|
and use of such Dependencies.
|
||||||
|
7. WARRANTY:
|
||||||
|
a) If You are located outside the US or Canada: AS THE SAMPLE CODE IS PROVIDED
|
||||||
|
TO YOU FREE OF CHARGE, SAP DOES NOT GUARANTEE OR WARRANT ANY FEATURES OR
|
||||||
|
QUALITIES OF THE SAMPLE CODE OR GIVE ANY UNDERTAKING WITH REGARD TO ANY OTHER
|
||||||
|
QUALITY. NO SUCH WARRANTY OR UNDERTAKING SHALL BE IMPLIED BY YOU FROM ANY
|
||||||
|
DESCRIPTION IN THE SAMPLE CODE OR ANY OTHER MATERIALS, COMMUNICATION OR
|
||||||
|
ADVERTISEMENT. IN PARTICULAR, SAP DOES NOT WARRANT THAT THE SAMPLE CODE WILL BE
|
||||||
|
AVAILABLE UNINTERRUPTED, ERROR FREE, OR PERMANENTLY AVAILABLE. ALL WARRANTY
|
||||||
|
CLAIMS RESPECTING THE SAMPLE CODE ARE SUBJECT TO THE LIMITATION OF LIABILITY
|
||||||
|
STIPULATED IN SECTION 8 BELOW.
|
||||||
|
b) If You are located in the US or Canada: THE SAMPLE CODE IS LICENSED TO YOU
|
||||||
|
"AS IS", WITHOUT ANY WARRANTY, ESCROW, TRAINING, MAINTENANCE, OR SERVICE
|
||||||
|
OBLIGATIONS WHATSOEVER ON THE PART OF SAP. SAP MAKES NO EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF SALE OF ANY TYPE WHATSOEVER, INCLUDING BUT NOT
|
||||||
|
LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY AND OF FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. IN PARTICULAR, SAP DOES NOT WARRANT THAT THE SAMPLE CODE WILL BE
|
||||||
|
AVAILABLE UNINTERRUPTED, ERROR FREE, OR PERMANENTLY AVAILABLE. YOU ASSUME ALL
|
||||||
|
RISKS ASSOCIATED WITH THE USE OF THE SAMPLE CODE, INCLUDING WITHOUT LIMITATION
|
||||||
|
RISKS RELATING TO QUALITY, AVAILABILITY, PERFORMANCE, DATA LOSS, AND UTILITY IN
|
||||||
|
A PRODUCTION ENVIRONMENT.
|
||||||
|
c) For all locations: SAP DOES NOT MAKE ANY REPRESENTATIONS OR WARRANTIES IN
|
||||||
|
RESPECT OF THIRD PARTY DEPENDENCIES, APIS, PRODUCTS AND SERVICES, INCLUDING BUT
|
||||||
|
NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY AND OF FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. IN PARTICULAR, SAP DOES NOT WARRANT THAT THIRDPARTY
|
||||||
|
DEPENDENCIES, APIS, PRODUCTS AND SERVICES WILL BE AVAILABLE, ERROR FREE,
|
||||||
|
INTEROPERABLE WITH THE SAMPLE CODE, SUITABLE FOR ANY PARTICULAR PURPOSE OR NONINFRINGING.
|
||||||
|
YOU ASSUME ALL RISKS ASSOCIATED WITH THE USE OF THIRD
|
||||||
|
PARTY DEPENDENCIES, APIS, PRODUCTS AND SERVICES, INCLUDING WITHOUT LIMITATION
|
||||||
|
RISKS RELATING TO QUALITY, AVAILABILITY, PERFORMANCE, DATA LOSS, UTILITY IN A
|
||||||
|
PRODUCTION ENVIRONMENT, AND NON-INFRINGEMENT. IN NO EVENT WILL SAP BE LIABLE
|
||||||
|
DIRECTLY OR INDIRECTLY IN RESPECT OF ANY USE OF THIRD PARTY DEPENDENCIES, APIS,
|
||||||
|
PRODUCTS AND SERVICES BY YOU.
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
8. LIMITATION OF LIABILITY:
|
||||||
including but not limited to software source code, documentation
|
a) If You are located outside the US or Canada: IRRESPECTIVE OF THE LEGAL
|
||||||
source, and configuration files.
|
REASONS, SAP SHALL ONLY BE LIABLE FOR DAMAGES UNDER THIS AGREEMENT IF SUCH
|
||||||
|
DAMAGE (I) CAN BE CLAIMED UNDER THE GERMAN PRODUCT LIABILITY ACT OR (II) IS
|
||||||
|
CAUSED BY INTENTIONAL MISCONDUCT OF SAP OR (III) CONSISTS OF PERSONAL INJURY.
|
||||||
|
IN ALL OTHER CASES, NEITHER SAP NOR ITS EMPLOYEES, AGENTS AND SUBCONTRACTORS
|
||||||
|
SHALL BE LIABLE FOR ANY KIND OF DAMAGE OR CLAIMS HEREUNDER.
|
||||||
|
b) If You are located in the US or Canada: IN NO EVENT SHALL SAP BE LIABLE TO
|
||||||
|
YOU, YOUR COMPANY OR TO ANY THIRD PARTY FOR ANY DAMAGES IN AN AMOUNT IN EXCESS
|
||||||
|
OF $100 ARISING IN CONNECTION WITH YOUR USE OF OR INABILITY TO USE THE SAMPLE
|
||||||
|
CODE OR IN CONNECTION WITH SAP'S PROVISION OF OR FAILURE TO PROVIDE SERVICES
|
||||||
|
PERTAINING TO THE SAMPLE CODE, OR AS A RESULT OF ANY DEFECT IN THE SAMPLE COED.
|
||||||
|
THIS DISCLAIMER OF LIABILITY SHALL APPLY REGARDLESS OF THE FORM OF ACTION THAT
|
||||||
|
MAY BE BROUGHT AGAINST SAP, WHETHER IN CONTRACT OR TORT, INCLUDING WITHOUT
|
||||||
|
LIMITATION ANY ACTION FOR NEGLIGENCE. YOUR SOLE REMEDY IN THE EVENT OF BREACH
|
||||||
|
OF THIS AGREEMENT BY SAP OR FOR ANY OTHER CLAIM RELATED TO THE SAMPLE CODE SHALL
|
||||||
|
BE TERMINATION OF THIS AGREEMENT. NOTWITHSTANDING ANYTHING TO THE CONTRARY
|
||||||
|
HEREIN, UNDER NO CIRCUMSTANCES SHALL SAP OR ITS LICENSORS BE LIABLE TO YOU OR
|
||||||
|
ANY OTHER PERSON OR ENTITY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR
|
||||||
|
INDIRECT DAMAGES, LOSS OF GOOD WILL OR BUSINESS PROFITS, WORK STOPPAGE, DATA
|
||||||
|
LOSS, COMPUTER FAILURE OR MALFUNCTION, ANY AND ALL OTHER COMMERCIAL DAMAGES OR
|
||||||
|
LOSS, OR EXEMPLARY OR PUNITIVE DAMAGES.
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
9. INDEMNITY: You will fully indemnify, hold harmless and defend SAP against
|
||||||
transformation or translation of a Source form, including but
|
law suits based on any claim: (a) that any of Your products, services or related
|
||||||
not limited to compiled object code, generated documentation,
|
technology that are based on or incorporate the Sample Code infringes or
|
||||||
and conversions to other media types.
|
misappropriates any patent, copyright, trademark, trade secrets, or other
|
||||||
|
proprietary rights of a third party, or (b) related to Your alleged violation
|
||||||
|
of the terms of this Agreement.
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
10. EXPORT: The Sample Code is subject to German, EU and US export control
|
||||||
Object form, made available under the License, as indicated by a
|
regulations. You confirm that: a) You will not use the Sample Code for, and
|
||||||
copyright notice that is included in or attached to the work
|
will not allow the Sample Code to be used for, any purposes prohibited by
|
||||||
(an example is provided in the Appendix below).
|
German, EU and US law, including, without limitation, for the development,
|
||||||
|
design, manufacture or production of nuclear, chemical or biological weapons of
|
||||||
|
mass destruction; b) You are not located in Cuba, Iran, Sudan, Iraq, North
|
||||||
|
Korea, Syria, nor any other country to which the United States has prohibited
|
||||||
|
export or that has been designated by the U.S. Government as a "terrorist
|
||||||
|
supporting" country (any, an "US Embargoed Country"); c) You are not a citizen,
|
||||||
|
national or resident of, and are not under the control of, a US Embargoed
|
||||||
|
Country; d) You will not download or otherwise export or re-export the Sample
|
||||||
|
Code, directly or indirectly, to a US Embargoed Country nor to citizens,
|
||||||
|
nationals or residents of a US Embargoed Country; e) You are not listed on the
|
||||||
|
United States Department of Treasury lists of Specially Designated Nationals,
|
||||||
|
Specially Designated Terrorists, and Specially Designated Narcotic Traffickers,
|
||||||
|
nor listed on the United States Department of Commerce Table of Denial Orders
|
||||||
|
or any other U.S. government list of prohibited or restricted parties and f)
|
||||||
|
You will not download or otherwise export or re-export the Sample Code, directly
|
||||||
|
or indirectly, to persons on the above-mentioned lists.
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
11. SUPPORT: SAP does not offer support for the Sample Code.
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
12. TERM AND TERMINATION: You may terminate this Agreement by destroying all
|
||||||
the original version of the Work and any modifications or additions
|
copies of the Sample Code in Your possession or control. SAP may terminate Your
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
license to use the Sample Code immediately if You fail to comply with any of
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
the terms of this Agreement, or, for SAP's convenience by providing you with
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
ten (10) days written notice of termination. In case of termination or
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
expiration of this Agreement, You must immediately destroy all copies of the
|
||||||
means any form of electronic, verbal, or written communication sent
|
Sample Code in your possession or control. In the event Your Company is acquired
|
||||||
to the Licensor or its representatives, including but not limited to
|
(by merger, purchase of stock, assets or intellectual property or exclusive
|
||||||
communication on electronic mailing lists, source code control systems,
|
license), or You become employed, by a direct competitor of SAP, then this
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
Agreement and all licenses granted to You in this Agreement shall immediately
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
terminate upon the date of such acquisition or change of employment.
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
13. LAW/VENUE:
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
a) If You are located outside the US or Canada: This Agreement is governed by
|
||||||
subsequently incorporated within the Work.
|
and construed in accordance with the laws of Germany without reference to its
|
||||||
|
conflicts of law principles. You and SAP agree to submit to the exclusive
|
||||||
|
jurisdiction of, and venue in, the courts located in Karlsruhe, Germany in any
|
||||||
|
dispute arising out of or relating to this Agreement or the Sample Code. The
|
||||||
|
United Nations Convention on Contracts for the International Sale of Goods shall
|
||||||
|
not apply to this Agreement.
|
||||||
|
b) If You are located in the US or Canada: This Agreement shall be governed by
|
||||||
|
and construed in accordance with the laws of the State of New York, USA without
|
||||||
|
reference to its conflicts of law principles. You and SAP agree to submit to
|
||||||
|
the exclusive jurisdiction of, and venue in, the courts located in New York,
|
||||||
|
New York, USA in any dispute arising out of or relating to this Agreement or
|
||||||
|
the Sample Code. The United Nations Convention on Contracts for the
|
||||||
|
International Sale of Goods shall not apply to this Agreement.
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
14. MISCELLANEOUS: This Agreement is the complete agreement between the parties
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
respecting the Sample Code. This Agreement supersedes all prior or
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
contemporaneous agreements or representations with regards to the Sample Code.
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
If any term of this Agreement is found to be invalid or unenforceable, the
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
surviving provisions shall remain effective. SAP's failure to enforce any right
|
||||||
Work and such Derivative Works in Source or Object form.
|
or provisions stipulated in this Agreement will not constitute a waiver of such
|
||||||
|
provision, or any other provision of this Agreement.
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
v1.0-071618
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------------------------------------------------
|
|
||||||
APIs
|
|
||||||
|
|
||||||
This project may include APIs to SAP or third-party products or services.
|
|
||||||
The use of these APIs, products and services may be subject to additional
|
|
||||||
agreements. In no event shall the application of the Apache Software
|
|
||||||
License, v.2 to this project grant any rights in or to these APIs,
|
|
||||||
products or services that would alter, expand, be inconsistent with,
|
|
||||||
or supersede any terms of these additional agreements. “API” means
|
|
||||||
application programming interfaces, as well as their respective
|
|
||||||
specifications and implementing code that allows other software
|
|
||||||
products to communicate with or call on SAP or third party products
|
|
||||||
or services (for example, SAP Enterprise Services, BAPIs, Idocs, RFCs
|
|
||||||
and ABAP calls or other user exits) and may be made available through
|
|
||||||
SAP or third party products, SDKs, documentation or other media.
|
|
||||||
|
|||||||
1
NOTICE
Normal file
1
NOTICE
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved.
|
||||||
50
README.md
50
README.md
@@ -1,58 +1,42 @@
|
|||||||
# Welcome to cap/samples
|
# Welcome to SAP Cloud Application Programming model samples
|
||||||
|
|
||||||
Find here a collection of samples for the [SAP Cloud Application Programming Model](https://cap.cloud.sap) organized in a simplistic [monorepo setup](samples.md#all-in-one-monorepo). → See [**Overview** of contained samples](samples.md)
|
Find here the samples for the openSAP course [Building Applications with the SAP Cloud Application Programming Model](https://open.sap.com/courses/cp7).
|
||||||
|
|
||||||

|
## Get Access to SAP Business Application Studio
|
||||||
|
The recommended environment for the course is SAP Business Application Studio. Watch [unit 2 of week 1](https://open.sap.com/courses/cp7/items/51pzQUzbXHr2kdbOmVs6jI) for how to get access.
|
||||||
|
|
||||||
### Preliminaries
|
## Setup
|
||||||
|
|
||||||
1. [Install @sap/cds-dk](https://cap.cloud.sap/docs/get-started/) as documented in [capire](https://cap.cloud.sap)
|
In SAP Business Application Studio, open a terminal.
|
||||||
2. _Optional:_ [Use Visual Studio Code](https://cap.cloud.sap/docs/get-started/in-vscode)
|
Then clone the repo with this specific branch:
|
||||||
|
|
||||||
|
|
||||||
### Download
|
|
||||||
|
|
||||||
Clone this repo as shown below, if you have [git](https://git-scm.com/downloads) installed,
|
|
||||||
otherwise [download as zip file](archive/master.zip).
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/sap-samples/cloud-cap-samples samples
|
git clone https://github.com/sap-samples/cloud-cap-samples projects/cloud-cap-samples -b openSAP-week4-unit2-final
|
||||||
cd samples
|
cd projects/cloud-cap-samples
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup
|
In the `cloud-cap-samples` folder run:
|
||||||
|
|
||||||
In the samples folder run:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run
|
## Run
|
||||||
|
|
||||||
With that you're ready to run the samples, for example:
|
|
||||||
|
|
||||||
|
Now you're ready to run the samples, for example:
|
||||||
```sh
|
```sh
|
||||||
cds watch bookshop
|
cd packages/bookshop
|
||||||
|
cds watch
|
||||||
```
|
```
|
||||||
|
|
||||||
After that open this link in your browser: [http://localhost:4004](http://localhost:4004)
|
After that, watch out for the little popup in the lower right corner of SAP Business Application Studio that asks you to open the application in your browser.
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
Run the provided tests with [_jest_](http://jestjs.io) or [_mocha_](http://mochajs.org), for example:
|
|
||||||
```sh
|
|
||||||
npx jest
|
|
||||||
```
|
|
||||||
> While mocha is a bit smaller and faster, jest runs tests in parallel and isolation, which allows to run all tests.
|
|
||||||
|
|
||||||
|
|
||||||
## Get Support
|
## Get Support
|
||||||
|
|
||||||
Check out the documentation at [https://cap.cloud.sap](https://cap.cloud.sap). <br>
|
Check out the cap docs at https://cap.cloud.sap. <br>
|
||||||
In case you find a bug or need support, please [open an issue in here](https://github.com/SAP-samples/cloud-cap-samples/issues/new).
|
In case you find a bug or need support, please [open an issue in here](https://github.com/SAP-samples/cloud-cap-samples/issues/new).
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](/LICENSE) file.
|
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under SAP Sample Code License Agreement, except as noted otherwise in the [LICENSE](/LICENSE) file.
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
cds.features.snapi = y
|
|
||||||
25
bookshop/.vscode/launch.json
vendored
25
bookshop/.vscode/launch.json
vendored
@@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Attach to...",
|
|
||||||
"type": "node",
|
|
||||||
"request": "attach",
|
|
||||||
"processId": "${command:PickProcess}",
|
|
||||||
"skipFiles": ["<node_internals>/**"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cds run",
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"runtimeExecutable": "npx",
|
|
||||||
"runtimeArgs": ["-n"],
|
|
||||||
"args": ["--", "cds", "run", "--with-mocks", "--in-memory?"],
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"skipFiles": ["<node_internals>/**"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
// Incorporate pre-build extensions from...
|
|
||||||
using from '@capire/common';
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/* global Vue axios */ //> from vue.html
|
|
||||||
const $ = sel => document.querySelector(sel)
|
|
||||||
const GET = (url) => axios.get('/browse'+url)
|
|
||||||
const POST = (cmd,data) => axios.post('/browse'+cmd,data)
|
|
||||||
|
|
||||||
const books = new Vue ({
|
|
||||||
|
|
||||||
el:'#app',
|
|
||||||
|
|
||||||
data: {
|
|
||||||
list: [],
|
|
||||||
book: { descr:'( click on a row to see details... )' },
|
|
||||||
order: { amount:1, succeeded:'', failed:'' }
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
search: ({target:{value:v}}) => books.fetch (v && '$search='+v),
|
|
||||||
|
|
||||||
async fetch (_filter='') {
|
|
||||||
const columns = 'ID,title,author,price,stock', details = 'genre,currency'
|
|
||||||
const {data} = await GET(`/Books?$select=${columns}&$expand=${details}&${_filter}`)
|
|
||||||
books.list = data.value
|
|
||||||
},
|
|
||||||
|
|
||||||
async inspect () {
|
|
||||||
const book = books.book = books.list [event.currentTarget.rowIndex-1]
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// initially fill list of books
|
|
||||||
books.fetch()
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title> Capire Books </title>
|
|
||||||
<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/vue"></script>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<body class="small-container", style="margin-top: 70px;">
|
|
||||||
<div id='app'>
|
|
||||||
|
|
||||||
<h1> Capire Books </h1>
|
|
||||||
|
|
||||||
<input type="text" placeholder="Search..." @input="search">
|
|
||||||
|
|
||||||
<table id='books'>
|
|
||||||
<thead>
|
|
||||||
<th> Book </th>
|
|
||||||
<th> Author </th>
|
|
||||||
<th> Genre </th>
|
|
||||||
<th> Price </th>
|
|
||||||
</thead>
|
|
||||||
<tr v-for="book in list" v-bind:id="book.ID" v-on:click="inspect">
|
|
||||||
<td>{{ book.title }}</td>
|
|
||||||
<td>{{ book.author }}</td>
|
|
||||||
<td>{{ book.genre.name }}</td>
|
|
||||||
<td>{{ book.currency.symbol }} {{ book.price }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
<script src="app.js"></script>
|
|
||||||
</html>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
ID;parent_ID;name
|
|
||||||
10;;Fiction
|
|
||||||
11;10;Drama
|
|
||||||
12;10;Poetry
|
|
||||||
13;10;Fantasy
|
|
||||||
14;10;Science Fiction
|
|
||||||
15;10;Romance
|
|
||||||
16;10;Mystery
|
|
||||||
17;10;Thriller
|
|
||||||
18;10;Dystopia
|
|
||||||
19;10;Fairy Tale
|
|
||||||
20;;Non-Fiction
|
|
||||||
21;20;Biography
|
|
||||||
22;20;Autobiography
|
|
||||||
23;20;Essay
|
|
||||||
24;20;Speech
|
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
using { Currency, managed, sap } from '@sap/cds/common';
|
|
||||||
namespace sap.capire.bookshop;
|
|
||||||
|
|
||||||
entity Books : managed {
|
|
||||||
key ID : Integer;
|
|
||||||
title : localized String(111);
|
|
||||||
descr : localized String(1111);
|
|
||||||
author : Association to Authors;
|
|
||||||
genre : Association to Genres;
|
|
||||||
stock : Integer;
|
|
||||||
price : Decimal(9,2);
|
|
||||||
currency : Currency;
|
|
||||||
}
|
|
||||||
|
|
||||||
entity Authors : managed {
|
|
||||||
key ID : Integer;
|
|
||||||
name : String(111);
|
|
||||||
dateOfBirth : Date;
|
|
||||||
dateOfDeath : Date;
|
|
||||||
placeOfBirth : String;
|
|
||||||
placeOfDeath : String;
|
|
||||||
books : Association to many Books on books.author = $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Hierarchically organized Code List for Genres */
|
|
||||||
entity Genres : sap.common.CodeList {
|
|
||||||
key ID : Integer;
|
|
||||||
parent : Association to Genres;
|
|
||||||
children : Composition of many Genres on children.parent = $self;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace sap.capire.bookshop; //> important for reflection
|
|
||||||
using from './db/schema';
|
|
||||||
using from './srv/cat-service';
|
|
||||||
using from './srv/admin-service';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
exports.CatalogService = require('./srv/cat-service')
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@capire/bookshop",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "A simple self-contained bookshop service.",
|
|
||||||
"dependencies": {
|
|
||||||
"@capire/common": "../common",
|
|
||||||
"@sap/cds": ">=3.33.1",
|
|
||||||
"express": "^4.17.1"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"genres": "cds serve test/genres.cds",
|
|
||||||
"start": "cds run",
|
|
||||||
"watch": "cds watch"
|
|
||||||
},
|
|
||||||
"cds": {
|
|
||||||
"requires": {
|
|
||||||
"db": {
|
|
||||||
"kind": "sql"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Bookshop Getting Started Sample
|
|
||||||
|
|
||||||
This stand-alone sample introduces the essential tasks in the development of CAP-based services as also covered in the [Getting Started guide in capire](https://cap.cloud.sap/docs/get-started/in-a-nutshell).
|
|
||||||
|
|
||||||
## Hypothetical Use Cases
|
|
||||||
|
|
||||||
1. Build a service that allows to browse _Books_ and _Authors_.
|
|
||||||
2. Books have assigned _Genres_ which are organized hierarchically.
|
|
||||||
3. All users may browse books without login.
|
|
||||||
4. All entries are maintained by Administrators.
|
|
||||||
5. End users may order books (the actual order mgmt being out of scope)
|
|
||||||
|
|
||||||
## Running the Sample
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run watch
|
|
||||||
```
|
|
||||||
|
|
||||||
## Content & Best Practices
|
|
||||||
|
|
||||||
| Links to capire | Sample files / folders |
|
|
||||||
| --------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
|
||||||
| [Project Setup and Layouts](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) | [`./`](./) |
|
|
||||||
| [Defining Domain Models](https://cap.cloud.sap/docs/guides/domain-models) | [`./db/schema.cds`](./db/schema.cds) |
|
|
||||||
| [Defining Services](https://cap.cloud.sap/docs/guides/providing-services) | [`./srv/*.cds`](./srv) |
|
|
||||||
| [Single-purposed Services](https://cap.cloud.sap/docs/guides/providing-services#single-purposed-services) | [`./srv/*.cds`](./srv) |
|
|
||||||
| [Generic Providers](https://cap.cloud.sap/docs/guides/providing-services) | http://localhost:4004 |
|
|
||||||
| Using Databases | [`./db/data/*.csv`](./db/data) |
|
|
||||||
| [Adding Custom Logic](https://cap.cloud.sap/docs/guides/service-impl) | [`./srv/*.js`](./srv) |
|
|
||||||
| Adding Tests | [`./test`](./test) |
|
|
||||||
| [Sharing for Reuse](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) | [`./index.cds`](./index.cds) |
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
using { sap.capire.bookshop as my } from '../db/schema';
|
|
||||||
service AdminService @(requires_:'admin') {
|
|
||||||
entity Books as projection on my.Books;
|
|
||||||
entity Authors as projection on my.Authors;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using { sap.capire.bookshop as my } from '../db/schema';
|
|
||||||
service CatalogService @(path:'/browse') {
|
|
||||||
|
|
||||||
@readonly entity Books as SELECT from my.Books {*,
|
|
||||||
author.name as author
|
|
||||||
} excluding { createdBy, modifiedBy };
|
|
||||||
|
|
||||||
@requires_: 'authenticated-user'
|
|
||||||
action submitOrder (book : Books.ID, amount: Integer);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const cds = require('@sap/cds')
|
|
||||||
module.exports = async function (){
|
|
||||||
|
|
||||||
const db = await cds.connect.to('db') // connect to database service
|
|
||||||
const { Books } = db.entities // get reflected definitions
|
|
||||||
|
|
||||||
// Reduce stock of ordered books if available stock suffices
|
|
||||||
this.on ('submitOrder', async req => {
|
|
||||||
const {book,amount} = req.data
|
|
||||||
const n = await UPDATE (Books, book)
|
|
||||||
.with ({ stock: {'-=': amount }})
|
|
||||||
.where ({ stock: {'>=': amount }})
|
|
||||||
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!`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
using { sap.capire.bookshop as my } from '../db/schema';
|
|
||||||
service TestService {
|
|
||||||
entity Genres as projection on my.Genres;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#################################################
|
|
||||||
#
|
|
||||||
# Genres
|
|
||||||
#
|
|
||||||
|
|
||||||
GET http://localhost:4004/test/Genres?
|
|
||||||
###
|
|
||||||
|
|
||||||
GET http://localhost:4004/test/Genres?
|
|
||||||
&$filter=parent_ID eq null&$select=name
|
|
||||||
&$expand=children($select=name)
|
|
||||||
###
|
|
||||||
|
|
||||||
POST http://localhost:4004/test/Genres?
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{ "ID":100, "name":"Some Sample Genres...", "children":[
|
|
||||||
{ "ID":101, "name":"Cat", "children":[
|
|
||||||
{ "ID":102, "name":"Kitty", "children":[
|
|
||||||
{ "ID":103, "name":"Kitty Cat", "children":[
|
|
||||||
{ "ID":104, "name":"Aristocat" } ]},
|
|
||||||
{ "ID":105, "name":"Kitty Bat" } ]},
|
|
||||||
{ "ID":106, "name":"Catwoman", "children":[
|
|
||||||
{ "ID":107, "name":"Catalina" } ]} ]},
|
|
||||||
{ "ID":108, "name":"Catweazle" }
|
|
||||||
]}
|
|
||||||
###
|
|
||||||
|
|
||||||
GET http://localhost:4004/test/Genres(100)?
|
|
||||||
# &$expand=children
|
|
||||||
# &$expand=children($expand=children($expand=children($expand=children)))
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE http://localhost:4004/test/Genres(103)
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE http://localhost:4004/test/Genres(100)
|
|
||||||
###
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
@server = http://localhost:4004
|
|
||||||
@me = Authorization: Basic {{$processEnv USER}}:
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
|
||||||
# Get service info
|
|
||||||
GET {{server}}/browse
|
|
||||||
{{me}}
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
|
||||||
# Get $metadata document
|
|
||||||
GET {{server}}/browse/$metadata
|
|
||||||
{{me}}
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
|
||||||
# Browse Books as any user
|
|
||||||
GET {{server}}/browse/Books?
|
|
||||||
# &$select=title,stock
|
|
||||||
# &$expand=currency
|
|
||||||
# &sap-language=de
|
|
||||||
{{me}}
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
|
||||||
# Fetch Authors as admin
|
|
||||||
GET {{server}}/admin/Authors?
|
|
||||||
# &$select=name,dateOfBirth,placeOfBirth
|
|
||||||
# &$expand=books($select=title;$expand=currency)
|
|
||||||
# &$filter=ID eq 101
|
|
||||||
# &sap-language=de
|
|
||||||
Authorization: Basic alice:
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
|
||||||
# Submit Order as authenticated user
|
|
||||||
# (send that three times to get out-of-stock message)
|
|
||||||
POST {{server}}/browse/submitOrder
|
|
||||||
Content-Type: application/json
|
|
||||||
{{me}}
|
|
||||||
|
|
||||||
{ "book":201, "amount":5 }
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
|
||||||
# Browse Genres
|
|
||||||
GET {{server}}/browse/Genres?
|
|
||||||
# &$filter=parent_ID eq null&$select=name
|
|
||||||
# &$expand=children($select=name)
|
|
||||||
{{me}}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
code;name;descr
|
|
||||||
AU;Australia;Commonwealth of Australia
|
|
||||||
CA;Canada;Canada
|
|
||||||
CN;China;People's Republic of China (PRC)
|
|
||||||
FR;France;French Republic
|
|
||||||
DE;Germany;Federal Republic of Germany
|
|
||||||
IN;India;Republic of India
|
|
||||||
IL;Israel;State of Israel
|
|
||||||
MM;Myanmar;Republic of the Union of Myanmar
|
|
||||||
GB;United Kingdom;United Kingdom of Great Britain and Northern Ireland
|
|
||||||
US;United States;United States of America (USA)
|
|
||||||
EU;European Union;European Union
|
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
code;locale;name;descr
|
|
||||||
AU;de;Australien;Commonwealth Australien
|
|
||||||
CA;de;Kanada;Canada
|
|
||||||
CN;de;China;Volksrepublik China
|
|
||||||
FR;de;Frankreich;Republik Frankreich
|
|
||||||
DE;de;Deutschland;Bundesrepublik Deutschland
|
|
||||||
IN;de;Indien;Republik Indien
|
|
||||||
IL;de;Israel;Staat Israel
|
|
||||||
MM;de;Myanmar;Republik der Union Myanmar
|
|
||||||
GB;de;Vereinigtes Königreich;Vereinigtes Königreich Großbritannien und Nordirland
|
|
||||||
US;de;Vereinigte Staaten;Vereinigte Staaten von Amerika
|
|
||||||
EU;de;Europäische Union;Europäische Union
|
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
code;symbol;name;descr;numcode;minor;exponent
|
|
||||||
EUR;€;Euro;European Euro;978;Cent;2
|
|
||||||
USD;$;US Dollar;United States Dollar;840;Cent;2
|
|
||||||
CAD;$;Canadian Dollar;Canadian Dollar;124;Cent;2
|
|
||||||
AUD;$;Australian Dollar;Canadian Dollar;036;Cent;2
|
|
||||||
GBP;£;British Pound;Great Britain Pound;826;Penny;2
|
|
||||||
ILS;₪;Shekel;Israeli New Shekel;376;Agorat;2
|
|
||||||
INR;₹;Rupee;Indian Rupee;356;Paise;2
|
|
||||||
QAR;﷼;Riyal;Katar Riyal;356;Dirham;2
|
|
||||||
SAR;﷼;Riyal;Saudi Riyal;682;Halala;2
|
|
||||||
JPY;¥;Yen;Japanese Yen;392;Sen;2
|
|
||||||
CNY;¥;Yuan;Chinese Yuan Renminbi;156;Jiao;1
|
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
code;name
|
|
||||||
de;German
|
|
||||||
fr;French
|
|
||||||
en;English
|
|
||||||
en_GB;British English
|
|
||||||
|
@@ -1,10 +0,0 @@
|
|||||||
code;locale;name
|
|
||||||
de;en;German
|
|
||||||
de;de;Deutsch
|
|
||||||
de;fr;Allemande
|
|
||||||
fr;en;French
|
|
||||||
fr;de;Französisch
|
|
||||||
fr;fr;Francais
|
|
||||||
en;en;English
|
|
||||||
en;de;Englisch
|
|
||||||
en;fr;Anglais
|
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
using { sap } from '@sap/cds/common';
|
|
||||||
|
|
||||||
extend sap.common.Currencies with {
|
|
||||||
// Currencies.code = ISO 4217 alphabetic three-letter code
|
|
||||||
// with the first two letters being equal to ISO 3166 alphabetic country codes
|
|
||||||
// See also:
|
|
||||||
// [1] https://www.iso.org/iso-4217-currency-codes.html
|
|
||||||
// [2] https://www.currency-iso.org/en/home/tables/table-a1.html
|
|
||||||
// [3] https://www.ibm.com/support/knowledgecenter/en/SSZLC2_7.0.0/com.ibm.commerce.payments.developer.doc/refs/rpylerl2mst97.htm
|
|
||||||
numcode : Integer;
|
|
||||||
exponent : Integer; //> e.g. 2 --> 1 Dollar = 10^2 Cent
|
|
||||||
minor : String; //> e.g. 'Cent'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Code Lists below are designed as optional extensions to
|
|
||||||
* the base schema. Switch them on by adding an Association to
|
|
||||||
* one of the code list entities in your models or by:
|
|
||||||
* annotate sap.common.Countries with @cds.persistence.skip:false;
|
|
||||||
*/
|
|
||||||
|
|
||||||
context sap.common_countries {
|
|
||||||
|
|
||||||
extend sap.common.Countries {
|
|
||||||
regions : Composition of many Regions on regions._parent = $self.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
entity Regions : sap.common.CodeList {
|
|
||||||
key code : String(5); // ISO 3166-2 alpha5 codes, e.g. DE-BW
|
|
||||||
children : Composition of many Regions on children._parent = $self.code;
|
|
||||||
cities : Composition of many Cities on cities.region = $self;
|
|
||||||
_parent : String(11);
|
|
||||||
}
|
|
||||||
entity Cities : sap.common.CodeList {
|
|
||||||
key code : String(11);
|
|
||||||
region : Association to Regions;
|
|
||||||
districts : Composition of many Districts on districts.city = $self;
|
|
||||||
}
|
|
||||||
entity Districts : sap.common.CodeList {
|
|
||||||
key code : String(11);
|
|
||||||
city : Association to Cities;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@capire/common",
|
|
||||||
"version": "1.0.0"
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
"env": {
|
|
||||||
"node": true,
|
|
||||||
"es6": true,
|
|
||||||
"jest": true
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2017
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"SELECT": true,
|
|
||||||
"INSERT": true,
|
|
||||||
"UPDATE": true,
|
|
||||||
"DELETE": true,
|
|
||||||
"CREATE": true,
|
|
||||||
"DROP": true,
|
|
||||||
"cds": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"no-console": "off",
|
|
||||||
"require-atomic-updates": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
ext/.gitignore
vendored
30
ext/.gitignore
vendored
@@ -1,30 +0,0 @@
|
|||||||
# CAP ext
|
|
||||||
_out
|
|
||||||
*.db
|
|
||||||
connection.properties
|
|
||||||
default-*.json
|
|
||||||
gen/
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Web IDE, App Studio
|
|
||||||
.che/
|
|
||||||
.gen/
|
|
||||||
|
|
||||||
# MTA
|
|
||||||
*_mta_build_tmp
|
|
||||||
*.mtar
|
|
||||||
mta_archives/
|
|
||||||
|
|
||||||
# Other
|
|
||||||
.DS_Store
|
|
||||||
*.orig
|
|
||||||
*.log
|
|
||||||
|
|
||||||
*.iml
|
|
||||||
*.flattened-pom.xml
|
|
||||||
|
|
||||||
# IDEs
|
|
||||||
.vscode
|
|
||||||
.idea
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
using { sap.capire.bookshop.Books } from '@capire/bookshop';
|
|
||||||
|
|
||||||
extend Books with {
|
|
||||||
ISBN : String;
|
|
||||||
discount : Decimal @assert.range:[0,1];
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ext",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "A simple CAP project.",
|
|
||||||
"repository": "<Add your repository here>",
|
|
||||||
"license": "UNLICENSED",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@capire/bookshop": "../bookshop",
|
|
||||||
"@sap/cds": "^4",
|
|
||||||
"express": "^4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"sqlite3": "^4"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "npx cds run"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
const cds = require ('@sap/cds')
|
|
||||||
const path = require ('path')
|
|
||||||
const fs = require ('fs')
|
|
||||||
const protected = {db:1,messaging:1,auth:1}
|
|
||||||
const { isfile } = cds.utils
|
|
||||||
|
|
||||||
cds.on('served', ()=>{
|
|
||||||
for (let each of cds.services) {
|
|
||||||
if (each.name in protected) continue
|
|
||||||
// search for local srv/<each>.js files and if exist
|
|
||||||
// activate them in a service extension sandbox
|
|
||||||
const impl = isfile (path.resolve('srv/'+each.name+'.js'))
|
|
||||||
if (impl) activate_sandboxed (each,impl)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function activate_sandboxed (srv,impl) {
|
|
||||||
console.log (`[cds] - extending ${srv.name} with sandboxed:`, {impl:path.relative(process.cwd(),impl)})
|
|
||||||
const src = fs.readFileSync (impl)
|
|
||||||
const sandbox = Object.keys(global).filter(name => name !== 'cds')
|
|
||||||
const fn = new Function (
|
|
||||||
'module','cds','global','process', ...sandbox,
|
|
||||||
src
|
|
||||||
)
|
|
||||||
// restricted sandboxed variant of 'module' and 'cds'
|
|
||||||
const module = {}
|
|
||||||
const cds = {
|
|
||||||
service: {
|
|
||||||
impl: fn=>fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn (module,cds,undefined,undefined, ...sandbox.map((()=>(undefined))))
|
|
||||||
if (typeof module.exports === 'function') try {
|
|
||||||
module.exports.call (srv,srv)
|
|
||||||
} catch (e) {
|
|
||||||
console.log (e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = cds.server
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
module.exports = cds.service.impl(function(){
|
|
||||||
|
|
||||||
this.before(['CREATE','UPDATE'],'Books', req => { //> ....
|
|
||||||
const book = req.data
|
|
||||||
if (book.stock < 10 && book.discount > 0.5) {
|
|
||||||
req.error('Hey, da sind so wenig übrig, die wollen wir nicht zu billig verticken')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
console.log ('Böses Zeug', global, process, cds)
|
|
||||||
// process.exit()
|
|
||||||
// const fs = require('fs')
|
|
||||||
// cds.run('Böses Zeugs')
|
|
||||||
// SELECT.from ('Foo')
|
|
||||||
|
|
||||||
module.exports = cds.service.impl(function(){
|
|
||||||
this.after('READ','Books', each => each.title += ' (served through sandbox)')
|
|
||||||
})
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
cds.features.snapi = y
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using AdminService from '@capire/bookshop';
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Books Object Page
|
|
||||||
//
|
|
||||||
|
|
||||||
annotate AdminService.Books with @(
|
|
||||||
UI: {
|
|
||||||
Facets: [
|
|
||||||
{$Type: 'UI.ReferenceFacet', Label: '{i18n>General}', Target: '@UI.FieldGroup#General'},
|
|
||||||
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Translations}', Target: 'texts/@UI.LineItem'},
|
|
||||||
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
|
|
||||||
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Admin}', Target: '@UI.FieldGroup#Admin'},
|
|
||||||
],
|
|
||||||
FieldGroup#General: {
|
|
||||||
Data: [
|
|
||||||
{Value: title},
|
|
||||||
{Value: author_ID},
|
|
||||||
{Value: genre_ID},
|
|
||||||
{Value: descr},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
FieldGroup#Details: {
|
|
||||||
Data: [
|
|
||||||
{Value: stock},
|
|
||||||
{Value: price},
|
|
||||||
{Value: currency_code, Label: '{i18n>Currency}'},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
FieldGroup#Admin: {
|
|
||||||
Data: [
|
|
||||||
{Value: createdBy},
|
|
||||||
{Value: createdAt},
|
|
||||||
{Value: modifiedBy},
|
|
||||||
{Value: modifiedAt}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Draft for Localized Data
|
|
||||||
//
|
|
||||||
|
|
||||||
annotate sap.capire.bookshop.Books with @fiori.draft.enabled;
|
|
||||||
annotate AdminService.Books with @odata.draft.enabled;
|
|
||||||
|
|
||||||
annotate AdminService.Books_texts with @(
|
|
||||||
UI: {
|
|
||||||
Identification: [{Value:title}],
|
|
||||||
SelectionFields: [ locale, title ],
|
|
||||||
LineItem: [
|
|
||||||
{Value: locale, Label: 'Locale'},
|
|
||||||
{Value: title, Label: 'Title'},
|
|
||||||
{Value: descr, Label: 'Description'},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add Value Help for Locales
|
|
||||||
annotate AdminService.Books_texts {
|
|
||||||
locale @ValueList:{entity:'Languages',type:#fixed}
|
|
||||||
}
|
|
||||||
// In addition we need to expose Languages through AdminService
|
|
||||||
using { sap } from '@sap/cds/common';
|
|
||||||
extend service AdminService {
|
|
||||||
entity Languages as projection on sap.common.Languages;
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("admin.Component", {
|
|
||||||
metadata:{ manifest:'json' }
|
|
||||||
}))
|
|
||||||
|
|
||||||
/* eslint no-undef:0 */
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("bookshop.Component", {
|
|
||||||
metadata:{ manifest:'json' }
|
|
||||||
}))
|
|
||||||
|
|
||||||
/* eslint no-undef:0 */
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("orders.Component", {
|
|
||||||
metadata:{ manifest:'json' }
|
|
||||||
}))
|
|
||||||
|
|
||||||
/* eslint no-undef:0 */
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
// Proxy for importing schema from bookshop sample
|
|
||||||
using from '@capire/bookshop';
|
|
||||||
namespace sap.capire.bookshop;
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@capire/fiori",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"dependencies": {
|
|
||||||
"@capire/bookshop": "../bookshop",
|
|
||||||
"@capire/orders": "../orders",
|
|
||||||
"@capire/common": "../common",
|
|
||||||
"@sap/cds": ">=3.33.1",
|
|
||||||
"express": "^4.17.1"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "cds run --in-memory?",
|
|
||||||
"watch": "cds watch"
|
|
||||||
},
|
|
||||||
"cds": {
|
|
||||||
"requires": {
|
|
||||||
"db": {
|
|
||||||
"kind": "sql"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
// Proxy for importing services from bookshop sample
|
|
||||||
using from '@capire/bookshop';
|
|
||||||
annotate AdminService with @impl:'srv/admin-service.js';
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
const cds = require('@sap/cds')
|
|
||||||
|
|
||||||
module.exports = cds.service.impl (async function() {
|
|
||||||
const {Books} = cds.entities
|
|
||||||
const {ID} = await SELECT.one.from(Books).columns('max(ID) as ID')
|
|
||||||
let newID = ID - ID % 100 + 100
|
|
||||||
this.before ('NEW','Books', req => req.data.ID = ++newID)
|
|
||||||
})
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@capire/hello-world",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"scripts": {
|
|
||||||
"watch": "cds serve world.cds"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
GET http://localhost:4004/say/hello(to='world')
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
service say {
|
|
||||||
function hello (to:String) returns String;
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module.exports = class say {
|
|
||||||
hello(req) { return `Hello ${req.data.to}!` }
|
|
||||||
}
|
|
||||||
1
lerna.json
Normal file
1
lerna.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"packages":["packages/*"],"version":"1.0.0"}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
namespace sap.capire.media;
|
|
||||||
|
|
||||||
entity Media {
|
|
||||||
|
|
||||||
key id:Integer;
|
|
||||||
@Core.MediaType: mediaType
|
|
||||||
content : LargeBinary ;
|
|
||||||
|
|
||||||
@Core.IsMediaType: true
|
|
||||||
mediaType : String;
|
|
||||||
fileName : String;
|
|
||||||
applicationName:String;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
using from './db/data-model';
|
|
||||||
using from './srv/media-service';
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@capire/media",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"dependencies": {
|
|
||||||
"lokijs": "^1.5.6"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"db",
|
|
||||||
"srv",
|
|
||||||
"index.cds"
|
|
||||||
],
|
|
||||||
"cds": {
|
|
||||||
"requires": {
|
|
||||||
"db": {
|
|
||||||
"kind": "sql"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using { sap.capire.media as db } from '../db/data-model';
|
|
||||||
namespace sap.capire.media;
|
|
||||||
|
|
||||||
service MediaServer {
|
|
||||||
entity Media as projection on db.Media ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
const loki = require('lokijs')
|
|
||||||
const db = new loki('DB')
|
|
||||||
const mediaDB = db.addCollection('Media')
|
|
||||||
const { Readable, PassThrough } = require('stream')
|
|
||||||
|
|
||||||
module.exports = srv => {
|
|
||||||
srv.before('CREATE', 'Media', req => {
|
|
||||||
const obj = mediaDB.insert({ media: '' })
|
|
||||||
req.data.id = obj.$loki
|
|
||||||
})
|
|
||||||
|
|
||||||
srv.on('UPDATE', 'Media', (req, next) => {
|
|
||||||
const url = req._.req.path
|
|
||||||
if (url.includes('content')) {
|
|
||||||
const id = req.data.id
|
|
||||||
const obj = mediaDB.get(id)
|
|
||||||
if (!obj) {
|
|
||||||
req.reject(404, 'No record found for the ID')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const stream = new PassThrough()
|
|
||||||
const chunks = []
|
|
||||||
stream.on('data', chunk => {
|
|
||||||
chunks.push(chunk)
|
|
||||||
})
|
|
||||||
stream.on('end', () => {
|
|
||||||
obj.media = Buffer.concat(chunks).toString('base64')
|
|
||||||
mediaDB.update(obj)
|
|
||||||
})
|
|
||||||
req.data.content.pipe(stream)
|
|
||||||
} else return next()
|
|
||||||
})
|
|
||||||
|
|
||||||
srv.on('READ', 'Media', (req, next) => {
|
|
||||||
const url = req._.req.path
|
|
||||||
if (url.includes('content')) {
|
|
||||||
const id = req.data.id
|
|
||||||
const mediaObj = mediaDB.get(id)
|
|
||||||
if (!mediaObj) {
|
|
||||||
req.reject(404, 'Media not found for the ID')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const decodedMedia = new Buffer(
|
|
||||||
mediaObj.media.split(';base64,').pop(),
|
|
||||||
'base64'
|
|
||||||
)
|
|
||||||
return _formatResult(decodedMedia)
|
|
||||||
} else return next() //> delegate to next/default handlers
|
|
||||||
})
|
|
||||||
|
|
||||||
srv.on('DELETE', 'Media', (req, next) => {
|
|
||||||
const id = req.data.id
|
|
||||||
mediaDB
|
|
||||||
.chain()
|
|
||||||
.find({ $loki: id })
|
|
||||||
.remove()
|
|
||||||
return next() //> delegate to next/default handlers
|
|
||||||
})
|
|
||||||
|
|
||||||
function _formatResult (decodedMedia) {
|
|
||||||
const readable = new Readable()
|
|
||||||
const result = new Array()
|
|
||||||
readable.push(decodedMedia)
|
|
||||||
readable.push(null)
|
|
||||||
result.push({ value: readable })
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,16 +0,0 @@
|
|||||||
using { sap.capire.bookshop.Books } from '@capire/bookshop';
|
|
||||||
using { Currency, managed, cuid } from '@sap/cds/common';
|
|
||||||
namespace sap.capire.bookshop;
|
|
||||||
|
|
||||||
entity Orders : cuid, managed {
|
|
||||||
OrderNo : String @title:'Order Number'; //> readable key
|
|
||||||
Items : Composition of many OrderItems on Items.parent = $self;
|
|
||||||
currency : Currency;
|
|
||||||
}
|
|
||||||
|
|
||||||
entity OrderItems : cuid {
|
|
||||||
parent : Association to Orders;
|
|
||||||
book : Association to Books;
|
|
||||||
amount : Integer;
|
|
||||||
netAmount : Decimal(9,2);
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@capire/orders",
|
|
||||||
"version": "1.0.0"
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
using { sap.capire.bookshop as my } from '../db/schema';
|
|
||||||
|
|
||||||
service OrdersService {
|
|
||||||
entity Orders as projection on my.Orders;
|
|
||||||
entity Books as projection on my.Books;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
const cds = require('@sap/cds')
|
|
||||||
|
|
||||||
module.exports = cds.service.impl(function() {
|
|
||||||
|
|
||||||
const { Books } = cds.entities
|
|
||||||
|
|
||||||
// Reduce stock of ordered books if available stock suffices
|
|
||||||
this.before ('CREATE', 'Orders', (req) => {
|
|
||||||
const { Items: OrderItems } = req.data
|
|
||||||
return cds.transaction(req) .run (()=> OrderItems.map (order =>
|
|
||||||
UPDATE (Books) .where ('ID =', order.book_ID)
|
|
||||||
.and ('stock >=', order.amount)
|
|
||||||
.set ('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}`
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
1228
package-lock.json
generated
Normal file
1228
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
47
package.json
47
package.json
@@ -1,31 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "@capire/samples",
|
"name": "@sap/capire-samples",
|
||||||
"version": "2.0.0",
|
"description": "The umbrella project for all samples to easily setup for local development and tests.",
|
||||||
"description": "A monorepo with several samples for CAP.",
|
"repository": "https://github.com/SAP-samples/cloud-cap-samples.git",
|
||||||
"repository": "https://github.com/sap-samples/cloud-cap-samples.git",
|
|
||||||
"author": "daniel.hutzel@sap.com",
|
"author": "daniel.hutzel@sap.com",
|
||||||
"dependencies": {
|
"private": true,
|
||||||
"@capire/bookshop": "file:bookshop",
|
|
||||||
"@capire/common": "file:common",
|
|
||||||
"@capire/fiori": "file:fiori",
|
|
||||||
"@capire/orders": "file:orders",
|
|
||||||
"@capire/reviews": "file:reviews",
|
|
||||||
"@capire/tests": "file:test"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"chai": "^4.2.0",
|
|
||||||
"chai-as-promised": "^7.1.1",
|
|
||||||
"chai-subset": "^1.6.0",
|
|
||||||
"sqlite3": "^4"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"mocha": "npx mocha || echo",
|
"cleanup": "lerna clean -y && rm -fr node_modules",
|
||||||
"jest": "npx jest --verbose",
|
"install": "(npm -s run lerna) && lerna bootstrap --hoist",
|
||||||
"test": "npm run jest -s"
|
"lerna": "npx --no-install lerna -v > /dev/null || npm i lerna --no-save",
|
||||||
|
"test": "jest",
|
||||||
|
"bookshop-enhanced": "cds watch packages/bookshop-enhanced",
|
||||||
|
"bookshop": "cds watch packages/bookshop",
|
||||||
|
"bookstore": "cds watch packages/bookstore",
|
||||||
|
"products-service": "cds watch packages/products-service",
|
||||||
|
"reviews-service": "cds watch packages/reviews-service"
|
||||||
},
|
},
|
||||||
"jest": {
|
"dependencies": {
|
||||||
"testEnvironment": "node"
|
"@sap/cds": "^3",
|
||||||
|
"express": "^4"
|
||||||
},
|
},
|
||||||
"license": "SAP SAMPLE CODE LICENSE",
|
"--add-these-to-devDependencies-for-tests": {
|
||||||
"private": true
|
"@types/jest": "*",
|
||||||
|
"sqlite3": "*",
|
||||||
|
"jest": "*"
|
||||||
|
},
|
||||||
|
"license": "SAP SAMPLE CODE LICENSE"
|
||||||
}
|
}
|
||||||
|
|||||||
37
packages/bookshop/app/admin/fiori-service.cds
Normal file
37
packages/bookshop/app/admin/fiori-service.cds
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using AdminService from '../../srv/admin-service';
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Books Object Page
|
||||||
|
//
|
||||||
|
annotate AdminService.Books with @(
|
||||||
|
UI: {
|
||||||
|
Facets: [
|
||||||
|
{$Type: 'UI.ReferenceFacet', Label: '{i18n>General}', Target: '@UI.FieldGroup#General'},
|
||||||
|
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
|
||||||
|
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Admin}', Target: '@UI.FieldGroup#Admin'},
|
||||||
|
],
|
||||||
|
FieldGroup#General: {
|
||||||
|
Data: [
|
||||||
|
{Value: title},
|
||||||
|
{Value: author_ID},
|
||||||
|
{Value: descr},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
FieldGroup#Details: {
|
||||||
|
Data: [
|
||||||
|
{Value: stock},
|
||||||
|
{Value: price},
|
||||||
|
{Value: currency_code, Label: '{i18n>Currency}'},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
FieldGroup#Admin: {
|
||||||
|
Data: [
|
||||||
|
{Value: createdBy},
|
||||||
|
{Value: createdAt},
|
||||||
|
{Value: modifiedBy},
|
||||||
|
{Value: modifiedAt}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
22
packages/bookshop/app/admin/webapp/Component.js
Normal file
22
packages/bookshop/app/admin/webapp/Component.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
sap.ui.define(["sap/fe/AppComponent"], ac => ac.extend("admin.Component", {
|
||||||
|
metadata:{ manifest:'json' }
|
||||||
|
}))
|
||||||
|
|
||||||
|
// sap.ui.define (["sap/ui/core/UIComponent"], ui5 => ui5.extend("bookshop.Component", {
|
||||||
|
// metadata: { manifest: "json" }
|
||||||
|
// }))
|
||||||
|
// sap.ui.define (["sap/ui/generic/app/AppComponent"], ui5 => ui5.extend("bookshop.Component", {
|
||||||
|
// metadata: { manifest: "json" }
|
||||||
|
// }))
|
||||||
|
|
||||||
|
// jQuery.sap.declare("bookshop.Component");
|
||||||
|
// sap.ui.getCore().loadLibrary("sap.ui.generic.app");
|
||||||
|
// jQuery.sap.require("sap.ui.generic.app.AppComponent");
|
||||||
|
|
||||||
|
// sap.ui.generic.app.AppComponent.extend("bookshop.Component", {
|
||||||
|
// metadata: {
|
||||||
|
// manifest: "json"
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
/* eslint no-undef:0 */
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using CatalogService from '@capire/bookshop';
|
using CatalogService from '../../srv/cat-service';
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -40,7 +40,6 @@ annotate CatalogService.Books with @(
|
|||||||
LineItem: [
|
LineItem: [
|
||||||
{Value: title},
|
{Value: title},
|
||||||
{Value: author, Label:'{i18n>Author}'},
|
{Value: author, Label:'{i18n>Author}'},
|
||||||
{Value: genre.name},
|
|
||||||
{Value: price},
|
{Value: price},
|
||||||
{Value: currency.symbol, Label:' '},
|
{Value: currency.symbol, Label:' '},
|
||||||
]
|
]
|
||||||
22
packages/bookshop/app/browse/webapp/Component.js
Normal file
22
packages/bookshop/app/browse/webapp/Component.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
sap.ui.define(["sap/fe/AppComponent"], ac => ac.extend("bookshop.Component", {
|
||||||
|
metadata:{ manifest:'json' }
|
||||||
|
}))
|
||||||
|
|
||||||
|
// sap.ui.define (["sap/ui/core/UIComponent"], ui5 => ui5.extend("bookshop.Component", {
|
||||||
|
// metadata: { manifest: "json" }
|
||||||
|
// }))
|
||||||
|
// sap.ui.define (["sap/ui/generic/app/AppComponent"], ui5 => ui5.extend("bookshop.Component", {
|
||||||
|
// metadata: { manifest: "json" }
|
||||||
|
// }))
|
||||||
|
|
||||||
|
// jQuery.sap.declare("bookshop.Component");
|
||||||
|
// sap.ui.getCore().loadLibrary("sap.ui.generic.app");
|
||||||
|
// jQuery.sap.require("sap.ui.generic.app.AppComponent");
|
||||||
|
|
||||||
|
// sap.ui.generic.app.AppComponent.extend("bookshop.Component", {
|
||||||
|
// metadata: {
|
||||||
|
// manifest: "json"
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
/* eslint no-undef:0 */
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
Common Annotations shared by all apps
|
Common Annotations shared by all apps
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using { sap.capire.bookshop as my } from '@capire/bookshop';
|
using { sap.capire.bookshop as my } from '../db/schema';
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -10,7 +10,6 @@ using { sap.capire.bookshop as my } from '@capire/bookshop';
|
|||||||
// Books Lists
|
// Books Lists
|
||||||
//
|
//
|
||||||
annotate my.Books with @(
|
annotate my.Books with @(
|
||||||
Common.SemanticKey: [title],
|
|
||||||
UI: {
|
UI: {
|
||||||
Identification: [{Value:title}],
|
Identification: [{Value:title}],
|
||||||
SelectionFields: [ ID, author_ID, price, currency_code ],
|
SelectionFields: [ ID, author_ID, price, currency_code ],
|
||||||
@@ -18,7 +17,6 @@ annotate my.Books with @(
|
|||||||
{Value: ID},
|
{Value: ID},
|
||||||
{Value: title},
|
{Value: title},
|
||||||
{Value: author.name, Label:'{i18n>Author}'},
|
{Value: author.name, Label:'{i18n>Author}'},
|
||||||
{Value: genre.name},
|
|
||||||
{Value: stock},
|
{Value: stock},
|
||||||
{Value: price},
|
{Value: price},
|
||||||
{Value: currency.symbol, Label:' '},
|
{Value: currency.symbol, Label:' '},
|
||||||
@@ -59,16 +57,12 @@ annotate my.Books with @(
|
|||||||
annotate my.Books with {
|
annotate my.Books with {
|
||||||
ID @title:'{i18n>ID}' @UI.HiddenFilter;
|
ID @title:'{i18n>ID}' @UI.HiddenFilter;
|
||||||
title @title:'{i18n>Title}';
|
title @title:'{i18n>Title}';
|
||||||
genre @title:'{i18n>Genre}' @Common: { Text: genre.name, TextArrangement: #TextOnly };
|
author @title:'{i18n>AuthorID}';
|
||||||
author @title:'{i18n>Author}' @Common: { Text: author.name, TextArrangement: #TextOnly };
|
|
||||||
price @title:'{i18n>Price}';
|
price @title:'{i18n>Price}';
|
||||||
stock @title:'{i18n>Stock}';
|
stock @title:'{i18n>Stock}';
|
||||||
descr @UI.MultiLineText;
|
descr @UI.MultiLineText;
|
||||||
}
|
}
|
||||||
|
|
||||||
annotate my.Genres with {
|
|
||||||
name @title: '{i18n>Genre}';
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
navigationMode: "embedded"
|
navigationMode: "embedded"
|
||||||
},
|
},
|
||||||
"manage-orders": {
|
"manage-orders": {
|
||||||
title: "Order Books",
|
title: "Manage Orders",
|
||||||
description: "... testing FE v42",
|
description: "... testing FE v42",
|
||||||
additionalInformation: "SAPUI5.Component=orders",
|
additionalInformation: "SAPUI5.Component=orders",
|
||||||
applicationType : "URL",
|
applicationType : "URL",
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<script src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
<script src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
|
||||||
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
|
||||||
data-sap-ui-compatVersion="edge"
|
data-sap-ui-compatVersion="edge"
|
||||||
data-sap-ui-theme="sap_fiori_3"
|
data-sap-ui-theme="sap_belize"
|
||||||
data-sap-ui-frameOptions="allow"
|
data-sap-ui-frameOptions="allow"
|
||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
@@ -6,5 +6,3 @@ using from './admin/fiori-service';
|
|||||||
using from './browse/fiori-service';
|
using from './browse/fiori-service';
|
||||||
using from './orders/fiori-service';
|
using from './orders/fiori-service';
|
||||||
using from './common';
|
using from './common';
|
||||||
|
|
||||||
using from '@capire/common';
|
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
using OrdersService from '@capire/orders/srv/orders-service';
|
using AdminService from '../../srv/admin-service';
|
||||||
|
|
||||||
annotate OrdersService.Books with {
|
annotate AdminService.Books with {
|
||||||
price @Common.FieldControl: #ReadOnly;
|
price @Common.FieldControl: #ReadOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Common
|
// Common
|
||||||
//
|
//
|
||||||
annotate OrdersService.OrderItems with {
|
annotate AdminService.OrderItems with {
|
||||||
book @(
|
book @(
|
||||||
Common: {
|
Common: {
|
||||||
Text: book.title,
|
Text: book.title,
|
||||||
@@ -23,8 +21,7 @@ annotate OrdersService.OrderItems with {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@odata.draft.enabled
|
annotate AdminService.Orders with @(
|
||||||
annotate OrdersService.Orders with @(
|
|
||||||
UI: {
|
UI: {
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -85,9 +82,9 @@ annotate OrdersService.Orders with @(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//The enity types name is OrdersService.my_bookshop_OrderItems
|
//The enity types name is AdminService.my_bookshop_OrderItems
|
||||||
//The annotations below are not generated in edmx WHY?
|
//The annotations below are not generated in edmx WHY?
|
||||||
annotate OrdersService.OrderItems with @(
|
annotate AdminService.OrderItems with @(
|
||||||
UI: {
|
UI: {
|
||||||
HeaderInfo: {
|
HeaderInfo: {
|
||||||
TypeName: 'Order Item', TypeNamePlural: ' ',
|
TypeName: 'Order Item', TypeNamePlural: ' ',
|
||||||
22
packages/bookshop/app/orders/webapp/Component.js
Normal file
22
packages/bookshop/app/orders/webapp/Component.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
sap.ui.define(["sap/fe/AppComponent"], ac => ac.extend("orders.Component", {
|
||||||
|
metadata:{ manifest:'json' }
|
||||||
|
}))
|
||||||
|
|
||||||
|
// sap.ui.define (["sap/ui/core/UIComponent"], ui5 => ui5.extend("bookshop.Component", {
|
||||||
|
// metadata: { manifest: "json" }
|
||||||
|
// }))
|
||||||
|
// sap.ui.define (["sap/ui/generic/app/AppComponent"], ui5 => ui5.extend("bookshop.Component", {
|
||||||
|
// metadata: { manifest: "json" }
|
||||||
|
// }))
|
||||||
|
|
||||||
|
// jQuery.sap.declare("bookshop.Component");
|
||||||
|
// sap.ui.getCore().loadLibrary("sap.ui.generic.app");
|
||||||
|
// jQuery.sap.require("sap.ui.generic.app.AppComponent");
|
||||||
|
|
||||||
|
// sap.ui.generic.app.AppComponent.extend("bookshop.Component", {
|
||||||
|
// metadata: {
|
||||||
|
// manifest: "json"
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
/* eslint no-undef:0 */
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
"sap.app": {
|
"sap.app": {
|
||||||
"id": "orders",
|
"id": "orders",
|
||||||
"type": "application",
|
"type": "application",
|
||||||
"title": "Order Books",
|
"title": "Manage Orders",
|
||||||
"description": "Sample Application",
|
"description": "Sample Application",
|
||||||
"i18n": "i18n/i18n.properties",
|
"i18n": "i18n/i18n.properties",
|
||||||
"dataSources": {
|
"dataSources": {
|
||||||
"OrdersService": {
|
"AdminService": {
|
||||||
"uri": "/orders/",
|
"uri": "/admin/",
|
||||||
"type": "OData",
|
"type": "OData",
|
||||||
"settings": {
|
"settings": {
|
||||||
"odataVersion": "4.0"
|
"odataVersion": "4.0"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"uri": "i18n/i18n.properties"
|
"uri": "i18n/i18n.properties"
|
||||||
},
|
},
|
||||||
"": {
|
"": {
|
||||||
"dataSource": "OrdersService",
|
"dataSource": "AdminService",
|
||||||
"settings": {
|
"settings": {
|
||||||
"synchronizationMode": "None",
|
"synchronizationMode": "None",
|
||||||
"operationMode": "Server",
|
"operationMode": "Server",
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
ID;title;descr;author_ID;stock;price;currency_code;genre_ID
|
ID;title;descr;author_ID;stock;price;currency_code
|
||||||
201;Wuthering Heights;"Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym ""Ellis Bell"". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850.";101;12;11.11;GBP;11
|
201;Wuthering Heights;"Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym ""Ellis Bell"". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850.";101;12;11.11;GBP
|
||||||
207;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";107;11;12.34;GBP;11
|
207;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";107;11;12.34;GBP
|
||||||
251;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";150;333;13.13;USD;16
|
251;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";150;333;13.13;USD
|
||||||
252;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";150;555;14;USD;16
|
252;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";150;555;14;USD
|
||||||
271;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;170;22;15;EUR;13
|
271;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;170;22;15;EUR
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
ID;locale;title;descr
|
ID;locale;title;descr
|
||||||
201;de;Sturmhöhe;Sturmhöhe (Originaltitel: Wuthering Heights) ist der einzige Roman der englischen Schriftstellerin Emily Brontë (1818–1848). Der 1847 unter dem Pseudonym Ellis Bell veröffentlichte Roman wurde vom viktorianischen Publikum weitgehend abgelehnt, heute gilt er als ein Klassiker der britischen Romanliteratur des 19. Jahrhunderts.
|
201;de;Sturmhöhe;Sturmhöhe (Originaltitel: Wuthering Heights) ist der einzige Roman der englischen Schriftstellerin Emily Brontë (1818–1848). Der 1847 unter dem Pseudonym Ellis Bell veröffentlichte Roman wurde vom viktorianischen Publikum weitgehend abgelehnt, heute gilt er als ein Klassiker der britischen Romanliteratur des 19. Jahrhunderts.
|
||||||
201;fr;Les Hauts de Hurlevent;Les Hauts de Hurlevent (titre original : Wuthering Heights), parfois orthographié Les Hauts de Hurle-Vent, est l'unique roman d'Emily Brontë, publié pour la première fois en 1847 sous le pseudonyme d’Ellis Bell. Loin d'être un récit moralisateur, Emily Brontë achève néanmoins le roman dans une atmosphère sereine, suggérant le triomphe de la paix et du Bien sur la vengeance et le Mal.
|
|
||||||
207;de;Jane Eyre;Jane Eyre. Eine Autobiographie (Originaltitel: Jane Eyre. An Autobiography), erstmals erschienen im Jahr 1847 unter dem Pseudonym Currer Bell, ist der erste veröffentlichte Roman der britischen Autorin Charlotte Brontë und ein Klassiker der viktorianischen Romanliteratur des 19. Jahrhunderts. Der Roman erzählt in Form einer Ich-Erzählung die Lebensgeschichte von Jane Eyre (ausgesprochen /ˌdʒeɪn ˈɛə/), die nach einer schweren Kindheit eine Stelle als Gouvernante annimmt und sich in ihren Arbeitgeber verliebt, jedoch immer wieder um ihre Freiheit und Selbstbestimmung kämpfen muss. Als klein, dünn, blass, stets schlicht dunkel gekleidet und mit strengem Mittelscheitel beschrieben, gilt die Heldin des Romans Jane Eyre nicht zuletzt aufgrund der Kino- und Fernsehversionen der melodramatischen Romanvorlage als die bekannteste englische Gouvernante der Literaturgeschichte
|
207;de;Jane Eyre;Jane Eyre. Eine Autobiographie (Originaltitel: Jane Eyre. An Autobiography), erstmals erschienen im Jahr 1847 unter dem Pseudonym Currer Bell, ist der erste veröffentlichte Roman der britischen Autorin Charlotte Brontë und ein Klassiker der viktorianischen Romanliteratur des 19. Jahrhunderts. Der Roman erzählt in Form einer Ich-Erzählung die Lebensgeschichte von Jane Eyre (ausgesprochen /ˌdʒeɪn ˈɛə/), die nach einer schweren Kindheit eine Stelle als Gouvernante annimmt und sich in ihren Arbeitgeber verliebt, jedoch immer wieder um ihre Freiheit und Selbstbestimmung kämpfen muss. Als klein, dünn, blass, stets schlicht dunkel gekleidet und mit strengem Mittelscheitel beschrieben, gilt die Heldin des Romans Jane Eyre nicht zuletzt aufgrund der Kino- und Fernsehversionen der melodramatischen Romanvorlage als die bekannteste englische Gouvernante der Literaturgeschichte
|
||||||
252;de;Eleonora;“Eleonora” ist eine Erzählung von Edgar Allan Poe. Sie wurde 1841 erstveröffentlicht. In ihr geht es um das Paradox der Treue in der Treulosigkeit.
|
252;de;Eleonora;“Eleonora” ist eine Erzählung von Edgar Allan Poe. Sie wurde 1841 erstveröffentlicht. In ihr geht es um das Paradox der Treue in der Treulosigkeit.
|
||||||
|
5
packages/bookshop/db/data/sap.capire.bookshop-Orders.csv
Normal file
5
packages/bookshop/db/data/sap.capire.bookshop-Orders.csv
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ID;modifiedAt;createdAt;createdBy;modifiedBy;OrderNo;currency_code;status
|
||||||
|
da86efd0-4ba1-4078-b7f0-5c9c530297f7;;2019-01-31;ALICE;;1;EUR;processing
|
||||||
|
2f2f2640-6866-4dcf-8f4d-3027aa831cad;;2019-03-25;ALICE;;10;EUR;completed
|
||||||
|
64e718c9-ff99-47f1-8ca3-950c850777d4;;2019-01-30;BOB;;2;EUR;processing
|
||||||
|
1af3322d-3cb1-46be-b312-0ae9ec311537;;2019-03-16;BOB;;9;EUR;completed
|
||||||
|
7
packages/bookshop/db/data/sap.common-Currencies.csv
Normal file
7
packages/bookshop/db/data/sap.common-Currencies.csv
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
code;symbol;name;descr
|
||||||
|
EUR;€;Euro;European Euro
|
||||||
|
USD;$;US Dollar;United States Dollar
|
||||||
|
CAD;$;Canadian Dollar;Canadian Dollar
|
||||||
|
AUD;$;Australian Dollar;Australian Dollar
|
||||||
|
GBP;£;Pound;Great Britain Pound
|
||||||
|
ILS;₪;Shekel;Israeli New Shekel
|
||||||
|
50
packages/bookshop/db/schema.cds
Normal file
50
packages/bookshop/db/schema.cds
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
namespace sap.capire.bookshop;
|
||||||
|
|
||||||
|
using {
|
||||||
|
Currency,
|
||||||
|
managed,
|
||||||
|
cuid
|
||||||
|
} from '@sap/cds/common';
|
||||||
|
|
||||||
|
type Status : String enum {
|
||||||
|
completed;
|
||||||
|
processing;
|
||||||
|
blocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity Books : managed {
|
||||||
|
key ID : Integer;
|
||||||
|
title : localized String(111);
|
||||||
|
descr : localized String(1111);
|
||||||
|
author : Association to Authors;
|
||||||
|
stock : Integer;
|
||||||
|
price : Decimal(9, 2);
|
||||||
|
currency : Currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity Authors : managed {
|
||||||
|
key ID : Integer;
|
||||||
|
name : String(111);
|
||||||
|
dateOfBirth : Date;
|
||||||
|
dateOfDeath : Date;
|
||||||
|
placeOfBirth : String;
|
||||||
|
placeOfDeath : String;
|
||||||
|
books : Association to many Books
|
||||||
|
on books.author = $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity Orders : cuid, managed {
|
||||||
|
OrderNo : String @title : 'Order Number'; //> readable key
|
||||||
|
status : Status default 'processing';
|
||||||
|
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);
|
||||||
|
}
|
||||||
28
packages/bookshop/package.json
Normal file
28
packages/bookshop/package.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "@sap/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": {
|
||||||
|
"@sap/cds": "^3",
|
||||||
|
"express": "^4",
|
||||||
|
"@sap/xb-msg-amqp-v100": "^0.9.35"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sqlite3": "^4.1.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "npx cds run"
|
||||||
|
},
|
||||||
|
"cds": {
|
||||||
|
"requires": {
|
||||||
|
"API_BUSINESS_PARTNER": {
|
||||||
|
"kind": "odata",
|
||||||
|
"model": "srv/external/API_BUSINESS_PARTNER",
|
||||||
|
"--credentials": {
|
||||||
|
"destination": "cap-api098"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
packages/bookshop/srv/admin-service.cds
Normal file
16
packages/bookshop/srv/admin-service.cds
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable Fiori Draft for Orders
|
||||||
|
annotate AdminService.Orders with @odata.draft.enabled;
|
||||||
|
// annotate AdminService.Books with @odata.draft.enabled;
|
||||||
|
|
||||||
|
// Temporary workaround -> https://github.wdf.sap.corp/cap/issues/issues/3121
|
||||||
|
extend service AdminService with {
|
||||||
|
entity OrderItems as select from my.OrderItems;
|
||||||
|
}
|
||||||
22
packages/bookshop/srv/cat-service.cds
Normal file
22
packages/bookshop/srv/cat-service.cds
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using { sap.capire.bookshop as my } from '../db/schema';
|
||||||
|
using { API_BUSINESS_PARTNER as external } from './external/API_BUSINESS_PARTNER.csn';
|
||||||
|
|
||||||
|
@path:'/browse'
|
||||||
|
service CatalogService {
|
||||||
|
|
||||||
|
@readonly entity Books as SELECT from my.Books {*,
|
||||||
|
author.name as author
|
||||||
|
} excluding { createdBy, modifiedBy };
|
||||||
|
|
||||||
|
@readonly entity BusinessPartners as projection on external.A_BusinessPartner {
|
||||||
|
key BusinessPartner as ID,
|
||||||
|
FirstName,
|
||||||
|
MiddleName,
|
||||||
|
LastName,
|
||||||
|
BusinessPartnerIsBlocked
|
||||||
|
};
|
||||||
|
|
||||||
|
@requires_: 'authenticated-user'
|
||||||
|
@insertonly entity Orders as projection on my.Orders;
|
||||||
|
|
||||||
|
}
|
||||||
28
packages/bookshop/srv/cat-service.js
Normal file
28
packages/bookshop/srv/cat-service.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
const cds = require('@sap/cds')
|
||||||
|
|
||||||
|
/** Service implementation for CatalogService */
|
||||||
|
module.exports = cds.service.impl(async function () {
|
||||||
|
const { Books, Orders, BusinessPartners } = this.entities
|
||||||
|
const bupaSrv = await cds.connect.to('API_BUSINESS_PARTNER')
|
||||||
|
this.after('READ', Books, each => each.stock > 111 && _addDiscount2(each, 11))
|
||||||
|
this.before('CREATE', Orders, _reduceStock)
|
||||||
|
this.on('READ', BusinessPartners, req => bupaSrv.tx(req).run(req.query))
|
||||||
|
|
||||||
|
/** 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}`
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
2426
packages/bookshop/srv/external/API_BUSINESS_PARTNER.csn
vendored
Normal file
2426
packages/bookshop/srv/external/API_BUSINESS_PARTNER.csn
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3261
packages/bookshop/srv/external/API_BUSINESS_PARTNER.edmx
vendored
Normal file
3261
packages/bookshop/srv/external/API_BUSINESS_PARTNER.edmx
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
packages/bookshop/srv/external/data/API_BUSINESS_PARTNER-A_BusinessPartner.csv
vendored
Normal file
4
packages/bookshop/srv/external/data/API_BUSINESS_PARTNER-A_BusinessPartner.csv
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
BusinessPartner;FirstName;MiddleName;LastName;BusinessPartnerIsBlocked
|
||||||
|
ALICE;Alice;In;Wonderland;false
|
||||||
|
BOB;Bob;The;Builder;false
|
||||||
|
JABBA;Jabba;The;Hutt;true
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user