Compare commits

..

1 Commits

Author SHA1 Message Date
nkaputnik
bbd09b1697 Simplified Extension Example 2021-05-26 11:55:16 +02:00
34 changed files with 10462 additions and 321 deletions

31
.gitignore vendored
View File

@@ -1,31 +0,0 @@
# CAP multitenancy
_out
*.db
connection.properties
default-*.json
gen/
node_modules/
target/
# Web IDE, App Studio
.che/
.gen/
# MTA
*_mta_build_tmp
*.mtar
mta_archives/
*mta-op*/
# Other
.DS_Store
*.orig
*.log
*.iml
*.flattened-pom.xml
*log*.txt
# IDEs
# .vscode
# .idea

View File

@@ -1,61 +1,44 @@
using {sap.capire.bookshop} from '_base/db/schema';
using {sap.capire.orders} from '_base/db/schema';
using from '_base/db/capire_common';
using {
cuid, managed, Country, sap.common.CodeList
} from '@sap/cds/common';
namespace Z_bookshop.extension;
// extend existing entity
extend orders.Orders with {
Z_Customer : Association to one Z_Customers;
Z_SalesRegion : Association to one Z_SalesRegion;
Z_priority : String @assert.range enum {high; medium; low} default 'medium';
Z_Remarks : Composition of many Z_Remarks on Z_Remarks.parent = $self;
}
// new entity - as association target
entity Z_Customers : cuid, managed
{
email : String;
firstName : String;
lastName : String;
creditCardNo : String;
dateOfBirth : Date;
status : String @assert.range enum {platinum; gold; silver; bronze} default 'bronze';
creditScore : Decimal @assert.range: [ 1.0, 100.0 ] default 50.0;
PostalAddresses : Composition of many Z_CustomerPostalAddresses on PostalAddresses.Customer = $self;
}
// new unique constraint (secondary index)
annotate Z_Customers with @assert.unique: { email: [ email ] }
{
email @mandatory; // mandatory check
}
// new entity - as composition target
entity Z_CustomerPostalAddresses : cuid, managed
{
Customer : Association to one Z_Customers;
description : String;
street : String;
town : String;
country : Country;
}
// new entity - as code list
entity Z_SalesRegion: CodeList {
key regionCode : String(11);
}
// new entity - as composition target
entity Z_Remarks : cuid, managed
{
parent : Association to one orders.Orders;
number : Integer;
remarksLine : String;
}
using {sap.capire.bookshop} from '_base/db/schema';
using {sap.capire.orders} from '_base/db/schema';
using from '_base/db/capire_common';
//using {Z_bookshop.fieldExtension as field} from './field_extension';
using {
cuid, managed, Country, sap.common.CodeList
} from '@sap/cds/common';
namespace Z_bookshop.assocExtension;
// extend existing entity
extend orders.Orders with {
Z_Customer : Association to one Z_Customers;
Z_SalesRegion : Association to one Z_SalesRegion;
}
// new entity - as association target
entity Z_Customers : cuid, managed
{
email : String;
firstName : String;
lastName : String;
creditCardNo : String;
dateOfBirth : Date;
status : String @assert.range enum {platinum; gold; silver; bronze} default 'bronze';
creditScore : Decimal @assert.range: [ 1.0, 100.0 ] default 50.0;
}
// new unique constraint (secondary index)
annotate Z_Customers with @assert.unique: { email: [ email ] }
{
email @mandatory; // mandatory check
}
// new entity - as code list
entity Z_SalesRegion: CodeList {
key regionCode : String(11);
}

41
db/comp_extension.cds_ Normal file
View File

@@ -0,0 +1,41 @@
using {sap.capire.bookshop} from '_base/db/schema';
using {sap.capire.orders} from '_base/db/schema';
using from '_base/db/capire_common';
using {Z_bookshop.assocExtension as assoc} from './assoc_extension';
using {
cuid, managed, Country, sap.common.CodeList
} from '@sap/cds/common';
namespace Z_bookshop.compExtension;
// extend existing entity
extend orders.Orders with {
Z_Remarks : Composition of many Z_Remarks on Z_Remarks.parent = $self;
}
// new entity - as composition target
entity Z_CustomerPostalAddresses : cuid, managed
{
Customer : Association to one assoc.Z_Customers;
description : String;
street : String;
town : String;
country : Country;
}
// new entity - as composition target
entity Z_Remarks : cuid, managed
{
parent : Association to one orders.Orders;
number : Integer;
remarksLine : String;
}
extend assoc.Z_Customers with {
PostalAddresses : Composition of many Z_CustomerPostalAddresses on PostalAddresses.Customer = $self;
}

View File

@@ -1,5 +1,5 @@
ID;modifiedAt;createdAt;createdBy;modifiedBy;Customer_ID;description;street;town;country_code
1e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-04-04;2019-01-31;admin@business.com;admin@business.com;8e2f2640-6866-4dcf-8f4d-3027aa831cad;Home;Hauptstrasse 11;Berlin;DE
24e718c9-ff99-47f1-8ca3-950c850777d4;2019-04-04;2019-01-30;admin@business.com;admin@business.com;74e718c9-ff99-47f1-8ca3-950c850777d4;Home;Main Street 22;London;GB
3e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-04-04;2019-01-31;admin@business.com;admin@business.com;8e2f2640-6866-4dcf-8f4d-3027aa831cad;Work;Siemensstrasse 21;Berlin;DE
44e718c9-ff99-47f1-8ca3-950c850777d4;2019-04-04;2019-01-30;admin@business.com;admin@business.com;74e718c9-ff99-47f1-8ca3-950c850777d4;Work;Work Street 34;London;GB
ID;modifiedAt;createdAt;createdBy;modifiedBy;Customer_ID;description;street;town;country_code
1e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-04-04;2019-01-31;admin@business.com;admin@business.com;8e2f2640-6866-4dcf-8f4d-3027aa831cad;Home;Hauptstrasse 11;Berlin;DE
24e718c9-ff99-47f1-8ca3-950c850777d4;2019-04-04;2019-01-30;admin@business.com;admin@business.com;74e718c9-ff99-47f1-8ca3-950c850777d4;Home;Main Street 22;London;GB
3e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-04-04;2019-01-31;admin@business.com;admin@business.com;8e2f2640-6866-4dcf-8f4d-3027aa831cad;Work;Siemensstrasse 21;Berlin;DE
44e718c9-ff99-47f1-8ca3-950c850777d4;2019-04-04;2019-01-30;admin@business.com;admin@business.com;74e718c9-ff99-47f1-8ca3-950c850777d4;Work;Work Street 34;London;GB

View File

@@ -1,3 +1,3 @@
ID;modifiedAt;createdAt;createdBy;modifiedBy;email;firstName;lastName;creditCardNo;dateOfBirth;status;creditScore
8e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-04-04;2019-01-31;admin@business.com;admin@business.com;john.doe@test.com;John;Doe;9977-6655-4433-2211;1970-01-01;gold;80.0
ID;modifiedAt;createdAt;createdBy;modifiedBy;email;firstName;lastName;creditCardNo;dateOfBirth;status;creditScore
8e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-04-04;2019-01-31;admin@business.com;admin@business.com;john.doe@test.com;John;Doe;9977-6655-4433-2211;1970-01-01;gold;80.0
74e718c9-ff99-47f1-8ca3-950c850777d4;2019-04-04;2019-01-30;admin@business.com;admin@business.com;jane.doe@sap.com;Jane;Doe;2211-3344-5566-7788;1980-11-11;platinum;100.0

View File

@@ -1,4 +1,4 @@
regionCode;name;descr
AMER;Americas;North, Central and South America
EMEA;Europe, the Middle East and Africa;Europe, the Middle East and Africa
regionCode;name;descr
AMER;Americas;North, Central and South America
EMEA;Europe, the Middle East and Africa;Europe, the Middle East and Africa
APJ;Asia Pacific and Japan;Asia Pacific and Japan

View File

@@ -1,3 +1,3 @@
ID;createdAt;createdBy;buyer;OrderNo;currency_code;Z_Customer_ID;Z_priority;Z_SalesRegion_regionCode
7e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-01-31;john.doe@test.com;john.doe@test.com;1;EUR;8e2f2640-6866-4dcf-8f4d-3027aa831cad;high;EMEA
64e718c9-ff99-47f1-8ca3-950c850777d4;2019-01-30;jane.doe@test.com;jane.doe@test.com;2;EUR;74e718c9-ff99-47f1-8ca3-950c850777d4;low;APJ
ID;createdAt;createdBy;buyer;OrderNo;currency_code;Z_orderInfo;Z_internalNo;Z_expectedDelivery;Z_priority;Z_discount;
7e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-01-31;john.doe@test.com;john.doe@test.com;1;EUR;Webshop order;202001;2019-03-31;high;5.0
64e718c9-ff99-47f1-8ca3-950c850777d4;2019-01-30;jane.doe@test.com;jane.doe@test.com;2;EUR;Walk in order;202002;2019-04-15;low;10.0
1 ID ID;createdAt;createdBy;buyer;OrderNo;currency_code;Z_orderInfo;Z_internalNo;Z_expectedDelivery;Z_priority;Z_discount; createdAt createdBy buyer OrderNo currency_code Z_Customer_ID Z_priority Z_SalesRegion_regionCode
2 7e2f2640-6866-4dcf-8f4d-3027aa831cad 7e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-01-31;john.doe@test.com;john.doe@test.com;1;EUR;Webshop order;202001;2019-03-31;high;5.0 2019-01-31 john.doe@test.com john.doe@test.com 1 EUR 8e2f2640-6866-4dcf-8f4d-3027aa831cad high EMEA
3 64e718c9-ff99-47f1-8ca3-950c850777d4 64e718c9-ff99-47f1-8ca3-950c850777d4;2019-01-30;jane.doe@test.com;jane.doe@test.com;2;EUR;Walk in order;202002;2019-04-15;low;10.0 2019-01-30 jane.doe@test.com jane.doe@test.com 2 EUR 74e718c9-ff99-47f1-8ca3-950c850777d4 low APJ

View File

@@ -0,0 +1,3 @@
ID;createdAt;createdBy;buyer;OrderNo;currency_code;Z_Customer_ID;Z_priority;Z_SalesRegion_regionCode
7e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-01-31;john.doe@test.com;john.doe@test.com;1;EUR;8e2f2640-6866-4dcf-8f4d-3027aa831cad;high;EMEA
64e718c9-ff99-47f1-8ca3-950c850777d4;2019-01-30;jane.doe@test.com;jane.doe@test.com;2;EUR;74e718c9-ff99-47f1-8ca3-950c850777d4;low;APJ

38
db/field_extension.cds Normal file
View File

@@ -0,0 +1,38 @@
using {sap.capire.bookshop} from '_base/db/schema';
using {sap.capire.orders} from '_base/db/schema';
using from '_base/db/capire_common';
using {
cuid,
managed,
Country,
sap.common.CodeList
} from '@sap/cds/common';
namespace Z_bookshop.fieldExtension;
// extend existing entity
extend orders.Orders with {
Z_orderInfo : String default 'Webshop order';
Z_internalNo : Integer; // uniqiue constraint
Z_expectedDelivery : Date; //mandatory
Z_priority : String
@assert.range enum {
high;
medium;
low
} default 'medium';
Z_discount : Decimal
@assert.range : [
0.0,
99.9
] default 0.0;
}
// new unique constraint (secondary index)
annotate orders.Orders with @assert.unique : {Z_internalNo : [Z_internalNo]} {
Z_expectedDelivery @mandatory; // mandatory check
}

1
gen/srv/.cfignore Normal file
View File

@@ -0,0 +1 @@
node_modules/

8
gen/srv/manifest.yml Normal file
View File

@@ -0,0 +1,8 @@
---
applications:
- name: multitenancy-srv
path: .
memory: 256M
buildpacks:
- nodejs_buildpack
services:

6
gen/srv/package.json Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "multitenancy",
"version": "0.1.0",
"description": "cds extension project",
"dependencies": {}
}

1302
gen/srv/srv/_i18n/i18n.json Normal file

File diff suppressed because it is too large Load Diff

6511
gen/srv/srv/csn.json Normal file

File diff suppressed because it is too large Load Diff

1302
node_modules/_base/_i18n/i18n.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

93
node_modules/_base/app/admin/fiori-service.cds generated vendored Normal file
View File

@@ -0,0 +1,93 @@
using { AdminService } from '../../db/schema';
////////////////////////////////////////////////////////////////////////////
//
// 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}
]
}
}
);
annotate AdminService.Authors with @(
UI: {
HeaderInfo: {
Description: {Value: lifetime}
},
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Books}', Target: 'books/@UI.LineItem'},
],
FieldGroup#Details: {
Data: [
{Value: placeOfBirth},
{Value: placeOfDeath},
{Value: dateOfBirth},
{Value: dateOfDeath},
{Value: age, Label: '{i18n>Age}'},
]
},
}
);
////////////////////////////////////////////////////////////
//
// 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;
}

50
node_modules/_base/app/browse/fiori-service.cds generated vendored Normal file
View File

@@ -0,0 +1,50 @@
using CatalogService from '../../srv/cat-service';
////////////////////////////////////////////////////////////////////////////
//
// Books Object Page
//
annotate CatalogService.Books with @(
UI: {
HeaderInfo: {
TypeName: 'Book',
TypeNamePlural: 'Books',
Description: {Value: author}
},
HeaderFacets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Description}', Target: '@UI.FieldGroup#Descr'},
],
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Price'},
],
FieldGroup#Descr: {
Data: [
{Value: descr},
]
},
FieldGroup#Price: {
Data: [
{Value: price},
{Value: currency.symbol, Label: '{i18n>Currency}'},
]
},
}
);
////////////////////////////////////////////////////////////////////////////
//
// Books Object Page
//
annotate CatalogService.Books with @(
UI: {
SelectionFields: [ ID, price, currency_code ],
LineItem: [
{Value: title},
{Value: author, Label:'{i18n>Author}'},
{Value: genre.name},
{Value: price},
{Value: currency.symbol, Label:' '},
]
},
);

257
node_modules/_base/app/common.cds generated vendored Normal file
View File

@@ -0,0 +1,257 @@
/*
Common Annotations shared by all apps
*/
using { sap.capire.bookshop as my } from '../db/schema';
using { sap.common } from '../db/capire_common';
////////////////////////////////////////////////////////////////////////////
//
// Books Lists
//
annotate my.Books with @(
Common.SemanticKey: [title],
UI: {
Identification: [{Value:title}],
SelectionFields: [ ID, author_ID, price, currency_code ],
LineItem: [
{Value: ID},
{Value: title},
{Value: author.name, Label:'{i18n>Author}'},
{Value: genre.name},
{Value: stock},
{Value: price},
{Value: currency.symbol, Label:' '},
]
}
) {
author @ValueList.entity:'Authors';
};
////////////////////////////////////////////////////////////////////////////
//
// Books Details
//
annotate my.Books with @(
UI: {
HeaderInfo: {
TypeName: '{i18n>Book}',
TypeNamePlural: '{i18n>Books}',
Title: {Value: title},
Description: {Value: author.name}
},
}
);
////////////////////////////////////////////////////////////////////////////
//
// Books Elements
//
annotate my.Books with {
ID @title:'{i18n>ID}' @UI.HiddenFilter;
title @title:'{i18n>Title}';
genre @title:'{i18n>Genre}' @Common: { Text: genre.name, TextArrangement: #TextOnly };
author @title:'{i18n>Author}' @Common: { Text: author.name, TextArrangement: #TextOnly };
price @title:'{i18n>Price}';
stock @title:'{i18n>Stock}';
descr @UI.MultiLineText;
}
////////////////////////////////////////////////////////////////////////////
//
// Genres List
//
annotate my.Genres with @(
Common.SemanticKey: [name],
UI: {
SelectionFields: [ name ],
LineItem:[
{Value: name},
{Value: parent.name, Label: 'Main Genre'},
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Genre Details
//
annotate my.Genres with @(
UI: {
Identification: [{Value:name}],
HeaderInfo: {
TypeName: '{i18n>Genre}',
TypeNamePlural: '{i18n>Genres}',
Title: {Value: name},
Description: {Value: ID}
},
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>SubGenres}', Target: 'children/@UI.LineItem'},
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Genres Elements
//
annotate my.Genres with {
ID @title: '{i18n>ID}';
name @title: '{i18n>Genre}';
}
////////////////////////////////////////////////////////////////////////////
//
// Authors List
//
annotate my.Authors with @(
Common.SemanticKey: [name],
UI: {
Identification: [{Value:name}],
SelectionFields: [ name ],
LineItem:[
{Value: ID},
{Value: name},
{Value: dateOfBirth},
{Value: dateOfDeath},
{Value: placeOfBirth},
{Value: placeOfDeath},
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Author Details
//
annotate my.Authors with @(
UI: {
HeaderInfo: {
TypeName: '{i18n>Author}',
TypeNamePlural: '{i18n>Authors}',
Title: {Value: name},
Description: {Value: dateOfBirth}
},
Facets: [
{$Type: 'UI.ReferenceFacet', Target: 'books/@UI.LineItem'},
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Authors Elements
//
annotate my.Authors with {
ID @title:'{i18n>ID}' @UI.HiddenFilter;
name @title:'{i18n>Name}';
dateOfBirth @title:'{i18n>DateOfBirth}';
dateOfDeath @title:'{i18n>DateOfDeath}';
placeOfBirth @title:'{i18n>PlaceOfBirth}';
placeOfDeath @title:'{i18n>PlaceOfDeath}';
}
////////////////////////////////////////////////////////////////////////////
//
// Languages List
//
annotate common.Languages with @(
Common.SemanticKey: [code],
Identification: [{Value:code}],
UI: {
SelectionFields: [ name, descr ],
LineItem:[
{Value: code},
{Value: name},
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Language Details
//
annotate common.Languages with @(
UI: {
HeaderInfo: {
TypeName: '{i18n>Language}',
TypeNamePlural: '{i18n>Languages}',
Title: {Value: name},
Description: {Value: descr}
},
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
],
FieldGroup#Details: {
Data: [
{Value: code},
{Value: name},
{Value: descr}
]
},
}
);
////////////////////////////////////////////////////////////////////////////
//
// Currencies List
//
annotate common.Currencies with @(
Common.SemanticKey: [code],
Identification: [{Value:code}],
UI: {
SelectionFields: [ name, descr ],
LineItem:[
{Value: descr},
{Value: symbol},
{Value: code},
],
}
);
////////////////////////////////////////////////////////////////////////////
//
// Currency Details
//
annotate common.Currencies with @(
UI: {
HeaderInfo: {
TypeName: '{i18n>Currency}',
TypeNamePlural: '{i18n>Currencies}',
Title: {Value: descr},
Description: {Value: code}
},
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Extended}', Target: '@UI.FieldGroup#Extended'},
],
FieldGroup#Details: {
Data: [
{Value: name},
{Value: symbol},
{Value: code},
{Value: descr}
]
},
FieldGroup#Extended: {
Data: [
{Value: numcode},
{Value: minor},
{Value: exponent}
]
},
}
);
////////////////////////////////////////////////////////////////////////////
//
// Currencies Elements
//
annotate common.Currencies with {
numcode @title:'{i18n>NumCode}';
minor @title:'{i18n>MinorUnit}';
exponent @title:'{i18n>Exponent}';
}

92
node_modules/_base/app/orders/fiori-service.cds generated vendored Normal file
View File

@@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////////////////////
//
// Note: this is designed for the OrdersService being co-located with
// bookshop. It does not work if OrdersService is run as a separate
// process, and is not intended to do so.
//
////////////////////////////////////////////////////////////////////////////
using { OrdersService } from '../../srv/orders-service';
@odata.draft.enabled
annotate OrdersService.Orders with @(
UI: {
SelectionFields: [ createdAt, createdBy ],
LineItem: [
{Value: OrderNo, Label:'OrderNo'},
{Value: buyer, Label:'Customer'},
{Value: createdAt, Label:'Date'}
],
HeaderInfo: {
TypeName: 'Order', TypeNamePlural: 'Orders',
Title: {
Label: 'Order number ', //A label is possible but it is not considered on the ObjectPage yet
Value: OrderNo
},
Description: {Value: createdBy}
},
Identification: [ //Is the main field group
{Value: createdBy, Label:'Customer'},
{Value: createdAt, Label:'Date'},
{Value: OrderNo },
],
HeaderFacets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Created}', Target: '@UI.FieldGroup#Created'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Modified}', Target: '@UI.FieldGroup#Modified'},
],
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>OrderItems}', Target: 'Items/@UI.LineItem'},
],
FieldGroup#Details: {
Data: [
{Value: currency.code, Label:'Currency'}
]
},
FieldGroup#Created: {
Data: [
{Value: createdBy},
{Value: createdAt},
]
},
FieldGroup#Modified: {
Data: [
{Value: modifiedBy},
{Value: modifiedAt},
]
},
},
) {
createdAt @UI.HiddenFilter:false;
createdBy @UI.HiddenFilter:false;
};
annotate OrdersService.Orders_Items with @(
UI: {
LineItem: [
{Value: product_ID, Label:'Product ID'},
{Value: title, Label:'Product Title'},
{Value: price, Label:'Unit Price'},
{Value: amount, Label:'Quantity'},
],
Identification: [ //Is the main field group
{Value: amount, Label:'Amount'},
{Value: title, Label:'Product'},
{Value: price, Label:'Unit Price'},
],
Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>OrderItems}', Target: '@UI.Identification'},
],
},
) {
amount @(
Common.FieldControl: #Mandatory
);
};

11
node_modules/_base/app/services.cds generated vendored Normal file
View File

@@ -0,0 +1,11 @@
/*
This model controls what gets served to Fiori frontends...
*/
using from './admin/fiori-service';
using from './browse/fiori-service';
using from './orders/fiori-service';
using from './common';
using from '../db/capire_common';

46
node_modules/_base/db/capire_common.cds generated vendored Normal file
View File

@@ -0,0 +1,46 @@
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;
}
}

4
node_modules/_base/db/schema.cds generated vendored Normal file
View File

@@ -0,0 +1,4 @@
using from './schema_bookshop';
using from './schema_orders';
annotate cds.UUID with @(Core.Computed : true);

31
node_modules/_base/db/schema_bookshop.cds generated vendored Normal file
View File

@@ -0,0 +1,31 @@
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;
currency : Currency;
image : LargeBinary @Core.MediaType : 'image/png';
}
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;
}

23
node_modules/_base/db/schema_orders.cds generated vendored Normal file
View File

@@ -0,0 +1,23 @@
using { Currency, User, managed, cuid } from '@sap/cds/common';
namespace sap.capire.orders;
entity Orders : cuid, managed {
OrderNo : String @title:'Order Number'; //> readable key
Items : Composition of many Orders_Items on Items.up_ = $self;
buyer : User;
currency : Currency;
}
entity Orders_Items {
key ID : UUID;
up_ : Association to Orders;
product : Association to Products @assert.integrity:false; // REVISIT: this is a temporary workaround for a glitch in cds-runtime
amount : Integer;
title : String; //> intentionally replicated as snapshot from product.title
price : Double;
}
/** This is a stand-in for arbitrary ordered Products */
entity Products @(cds.persistence.skip:'always') {
key ID : String;
}

135
node_modules/_base/node_modules/@sap/cds/common.cds generated vendored Normal file
View File

@@ -0,0 +1,135 @@
type Language : Association to sap.common.Languages;
type Currency : Association to sap.common.Currencies;
type Country : Association to sap.common.Countries;
/**
* Entities to serve the reuse types with extensible code lists
* including built-in support for value lists in Fiori.
*/
context sap.common {
entity Languages : CodeList {
key code : String(14) @(title : '{i18n>LanguageCode}');
//> length=14 is to accommodate values like these:
// en_US_x_saptrc - (1Q) used as a technical SAP language code
// en_US_x_sappsd - (2Q) used as a technical SAP language code
}
entity Countries : CodeList {
key code : String(3) @(title : '{i18n>CountryCode}');
}
entity Currencies : CodeList {
key code : String(3) @(title : '{i18n>CurrencyCode}');
symbol : String(5) @(title : '{i18n>CurrencySymbol}');
}
aspect CodeList @(
cds.autoexpose,
cds.persistence.skip : 'if-unused'
) {
name : localized String(255) @title : '{i18n>Name}';
descr : localized String(1000) @title : '{i18n>Description}';
}
}
/*
* Aspect for entities with canonical universal IDs.
*/
aspect cuid {
key ID : UUID; //> automatically filled in
}
/*
* Aspect to capture changes by user and name.
*/
aspect managed {
createdAt : Timestamp @cds.on.insert : $now;
createdBy : User @cds.on.insert : $user;
modifiedAt : Timestamp @cds.on.insert : $now @cds.on.update : $now;
modifiedBy : User @cds.on.insert : $user @cds.on.update : $user;
}
/*
* Aspects for entities with temporal data.
*/
aspect temporal {
validFrom : Timestamp @cds.valid.from;
validTo : Timestamp @cds.valid.to;
}
/**
* Canonical user ID
*/
type User : String(255);
//---------------------------------------------------------------------------
// Annotations for Fiori UIs...
annotate sap.common.CodeList with @UI.Identification : [{Value:name}];
annotate sap.common.CodeList with @cds.odata.valuelist;
annotate managed with {
createdAt @UI.HiddenFilter;
createdBy @UI.HiddenFilter;
modifiedAt @UI.HiddenFilter;
modifiedBy @UI.HiddenFilter;
}
annotate managed with {
createdAt @Core.Immutable;
createdBy @Core.Immutable;
}
annotate sap.common.Countries with { code @Common.Text:name; }
annotate sap.common.Currencies with { code @Common.Text:name; }
annotate sap.common.Languages with { code @Common.Text:name; }
//---------------------------------------------------------------------------
// Common Annotations...
annotate Language with @(
title : '{i18n>Language}',
description : '{i18n>LanguageCode.Description}'
);
annotate Currency with @(
title : '{i18n>Currency}',
description : '{i18n>CurrencyCode.Description}'
);
annotate Country with @(
title : '{i18n>Country}',
description : '{i18n>CountryCode.Description}'
);
annotate User with @(
title : '{i18n>UserID}',
description : '{i18n>UserID.Description}'
);
annotate managed with {
createdAt @title : '{i18n>CreatedAt}';
createdBy @title : '{i18n>CreatedBy}';
modifiedAt @title : '{i18n>ChangedAt}';
modifiedBy @title : '{i18n>ChangedBy}';
}
//---------------------------------------------------------------------------
// Temporary Workarounds...
// REVISIT: change @odata.on... to @cds.on...
// REVISIT: @cds.on... should automatically result in @readonly @Core.Computed
annotate managed with {
modifiedAt @readonly @odata.on.update : #now;
createdAt @readonly @odata.on.insert : #now;
createdBy @readonly @odata.on.insert : #user;
modifiedBy @readonly @odata.on.update : #user;
}
//---------------------------------------------------------------------------

7
node_modules/_base/srv/admin-service.cds generated vendored Normal file
View File

@@ -0,0 +1,7 @@
using { sap.capire.bookshop as my } from '../db/schema';
//service AdminService @(requires:'admin') {
service AdminService {
entity Books as projection on my.Books;
entity Authors as projection on my.Authors;
}

16
node_modules/_base/srv/cat-service.cds generated vendored Normal file
View File

@@ -0,0 +1,16 @@
using { sap.capire.bookshop as my } from '../db/schema';
service CatalogService @(path:'/browse') {
/** For displaying lists of Books */
@readonly entity ListOfBooks as projection on Books
excluding { descr };
/** For display in details pages */
@readonly entity Books as projection on my.Books { *,
author.name as author
} excluding { createdBy, modifiedBy };
//@__requires: 'authenticated-user'
action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer };
event OrderedBook : { book: Books:ID; amount: Integer; buyer: String };
}

27
node_modules/_base/srv/mashup.cds generated vendored Normal file
View File

@@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////////////////////
//
// Mashing up imported models...
//
using { sap.capire.bookshop.Books } from '../db/schema';
//
// Extend Books with access to Reviews and average ratings
//
/*
using { ReviewsService.Reviews } from '@capire/reviews';
extend Books with {
reviews : Composition of many Reviews on reviews.subject = $self.ID;
rating : Decimal;
}
*/
//
// Extend Orders with Books as Products
//
using { sap.capire.orders.Orders_Items } from '../db/schema';
extend Orders_Items with {
book : Association to Books on product.ID = book.ID
}

5
node_modules/_base/srv/orders-service.cds generated vendored Normal file
View File

@@ -0,0 +1,5 @@
using { sap.capire.orders as my } from '../db/schema';
service OrdersService {
entity Orders as projection on my.Orders;
}

View File

@@ -2,10 +2,5 @@ using from '_base/srv/admin-service';
using from '_base/srv/cat-service';
using from '_base/srv/orders-service';
using { Z_bookshop.extension as ext } from '../db/extension';
using from '../db/field_extension';
extend service OrdersService with {
entity Z_Customers as projection on ext.Z_Customers;
entity Z_SalesRegion as projection on ext.Z_SalesRegion;
}

View File

@@ -0,0 +1,14 @@
using from '_base/srv/admin-service';
using from '_base/srv/cat-service';
using from '_base/srv/orders-service';
using from '../db/field_extension';
using { Z_bookshop.compExtension as comp } from '../db/comp_extension';
using { Z_bookshop.assocExtension as assoc } from '../db/assoc_extension';
extend service OrdersService with {
entity Z_Customers as projection on assoc.Z_Customers;
entity Z_SalesRegion as projection on assoc.Z_SalesRegion;
}

View File

@@ -1,210 +0,0 @@
using from '_base/app/services';
using OrdersService from './extension_service';
// new entity -- draft enabled
annotate OrdersService.Z_Customers with @odata.draft.enabled;
// new entity -- titles
annotate OrdersService.Z_Customers with {
ID @(
UI.Hidden,
Common : {Text : email}
);
firstName @title : 'First Name';
lastName @title : 'Last Name';
email @title : 'Email';
creditCardNo @title : 'Credit Card No';
dateOfBirth @title : 'Date of Birth';
status @title : 'Status';
creditScore @title : 'Credit Score';
}
// new entity -- titles
annotate OrdersService.Z_CustomerPostalAddresses with {
ID @(
UI.Hidden,
Common : {Text : description}
);
description @title : 'Description';
street @title : 'Street';
town @title : 'Town';
country @title : 'Country';
}
// new entity -- titles
annotate OrdersService.Z_SalesRegion with {
regionCode @title: 'Region Code';
}
// new entity -- titles
annotate OrdersService.Z_Remarks with {
number @title: 'Remark Number';
remarksLine @title: 'Remark';
}
// new entity in service -- UI
annotate OrdersService.Z_Customers with @(UI : {
HeaderInfo : {
TypeName : 'Customer',
TypeNamePlural : 'Customers',
Title : {
$Type : 'UI.DataField',
Value : email
}
},
LineItem : [
{Value : firstName},
{Value : lastName},
{Value : email},
{Value : status},
{Value : creditScore}
],
Facets : [
{$Type: 'UI.ReferenceFacet', Label: 'Main', Target : '@UI.FieldGroup#Main'},
{$Type: 'UI.ReferenceFacet', Label: 'Customer Postal Addresses', Target: 'PostalAddresses/@UI.LineItem'}
],
FieldGroup #Main : {Data : [
{Value : firstName},
{Value : lastName},
{Value : email},
{Value : status},
{Value : creditScore}
]}
} ) ;
// new entity -- UI
annotate OrdersService.Z_CustomerPostalAddresses with @(UI : {
HeaderInfo : {
TypeName : 'CustomerPostalAddress',
TypeNamePlural : 'CustomerPostalAddresses',
Title : {
$Type : 'UI.DataField',
Value : description
}
},
LineItem : [
{Value : description},
{Value : street},
{Value : town},
{Value : country_code}
],
Facets : [
{$Type: 'UI.ReferenceFacet', Label: 'Main', Target : '@UI.FieldGroup#Main'}
],
FieldGroup #Main : {Data : [
{Value : description},
{Value : street},
{Value : town},
{Value : country_code}
]}
}, ) {
};
// new entity -- UI
annotate OrdersService.Z_SalesRegion with @(
UI: {
HeaderInfo: {
TypeName: 'Sales Region',
TypeNamePlural: 'Sales Regions',
Title : {
$Type : 'UI.DataField',
Value : regionCode
}
},
LineItem: [
{Value: regionCode},
{Value: name},
{Value: descr}
],
Facets: [
{$Type: 'UI.ReferenceFacet', Label: 'Main', Target: '@UI.FieldGroup#Main'}
],
FieldGroup#Main: {
Data: [
{Value: regionCode},
{Value: name},
{Value: descr}
]
}
},
) {
};
// new entity -- UI
annotate OrdersService.Z_Remarks with @(
UI: {
HeaderInfo: {
TypeName: 'Remark',
TypeNamePlural: 'Remarks',
Title : {
$Type : 'UI.DataField',
Value : number
}
},
LineItem: [
{Value: number},
{Value: remarksLine}
],
Facets: [
{$Type: 'UI.ReferenceFacet', Label: 'Main', Target: '@UI.FieldGroup#Main'}
],
FieldGroup#Main: {
Data: [
{Value: number},
{Value: remarksLine}
]
}
},
) {
};
// extend existing entity Orders with new extension fields and new composition
annotate OrdersService.Orders with @(
UI: {
LineItem: [...,
{Value: Z_Customer_ID, Label:'Customer'}, // extension field
{Value: Z_SalesRegion_regionCode, Label:'Sales Region'}, // extension field
{Value: Z_priority, Label:'Priority'}, // extension field
],
Facets: [...,
{$Type: 'UI.ReferenceFacet', Label: 'Remarks', Target: 'Z_Remarks/@UI.LineItem'} // new composition
],
FieldGroup#Details: {
Data: [...,
{Value: Z_Customer_ID, Label:'Customer'}, // extension field
{Value: Z_SalesRegion_regionCode, Label:'Sales Region'}, // extension field
{Value: Z_priority, Label:'Priority'} // extension field
]
}
}
);
// new field in existing service -- exchange ID with text
annotate OrdersService.Orders with {
Z_Customer @(
Common: {
//show email, not id for Customer in the context of Orders
Text: Z_Customer.email , TextArrangement: #TextOnly,
ValueList: {
Label: 'Customers',
CollectionPath: 'Z_Customers',
Parameters: [
{ $Type: 'Common.ValueListParameterInOut',
LocalDataProperty: Z_Customer_ID,
ValueListProperty: 'ID'
},
{ $Type: 'Common.ValueListParameterDisplayOnly',
ValueListProperty: 'email'
}
]
}
}
);
}

View File

@@ -0,0 +1,311 @@
using from '_base/app/services';
using OrdersService from './extension_service';
// new entity -- draft enabled
annotate OrdersService.Z_Customers with @odata.draft.enabled;
// new codelist entity -- draft enabled
annotate OrdersService.Z_SalesRegion with @odata.draft.enabled;
// new entity -- titles
annotate OrdersService.Z_Customers with {
ID @(
UI.Hidden,
Common : {Text : email}
);
firstName @title : 'First Name';
lastName @title : 'Last Name';
email @title : 'Email';
creditCardNo @title : 'Credit Card No';
dateOfBirth @title : 'Date of Birth';
status @title : 'Status';
creditScore @title : 'Credit Score';
}
// new entity -- titles
annotate OrdersService.Z_CustomerPostalAddresses with {
ID @(
UI.Hidden,
Common : {Text : description}
);
description @title : 'Description';
street @title : 'Street';
town @title : 'Town';
country @title : 'Country';
}
// new entity -- titles
annotate OrdersService.Z_SalesRegion with {
regionCode @title : 'Region Code';
}
// new entity -- titles
annotate OrdersService.Z_Remarks with {
number @title : 'Remark Number';
remarksLine @title : 'Remark';
}
// new entity in service -- UI
annotate OrdersService.Z_Customers with @(UI : {
HeaderInfo : {
TypeName : 'Customer',
TypeNamePlural : 'Customers',
Title : {
$Type : 'UI.DataField',
Value : email
}
},
LineItem : [
{Value : firstName},
{Value : lastName},
{Value : email},
{Value : status},
{Value : creditScore}
],
Facets : [
{
$Type : 'UI.ReferenceFacet',
Label : 'Main',
Target : '@UI.FieldGroup#Main'
},
{
$Type : 'UI.ReferenceFacet',
Label : 'Customer Postal Addresses',
Target : 'PostalAddresses/@UI.LineItem'
}
],
FieldGroup #Main : {Data : [
{Value : firstName},
{Value : lastName},
{Value : email},
{Value : status},
{Value : creditScore}
]}
});
// new entity -- UI
annotate OrdersService.Z_CustomerPostalAddresses with @(UI : {
HeaderInfo : {
TypeName : 'CustomerPostalAddress',
TypeNamePlural : 'CustomerPostalAddresses',
Title : {
$Type : 'UI.DataField',
Value : description
}
},
LineItem : [
{Value : description},
{Value : street},
{Value : town},
{Value : country_code}
],
Facets : [{
$Type : 'UI.ReferenceFacet',
Label : 'Main',
Target : '@UI.FieldGroup#Main'
}],
FieldGroup #Main : {Data : [
{Value : description},
{Value : street},
{Value : town},
{Value : country_code}
]}
}, ) {
};
// new entity -- UI
annotate OrdersService.Z_SalesRegion with @(UI : {
HeaderInfo : {
TypeName : 'Sales Region',
TypeNamePlural : 'Sales Regions',
Title : {
$Type : 'UI.DataField',
Value : regionCode
}
},
LineItem : [
{Value : regionCode},
{Value : name},
{Value : descr}
],
Facets : [{
$Type : 'UI.ReferenceFacet',
Label : 'Main',
Target : '@UI.FieldGroup#Main'
}],
FieldGroup #Main : {Data : [
{Value : regionCode},
{Value : name},
{Value : descr}
]}
}, ) {
};
// new entity -- UI
annotate OrdersService.Z_Remarks with @(UI : {
HeaderInfo : {
TypeName : 'Remark',
TypeNamePlural : 'Remarks',
Title : {
$Type : 'UI.DataField',
Value : number
}
},
LineItem : [
{Value : number},
{Value : remarksLine}
],
Facets : [{
$Type : 'UI.ReferenceFacet',
Label : 'Main',
Target : '@UI.FieldGroup#Main'
}],
FieldGroup #Main : {Data : [
{Value : number},
{Value : remarksLine}
]}
}, ) {
};
// extend existing entity Orders with new extension fields and new composition
@odata.draft.enabled
annotate OrdersService.Orders with @(UI : {
SelectionFields : [
createdAt,
createdBy
],
LineItem : [
{
Value : OrderNo,
Label : 'OrderNo'
},
{
Value : Z_Customer_ID,
Label : 'Customer'
}, // extension field
{
Value : Z_SalesRegion_regionCode,
Label : 'Sales Region'
}, // extension field
{
Value : Z_priority,
Label : 'Priority'
}, // extension field
{
Value : createdAt,
Label : 'Date'
}
],
HeaderInfo : {
TypeName : 'Order',
TypeNamePlural : 'Orders',
Title : {
Label : 'Order number ', //A label is possible but it is not considered on the ObjectPage yet
Value : OrderNo
},
Description : {Value : createdBy}
},
Identification : [ //Is the main field group
{
Value : createdBy,
Label : 'Customer'
},
{
Value : createdAt,
Label : 'Date'
},
{Value : OrderNo},
],
HeaderFacets : [
{
$Type : 'UI.ReferenceFacet',
Label : '{i18n>Created}',
Target : '@UI.FieldGroup#Created'
},
{
$Type : 'UI.ReferenceFacet',
Label : '{i18n>Modified}',
Target : '@UI.FieldGroup#Modified'
},
],
Facets : [
{
$Type : 'UI.ReferenceFacet',
Label : '{i18n>Details}',
Target : '@UI.FieldGroup#Details'
},
{
$Type : 'UI.ReferenceFacet',
Label : '{i18n>OrderItems}',
Target : 'Items/@UI.LineItem'
},
{
$Type : 'UI.ReferenceFacet',
Label : 'Remarks',
Target : 'Z_Remarks/@UI.LineItem'
} // new composition
],
FieldGroup #Details : {Data : [
{
Value : currency_code,
Label : 'Currency'
},
{
Value : Z_Customer_ID,
Label : 'Customer'
}, // extension field
{
Value : Z_SalesRegion_regionCode,
Label : 'Sales Region'
}, // extension field
{
Value : Z_priority,
Label : 'Priority'
} // extension field
]},
FieldGroup #Created : {Data : [
{Value : createdBy},
{Value : createdAt},
]},
FieldGroup #Modified : {Data : [
{Value : modifiedBy},
{Value : modifiedAt},
]},
}, )
{
createdAt @UI.HiddenFilter : false;
createdBy @UI.HiddenFilter : false;
};
// new field in existing service -- exchange ID with text
annotate OrdersService.Orders with {
Z_Customer @(Common : {
//show email, not id for Customer in the context of Orders
Text : Z_Customer.email,
TextArrangement : #TextOnly,
ValueList : {
Label : 'Customers',
CollectionPath : 'Z_Customers',
Parameters : [
{
$Type : 'Common.ValueListParameterInOut',
LocalDataProperty : Z_Customer_ID,
ValueListProperty : 'ID'
},
{
$Type : 'Common.ValueListParameterDisplayOnly',
ValueListProperty : 'email'
}
]
}
});
}

View File

@@ -0,0 +1,70 @@
using from '_base/app/services';
using OrdersService from './extension_service';
// extend existing entity Orders with new extension fields and new composition
@odata.draft.enabled
annotate OrdersService.Orders with @(UI : {
LineItem : [
{
Value : OrderNo,
Label : 'OrderNo'
},
{
Value : Z_orderInfo,
Label : 'Additional Information'
}, // extension field
{
Value : Z_internalNo,
Label : 'Internal Order Number'
}, // extension field
{
Value : Z_expectedDelivery,
Label : 'Expecxted Delivery Date'
}, // extension field
{
Value : Z_priority,
Label : 'Priority'
}, // extension field
{
Value : Z_discount,
Label : 'Discount'
}, // extension field
{
Value : createdAt,
Label : 'Date'
},
],
FieldGroup #Details : {Data : [
{
Value : currency_code,
Label : 'Currency'
},
{
Value : Z_orderInfo,
Label : 'Additional Information'
}, // extension field
{
Value : Z_internalNo,
Label : 'Internal Order Number'
}, // extension field
{
Value : Z_expectedDelivery,
Label : 'Expected Delivery Date'
}, // extension field
{
Value : Z_priority,
Label : 'Priority'
}, // extension field
{
Value : Z_discount,
Label : 'Discount'
}, // extension field
]},
})
{
createdAt @UI.HiddenFilter : false;
createdBy @UI.HiddenFilter : false;
};