Adding suppliers showing integration with S/4
This commit is contained in:
@@ -3,9 +3,10 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capire/bookshop": "*",
|
"@capire/bookshop": "*",
|
||||||
"@capire/reviews": "*",
|
|
||||||
"@capire/orders": "*",
|
|
||||||
"@capire/common": "*",
|
"@capire/common": "*",
|
||||||
|
"@capire/orders": "*",
|
||||||
|
"@capire/reviews": "*",
|
||||||
|
"@capire/suppliers": "*",
|
||||||
"@sap/cds": "^4",
|
"@sap/cds": "^4",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"passport": "0.4.1"
|
"passport": "0.4.1"
|
||||||
@@ -16,6 +17,10 @@
|
|||||||
},
|
},
|
||||||
"cds": {
|
"cds": {
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"API_BUSINESS_PARTNER": {
|
||||||
|
"kind": "odata",
|
||||||
|
"model": "@capire/suppliers"
|
||||||
|
},
|
||||||
"ReviewsService": {
|
"ReviewsService": {
|
||||||
"kind": "odata", "model": "@capire/reviews"
|
"kind": "odata", "model": "@capire/reviews"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ cds.once('bootstrap',(app)=>{
|
|||||||
})
|
})
|
||||||
|
|
||||||
cds.once('served', require('./srv/mashup'))
|
cds.once('served', require('./srv/mashup'))
|
||||||
|
cds.once('served', require('@capire/suppliers/srv/mashup'))
|
||||||
|
|
||||||
module.exports = cds.server
|
module.exports = cds.server
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
"@capire/hello": "./hello",
|
"@capire/hello": "./hello",
|
||||||
"@capire/media": "./media",
|
"@capire/media": "./media",
|
||||||
"@capire/orders": "./orders",
|
"@capire/orders": "./orders",
|
||||||
"@capire/reviews": "./reviews"
|
"@capire/reviews": "./reviews",
|
||||||
|
"@capire/suppliers": "./suppliers"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
|
|||||||
12
samples.md
12
samples.md
@@ -49,14 +49,22 @@ Each sub directory essentially is an individual npm package arranged in an [all-
|
|||||||
- Late-cut Micro Services
|
- Late-cut Micro Services
|
||||||
- As well as managed data, input validations, and authorization
|
- As well as managed data, input validations, and authorization
|
||||||
|
|
||||||
|
## [@capire/suppliers](suppliers)
|
||||||
|
|
||||||
|
- Shows how to integrate remote services, in this case the BusinessPartner service from S/4.
|
||||||
|
- Extending [@capire/bookshop](bookshop) with suppliers from S/4
|
||||||
|
- Providing that as a pre-built integration & extension package
|
||||||
|
- Used in [@capire/fiori](fiori)
|
||||||
|
|
||||||
|
|
||||||
## [@capire/fiori](fiori)
|
## [@capire/fiori](fiori)
|
||||||
|
|
||||||
- A [composite app, reusing and combining](https://cap.cloud.sap/docs/guides/verticalize) these packages:
|
- A [composite app, reusing and combining](https://cap.cloud.sap/docs/guides/verticalize) these packages:
|
||||||
- [@capire/bookshop](bookshop)
|
- [@capire/bookshop](bookshop)
|
||||||
- [@capire/reviews](reviews)
|
|
||||||
- [@capire/orders](orders)
|
|
||||||
- [@capire/common](common)
|
- [@capire/common](common)
|
||||||
|
- [@capire/orders](orders)
|
||||||
|
- [@capire/reviews](reviews)
|
||||||
|
- [@capire/suppliers](suppliers)
|
||||||
- [Adds a SAP Fiori elements application](https://cap.cloud.sap/docs/guides/fiori/) to bookshop, thereby introducing to:
|
- [Adds a SAP Fiori elements application](https://cap.cloud.sap/docs/guides/fiori/) to bookshop, thereby introducing to:
|
||||||
- [OData Annotations](https://cap.cloud.sap/docs/guides/fiori#adding-odata-annotations) in `.cds` files
|
- [OData Annotations](https://cap.cloud.sap/docs/guides/fiori#adding-odata-annotations) in `.cds` files
|
||||||
- Support for [Fiori Draft](https://cap.cloud.sap/docs/guides/fiori#draft)
|
- Support for [Fiori Draft](https://cap.cloud.sap/docs/guides/fiori#draft)
|
||||||
|
|||||||
29
suppliers/.gitignore
vendored
Normal file
29
suppliers/.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# CAP demo
|
||||||
|
_out
|
||||||
|
*.db
|
||||||
|
connection.properties
|
||||||
|
default-*.json
|
||||||
|
gen/
|
||||||
|
node_modules/
|
||||||
|
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
|
||||||
20
suppliers/.vscode/extensions.json
vendored
Normal file
20
suppliers/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// 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": [
|
||||||
|
// >>>>>>>> Add CDS Editor here as soon it is available of vscode marketplace!,
|
||||||
|
"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": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
15
suppliers/.vscode/launch.json
vendored
Normal file
15
suppliers/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// 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": [
|
||||||
|
{
|
||||||
|
"command": "cds run --with-mocks --in-memory?",
|
||||||
|
"name": "cds run",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal",
|
||||||
|
"skipFiles": [ "<node_internals>/**" ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
7
suppliers/.vscode/settings.json
vendored
Normal file
7
suppliers/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.gitignore": true,
|
||||||
|
"**/.git": true,
|
||||||
|
"**/.vscode": true
|
||||||
|
}
|
||||||
|
}
|
||||||
25
suppliers/.vscode/tasks.json
vendored
Normal file
25
suppliers/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"label": "cds watch",
|
||||||
|
"command": "cds",
|
||||||
|
"args": ["watch"],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"label": "cds run",
|
||||||
|
"command": "cds",
|
||||||
|
"args": ["run", "--with-mocks", "--in-memory?"],
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1
suppliers/index.cds
Normal file
1
suppliers/index.cds
Normal file
@@ -0,0 +1 @@
|
|||||||
|
using from './srv/mashup';
|
||||||
24
suppliers/package.json
Normal file
24
suppliers/package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@capire/suppliers",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Shows integration with S/4, in turn provided as a reusable extension package to bookshop.",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@capire/common": "*",
|
||||||
|
"@sap/cds": "^4",
|
||||||
|
"express": "^4"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "cds run --in-memory?",
|
||||||
|
"watch": "cds watch",
|
||||||
|
"mocked-s4": "cds mock API_BUSINESS_PARTNER"
|
||||||
|
},
|
||||||
|
"cds": {
|
||||||
|
"requires": {
|
||||||
|
"API_BUSINESS_PARTNER": {
|
||||||
|
"kind": "odata",
|
||||||
|
"model": "srv/external/API_BUSINESS_PARTNER"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
suppliers/server.js
Normal file
3
suppliers/server.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const cds = require ('@sap/cds')
|
||||||
|
cds.once('served', require('./srv/mashup'))
|
||||||
|
module.exports = cds.server
|
||||||
2425
suppliers/srv/external/API_BUSINESS_PARTNER.csn
vendored
Normal file
2425
suppliers/srv/external/API_BUSINESS_PARTNER.csn
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3261
suppliers/srv/external/API_BUSINESS_PARTNER.edmx
vendored
Normal file
3261
suppliers/srv/external/API_BUSINESS_PARTNER.edmx
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
suppliers/srv/external/data/API_BUSINESS_PARTNER-A_BusinessPartner.csv
vendored
Normal file
7
suppliers/srv/external/data/API_BUSINESS_PARTNER-A_BusinessPartner.csv
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
BusinessPartner;BusinessPartnerFullName
|
||||||
|
ACME;A Company Making Everything
|
||||||
|
B4U;Books for You
|
||||||
|
S&C;Shakespeare & Co.
|
||||||
|
WSL;Waterstones
|
||||||
|
TLD;Thalia
|
||||||
|
PNG;Penguin Books
|
||||||
|
5
suppliers/srv/external/data/API_BUSINESS_PARTNER-Suppliers.csv
vendored
Normal file
5
suppliers/srv/external/data/API_BUSINESS_PARTNER-Suppliers.csv
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ID;name
|
||||||
|
ACME;A Company Making Everything
|
||||||
|
B4U;Books for You
|
||||||
|
S&C;Shakespeare & Co.
|
||||||
|
WSL;Waterstones
|
||||||
|
47
suppliers/srv/mashup.cds
Normal file
47
suppliers/srv/mashup.cds
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
Optionally add projections to external entities, to capture what
|
||||||
|
you actually want to use from there.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using { API_BUSINESS_PARTNER as S4 } from './external/API_BUSINESS_PARTNER.csn';
|
||||||
|
extend service S4 with {
|
||||||
|
entity Suppliers as projection on S4.A_BusinessPartner {
|
||||||
|
key BusinessPartner as ID,
|
||||||
|
BusinessPartnerFullName as name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can mashup entities from external services, or projections
|
||||||
|
thereof, with your project's own entities
|
||||||
|
*/
|
||||||
|
using { sap.capire.bookshop.Books } from '@capire/bookshop';
|
||||||
|
extend Books with {
|
||||||
|
supplier : Association to S4.Suppliers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can also expose external entities through your own services
|
||||||
|
For this to work, you need to delegate the respective calls
|
||||||
|
addressed to your services into calls to the external service.
|
||||||
|
*/
|
||||||
|
extend service AdminService with {
|
||||||
|
entity Suppliers as projection on S4.Suppliers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Optionally add a local persistence to keep replicas of external
|
||||||
|
entities to have data in fast access locally; much like a cache.
|
||||||
|
*/
|
||||||
|
annotate S4.Suppliers with @cds.persistence:{table,skip:false};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Having locally cached replicas also allows us to display supplier
|
||||||
|
data in lists of books, which otherwise would generate unwanted
|
||||||
|
traffic on S4 backends.
|
||||||
|
*/
|
||||||
|
extend projection CatalogService.ListOfBooks with {
|
||||||
|
supplier
|
||||||
|
}
|
||||||
52
suppliers/srv/mashup.js
Normal file
52
suppliers/srv/mashup.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Mashing up provided and required services...
|
||||||
|
//
|
||||||
|
module.exports = async()=>{ // called by server.js
|
||||||
|
|
||||||
|
if (!cds.services.AdminService) return //> mocking S4 service only
|
||||||
|
|
||||||
|
// Connect to services we want to mashup below...
|
||||||
|
const S4bupa = await cds.connect.to('API_BUSINESS_PARTNER') //> external S4 service
|
||||||
|
const admin = await cds.connect.to('AdminService') //> local domain service
|
||||||
|
const db = await cds.connect.to('db') //> our primary database
|
||||||
|
|
||||||
|
// Reflect CDS definition of the Suppliers entity
|
||||||
|
const { Suppliers } = S4bupa.entities
|
||||||
|
|
||||||
|
admin.prepend (()=>{
|
||||||
|
|
||||||
|
// Delegate Value Help reads for Suppliers to S4 backend
|
||||||
|
admin.on ('READ', 'Suppliers', async req => {
|
||||||
|
console.log ('>> delegating to S4 service...')
|
||||||
|
return await S4bupa.run(req.query)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Replicate Supplier data when Books are edited
|
||||||
|
admin.on (['CREATE','UPDATE'], 'Books', async (req,next) => {
|
||||||
|
let { supplier } = req.data
|
||||||
|
if (supplier) {
|
||||||
|
let cached = await db.exists (Suppliers, supplier)
|
||||||
|
if (!cached) await replicate (supplier,'initial')
|
||||||
|
}
|
||||||
|
return next()
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// Subscribe to changes in the S4 origin of Suppliers data
|
||||||
|
S4bupa.on ('BusinessPartner/Changed', async msg => {
|
||||||
|
let cached = await SELECT('ID').from (Suppliers)
|
||||||
|
.where ('ID in', msg.businessPartner.KEYS)
|
||||||
|
for (let each of cached) replicate (each)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Helper function to replicate Suppliers data
|
||||||
|
async function replicate (ID,_initial) {
|
||||||
|
let data = await S4bupa.read (Suppliers, ID)
|
||||||
|
if (_initial) return db.insert (data) .into (Suppliers)
|
||||||
|
else return db.update (Suppliers,ID) .with (data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user